Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / libguile / async.c
CommitLineData
fc7bd367 1/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2002, 2004, 2006, 2008, 2009, 2010, 2011 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
MV
135static scm_i_pthread_mutex_t async_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
136
2d3179db 137/* System asyncs. */
0f2d19dd 138
2d3179db 139void
27c6ebcb 140scm_async_tick (void)
0f2d19dd 141{
9de87eea
MV
142 scm_i_thread *t = SCM_I_CURRENT_THREAD;
143 SCM asyncs;
144
402858a4 145 /* Reset pending_asyncs even when asyncs are blocked and not really
9de87eea
MV
146 executed since this will avoid future futile calls to this
147 function. When asyncs are unblocked again, this function is
148 invoked even when pending_asyncs is zero.
402858a4 149 */
2d3179db 150
9de87eea
MV
151 scm_i_scm_pthread_mutex_lock (&async_mutex);
152 t->pending_asyncs = 0;
153 if (t->block_asyncs == 0)
2d3179db 154 {
9de87eea
MV
155 asyncs = t->active_asyncs;
156 t->active_asyncs = SCM_EOL;
157 }
158 else
159 asyncs = SCM_EOL;
160 scm_i_pthread_mutex_unlock (&async_mutex);
161
162 while (scm_is_pair (asyncs))
163 {
164 SCM next = SCM_CDR (asyncs);
165 SCM_SETCDR (asyncs, SCM_BOOL_F);
166 scm_call_0 (SCM_CAR (asyncs));
167 asyncs = next;
2d3179db 168 }
0f2d19dd
JB
169}
170
2d3179db 171void
9de87eea 172scm_i_queue_async_cell (SCM c, scm_i_thread *t)
2d3179db 173{
9de87eea
MV
174 SCM sleep_object;
175 scm_i_pthread_mutex_t *sleep_mutex;
176 int sleep_fd;
177 SCM p;
178
179 scm_i_scm_pthread_mutex_lock (&async_mutex);
180 p = t->active_asyncs;
402858a4 181 SCM_SETCDR (c, SCM_EOL);
9de87eea
MV
182 if (!scm_is_pair (p))
183 t->active_asyncs = c;
402858a4 184 else
2d3179db 185 {
402858a4 186 SCM pp;
9de87eea 187 while (scm_is_pair (pp = SCM_CDR (p)))
f6b44bd9 188 {
9de87eea
MV
189 if (scm_is_eq (SCM_CAR (p), SCM_CAR (c)))
190 {
191 scm_i_pthread_mutex_unlock (&async_mutex);
192 return;
193 }
402858a4 194 p = pp;
f6b44bd9 195 }
402858a4 196 SCM_SETCDR (p, c);
2d3179db 197 }
9de87eea
MV
198 t->pending_asyncs = 1;
199 sleep_object = t->sleep_object;
200 sleep_mutex = t->sleep_mutex;
201 sleep_fd = t->sleep_fd;
202 scm_i_pthread_mutex_unlock (&async_mutex);
203
204 if (sleep_mutex)
205 {
206 /* By now, the thread T might be out of its sleep already, or
207 might even be in the next, unrelated sleep. Interrupting it
208 anyway does no harm, however.
209
210 The important thing to prevent here is to signal sleep_cond
211 before T waits on it. This can not happen since T has
212 sleep_mutex locked while setting t->sleep_mutex and will only
213 unlock it again while waiting on sleep_cond.
214 */
215 scm_i_scm_pthread_mutex_lock (sleep_mutex);
216 scm_i_pthread_cond_signal (&t->sleep_cond);
217 scm_i_pthread_mutex_unlock (sleep_mutex);
218 }
219
220 if (sleep_fd >= 0)
221 {
222 char dummy = 0;
634aa8de 223
9de87eea
MV
224 /* Likewise, T might already been done with sleeping here, but
225 interrupting it once too often does no harm. T might also
226 not yet have started sleeping, but this is no problem either
227 since the data written to a pipe will not be lost, unlike a
634aa8de
LC
228 condition variable signal. */
229 full_write (sleep_fd, &dummy, 1);
9de87eea
MV
230 }
231
232 /* This is needed to protect sleep_mutex.
233 */
234 scm_remember_upto_here_1 (sleep_object);
235}
236
237int
238scm_i_setup_sleep (scm_i_thread *t,
239 SCM sleep_object, scm_i_pthread_mutex_t *sleep_mutex,
240 int sleep_fd)
241{
242 int pending;
243
244 scm_i_scm_pthread_mutex_lock (&async_mutex);
245 pending = t->pending_asyncs;
246 if (!pending)
247 {
248 t->sleep_object = sleep_object;
249 t->sleep_mutex = sleep_mutex;
250 t->sleep_fd = sleep_fd;
251 }
252 scm_i_pthread_mutex_unlock (&async_mutex);
253 return pending;
254}
255
256void
257scm_i_reset_sleep (scm_i_thread *t)
258{
259 scm_i_scm_pthread_mutex_lock (&async_mutex);
260 t->sleep_object = SCM_BOOL_F;
261 t->sleep_mutex = NULL;
262 t->sleep_fd = -1;
263 scm_i_pthread_mutex_unlock (&async_mutex);
2d3179db 264}
0f2d19dd 265
2d3179db
MV
266SCM_DEFINE (scm_system_async_mark_for_thread, "system-async-mark", 1, 1, 0,
267 (SCM proc, SCM thread),
0a50eeaa
NJ
268 "Mark @var{proc} (a procedure with zero arguments) for future execution\n"
269 "in @var{thread}. If @var{proc} has already been marked for\n"
270 "@var{thread} but has not been executed yet, this call has no effect.\n"
271 "If @var{thread} is omitted, the thread that called\n"
272 "@code{system-async-mark} is used.\n\n"
273 "This procedure is not safe to be called from C signal handlers. Use\n"
274 "@code{scm_sigaction} or @code{scm_sigaction_for_thread} to install\n"
275 "signal handlers.")
2d3179db
MV
276#define FUNC_NAME s_scm_system_async_mark_for_thread
277{
9de87eea
MV
278 /* The current thread might not have a handle yet. This can happen
279 when the GC runs immediately before allocating the handle. At
280 the end of that GC, a system async might be marked. Thus, we can
281 not use scm_current_thread here.
282 */
283
284 scm_i_thread *t;
285
028e573c 286 if (SCM_UNBNDP (thread))
9de87eea 287 t = SCM_I_CURRENT_THREAD;
028e573c 288 else
402858a4
MV
289 {
290 SCM_VALIDATE_THREAD (2, thread);
291 if (scm_c_thread_exited_p (thread))
292 SCM_MISC_ERROR ("thread has already exited", SCM_EOL);
9de87eea 293 t = SCM_I_THREAD_DATA (thread);
402858a4 294 }
9de87eea 295 scm_i_queue_async_cell (scm_cons (proc, SCM_BOOL_F), t);
2d3179db
MV
296 return SCM_UNSPECIFIED;
297}
298#undef FUNC_NAME
9f0e55a6 299
2d3179db
MV
300SCM
301scm_system_async_mark (SCM proc)
302#define FUNC_NAME s_scm_system_async_mark_for_thread
0f2d19dd 303{
2d3179db 304 return scm_system_async_mark_for_thread (proc, SCM_UNDEFINED);
0f2d19dd 305}
1bbd0b84 306#undef FUNC_NAME
0f2d19dd
JB
307
308\f
309
310
2d3179db
MV
311SCM_DEFINE (scm_noop, "noop", 0, 0, 1,
312 (SCM args),
313 "Do nothing. When called without arguments, return @code{#f},\n"
314 "otherwise return the first argument.")
315#define FUNC_NAME s_scm_noop
0f2d19dd 316{
2d3179db
MV
317 SCM_VALIDATE_REST_ARGUMENT (args);
318 return (SCM_NULL_OR_NIL_P (args) ? SCM_BOOL_F : SCM_CAR (args));
0f2d19dd 319}
1bbd0b84 320#undef FUNC_NAME
0f2d19dd 321
0f2d19dd 322
0f2d19dd
JB
323\f
324
e292f7aa 325static void
9de87eea 326increase_block (void *data)
e292f7aa 327{
c98ce8f5
AW
328 scm_i_thread *t = data;
329 t->block_asyncs++;
e292f7aa
MV
330}
331
332static void
9de87eea 333decrease_block (void *data)
e292f7aa 334{
c98ce8f5
AW
335 scm_i_thread *t = data;
336 if (--t->block_asyncs == 0)
27c6ebcb 337 scm_async_tick ();
e292f7aa
MV
338}
339
c98ce8f5
AW
340void
341scm_dynwind_block_asyncs (void)
342{
343 scm_i_thread *t = SCM_I_CURRENT_THREAD;
344 scm_dynwind_rewind_handler (increase_block, t, SCM_F_WIND_EXPLICITLY);
345 scm_dynwind_unwind_handler (decrease_block, t, SCM_F_WIND_EXPLICITLY);
346}
347
348void
349scm_dynwind_unblock_asyncs (void)
350{
351 scm_i_thread *t = SCM_I_CURRENT_THREAD;
352 if (t->block_asyncs == 0)
353 scm_misc_error ("scm_with_unblocked_asyncs",
354 "asyncs already unblocked", SCM_EOL);
355 scm_dynwind_rewind_handler (decrease_block, t, SCM_F_WIND_EXPLICITLY);
356 scm_dynwind_unwind_handler (increase_block, t, SCM_F_WIND_EXPLICITLY);
357}
358
e292f7aa
MV
359SCM_DEFINE (scm_call_with_blocked_asyncs, "call-with-blocked-asyncs", 1, 0, 0,
360 (SCM proc),
361 "Call @var{proc} with no arguments and block the execution\n"
362 "of system asyncs by one level for the current thread while\n"
363 "it is running. Return the value returned by @var{proc}.\n")
364#define FUNC_NAME s_scm_call_with_blocked_asyncs
365{
c98ce8f5
AW
366 SCM ans;
367
368 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
369 scm_dynwind_block_asyncs ();
370 ans = scm_call_0 (proc);
371 scm_dynwind_end ();
372
373 return ans;
e292f7aa
MV
374}
375#undef FUNC_NAME
376
377void *
378scm_c_call_with_blocked_asyncs (void *(*proc) (void *data), void *data)
379{
c98ce8f5
AW
380 void* ans;
381
382 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
383 scm_dynwind_block_asyncs ();
384 ans = proc (data);
385 scm_dynwind_end ();
386
387 return ans;
e292f7aa
MV
388}
389
390
391SCM_DEFINE (scm_call_with_unblocked_asyncs, "call-with-unblocked-asyncs", 1, 0, 0,
392 (SCM proc),
393 "Call @var{proc} with no arguments and unblock the execution\n"
394 "of system asyncs by one level for the current thread while\n"
395 "it is running. Return the value returned by @var{proc}.\n")
396#define FUNC_NAME s_scm_call_with_unblocked_asyncs
397{
c98ce8f5
AW
398 SCM ans;
399
9de87eea 400 if (SCM_I_CURRENT_THREAD->block_asyncs == 0)
e292f7aa 401 SCM_MISC_ERROR ("asyncs already unblocked", SCM_EOL);
c98ce8f5
AW
402
403 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
404 scm_dynwind_unblock_asyncs ();
405 ans = scm_call_0 (proc);
406 scm_dynwind_end ();
407
408 return ans;
e292f7aa
MV
409}
410#undef FUNC_NAME
411
412void *
413scm_c_call_with_unblocked_asyncs (void *(*proc) (void *data), void *data)
414{
c98ce8f5
AW
415 void* ans;
416
9de87eea 417 if (SCM_I_CURRENT_THREAD->block_asyncs == 0)
e292f7aa
MV
418 scm_misc_error ("scm_c_call_with_unblocked_asyncs",
419 "asyncs already unblocked", SCM_EOL);
e292f7aa 420
c98ce8f5
AW
421 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
422 scm_dynwind_unblock_asyncs ();
423 ans = proc (data);
424 scm_dynwind_end ();
b57a0953 425
c98ce8f5 426 return ans;
b57a0953
MV
427}
428
46935a1f
LC
429\f
430/* These are function variants of the same-named macros (uppercase) for use
431 outside of libguile. This is so that `SCM_I_CURRENT_THREAD', which may
432 reside in TLS, is not accessed from outside of libguile. It thus allows
433 libguile to be built with the "local-dynamic" TLS model. */
434
435void
436scm_critical_section_start (void)
437{
438 SCM_CRITICAL_SECTION_START;
439}
440
441void
442scm_critical_section_end (void)
443{
444 SCM_CRITICAL_SECTION_END;
445}
446
0f2d19dd
JB
447\f
448
0f2d19dd
JB
449void
450scm_init_async ()
0f2d19dd 451{
73ea78af 452 tc16_async = scm_make_smob_type ("async", 0);
73ea78af 453
a0599745 454#include "libguile/async.x"
0f2d19dd 455}
89e00824
ML
456
457/*
458 Local Variables:
459 c-file-style: "gnu"
460 End:
461*/