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