Allow 'browse-url-emacs' to fetch URL in the selected window
[emacs.git] / src / systhread.c
blobe972ed398ac6accce3d808c4a95e5c9bfed968c7
1 /* System thread definitions
2 Copyright (C) 2012-2018 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
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.
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.
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/>. */
19 #include <config.h>
20 #include <setjmp.h>
21 #include "lisp.h"
23 #ifdef HAVE_NS
24 #include "nsterm.h"
25 #endif
27 #ifndef THREADS_ENABLED
29 void
30 sys_mutex_init (sys_mutex_t *m)
32 *m = 0;
35 void
36 sys_mutex_lock (sys_mutex_t *m)
40 void
41 sys_mutex_unlock (sys_mutex_t *m)
45 void
46 sys_cond_init (sys_cond_t *c)
48 *c = 0;
51 void
52 sys_cond_wait (sys_cond_t *c, sys_mutex_t *m)
56 void
57 sys_cond_signal (sys_cond_t *c)
61 void
62 sys_cond_broadcast (sys_cond_t *c)
66 void
67 sys_cond_destroy (sys_cond_t *c)
71 sys_thread_t
72 sys_thread_self (void)
74 return 0;
77 bool
78 sys_thread_equal (sys_thread_t t, sys_thread_t u)
80 return t == u;
83 int
84 sys_thread_create (sys_thread_t *t, const char *name,
85 thread_creation_function *func, void *datum)
87 return 0;
90 void
91 sys_thread_yield (void)
95 #elif defined (HAVE_PTHREAD)
97 #include <sched.h>
99 #ifdef HAVE_SYS_PRCTL_H
100 #include <sys/prctl.h>
101 #endif
103 void
104 sys_mutex_init (sys_mutex_t *mutex)
106 pthread_mutex_init (mutex, NULL);
109 void
110 sys_mutex_lock (sys_mutex_t *mutex)
112 pthread_mutex_lock (mutex);
115 void
116 sys_mutex_unlock (sys_mutex_t *mutex)
118 pthread_mutex_unlock (mutex);
121 void
122 sys_cond_init (sys_cond_t *cond)
124 pthread_cond_init (cond, NULL);
127 void
128 sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex)
130 pthread_cond_wait (cond, mutex);
133 void
134 sys_cond_signal (sys_cond_t *cond)
136 pthread_cond_signal (cond);
139 void
140 sys_cond_broadcast (sys_cond_t *cond)
142 pthread_cond_broadcast (cond);
143 #ifdef HAVE_NS
144 /* Send an app defined event to break out of the NS run loop.
145 It seems that if ns_select is running the NS run loop, this
146 broadcast has no effect until the loop is done, breaking a couple
147 of tests in thread-tests.el. */
148 ns_run_loop_break ();
149 #endif
152 void
153 sys_cond_destroy (sys_cond_t *cond)
155 pthread_cond_destroy (cond);
158 sys_thread_t
159 sys_thread_self (void)
161 return pthread_self ();
164 bool
165 sys_thread_equal (sys_thread_t t, sys_thread_t u)
167 return pthread_equal (t, u);
171 sys_thread_create (sys_thread_t *thread_ptr, const char *name,
172 thread_creation_function *func, void *arg)
174 pthread_attr_t attr;
175 int result = 0;
177 if (pthread_attr_init (&attr))
178 return 0;
180 /* Avoid crash on macOS with deeply nested GC (Bug#30364). */
181 size_t stack_size;
182 size_t required_stack_size = sizeof (void *) * 1024 * 1024;
183 if (pthread_attr_getstacksize (&attr, &stack_size) == 0
184 && stack_size < required_stack_size)
185 pthread_attr_setstacksize (&attr, required_stack_size);
187 if (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED))
189 result = pthread_create (thread_ptr, &attr, func, arg) == 0;
190 #if defined (HAVE_SYS_PRCTL_H) && defined (HAVE_PRCTL) && defined (PR_SET_NAME)
191 if (result && name != NULL)
192 prctl (PR_SET_NAME, name);
193 #endif
196 pthread_attr_destroy (&attr);
198 return result;
201 void
202 sys_thread_yield (void)
204 sched_yield ();
207 #elif defined (WINDOWSNT)
209 #include <w32term.h>
211 /* Cannot include <process.h> because of the local header by the same
212 name, sigh. */
213 uintptr_t _beginthread (void (__cdecl *)(void *), unsigned, void *);
215 /* Mutexes are implemented as critical sections, because they are
216 faster than Windows mutex objects (implemented in userspace), and
217 satisfy the requirements, since we only need to synchronize within a
218 single process. */
219 void
220 sys_mutex_init (sys_mutex_t *mutex)
222 InitializeCriticalSection ((LPCRITICAL_SECTION)mutex);
225 void
226 sys_mutex_lock (sys_mutex_t *mutex)
228 /* FIXME: What happens if the owning thread exits without releasing
229 the mutex? According to MSDN, the result is undefined behavior. */
230 EnterCriticalSection ((LPCRITICAL_SECTION)mutex);
233 void
234 sys_mutex_unlock (sys_mutex_t *mutex)
236 LeaveCriticalSection ((LPCRITICAL_SECTION)mutex);
239 void
240 sys_cond_init (sys_cond_t *cond)
242 cond->initialized = false;
243 cond->wait_count = 0;
244 /* Auto-reset event for signal. */
245 cond->events[CONDV_SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL);
246 /* Manual-reset event for broadcast. */
247 cond->events[CONDV_BROADCAST] = CreateEvent (NULL, TRUE, FALSE, NULL);
248 if (!cond->events[CONDV_SIGNAL] || !cond->events[CONDV_BROADCAST])
249 return;
250 InitializeCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
251 cond->initialized = true;
254 void
255 sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex)
257 DWORD wait_result;
258 bool last_thread_waiting;
260 if (!cond->initialized)
261 return;
263 /* Increment the wait count avoiding race conditions. */
264 EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
265 cond->wait_count++;
266 LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
268 /* Release the mutex and wait for either the signal or the broadcast
269 event. */
270 LeaveCriticalSection ((LPCRITICAL_SECTION)mutex);
271 wait_result = WaitForMultipleObjects (2, cond->events, FALSE, INFINITE);
273 /* Decrement the wait count and see if we are the last thread
274 waiting on the condition variable. */
275 EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
276 cond->wait_count--;
277 last_thread_waiting =
278 wait_result == WAIT_OBJECT_0 + CONDV_BROADCAST
279 && cond->wait_count == 0;
280 LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
282 /* Broadcast uses a manual-reset event, so when the last thread is
283 released, we must manually reset that event. */
284 if (last_thread_waiting)
285 ResetEvent (cond->events[CONDV_BROADCAST]);
287 /* Per the API, re-acquire the mutex. */
288 EnterCriticalSection ((LPCRITICAL_SECTION)mutex);
291 void
292 sys_cond_signal (sys_cond_t *cond)
294 bool threads_waiting;
296 if (!cond->initialized)
297 return;
299 EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
300 threads_waiting = cond->wait_count > 0;
301 LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
303 if (threads_waiting)
304 SetEvent (cond->events[CONDV_SIGNAL]);
307 void
308 sys_cond_broadcast (sys_cond_t *cond)
310 bool threads_waiting;
312 if (!cond->initialized)
313 return;
315 EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
316 threads_waiting = cond->wait_count > 0;
317 LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
319 if (threads_waiting)
320 SetEvent (cond->events[CONDV_BROADCAST]);
323 void
324 sys_cond_destroy (sys_cond_t *cond)
326 if (cond->events[CONDV_SIGNAL])
327 CloseHandle (cond->events[CONDV_SIGNAL]);
328 if (cond->events[CONDV_BROADCAST])
329 CloseHandle (cond->events[CONDV_BROADCAST]);
331 if (!cond->initialized)
332 return;
334 /* FIXME: What if wait_count is non-zero, i.e. there are still
335 threads waiting on this condition variable? */
336 DeleteCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
339 sys_thread_t
340 sys_thread_self (void)
342 return (sys_thread_t) GetCurrentThreadId ();
345 bool
346 sys_thread_equal (sys_thread_t t, sys_thread_t u)
348 return t == u;
351 static thread_creation_function *thread_start_address;
353 /* _beginthread wants a void function, while we are passed a function
354 that returns a pointer. So we use a wrapper. See the command in
355 w32term.h about the need for ALIGN_STACK attribute. */
356 static void ALIGN_STACK
357 w32_beginthread_wrapper (void *arg)
359 (void)thread_start_address (arg);
363 sys_thread_create (sys_thread_t *thread_ptr, const char *name,
364 thread_creation_function *func, void *arg)
366 /* FIXME: Do threads that run Lisp require some minimum amount of
367 stack? Zero here means each thread will get the same amount as
368 the main program. On GNU/Linux, it seems like the stack is 2MB
369 by default, overridden by RLIMIT_STACK at program start time.
370 Not sure what to do with this. See also the comment in
371 w32proc.c:new_child. */
372 const unsigned stack_size = 0;
373 uintptr_t thandle;
375 thread_start_address = func;
377 /* We use _beginthread rather than CreateThread because the former
378 arranges for the thread handle to be automatically closed when
379 the thread exits, thus preventing handle leaks and/or the need to
380 track all the threads and close their handles when they exit.
381 Also, MSDN seems to imply that code which uses CRT _must_ call
382 _beginthread, although if that is true, we already violate that
383 rule in many places... */
384 thandle = _beginthread (w32_beginthread_wrapper, stack_size, arg);
385 if (thandle == (uintptr_t)-1L)
386 return 0;
388 /* Kludge alert! We use the Windows thread ID, an unsigned 32-bit
389 number, as the sys_thread_t type, because that ID is the only
390 unique identifier of a thread on Windows. But _beginthread
391 returns a handle of the thread, and there's no easy way of
392 getting the thread ID given a handle (GetThreadId is available
393 only since Vista, so we cannot use it portably). Fortunately,
394 the value returned by sys_thread_create is not used by its
395 callers; instead, run_thread, which runs in the context of the
396 new thread, calls sys_thread_self and uses its return value;
397 sys_thread_self in this implementation calls GetCurrentThreadId.
398 Therefore, we return some more or less arbitrary value of the
399 thread ID from this function. */
400 *thread_ptr = thandle & 0xFFFFFFFF;
401 return 1;
404 void
405 sys_thread_yield (void)
407 Sleep (0);
410 #else
412 #error port me
414 #endif