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