root/unix/thread_api_traits_impl.hpp

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. get_current_process_id
  2. get_current_thread_id
  3. get_current_thread
  4. demangle_name
  5. gen_backtrace
  6. SIG_to_string
  7. abort_handler
  8. set_backtrace_on_signal
  9. dump_bt_to_cerr
  10. set_backtrace_on_terminate
  11. create
  12. suspend
  13. resume
  14. state
  15. exit
  16. terminate
  17. cleanup
  18. set_kernel_priority
  19. set_kernel_affinity
  20. get_kernel_affinity
  21. get_kernel_priority
  22. set_cancelstate
  23. sleep
  24. wait_thread_exit
  25. create
  26. suspend
  27. resume
  28. state
  29. is_running
  30. exit
  31. terminate
  32. cleanup
  33. set_kernel_priority
  34. get_kernel_priority
  35. get_current_process_id
  36. get_current_thread_id
  37. get_current_thread
  38. set_kernel_affinity
  39. get_kernel_affinity
  40. set_cancelstate
  41. sleep
  42. wait_thread_exit
  43. demangle_name
  44. gen_backtrace
  45. set_backtrace_on_signal
  46. set_backtrace_on_terminate

   1 /******************************************************************************
   2 ** $Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/unix/thread_api_traits_impl.hpp 2288 2018-06-25 17:15:01Z jmmcg $
   3 **
   4 ** Copyright (c) 2004 by J.M.McGuiness, coder@hussar.me.uk
   5 **
   6 ** This library is free software; you can redistribute it and/or
   7 ** modify it under the terms of the GNU Lesser General Public
   8 ** License as published by the Free Software Foundation; either
   9 ** version 2.1 of the License, or (at your option) any later version.
  10 **
  11 ** This library is distributed in the hope that it will be useful,
  12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14 ** Lesser General Public License for more details.
  15 **
  16 ** You should have received a copy of the GNU Lesser General Public
  17 ** License along with this library; if not, write to the Free Software
  18 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19 */
  20 
  21 #include "../core/deleter.hpp"
  22 
  23 #include <cxxabi.h>
  24 #include <execinfo.h>
  25 #include <signal.h>
  26 
  27 namespace jmmcg { namespace ppd {
  28 
  29 // Implementation details..... Don't look below here!!! ;)
  30 
  31 //      "api_threading_traits" implementation...
  32 
  33         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::api_params_type::pid_type __fastcall
  34         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::get_current_process_id() noexcept(true) {
  35                 return getpid();
  36         }
  37 
  38         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::api_params_type::tid_type __fastcall
  39         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::get_current_thread_id() noexcept(true) {
  40                 return pthread_self();
  41         }
  42 
  43         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::api_params_type::handle_type __fastcall
  44         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::get_current_thread() noexcept(true) {
  45                 return pthread_self();
  46         }
  47 
  48         template<> inline void __fastcall
  49         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::demangle_name(char * const mangled_name, demangled_name_t &demangled_name) noexcept(true) {
  50                 // Find the beginning and the end of the useful part of the trace.
  51                 char *begin=strchr(mangled_name, '(');
  52                 if (begin) {
  53                         ++begin;
  54                 }
  55                 char *end=strrchr(mangled_name, '+');
  56                 // If they were found, we'll go ahead and demangle.
  57                 if (begin && end) {
  58                         *end='\0';
  59                         int demangleStatus=-1;
  60                         size_t length=sizeof(demangled_name_t);
  61                         // The demangled name is now in our trace string.
  62                         const char *ret=abi::__cxa_demangle(begin, demangled_name, &length, &demangleStatus);
  63                         if (ret!=demangled_name || demangleStatus!=0) {
  64                                 ::strcpy(demangled_name, begin);
  65                         }
  66                 }
  67         }
  68         /**
  69                 Implementation blagged from:
  70                 <a href="http://stackoverflow.com/questions/1274036/generating-c-backtraces-in-os-x-10-5-7"/>
  71         */
  72         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::demangled_names_t __fastcall
  73         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::gen_backtrace() noexcept(true) {
  74 
  75                 void *buffer[max_num_fn_ptrs];
  76                 const int num_fn_ptrs_ret=::backtrace(buffer, max_num_fn_ptrs);
  77                 const free_ptr<char **> fn_strings(::backtrace_symbols(buffer, num_fn_ptrs_ret));
  78                 if (fn_strings.ptr==NULL) {
  79                         JMMCG_TRACE(_T("backtrace_symbols() failure."));
  80                 }
  81                 demangled_names_t demangled_names;
  82                 demangled_names[0]='\0';
  83                 demangled_names_t::iterator demangled_ptr=demangled_names.begin();
  84                 for (int j=0; j<num_fn_ptrs_ret; ++j) {
  85                         demangled_name_t demangled_name;
  86                         demangled_name[0]='\0';
  87                         demangle_name(fn_strings.ptr[j], demangled_name);
  88                         ::strcpy(demangled_ptr, demangled_name);
  89                         demangled_ptr+=strlen(demangled_name);
  90                         *demangled_ptr='\n';
  91                         ++demangled_ptr;
  92                 }
  93                 *demangled_ptr='\0';
  94                 return demangled_names;
  95         }
  96 
  97         inline char const * SIG_to_string(int signal_number) noexcept(true) {
  98                 static char const * const signal_names[]={
  99                         "SIGILL /* Illegal instruction (ANSI).  */",
 100                         "SIGABRT /* Abort (ANSI).  */",
 101                         "SIGBUS /* BUS error (4.2 BSD).  */",
 102                         "SIGFPE /* Floating-point exception (ANSI).  */",
 103                         "SIGSEGV /* Segmentation violation (ANSI).  */",
 104                         "SIGSTKFLT /* Stack fault.  */",
 105                         "SIGSYS /* Bad system call.  */",
 106                         "unknown"
 107                 };
 108                 switch (signal_number) {
 109                 case SIGILL:
 110                         return signal_names[0];
 111                 case SIGABRT:
 112                         return signal_names[1];
 113                 case SIGBUS:
 114                         return signal_names[2];
 115                 case SIGFPE:
 116                         return signal_names[3];
 117                 case SIGSEGV:
 118                         return signal_names[4];
 119                 case SIGSTKFLT:
 120                         return signal_names[5];
 121                 case SIGSYS:
 122                         return signal_names[6];
 123                 default:
 124                         return signal_names[7];
 125                 };
 126         }
 127 
 128         inline std::ostream &
 129         operator<<(std::ostream &os, siginfo_t const &si) noexcept(true) {
 130                 os
 131                         <<"Signal number=0x"<<std::hex<<si.si_signo
 132                         <<", "<<TStringToString(dump_crt_errno(si.si_errno))
 133                         <<", signal code=0x"<<std::hex<<si.si_code;
 134                 return os;
 135         }
 136 
 137         extern "C" inline void abort_handler(int signal_number, siginfo_t *info, void */*context*/) noexcept(true) {
 138                 try {
 139 // TODO output some useful info to the user:                    ucontext_t const *cxt=reinterpret_cast<ucontext_t const *>(context);
 140                         std::cerr<<"Signal trapped=0x"<<std::hex<<signal_number<<_T(", ")<<SIG_to_string(signal_number)<<std::endl
 141                                 <<*info<<std::endl
 142                                 <<api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::gen_backtrace().begin()<<std::endl;
 143                 } catch (...) {
 144                         std::cerr<<"Error with backtracing..."<<std::endl;
 145                 }
 146                 ::abort();
 147         }
 148 
 149         template<> inline void __fastcall
 150         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::set_backtrace_on_signal() noexcept(true) {
 151                 struct sigaction new_sa;
 152                 sigemptyset(&new_sa.sa_mask);
 153                 new_sa.sa_handler=nullptr;
 154                 new_sa.sa_sigaction=abort_handler;
 155                 new_sa.sa_flags=0;
 156                 new_sa.sa_flags&=SA_SIGINFO;
 157                 [[maybe_unused]] int ret=sigaction(SIGABRT, &new_sa, 0);
 158                 assert(ret==0);
 159                 ret=sigaction(SIGILL, &new_sa, 0);
 160                 assert(ret==0);
 161                 ret=sigaction(SIGTRAP, &new_sa, 0);
 162                 assert(ret==0);
 163                 ret=sigaction(SIGABRT, &new_sa, 0);
 164                 assert(ret==0);
 165                 ret=sigaction(SIGBUS, &new_sa, 0);
 166                 assert(ret==0);
 167                 ret=sigaction(SIGFPE, &new_sa, 0);
 168                 assert(ret==0);
 169                 ret=sigaction(SIGSEGV, &new_sa, 0);
 170                 assert(ret==0);
 171                 ret=sigaction(SIGSTKFLT, &new_sa, 0);
 172                 assert(ret==0);
 173                 ret=sigaction(SIGSYS, &new_sa, 0);
 174                 assert(ret==0);
 175         }
 176 
 177         inline void dump_bt_to_cerr() {
 178                 auto const &bt=api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::gen_backtrace();
 179                 std::cerr<<bt.begin()<<std::endl;
 180         }
 181 
 182         template<> inline void __fastcall
 183         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::set_backtrace_on_terminate() noexcept(true) {
 184                 std::set_terminate(&dump_bt_to_cerr);
 185         }
 186 
 187         /// Run the work only once if it returns at all, unlike the multi-threaded variant.
 188         /**
 189                 If the worker_fn() returns true then it will run once, then exit, otherwise it will depend upon the return value for pre_exit() & post_exit(). If this always returns false, then the system will enter an infinite loop. By default pre_exit() & post_exit() for sequential mode returns false.
 190 
 191                 \see worker_fn(), pre_exit(), post_exit(), process()
 192         */
 193         template<> inline bool __fastcall
 194         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::create(const api_params_type::creation_flags creflag, api_params_type &parms) noexcept(true) {
 195                 parms.id=get_current_thread_id();
 196                 assert(parms.work_fn);
 197                 if (creflag==api_params_type::create_running) {
 198                         (*parms.work_fn)(parms.arglist);
 199                 }
 200                 return true;
 201         }
 202 
 203         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::api_params_type::suspend_count __fastcall
 204         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::suspend(api_params_type const &) noexcept(true) {
 205                 return static_cast<api_params_type::suspend_count>(0);
 206         }
 207 
 208         /// This does not run the work at all, unlike the multi-threaded variant.
 209         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::api_params_type::suspend_count __fastcall
 210         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::resume(api_params_type const &parms) noexcept(true) {
 211                 (*parms.work_fn)(parms.arglist);
 212                 return static_cast<api_params_type::suspend_count>(0);
 213         }
 214 
 215         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::api_params_type::states __fastcall
 216         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::state(api_params_type &) noexcept(true) {
 217                 return static_cast<api_params_type::states>(api_params_type::no_kernel_thread);
 218         }
 219 
 220         template<> inline void __fastcall
 221         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::exit(api_params_type::states &) noexcept(true) {
 222         }
 223 
 224         template<> inline void __fastcall
 225         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::terminate(api_params_type::handle_type) noexcept(false) {
 226         }
 227 
 228         template<> inline void __fastcall
 229         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::cleanup(api_params_type::handle_type) noexcept(false) {
 230         }
 231 
 232         template<> inline void __fastcall
 233         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::set_kernel_priority(api_params_type::handle_type, const api_params_type::priority_type) noexcept(false) {
 234         }
 235 
 236         template<> inline void __fastcall
 237         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::set_kernel_affinity(typename api_params_type::handle_type const, const api_params_type::processor_mask_type) noexcept(false) {
 238         }
 239 
 240         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::api_params_type::processor_mask_type __fastcall
 241         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::get_kernel_affinity(typename api_params_type::handle_type const) noexcept(false) {
 242                 return api_params_type::processor_mask_type();
 243         }
 244 
 245         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::api_params_type::priority_type __fastcall
 246         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::get_kernel_priority(api_params_type::handle_type) noexcept(false) {
 247                 return api_params_type::normal;
 248         }
 249 
 250         template<> inline void __fastcall
 251         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::set_cancelstate(api_params_type::thread_cancel_state) noexcept(false) {
 252         }
 253 
 254         template<> inline void __fastcall
 255         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::sleep(const api_params_type::suspend_period_ms) noexcept(false) {
 256         }
 257 
 258         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::api_params_type::states __fastcall
 259         api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::wait_thread_exit(api_params_type &, const lock_traits::timeout_type) noexcept(false) {
 260                 return api_params_type::no_kernel_thread;
 261         }
 262 
 263         template<> inline bool
 264         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::create(const api_params_type::creation_flags, api_params_type &cp) noexcept(true) {
 265                 assert(cp.work_fn);
 266                 assert(cp.arglist);
 267                 const int ret=pthread_create(&cp.id, static_cast<const pthread_attr_t *>(cp.initflag), cp.work_fn, cp.arglist);
 268                 assert(ret==0 && cp.id!=0);
 269                 return !static_cast<bool>(ret);
 270         }
 271 
 272         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::api_params_type::suspend_count
 273         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::suspend(api_params_type const &) noexcept(true) {
 274                 return static_cast<api_params_type::suspend_count>(0); // TODO JMG: can't suspend one thread from another...
 275         }
 276 
 277         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::api_params_type::suspend_count
 278         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::resume(api_params_type const &) noexcept(true) {
 279                 return static_cast<api_params_type::suspend_count>(0); // TODO JMG: can't suspend one thread from another...
 280         }
 281 
 282         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::api_params_type::states
 283         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::state(api_params_type &thread) noexcept(true) {
 284                 if (thread.state!=api_params_type::no_kernel_thread) {
 285                         api_params_type::states exit_code=api_params_type::unknown;
 286                         const int ret=pthread_tryjoin_np(thread.id, reinterpret_cast<void **>(&exit_code));
 287                         thread.state=static_cast<api_params_type::states>(exit_code);
 288                         switch (ret) {
 289                         case 0:
 290                                 thread.id=0;
 291                                 if (!thread.state) {
 292                                         thread.state=api_params_type::no_kernel_thread;
 293                                 } else if (thread.state==static_cast<api_params_type::states>(reinterpret_cast<long>(PTHREAD_CANCELED))) {
 294                                         thread.state=api_params_type::cancelled;
 295                                 }
 296                                 break;
 297                         case EDEADLK:
 298                                 thread.state=api_params_type::deadlocked_with_another_thread;
 299                                 break;
 300                         case EINVAL:
 301                                 thread.state=api_params_type::invalid_thread;
 302                                 break;
 303                         case ESRCH:
 304                                 thread.state=api_params_type::thread_id_not_found;
 305                                 break;
 306                         case EBUSY:
 307                                 thread.state=api_params_type::active;
 308                                 break;
 309                         default:
 310                                 thread.state=api_params_type::get_exit_code_failure;
 311                         }
 312                         return thread.state;
 313                 } else {
 314                         return thread.state;
 315                 }
 316         }
 317 
 318         template<> inline bool __fastcall
 319         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::is_running(api_params_type &thread) noexcept(true) {
 320                 api_params_type::states const st=state(thread);
 321                 return st==api_params_type::active || st==api_params_type::deadlocked_with_another_thread;
 322         }
 323 
 324         template<> inline void
 325         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::exit(api_params_type::states &exit_code) noexcept(true) {
 326                 pthread_exit(static_cast<void *>(&exit_code));
 327         }
 328 
 329         template<> inline void
 330         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::terminate(api_params_type::handle_type thread) noexcept(false) {
 331                 assert(thread);
 332                 const int pth_err=pthread_cancel(thread);
 333                 if (pth_err) {
 334                         assert(pth_err==ESRCH);
 335                         info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(void), info::function::argument(_T("api_params_type::handle_type thread"), tostring(thread)));
 336                         fun.add_arg(info::function::argument(_T("Return code"), tostring(pth_err)));
 337                         throw lock_traits::exception_type(_T("Could not send a cancel request to the thread."), fun, JMMCG_REVISION_HDR(_T("$Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/unix/thread_api_traits_impl.hpp 2288 2018-06-25 17:15:01Z jmmcg $")));
 338                 }
 339         }
 340 
 341         template<> inline void
 342         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::cleanup(api_params_type::handle_type thread) noexcept(false) {
 343                 if (thread) {
 344                         void *exit_code_p=reinterpret_cast<void *>(api_params_type::unknown);
 345                         const int pth_err=pthread_join(thread, &exit_code_p);
 346                         const api_params_type::states exit_code=static_cast<api_params_type::states>(reinterpret_cast<long>(exit_code_p));
 347                         if (pth_err) {
 348                                 info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(void), info::function::argument(_T("api_params_type::handle_type thread"), tostring(thread)));
 349                                 fun.add_arg(info::function::argument(_T("Return code"), tostring(pth_err)));
 350                                 fun.add_arg(info::function::argument(_T("Return code from thread"), tostring(exit_code)));
 351                                 throw lock_traits::exception_type(_T("Could not join with the requested thread."), fun, JMMCG_REVISION_HDR(_T("$Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/unix/thread_api_traits_impl.hpp 2288 2018-06-25 17:15:01Z jmmcg $")));
 352                         }
 353                 }
 354         }
 355 
 356         template<> inline void
 357         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::set_kernel_priority(api_params_type::handle_type, const api_params_type::priority_type priority) noexcept(false) {
 358                 // Note that this affects the entire process & all threads within it.
 359                 const int schedule_policy=sched_getscheduler(0);
 360                 if (schedule_policy!=-1) {
 361                         const int max_priority=sched_get_priority_max(schedule_policy);
 362                         const int min_priority=sched_get_priority_min(schedule_policy);
 363                         if ((max_priority!=-1) && (min_priority!=-1)) {
 364                                 sched_param param;
 365                                 int err=sched_getparam(0, &param);
 366                                 if (err!=-1) {
 367                                         const int checked_priority=(std::min(std::max(static_cast<int>(priority), min_priority), max_priority));
 368                                         param.sched_priority=checked_priority;
 369                                         err=sched_setparam(0, &param);
 370                                         if (err!=-1) {
 371                                                 return;
 372                                         } else {
 373                                                 throw lock_traits::exception_type(_T("Failed to set the new priority."), info::function(__LINE__, __PRETTY_FUNCTION__, typeid(void), info::function::argument(_T("api_params_type::priority_type priority"), tostring(priority))), JMMCG_REVISION_HDR(_T("$Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/unix/thread_api_traits_impl.hpp 2288 2018-06-25 17:15:01Z jmmcg $")));
 374                                         }
 375                                 } else {
 376                                         throw lock_traits::exception_type(_T("Failed to get the existing scheduler details."), info::function(__LINE__, __PRETTY_FUNCTION__, typeid(void), info::function::argument(_T("api_params_type::priority_type priority"), tostring(priority))), JMMCG_REVISION_HDR(_T("$Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/unix/thread_api_traits_impl.hpp 2288 2018-06-25 17:15:01Z jmmcg $")));
 377                                 }
 378                         } else {
 379                                 throw lock_traits::exception_type(_T("Failed to get the max & min priorities of the scheduler."), info::function(__LINE__, __PRETTY_FUNCTION__, typeid(void), info::function::argument(_T("api_params_type::priority_type priority"), tostring(priority))), JMMCG_REVISION_HDR(_T("$Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/unix/thread_api_traits_impl.hpp 2288 2018-06-25 17:15:01Z jmmcg $")));
 380                         }
 381                 } else {
 382                         throw lock_traits::exception_type(_T("Failed to get the type of scheduler in use."), info::function(__LINE__, __PRETTY_FUNCTION__, typeid(void), info::function::argument(_T("api_params_type::priority_type priority"), tostring(priority))), JMMCG_REVISION_HDR(_T("$Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/unix/thread_api_traits_impl.hpp 2288 2018-06-25 17:15:01Z jmmcg $")));
 383                 }
 384         }
 385 
 386         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::api_params_type::priority_type
 387         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::get_kernel_priority(api_params_type::handle_type thread) noexcept(false) {
 388                 sched_param param;
 389                 const int err=sched_getparam(0, &param);
 390                 if (err!=-1) {
 391                         return static_cast<api_params_type::priority_type>(param.sched_priority);
 392                 } else {
 393                         info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(void), info::function::argument(_T("typename api_params_type::handle_type thread"), tostring(thread)));
 394                         fun.add_arg(info::function::argument(_T("Return code"), tostring(err)));
 395                         throw lock_traits::exception_type(_T("Could not get the kernel priority of the specified thread."), fun, JMMCG_REVISION_HDR(_T("$Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/unix/thread_api_traits_impl.hpp 2288 2018-06-25 17:15:01Z jmmcg $")));
 396                 }
 397         }
 398 
 399         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::api_params_type::pid_type
 400         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::get_current_process_id() noexcept(true) {
 401                 return getpid();
 402         }
 403 
 404         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::api_params_type::tid_type
 405         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::get_current_thread_id() noexcept(true) {
 406                 return pthread_self();
 407         }
 408 
 409         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::api_params_type::handle_type
 410         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::get_current_thread() noexcept(true) {
 411                 return pthread_self();
 412         }
 413 
 414         template<> inline void __fastcall
 415         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::set_kernel_affinity(typename api_params_type::handle_type const thread_id, api_params_type::processor_mask_type const mask) noexcept(false) {
 416                 const int pth_err=pthread_setaffinity_np(thread_id, sizeof(api_params_type::processor_mask_type), &mask.mask());
 417                 if (pth_err) {
 418                         info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(void), info::function::argument(_T("typename api_params_type::handle_type const thread_id"), tostring(thread_id)));
 419                         fun.add_arg(info::function::argument(_T("api_params_type::processor_mask_type const mask"), tostring(mask)));
 420                         fun.add_arg(info::function::argument(_T("Return code"), tostring(pth_err)));
 421                         throw lock_traits::exception_type(_T("Could not set the kernel affinity of the specified thread."), fun, JMMCG_REVISION_HDR(_T("$Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/unix/thread_api_traits_impl.hpp 2288 2018-06-25 17:15:01Z jmmcg $")));
 422                 }
 423         }
 424 
 425         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::api_params_type::processor_mask_type __fastcall
 426         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::get_kernel_affinity(typename api_params_type::handle_type const thread_id) noexcept(false) {
 427                 api_params_type::processor_mask_type mask;
 428                 const int pth_err=pthread_getaffinity_np(thread_id, sizeof(api_params_type::processor_mask_type), &mask.mask());
 429                 if (pth_err) {
 430                         info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(void), info::function::argument(_T("typename api_params_type::handle_type const thread_id"), tostring(thread_id)));
 431                         fun.add_arg(info::function::argument(_T("Return code"), tostring(pth_err)));
 432                         throw lock_traits::exception_type(_T("Could not get the kernel affinity of the specified thread."), fun, JMMCG_REVISION_HDR(_T("$Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/unix/thread_api_traits_impl.hpp 2288 2018-06-25 17:15:01Z jmmcg $")));
 433                 }
 434                 return mask;
 435         }
 436 
 437         template<> inline void __fastcall
 438         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::set_cancelstate(api_params_type::thread_cancel_state state) noexcept(false) {
 439                 int old_state;
 440                 const int pth_err=pthread_setcancelstate(state, &old_state);
 441                 if (pth_err) {
 442                         info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(void), info::function::argument(_T("api_params_type::thread_cancel_state state"), tostring(state)));
 443                         fun.add_arg(info::function::argument(_T("Return code"), tostring(pth_err)));
 444                         throw lock_traits::exception_type(_T("Could not set the cancel state of the current thread."), fun, JMMCG_REVISION_HDR(_T("$Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/unix/thread_api_traits_impl.hpp 2288 2018-06-25 17:15:01Z jmmcg $")));
 445                 }
 446         }
 447 
 448         template<> inline void
 449         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::sleep(const api_params_type::suspend_period_ms period) noexcept(false) {
 450                 if (period) {
 451                         assert(period<=std::numeric_limits<api_params_type::suspend_period_ms>::max()/1000);
 452                         const timespec period_ns={
 453                                 static_cast<long>(period/1000),
 454                                 static_cast<long>((period%1000)*1000000)
 455                         };
 456                         timespec requested;
 457                         const int err=::nanosleep(&period_ns, &requested);
 458                         if (err) {
 459                                 info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(void), info::function::argument(_T("api_params_type::suspend_period_ms period"), tostring(period)));
 460                                 fun.add_arg(info::function::argument(_T("Return code"), tostring(err)));
 461                                 throw lock_traits::exception_type(_T("Could not suspend for the requested period."), fun, JMMCG_REVISION_HDR(_T("$Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/unix/thread_api_traits_impl.hpp 2288 2018-06-25 17:15:01Z jmmcg $")));
 462                         }
 463                 } else {
 464                         const int err=::sched_yield();
 465                         if (err) {
 466                                 info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(void), info::function::argument(_T("api_params_type::suspend_period_ms period"), tostring(period)));
 467                                 fun.add_arg(info::function::argument(_T("Return code"), tostring(err)));
 468                                 throw lock_traits::exception_type(_T("Period of zero implies a yield, which failed."), fun, JMMCG_REVISION_HDR(_T("$Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/unix/thread_api_traits_impl.hpp 2288 2018-06-25 17:15:01Z jmmcg $")));
 469                         }
 470                 }
 471         }
 472 
 473         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::api_params_type::states
 474         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::wait_thread_exit(api_params_type &thread, const lock_traits::timeout_type) noexcept(false) {
 475                 if (thread.id) {
 476                         api_params_type::states exit_code=api_params_type::unknown;
 477                         assert(thread.detach_state()==api_params_type::joinable);
 478                         // TODO should use "pthread_timedjoin_np()", but it uses the very irritating Epoch for the abstimeout.
 479                         const int ret=pthread_join(thread.id, reinterpret_cast<void **>(&exit_code));
 480                         thread.state=exit_code;
 481                         switch (ret) {
 482                         case 0:
 483                                 thread.id=0;
 484                                 if (!thread.state) {
 485                                         thread.state=api_params_type::no_kernel_thread;
 486                                 }
 487                                 break;
 488                         case EDEADLK:
 489                                 thread.state=api_params_type::deadlocked_with_another_thread;
 490                                 break;
 491                         case EINVAL:
 492                                 thread.state=api_params_type::invalid_thread;
 493                                 break;
 494                         case ESRCH:
 495                                 thread.state=api_params_type::thread_id_not_found;
 496                                 break;
 497                         case EBUSY:
 498                                 thread.state=api_params_type::active;
 499                                 break;
 500                         default:
 501                                 thread.state=api_params_type::get_exit_code_failure;
 502                         }
 503                         return thread.state;
 504                 } else {
 505                         return thread.state;
 506                 }
 507         }
 508 
 509         template<> inline void __fastcall
 510         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::demangle_name(char * const mangled_name, demangled_name_t &demangled_name) noexcept(true) {
 511                 api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::demangle_name(mangled_name, demangled_name);
 512         }
 513 
 514         template<> inline api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::demangled_names_t __fastcall
 515         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::gen_backtrace() noexcept(true) {
 516                 return api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::gen_backtrace();
 517         }
 518 
 519         template<> inline void __fastcall
 520         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::set_backtrace_on_signal() noexcept(true) {
 521                 api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::set_backtrace_on_signal();
 522         }
 523 
 524         template<> inline void __fastcall
 525         api_threading_traits<generic_traits::api_type::posix_pthreads, heavyweight_threading>::set_backtrace_on_terminate() noexcept(true) {
 526                 api_threading_traits<generic_traits::api_type::posix_pthreads, sequential_mode>::set_backtrace_on_terminate();
 527         }
 528 
 529 } }

/* [<][>][^][v][top][bottom][index][help] */