Removed GUILE_OLD_ASYNC_CLICK code. Reorganized so that system asnycs
[bpt/guile.git] / libguile / async.c
1 /* Copyright (C) 1995,1996,1997,1998,2000,2001, 2002 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41
42
43 \f
44
45 #include <signal.h>
46 #include "libguile/_scm.h"
47 #include "libguile/eval.h"
48 #include "libguile/throw.h"
49 #include "libguile/root.h"
50 #include "libguile/smob.h"
51 #include "libguile/lang.h"
52 #include "libguile/deprecation.h"
53
54 #include "libguile/validate.h"
55 #include "libguile/async.h"
56
57 #ifdef HAVE_STRING_H
58 #include <string.h>
59 #endif
60 #ifdef HAVE_UNISTD_H
61 #include <unistd.h>
62 #endif
63
64
65 \f
66 /* {Asynchronous Events}
67 *
68 * There are two kinds of asyncs: system asyncs and user asyncs. The
69 * two kinds have some concepts in commen but work slightly
70 * differently and are not interchangeable.
71 *
72 * System asyncs are used to run arbitrary code at the next safe point
73 * in a specified thread. You can use them to trigger execution of
74 * Scheme code from signal handlers or to interrupt a thread, for
75 * example.
76 *
77 * Each thread has a list of 'activated asyncs', which is a normal
78 * Scheme list of procedures with zero arguments. When a thread
79 * executes a SCM_ASYNC_TICK statement (which is included in
80 * SCM_TICK), it will call all procedures on this list.
81 *
82 * Also, a thread will wake up when a procedure is added to its list
83 * of active asyncs and call them. After that, it will go to sleep
84 * again. (Not implemented yet.)
85 *
86 *
87 * User asyncs are a little data structure that consists of a
88 * procedure of zero arguments and a mark. There are functions for
89 * setting the mark of a user async and for calling all procedures of
90 * marked asyncs in a given list. Nothing you couldn't quickly
91 * implement yourself.
92 */
93
94 /* True between SCM_DEFER_INTS and SCM_ALLOW_INTS, and
95 * when the interpreter is not running at all.
96 */
97 int scm_ints_disabled = 1;
98 unsigned int scm_mask_ints = 1;
99
100 \f
101
102 /* User asyncs. */
103
104 static scm_t_bits tc16_async;
105
106 /* cmm: this has SCM_ prefix because SCM_MAKE_VALIDATE expects it.
107 this is ugly. */
108 #define SCM_ASYNCP(X) SCM_TYP16_PREDICATE (tc16_async, X)
109 #define VALIDATE_ASYNC(pos, a) SCM_MAKE_VALIDATE(pos, a, ASYNCP)
110
111 #define ASYNC_GOT_IT(X) (SCM_CELL_WORD_0 (X) >> 16)
112 #define SET_ASYNC_GOT_IT(X, V) (SCM_SET_CELL_WORD_0 ((X), SCM_TYP16 (X) | ((V) << 16)))
113 #define ASYNC_THUNK(X) SCM_CELL_OBJECT_1 (X)
114
115 static SCM
116 async_gc_mark (SCM obj)
117 {
118 return ASYNC_THUNK (obj);
119 }
120
121 SCM_DEFINE (scm_async, "async", 1, 0, 0,
122 (SCM thunk),
123 "Create a new async for the procedure @var{thunk}.")
124 #define FUNC_NAME s_scm_async
125 {
126 SCM_RETURN_NEWSMOB (tc16_async, SCM_UNPACK (thunk));
127 }
128 #undef FUNC_NAME
129
130 SCM_DEFINE (scm_async_mark, "async-mark", 1, 0, 0,
131 (SCM a),
132 "Mark the async @var{a} for future execution.")
133 #define FUNC_NAME s_scm_async_mark
134 {
135 VALIDATE_ASYNC (1, a);
136 SET_ASYNC_GOT_IT (a, 1);
137 return SCM_UNSPECIFIED;
138 }
139 #undef FUNC_NAME
140
141 SCM_DEFINE (scm_run_asyncs, "run-asyncs", 1, 0, 0,
142 (SCM list_of_a),
143 "Execute all thunks from the asyncs of the list @var{list_of_a}.")
144 #define FUNC_NAME s_scm_run_asyncs
145 {
146 while (! SCM_NULL_OR_NIL_P (list_of_a))
147 {
148 SCM a;
149 SCM_VALIDATE_CONS (1, list_of_a);
150 a = SCM_CAR (list_of_a);
151 VALIDATE_ASYNC (SCM_ARG1, a);
152 scm_mask_ints = 1;
153 if (ASYNC_GOT_IT (a))
154 {
155 SET_ASYNC_GOT_IT (a, 0);
156 scm_call_0 (ASYNC_THUNK (a));
157 }
158 scm_mask_ints = 0;
159 list_of_a = SCM_CDR (list_of_a);
160 }
161 return SCM_BOOL_T;
162 }
163 #undef FUNC_NAME
164
165 \f
166
167 /* System asyncs. */
168
169 void
170 scm_async_click ()
171 {
172 SCM asyncs;
173
174 if (!scm_mask_ints)
175 {
176 while (!SCM_NULLP(asyncs = scm_active_asyncs))
177 {
178 scm_active_asyncs = SCM_EOL;
179 do
180 {
181 SCM c = SCM_CDR (asyncs);
182 SCM_SETCDR (asyncs, SCM_EOL);
183 scm_call_0 (SCM_CAR (asyncs));
184 asyncs = c;
185 }
186 while (!SCM_NULLP(asyncs));
187 }
188 }
189 }
190
191 SCM_DEFINE (scm_system_async, "system-async", 1, 0, 0,
192 (SCM thunk),
193 "This function is deprecated. You can use @var{thunk} directly\n"
194 "instead of explicitely creating a asnc object.\n")
195 #define FUNC_NAME s_scm_system_async
196 {
197 scm_c_issue_deprecation_warning
198 ("'system-async' is deprecated. "
199 "Use the procedure directly with 'system-async-mark'.");
200 return thunk;
201 }
202 #undef FUNC_NAME
203
204 void
205 scm_i_queue_async_cell (SCM c, scm_root_state *root)
206 {
207 if (SCM_CDR (c) == SCM_EOL)
208 {
209 SCM_SETCDR (c, root->active_asyncs);
210 root->active_asyncs = c;
211 }
212 }
213
214 SCM_DEFINE (scm_system_async_mark_for_thread, "system-async-mark", 1, 1, 0,
215 (SCM proc, SCM thread),
216 "Register the procedure @var{proc} for future execution\n"
217 "in @var{thread}. When @var{thread} is not specified,\n"
218 "use the current thread.")
219 #define FUNC_NAME s_scm_system_async_mark_for_thread
220 {
221 scm_i_queue_async_cell (scm_cons (proc, SCM_EOL),
222 (SCM_UNBNDP (thread)
223 ? scm_root
224 : scm_i_thread_root (thread)));
225 return SCM_UNSPECIFIED;
226 }
227 #undef FUNC_NAME
228
229 SCM
230 scm_system_async_mark (SCM proc)
231 #define FUNC_NAME s_scm_system_async_mark_for_thread
232 {
233 return scm_system_async_mark_for_thread (proc, SCM_UNDEFINED);
234 }
235 #undef FUNC_NAME
236
237 \f
238
239
240 SCM_DEFINE (scm_noop, "noop", 0, 0, 1,
241 (SCM args),
242 "Do nothing. When called without arguments, return @code{#f},\n"
243 "otherwise return the first argument.")
244 #define FUNC_NAME s_scm_noop
245 {
246 SCM_VALIDATE_REST_ARGUMENT (args);
247 return (SCM_NULL_OR_NIL_P (args) ? SCM_BOOL_F : SCM_CAR (args));
248 }
249 #undef FUNC_NAME
250
251
252 \f
253
254 SCM_DEFINE (scm_unmask_signals, "unmask-signals", 0, 0, 0,
255 (),
256 "Unmask signals. The returned value is not specified.")
257 #define FUNC_NAME s_scm_unmask_signals
258 {
259 scm_mask_ints = 0;
260 return SCM_UNSPECIFIED;
261 }
262 #undef FUNC_NAME
263
264
265 SCM_DEFINE (scm_mask_signals, "mask-signals", 0, 0, 0,
266 (),
267 "Mask signals. The returned value is not specified.")
268 #define FUNC_NAME s_scm_mask_signals
269 {
270 scm_mask_ints = 1;
271 return SCM_UNSPECIFIED;
272 }
273 #undef FUNC_NAME
274
275 \f
276
277 void
278 scm_init_async ()
279 {
280 scm_asyncs = SCM_EOL;
281 tc16_async = scm_make_smob_type ("async", 0);
282 scm_set_smob_mark (tc16_async, async_gc_mark);
283
284 #include "libguile/async.x"
285 }
286
287 /*
288 Local Variables:
289 c-file-style: "gnu"
290 End:
291 */