root/src/systhread.c

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

DEFINITIONS

This source file includes following definitions.
  1. sys_mutex_init
  2. sys_mutex_lock
  3. sys_mutex_unlock
  4. sys_cond_init
  5. sys_cond_wait
  6. sys_cond_signal
  7. sys_cond_broadcast
  8. sys_cond_destroy
  9. sys_thread_self
  10. sys_thread_equal
  11. sys_thread_set_name
  12. sys_thread_create
  13. sys_thread_yield
  14. sys_mutex_init
  15. sys_mutex_lock
  16. sys_mutex_unlock
  17. sys_cond_init
  18. sys_cond_wait
  19. sys_cond_signal
  20. sys_cond_broadcast
  21. sys_cond_destroy
  22. sys_thread_self
  23. sys_thread_equal
  24. sys_thread_set_name
  25. sys_thread_create
  26. sys_thread_yield
  27. sys_mutex_init
  28. sys_mutex_lock
  29. sys_mutex_unlock
  30. sys_cond_init
  31. sys_cond_wait
  32. sys_cond_signal
  33. sys_cond_broadcast
  34. sys_cond_destroy
  35. sys_thread_self
  36. sys_thread_equal
  37. w32_set_thread_name
  38. sys_thread_set_name
  39. w32_beginthread_wrapper
  40. sys_thread_create
  41. sys_thread_yield

     1 /* System thread definitions
     2 Copyright (C) 2012-2023 Free Software Foundation, Inc.
     3 
     4 This file is part of GNU Emacs.
     5 
     6 GNU Emacs is free software: you can redistribute it and/or modify
     7 it under the terms of the GNU General Public License as published by
     8 the Free Software Foundation, either version 3 of the License, or
     9 (at your option) any later version.
    10 
    11 GNU Emacs 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
    14 GNU General Public License for more details.
    15 
    16 You should have received a copy of the GNU General Public License
    17 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    18 
    19 #include <config.h>
    20 #include <setjmp.h>
    21 #include <stdio.h>
    22 #include <string.h>
    23 #include "lisp.h"
    24 
    25 #ifdef HAVE_NS
    26 #include "nsterm.h"
    27 #endif
    28 
    29 #ifdef HAVE_PTHREAD_SET_NAME_NP
    30 #include <pthread_np.h>
    31 #endif
    32 
    33 #ifndef THREADS_ENABLED
    34 
    35 void
    36 sys_mutex_init (sys_mutex_t *m)
    37 {
    38   *m = 0;
    39 }
    40 
    41 void
    42 sys_mutex_lock (sys_mutex_t *m)
    43 {
    44 }
    45 
    46 void
    47 sys_mutex_unlock (sys_mutex_t *m)
    48 {
    49 }
    50 
    51 void
    52 sys_cond_init (sys_cond_t *c)
    53 {
    54   *c = 0;
    55 }
    56 
    57 void
    58 sys_cond_wait (sys_cond_t *c, sys_mutex_t *m)
    59 {
    60 }
    61 
    62 void
    63 sys_cond_signal (sys_cond_t *c)
    64 {
    65 }
    66 
    67 void
    68 sys_cond_broadcast (sys_cond_t *c)
    69 {
    70 }
    71 
    72 void
    73 sys_cond_destroy (sys_cond_t *c)
    74 {
    75 }
    76 
    77 sys_thread_t
    78 sys_thread_self (void)
    79 {
    80   return 0;
    81 }
    82 
    83 bool
    84 sys_thread_equal (sys_thread_t t, sys_thread_t u)
    85 {
    86   return t == u;
    87 }
    88 void
    89 sys_thread_set_name (const char *name)
    90 {
    91 }
    92 
    93 bool
    94 sys_thread_create (sys_thread_t *t, thread_creation_function *func, void *datum)
    95 {
    96   return false;
    97 }
    98 
    99 void
   100 sys_thread_yield (void)
   101 {
   102 }
   103 
   104 #elif defined (HAVE_PTHREAD)
   105 
   106 #include <sched.h>
   107 
   108 void
   109 sys_mutex_init (sys_mutex_t *mutex)
   110 {
   111   pthread_mutexattr_t *attr_ptr;
   112 #ifdef ENABLE_CHECKING
   113   pthread_mutexattr_t attr;
   114   {
   115     int error = pthread_mutexattr_init (&attr);
   116     eassert (error == 0);
   117     error = pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK);
   118     eassert (error == 0);
   119   }
   120   attr_ptr = &attr;
   121 #else
   122   attr_ptr = NULL;
   123 #endif
   124   int error = pthread_mutex_init (mutex, attr_ptr);
   125   /* We could get ENOMEM.  Can't do anything except aborting.  */
   126   if (error != 0)
   127     {
   128       fprintf (stderr, "\npthread_mutex_init failed: %s\n", strerror (error));
   129       emacs_abort ();
   130     }
   131 #ifdef ENABLE_CHECKING
   132   error = pthread_mutexattr_destroy (&attr);
   133   eassert (error == 0);
   134 #endif
   135 }
   136 
   137 void
   138 sys_mutex_lock (sys_mutex_t *mutex)
   139 {
   140   int error = pthread_mutex_lock (mutex);
   141   eassert (error == 0);
   142 }
   143 
   144 void
   145 sys_mutex_unlock (sys_mutex_t *mutex)
   146 {
   147   int error = pthread_mutex_unlock (mutex);
   148   eassert (error == 0);
   149 }
   150 
   151 void
   152 sys_cond_init (sys_cond_t *cond)
   153 {
   154   int error = pthread_cond_init (cond, NULL);
   155   /* We could get ENOMEM.  Can't do anything except aborting.  */
   156   if (error != 0)
   157     {
   158       fprintf (stderr, "\npthread_cond_init failed: %s\n", strerror (error));
   159       emacs_abort ();
   160     }
   161 }
   162 
   163 void
   164 sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex)
   165 {
   166   int error = pthread_cond_wait (cond, mutex);
   167   eassert (error == 0);
   168 }
   169 
   170 void
   171 sys_cond_signal (sys_cond_t *cond)
   172 {
   173   int error = pthread_cond_signal (cond);
   174   eassert (error == 0);
   175 }
   176 
   177 void
   178 sys_cond_broadcast (sys_cond_t *cond)
   179 {
   180   int error = pthread_cond_broadcast (cond);
   181   eassert (error == 0);
   182 #ifdef HAVE_NS
   183   /* Send an app defined event to break out of the NS run loop.
   184      It seems that if ns_select is running the NS run loop, this
   185      broadcast has no effect until the loop is done, breaking a couple
   186      of tests in thread-tests.el. */
   187   ns_run_loop_break ();
   188 #endif
   189 }
   190 
   191 void
   192 sys_cond_destroy (sys_cond_t *cond)
   193 {
   194   int error = pthread_cond_destroy (cond);
   195   eassert (error == 0);
   196 }
   197 
   198 sys_thread_t
   199 sys_thread_self (void)
   200 {
   201   return pthread_self ();
   202 }
   203 
   204 bool
   205 sys_thread_equal (sys_thread_t t, sys_thread_t u)
   206 {
   207   return pthread_equal (t, u);
   208 }
   209 
   210 void
   211 sys_thread_set_name (const char *name)
   212 {
   213 #ifdef HAVE_PTHREAD_SETNAME_NP
   214   /* We need to truncate here otherwise pthread_setname_np
   215      fails to set the name.  TASK_COMM_LEN is what the length
   216      is called in the Linux kernel headers (Bug#38632).  */
   217 #define TASK_COMM_LEN 16
   218   char p_name[TASK_COMM_LEN];
   219   strncpy (p_name, name, TASK_COMM_LEN - 1);
   220   p_name[TASK_COMM_LEN - 1] = '\0';
   221 # ifdef HAVE_PTHREAD_SETNAME_NP_1ARG
   222   pthread_setname_np (p_name);
   223 # elif defined HAVE_PTHREAD_SETNAME_NP_3ARG
   224   pthread_setname_np (pthread_self (), "%s", p_name);
   225 # else
   226   pthread_setname_np (pthread_self (), p_name);
   227 # endif
   228 #elif HAVE_PTHREAD_SET_NAME_NP
   229   /* The name will automatically be truncated if it exceeds a
   230      system-specific length.  */
   231   pthread_set_name_np (pthread_self (), name);
   232 #endif
   233 }
   234 
   235 bool
   236 sys_thread_create (sys_thread_t *thread_ptr, thread_creation_function *func,
   237                    void *arg)
   238 {
   239   pthread_attr_t attr;
   240   bool result = false;
   241 
   242   if (pthread_attr_init (&attr))
   243     return false;
   244 
   245   /* Avoid crash on macOS with deeply nested GC (Bug#30364).  */
   246   size_t stack_size;
   247   size_t required_stack_size = sizeof (void *) * 1024 * 1024;
   248   if (pthread_attr_getstacksize (&attr, &stack_size) == 0
   249       && stack_size < required_stack_size)
   250     {
   251       if (pthread_attr_setstacksize (&attr, required_stack_size) != 0)
   252         goto out;
   253     }
   254 
   255   if (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED))
   256     result = pthread_create (thread_ptr, &attr, func, arg) == 0;
   257 
   258  out: ;
   259   int error = pthread_attr_destroy (&attr);
   260   eassert (error == 0);
   261 
   262   return result;
   263 }
   264 
   265 void
   266 sys_thread_yield (void)
   267 {
   268   sched_yield ();
   269 }
   270 
   271 #elif defined (WINDOWSNT)
   272 
   273 #include <mbctype.h>
   274 #include "w32term.h"
   275 
   276 /* Cannot include <process.h> because of the local header by the same
   277    name, sigh.  */
   278 uintptr_t _beginthread (void (__cdecl *)(void *), unsigned, void *);
   279 
   280 /* Mutexes are implemented as critical sections, because they are
   281    faster than Windows mutex objects (implemented in userspace), and
   282    satisfy the requirements, since we only need to synchronize within a
   283    single process.  */
   284 void
   285 sys_mutex_init (sys_mutex_t *mutex)
   286 {
   287   InitializeCriticalSection ((LPCRITICAL_SECTION)mutex);
   288 }
   289 
   290 void
   291 sys_mutex_lock (sys_mutex_t *mutex)
   292 {
   293   /* FIXME: What happens if the owning thread exits without releasing
   294      the mutex?  According to MSDN, the result is undefined behavior.  */
   295   EnterCriticalSection ((LPCRITICAL_SECTION)mutex);
   296 }
   297 
   298 void
   299 sys_mutex_unlock (sys_mutex_t *mutex)
   300 {
   301   LeaveCriticalSection ((LPCRITICAL_SECTION)mutex);
   302 }
   303 
   304 void
   305 sys_cond_init (sys_cond_t *cond)
   306 {
   307   cond->initialized = false;
   308   cond->wait_count = 0;
   309   /* Auto-reset event for signal.  */
   310   cond->events[CONDV_SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL);
   311   /* Manual-reset event for broadcast.  */
   312   cond->events[CONDV_BROADCAST] = CreateEvent (NULL, TRUE, FALSE, NULL);
   313   if (!cond->events[CONDV_SIGNAL] || !cond->events[CONDV_BROADCAST])
   314     return;
   315   InitializeCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
   316   cond->initialized = true;
   317 }
   318 
   319 void
   320 sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex)
   321 {
   322   DWORD wait_result;
   323   bool last_thread_waiting;
   324 
   325   if (!cond->initialized)
   326     return;
   327 
   328   /* Increment the wait count avoiding race conditions.  */
   329   EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
   330   cond->wait_count++;
   331   LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
   332 
   333   /* Release the mutex and wait for either the signal or the broadcast
   334      event.  */
   335   LeaveCriticalSection ((LPCRITICAL_SECTION)mutex);
   336   wait_result = WaitForMultipleObjects (2, cond->events, FALSE, INFINITE);
   337 
   338   /* Decrement the wait count and see if we are the last thread
   339      waiting on the condition variable.  */
   340   EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
   341   cond->wait_count--;
   342   last_thread_waiting =
   343     wait_result == WAIT_OBJECT_0 + CONDV_BROADCAST
   344     && cond->wait_count == 0;
   345   LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
   346 
   347   /* Broadcast uses a manual-reset event, so when the last thread is
   348      released, we must manually reset that event.  */
   349   if (last_thread_waiting)
   350     ResetEvent (cond->events[CONDV_BROADCAST]);
   351 
   352   /* Per the API, re-acquire the mutex.  */
   353   EnterCriticalSection ((LPCRITICAL_SECTION)mutex);
   354 }
   355 
   356 void
   357 sys_cond_signal (sys_cond_t *cond)
   358 {
   359   bool threads_waiting;
   360 
   361   if (!cond->initialized)
   362     return;
   363 
   364   EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
   365   threads_waiting = cond->wait_count > 0;
   366   LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
   367 
   368   if (threads_waiting)
   369     SetEvent (cond->events[CONDV_SIGNAL]);
   370 }
   371 
   372 void
   373 sys_cond_broadcast (sys_cond_t *cond)
   374 {
   375   bool threads_waiting;
   376 
   377   if (!cond->initialized)
   378     return;
   379 
   380   EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
   381   threads_waiting = cond->wait_count > 0;
   382   LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
   383 
   384   if (threads_waiting)
   385     SetEvent (cond->events[CONDV_BROADCAST]);
   386 }
   387 
   388 void
   389 sys_cond_destroy (sys_cond_t *cond)
   390 {
   391   if (cond->events[CONDV_SIGNAL])
   392     CloseHandle (cond->events[CONDV_SIGNAL]);
   393   if (cond->events[CONDV_BROADCAST])
   394     CloseHandle (cond->events[CONDV_BROADCAST]);
   395 
   396   if (!cond->initialized)
   397     return;
   398 
   399   /* FIXME: What if wait_count is non-zero, i.e. there are still
   400      threads waiting on this condition variable?  */
   401   DeleteCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
   402 }
   403 
   404 sys_thread_t
   405 sys_thread_self (void)
   406 {
   407   return (sys_thread_t) GetCurrentThreadId ();
   408 }
   409 
   410 bool
   411 sys_thread_equal (sys_thread_t t, sys_thread_t u)
   412 {
   413   return t == u;
   414 }
   415 
   416 /* Special exception used to communicate with a debugger.  The name is
   417    taken from example code shown on MSDN.  */
   418 #define MS_VC_EXCEPTION 0x406d1388UL
   419 
   420 /* Structure used to communicate thread name to a debugger.  */
   421 typedef struct _THREADNAME_INFO
   422 {
   423   DWORD_PTR  type;
   424   LPCSTR name;
   425   DWORD_PTR  thread_id;
   426   DWORD_PTR  reserved;
   427 } THREADNAME_INFO;
   428 
   429 typedef BOOL (WINAPI *IsDebuggerPresent_Proc) (void);
   430 extern IsDebuggerPresent_Proc is_debugger_present;
   431 extern int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
   432 typedef HRESULT (WINAPI *SetThreadDescription_Proc)
   433   (HANDLE hThread, PCWSTR lpThreadDescription);
   434 extern SetThreadDescription_Proc set_thread_description;
   435 
   436 /* Set the name of the thread identified by its thread ID.  */
   437 static void
   438 w32_set_thread_name (DWORD thread_id, const char *name)
   439 {
   440   if (!name || !*name)
   441     return;
   442 
   443   /* Use the new API provided since Windows 10, if available.  */
   444   if (set_thread_description)
   445     {
   446       /* GDB pulls only the first 1024 characters of thread's name.  */
   447       wchar_t name_w[1025];
   448       /* The thread name is encoded in locale's encoding, but
   449          SetThreadDescription wants a wchar_t string.  */
   450       int codepage = _getmbcp ();
   451       if (!codepage)
   452         codepage = GetACP ();
   453       int cnv_result = pMultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS,
   454                                              name, -1,
   455                                              name_w, 1025);
   456       if (cnv_result
   457           && set_thread_description (GetCurrentThread (), name_w) == S_OK)
   458         return;
   459     }
   460   /* We can only support this fallback method when Emacs is being
   461      debugged.  */
   462   if (!(is_debugger_present && is_debugger_present ()))
   463     return;
   464 
   465   THREADNAME_INFO tninfo;
   466 
   467   tninfo.type = 0x1000; /* magic constant */
   468   tninfo.name = name;
   469   tninfo.thread_id = thread_id;
   470   tninfo.reserved = 0;
   471   RaiseException (MS_VC_EXCEPTION, 0, sizeof (tninfo) / sizeof (ULONG_PTR),
   472                   (ULONG_PTR *) &tninfo);
   473 }
   474 
   475 static thread_creation_function *thread_start_address;
   476 
   477 void
   478 sys_thread_set_name (const char *name)
   479 {
   480   w32_set_thread_name (GetCurrentThreadId (), name);
   481 }
   482 
   483 /* _beginthread wants a void function, while we are passed a function
   484    that returns a pointer.  So we use a wrapper.  See the command in
   485    w32term.h about the need for ALIGN_STACK attribute.  */
   486 static void ALIGN_STACK
   487 w32_beginthread_wrapper (void *arg)
   488 {
   489   (void)thread_start_address (arg);
   490 }
   491 
   492 bool
   493 sys_thread_create (sys_thread_t *thread_ptr, thread_creation_function *func,
   494                    void *arg)
   495 {
   496   /* FIXME: Do threads that run Lisp require some minimum amount of
   497      stack?  Zero here means each thread will get the same amount as
   498      the main program.  On GNU/Linux, it seems like the stack is 2MB
   499      by default, overridden by RLIMIT_STACK at program start time.
   500      Not sure what to do with this.  See also the comment in
   501      w32proc.c:new_child.  */
   502   const unsigned stack_size = 0;
   503   uintptr_t thandle;
   504 
   505   thread_start_address = func;
   506 
   507   /* We use _beginthread rather than CreateThread because the former
   508      arranges for the thread handle to be automatically closed when
   509      the thread exits, thus preventing handle leaks and/or the need to
   510      track all the threads and close their handles when they exit.
   511      Also, MSDN seems to imply that code which uses CRT _must_ call
   512      _beginthread, although if that is true, we already violate that
   513      rule in many places...  */
   514   thandle = _beginthread (w32_beginthread_wrapper, stack_size, arg);
   515   if (thandle == (uintptr_t)-1L)
   516     return false;
   517 
   518   /* Kludge alert!  We use the Windows thread ID, an unsigned 32-bit
   519      number, as the sys_thread_t type, because that ID is the only
   520      unique identifier of a thread on Windows.  But _beginthread
   521      returns a handle of the thread, and there's no easy way of
   522      getting the thread ID given a handle (GetThreadId is available
   523      only since Vista, so we cannot use it portably).  Fortunately,
   524      the value returned by sys_thread_create is not used by its
   525      callers; instead, run_thread, which runs in the context of the
   526      new thread, calls sys_thread_self and uses its return value;
   527      sys_thread_self in this implementation calls GetCurrentThreadId.
   528      Therefore, we return some more or less arbitrary value of the
   529      thread ID from this function. */
   530   *thread_ptr = thandle & 0xFFFFFFFF;
   531   return true;
   532 }
   533 
   534 void
   535 sys_thread_yield (void)
   536 {
   537   Sleep (0);
   538 }
   539 
   540 #else
   541 
   542 #error port me
   543 
   544 #endif

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