install pthread_atfork handlers for guile's static mutexen
[bpt/guile.git] / libguile / async.c
CommitLineData
6a97b1f9 1/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2002, 2004, 2006, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
843e4e9d 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
843e4e9d 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
843e4e9d 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
0f2d19dd 20\f
dbb605f5 21#ifdef HAVE_CONFIG_H
ef92a2a2
RB
22# include <config.h>
23#endif
0f2d19dd 24
a0599745
MD
25#include "libguile/_scm.h"
26#include "libguile/eval.h"
27#include "libguile/throw.h"
28#include "libguile/root.h"
29#include "libguile/smob.h"
e292f7aa 30#include "libguile/dynwind.h"
2d3179db 31#include "libguile/deprecation.h"
20e6290e 32
a0599745
MD
33#include "libguile/validate.h"
34#include "libguile/async.h"
0f2d19dd 35
95b88819
GH
36#ifdef HAVE_STRING_H
37#include <string.h>
38#endif
0f2d19dd
JB
39#ifdef HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42
634aa8de
LC
43#include <full-write.h>
44
0f2d19dd
JB
45\f
46/* {Asynchronous Events}
47 *
2d3179db
MV
48 * There are two kinds of asyncs: system asyncs and user asyncs. The
49 * two kinds have some concepts in commen but work slightly
50 * differently and are not interchangeable.
0f2d19dd 51 *
2d3179db
MV
52 * System asyncs are used to run arbitrary code at the next safe point
53 * in a specified thread. You can use them to trigger execution of
54 * Scheme code from signal handlers or to interrupt a thread, for
55 * example.
0f2d19dd 56 *
2d3179db
MV
57 * Each thread has a list of 'activated asyncs', which is a normal
58 * Scheme list of procedures with zero arguments. When a thread
59 * executes a SCM_ASYNC_TICK statement (which is included in
60 * SCM_TICK), it will call all procedures on this list.
843e4e9d 61 *
2d3179db
MV
62 * Also, a thread will wake up when a procedure is added to its list
63 * of active asyncs and call them. After that, it will go to sleep
64 * again. (Not implemented yet.)
0f2d19dd 65 *
0f2d19dd 66 *
2d3179db
MV
67 * User asyncs are a little data structure that consists of a
68 * procedure of zero arguments and a mark. There are functions for
69 * setting the mark of a user async and for calling all procedures of
70 * marked asyncs in a given list. Nothing you couldn't quickly
71 * implement yourself.
0f2d19dd
JB
72 */
73
0f2d19dd 74
2d3179db 75\f
0f2d19dd 76
2d3179db 77/* User asyncs. */
e94e3f21 78
2d3179db 79static scm_t_bits tc16_async;
e94e3f21
ML
80
81/* cmm: this has SCM_ prefix because SCM_MAKE_VALIDATE expects it.
82 this is ugly. */
e841c3e0 83#define SCM_ASYNCP(X) SCM_TYP16_PREDICATE (tc16_async, X)
6182ceac 84#define VALIDATE_ASYNC(pos, a) SCM_MAKE_VALIDATE_MSG(pos, a, ASYNCP, "user async")
e94e3f21 85
e779fef7
AW
86#define ASYNC_GOT_IT(X) (SCM_SMOB_FLAGS (X))
87#define SET_ASYNC_GOT_IT(X, V) (SCM_SET_SMOB_FLAGS ((X), ((V))))
88#define ASYNC_THUNK(X) SCM_SMOB_OBJECT_1 (X)
0f2d19dd 89
0f2d19dd 90
843e4e9d 91SCM_DEFINE (scm_async, "async", 1, 0, 0,
811cf846
MG
92 (SCM thunk),
93 "Create a new async for the procedure @var{thunk}.")
1bbd0b84 94#define FUNC_NAME s_scm_async
0f2d19dd 95{
e94e3f21 96 SCM_RETURN_NEWSMOB (tc16_async, SCM_UNPACK (thunk));
0f2d19dd 97}
1bbd0b84 98#undef FUNC_NAME
0f2d19dd 99
843e4e9d 100SCM_DEFINE (scm_async_mark, "async-mark", 1, 0, 0,
1bbd0b84 101 (SCM a),
811cf846 102 "Mark the async @var{a} for future execution.")
1bbd0b84 103#define FUNC_NAME s_scm_async_mark
0f2d19dd 104{
e94e3f21 105 VALIDATE_ASYNC (1, a);
e94e3f21 106 SET_ASYNC_GOT_IT (a, 1);
0f2d19dd
JB
107 return SCM_UNSPECIFIED;
108}
1bbd0b84 109#undef FUNC_NAME
0f2d19dd 110
843e4e9d 111SCM_DEFINE (scm_run_asyncs, "run-asyncs", 1, 0, 0,
811cf846
MG
112 (SCM list_of_a),
113 "Execute all thunks from the asyncs of the list @var{list_of_a}.")
1bbd0b84 114#define FUNC_NAME s_scm_run_asyncs
0f2d19dd 115{
c96d76b8 116 while (! SCM_NULL_OR_NIL_P (list_of_a))
0f2d19dd
JB
117 {
118 SCM a;
9f0e55a6 119 SCM_VALIDATE_CONS (1, list_of_a);
1bbd0b84 120 a = SCM_CAR (list_of_a);
e94e3f21 121 VALIDATE_ASYNC (SCM_ARG1, a);
e94e3f21 122 if (ASYNC_GOT_IT (a))
0f2d19dd 123 {
e94e3f21 124 SET_ASYNC_GOT_IT (a, 0);
fdc28395 125 scm_call_0 (ASYNC_THUNK (a));
0f2d19dd 126 }
1bbd0b84 127 list_of_a = SCM_CDR (list_of_a);
0f2d19dd
JB
128 }
129 return SCM_BOOL_T;
130}
1bbd0b84 131#undef FUNC_NAME
0f2d19dd
JB
132
133\f
134
9de87eea 135static scm_i_pthread_mutex_t async_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
6a97b1f9 136SCM_PTHREAD_ATFORK_LOCK_STATIC_MUTEX (async_mutex);
9de87eea 137
2d3179db 138/* System asyncs. */
0f2d19dd 139
2d3179db 140void
27c6ebcb 141scm_async_tick (void)
0f2d19dd 142{
9de87eea
MV
143 scm_i_thread *t = SCM_I_CURRENT_THREAD;
144 SCM asyncs;
145
402858a4 146 /* Reset pending_asyncs even when asyncs are blocked and not really
9de87eea
MV
147 executed since this will avoid future futile calls to this
148 function. When asyncs are unblocked again, this function is
149 invoked even when pending_asyncs is zero.
402858a4 150 */
2d3179db 151
9de87eea
MV
152 scm_i_scm_pthread_mutex_lock (&async_mutex);
153 t->pending_asyncs = 0;
154 if (t->block_asyncs == 0)
2d3179db 155 {
9de87eea
MV
156 asyncs = t->active_asyncs;
157 t->active_asyncs = SCM_EOL;
158 }
159 else
160 asyncs = SCM_EOL;
161 scm_i_pthread_mutex_unlock (&async_mutex);
162
163 while (scm_is_pair (asyncs))
164 {
165 SCM next = SCM_CDR (asyncs);
166 SCM_SETCDR (asyncs, SCM_BOOL_F);
167 scm_call_0 (SCM_CAR (asyncs));
168 asyncs = next;
2d3179db 169 }
0f2d19dd
JB
170}
171
2d3179db 172void
9de87eea 173scm_i_queue_async_cell (SCM c, scm_i_thread *t)
2d3179db 174{
9de87eea
MV
175 SCM sleep_object;
176 scm_i_pthread_mutex_t *sleep_mutex;
177 int sleep_fd;
178 SCM p;
179
180 scm_i_scm_pthread_mutex_lock (&async_mutex);
181 p = t->active_asyncs;
402858a4 182 SCM_SETCDR (c, SCM_EOL);
9de87eea
MV
183 if (!scm_is_pair (p))
184 t->active_asyncs = c;
402858a4 185 else
2d3179db 186 {
402858a4 187 SCM pp;
9de87eea 188 while (scm_is_pair (pp = SCM_CDR (p)))
f6b44bd9 189 {
9de87eea
MV
190 if (scm_is_eq (SCM_CAR (p), SCM_CAR (c)))
191 {
192 scm_i_pthread_mutex_unlock (&async_mutex);
193 return;
194 }
402858a4 195 p = pp;
f6b44bd9 196 }
402858a4 197 SCM_SETCDR (p, c);
2d3179db 198 }
9de87eea
MV
199 t->pending_asyncs = 1;
200 sleep_object = t->sleep_object;
201 sleep_mutex = t->sleep_mutex;
202 sleep_fd = t->sleep_fd;
203 scm_i_pthread_mutex_unlock (&async_mutex);
204
205 if (sleep_mutex)
206 {
207 /* By now, the thread T might be out of its sleep already, or
208 might even be in the next, unrelated sleep. Interrupting it
209 anyway does no harm, however.
210
211 The important thing to prevent here is to signal sleep_cond
212 before T waits on it. This can not happen since T has
213 sleep_mutex locked while setting t->sleep_mutex and will only
214 unlock it again while waiting on sleep_cond.
215 */
216 scm_i_scm_pthread_mutex_lock (sleep_mutex);
217 scm_i_pthread_cond_signal (&t->sleep_cond);
218 scm_i_pthread_mutex_unlock (sleep_mutex);
219 }
220
221 if (sleep_fd >= 0)
222 {
223 char dummy = 0;
634aa8de 224
9de87eea
MV
225 /* Likewise, T might already been done with sleeping here, but
226 interrupting it once too often does no harm. T might also
227 not yet have started sleeping, but this is no problem either
228 since the data written to a pipe will not be lost, unlike a
634aa8de
LC
229 condition variable signal. */
230 full_write (sleep_fd, &dummy, 1);
9de87eea
MV
231 }
232
233 /* This is needed to protect sleep_mutex.
234 */
235 scm_remember_upto_here_1 (sleep_object);
236}
237
238int
239scm_i_setup_sleep (scm_i_thread *t,
240 SCM sleep_object, scm_i_pthread_mutex_t *sleep_mutex,
241 int sleep_fd)
242{
243 int pending;
244
245 scm_i_scm_pthread_mutex_lock (&async_mutex);
246 pending = t->pending_asyncs;
247 if (!pending)
248 {
249 t->sleep_object = sleep_object;
250 t->sleep_mutex = sleep_mutex;
251 t->sleep_fd = sleep_fd;
252 }
253 scm_i_pthread_mutex_unlock (&async_mutex);
254 return pending;
255}
256
257void
258scm_i_reset_sleep (scm_i_thread *t)
259{
260 scm_i_scm_pthread_mutex_lock (&async_mutex);
261 t->sleep_object = SCM_BOOL_F;
262 t->sleep_mutex = NULL;
263 t->sleep_fd = -1;
264 scm_i_pthread_mutex_unlock (&async_mutex);
2d3179db 265}
0f2d19dd 266
2d3179db
MV
267SCM_DEFINE (scm_system_async_mark_for_thread, "system-async-mark", 1, 1, 0,
268 (SCM proc, SCM thread),
0a50eeaa
NJ
269 "Mark @var{proc} (a procedure with zero arguments) for future execution\n"
270 "in @var{thread}. If @var{proc} has already been marked for\n"
271 "@var{thread} but has not been executed yet, this call has no effect.\n"
272 "If @var{thread} is omitted, the thread that called\n"
273 "@code{system-async-mark} is used.\n\n"
274 "This procedure is not safe to be called from C signal handlers. Use\n"
275 "@code{scm_sigaction} or @code{scm_sigaction_for_thread} to install\n"
276 "signal handlers.")
2d3179db
MV
277#define FUNC_NAME s_scm_system_async_mark_for_thread
278{
9de87eea
MV
279 /* The current thread might not have a handle yet. This can happen
280 when the GC runs immediately before allocating the handle. At
281 the end of that GC, a system async might be marked. Thus, we can
282 not use scm_current_thread here.
283 */
284
285 scm_i_thread *t;
286
028e573c 287 if (SCM_UNBNDP (thread))
9de87eea 288 t = SCM_I_CURRENT_THREAD;
028e573c 289 else
402858a4
MV
290 {
291 SCM_VALIDATE_THREAD (2, thread);
292 if (scm_c_thread_exited_p (thread))
293 SCM_MISC_ERROR ("thread has already exited", SCM_EOL);
9de87eea 294 t = SCM_I_THREAD_DATA (thread);
402858a4 295 }
9de87eea 296 scm_i_queue_async_cell (scm_cons (proc, SCM_BOOL_F), t);
2d3179db
MV
297 return SCM_UNSPECIFIED;
298}
299#undef FUNC_NAME
9f0e55a6 300
2d3179db
MV
301SCM
302scm_system_async_mark (SCM proc)
303#define FUNC_NAME s_scm_system_async_mark_for_thread
0f2d19dd 304{
2d3179db 305 return scm_system_async_mark_for_thread (proc, SCM_UNDEFINED);
0f2d19dd 306}
1bbd0b84 307#undef FUNC_NAME
0f2d19dd
JB
308
309\f
310
311
2d3179db
MV
312SCM_DEFINE (scm_noop, "noop", 0, 0, 1,
313 (SCM args),
314 "Do nothing. When called without arguments, return @code{#f},\n"
315 "otherwise return the first argument.")
316#define FUNC_NAME s_scm_noop
0f2d19dd 317{
2d3179db
MV
318 SCM_VALIDATE_REST_ARGUMENT (args);
319 return (SCM_NULL_OR_NIL_P (args) ? SCM_BOOL_F : SCM_CAR (args));
0f2d19dd 320}
1bbd0b84 321#undef FUNC_NAME
0f2d19dd 322
0f2d19dd 323
0f2d19dd
JB
324\f
325
e292f7aa 326static void
9de87eea 327increase_block (void *data)
e292f7aa 328{
c98ce8f5
AW
329 scm_i_thread *t = data;
330 t->block_asyncs++;
e292f7aa
MV
331}
332
333static void
9de87eea 334decrease_block (void *data)
e292f7aa 335{
c98ce8f5
AW
336 scm_i_thread *t = data;
337 if (--t->block_asyncs == 0)
27c6ebcb 338 scm_async_tick ();
e292f7aa
MV
339}
340
c98ce8f5
AW
341void
342scm_dynwind_block_asyncs (void)
343{
344 scm_i_thread *t = SCM_I_CURRENT_THREAD;
345 scm_dynwind_rewind_handler (increase_block, t, SCM_F_WIND_EXPLICITLY);
346 scm_dynwind_unwind_handler (decrease_block, t, SCM_F_WIND_EXPLICITLY);
347}
348
349void
350scm_dynwind_unblock_asyncs (void)
351{
352 scm_i_thread *t = SCM_I_CURRENT_THREAD;
353 if (t->block_asyncs == 0)
354 scm_misc_error ("scm_with_unblocked_asyncs",
355 "asyncs already unblocked", SCM_EOL);
356 scm_dynwind_rewind_handler (decrease_block, t, SCM_F_WIND_EXPLICITLY);
357 scm_dynwind_unwind_handler (increase_block, t, SCM_F_WIND_EXPLICITLY);
358}
359
e292f7aa
MV
360SCM_DEFINE (scm_call_with_blocked_asyncs, "call-with-blocked-asyncs", 1, 0, 0,
361 (SCM proc),
362 "Call @var{proc} with no arguments and block the execution\n"
363 "of system asyncs by one level for the current thread while\n"
364 "it is running. Return the value returned by @var{proc}.\n")
365#define FUNC_NAME s_scm_call_with_blocked_asyncs
366{
c98ce8f5
AW
367 SCM ans;
368
369 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
370 scm_dynwind_block_asyncs ();
371 ans = scm_call_0 (proc);
372 scm_dynwind_end ();
373
374 return ans;
e292f7aa
MV
375}
376#undef FUNC_NAME
377
378void *
379scm_c_call_with_blocked_asyncs (void *(*proc) (void *data), void *data)
380{
c98ce8f5
AW
381 void* ans;
382
383 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
384 scm_dynwind_block_asyncs ();
385 ans = proc (data);
386 scm_dynwind_end ();
387
388 return ans;
e292f7aa
MV
389}
390
391
392SCM_DEFINE (scm_call_with_unblocked_asyncs, "call-with-unblocked-asyncs", 1, 0, 0,
393 (SCM proc),
394 "Call @var{proc} with no arguments and unblock the execution\n"
395 "of system asyncs by one level for the current thread while\n"
396 "it is running. Return the value returned by @var{proc}.\n")
397#define FUNC_NAME s_scm_call_with_unblocked_asyncs
398{
c98ce8f5
AW
399 SCM ans;
400
9de87eea 401 if (SCM_I_CURRENT_THREAD->block_asyncs == 0)
e292f7aa 402 SCM_MISC_ERROR ("asyncs already unblocked", SCM_EOL);
c98ce8f5
AW
403
404 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
405 scm_dynwind_unblock_asyncs ();
406 ans = scm_call_0 (proc);
407 scm_dynwind_end ();
408
409 return ans;
e292f7aa
MV
410}
411#undef FUNC_NAME
412
413void *
414scm_c_call_with_unblocked_asyncs (void *(*proc) (void *data), void *data)
415{
c98ce8f5
AW
416 void* ans;
417
9de87eea 418 if (SCM_I_CURRENT_THREAD->block_asyncs == 0)
e292f7aa
MV
419 scm_misc_error ("scm_c_call_with_unblocked_asyncs",
420 "asyncs already unblocked", SCM_EOL);
e292f7aa 421
c98ce8f5
AW
422 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
423 scm_dynwind_unblock_asyncs ();
424 ans = proc (data);
425 scm_dynwind_end ();
b57a0953 426
c98ce8f5 427 return ans;
b57a0953
MV
428}
429
46935a1f
LC
430\f
431/* These are function variants of the same-named macros (uppercase) for use
432 outside of libguile. This is so that `SCM_I_CURRENT_THREAD', which may
433 reside in TLS, is not accessed from outside of libguile. It thus allows
434 libguile to be built with the "local-dynamic" TLS model. */
435
436void
437scm_critical_section_start (void)
438{
439 SCM_CRITICAL_SECTION_START;
440}
441
442void
443scm_critical_section_end (void)
444{
445 SCM_CRITICAL_SECTION_END;
446}
447
0f2d19dd
JB
448\f
449
0f2d19dd
JB
450void
451scm_init_async ()
0f2d19dd 452{
73ea78af 453 tc16_async = scm_make_smob_type ("async", 0);
73ea78af 454
a0599745 455#include "libguile/async.x"
0f2d19dd 456}
89e00824
ML
457
458/*
459 Local Variables:
460 c-file-style: "gnu"
461 End:
462*/