1 /* Copyright (C) 1995,1996,1997,1998,2000,2001, 2002, 2003 Free Software Foundation, Inc.
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
8 * This library 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 GNU
11 * Lesser General Public License for more details.
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
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 /* This whole file is not being compiled. See futures.h for the
27 #include "libguile/_scm.h"
28 #include "libguile/eval.h"
29 #include "libguile/ports.h"
30 #include "libguile/validate.h"
31 #include "libguile/stime.h"
32 #include "libguile/threads.h"
34 #include "libguile/futures.h"
36 #define LINK(list, obj) \
38 SCM_SET_FUTURE_NEXT (obj, list); \
42 #define UNLINK(list, obj) \
45 list = SCM_FUTURE_NEXT (list); \
48 scm_i_pthread_mutex_t future_admin_mutex
= SCM_I_PTHREAD_MUTEX_INITIALIZER
;
50 static SCM futures
= SCM_EOL
;
51 static SCM young
= SCM_EOL
;
52 static SCM old
= SCM_EOL
;
53 static SCM undead
= SCM_EOL
;
55 static long last_switch
;
57 #ifdef SCM_FUTURES_DEBUG
58 static int n_dead
= 0;
64 while (!scm_is_null (ls
))
67 ls
= SCM_FUTURE_NEXT (ls
);
69 return scm_from_int (n
);
72 extern SCM
scm_future_cache_status (void);
74 SCM_DEFINE (scm_future_cache_status
, "future-cache-status", 0, 0, 0,
76 "Return a list containing number of futures, youngs, olds, undeads and deads.")
77 #define FUNC_NAME s_scm_future_cache_status
81 return scm_list_5 (count (futures
),
91 SCM
*scm_loc_sys_thread_handler
;
93 SCM_DEFINE (scm_make_future
, "make-future", 1, 0, 0,
95 "Make a future evaluating THUNK.")
96 #define FUNC_NAME s_scm_make_future
98 SCM_VALIDATE_THUNK (1, thunk
);
99 return scm_i_make_future (thunk
);
103 static char *s_future
= "future";
106 cleanup (scm_t_future
*future
)
108 scm_i_pthread_mutex_destroy (&future
->mutex
);
109 scm_i_pthread_cond_destroy (&future
->cond
);
110 scm_gc_free (future
, sizeof (*future
), s_future
);
111 #ifdef SCM_FUTURES_DEBUG
117 future_loop (scm_t_future
*future
)
119 scm_i_scm_pthread_mutex_lock (&future
->mutex
);
121 if (future
->status
== SCM_FUTURE_SIGNAL_ME
)
122 scm_i_pthread_cond_broadcast (&future
->cond
);
123 future
->status
= SCM_FUTURE_COMPUTING
;
124 future
->data
= (SCM_CLOSUREP (future
->data
)
125 ? scm_i_call_closure_0 (future
->data
)
126 : scm_call_0 (future
->data
));
127 scm_i_scm_pthread_cond_wait (&future
->cond
, &future
->mutex
);
128 } while (!future
->die_p
);
129 future
->status
= SCM_FUTURE_DEAD
;
130 scm_i_pthread_mutex_unlock (&future
->mutex
);
131 return SCM_UNSPECIFIED
;
135 future_handler (scm_t_future
*future
, SCM key
, SCM args
)
137 future
->status
= SCM_FUTURE_DEAD
;
138 scm_i_pthread_mutex_unlock (&future
->mutex
);
139 return scm_apply_1 (*scm_loc_sys_thread_handler
, key
, args
);
143 alloc_future (SCM thunk
)
145 scm_t_future
*f
= scm_gc_malloc (sizeof (*f
), s_future
);
147 f
->data
= SCM_BOOL_F
;
148 scm_i_pthread_mutex_init (&f
->mutex
, NULL
);
149 scm_i_pthread_cond_init (&f
->cond
, NULL
);
151 f
->status
= SCM_FUTURE_TASK_ASSIGNED
;
152 scm_i_scm_pthread_mutex_lock (&future_admin_mutex
);
153 SCM_NEWSMOB2 (future
, scm_tc16_future
, futures
, f
);
154 SCM_SET_FUTURE_DATA (future
, thunk
);
156 scm_i_pthread_mutex_unlock (&future_admin_mutex
);
157 scm_spawn_thread ((scm_t_catch_body
) future_loop
,
159 (scm_t_catch_handler
) future_handler
,
160 SCM_FUTURE (future
));
165 kill_future (SCM future
)
167 SCM_FUTURE (future
)->die_p
= 1;
168 LINK (undead
, future
);
172 scm_i_make_future (SCM thunk
)
175 scm_i_scm_pthread_mutex_lock (&future_admin_mutex
);
178 if (!scm_is_null (old
))
179 UNLINK (old
, future
);
180 else if (!scm_is_null (young
))
181 UNLINK (young
, future
);
184 scm_i_pthread_mutex_unlock (&future_admin_mutex
);
185 return alloc_future (thunk
);
187 if (scm_i_pthread_mutex_trylock (SCM_FUTURE_MUTEX (future
)))
188 kill_future (future
);
189 else if (!SCM_FUTURE_ALIVE_P (future
))
191 scm_i_pthread_mutex_unlock (SCM_FUTURE_MUTEX (future
));
192 cleanup (SCM_FUTURE (future
));
197 LINK (futures
, future
);
198 scm_i_pthread_mutex_unlock (&future_admin_mutex
);
199 SCM_SET_FUTURE_DATA (future
, thunk
);
200 SCM_SET_FUTURE_STATUS (future
, SCM_FUTURE_TASK_ASSIGNED
);
201 scm_i_pthread_cond_signal (SCM_FUTURE_COND (future
));
202 scm_i_pthread_mutex_unlock (SCM_FUTURE_MUTEX (future
));
207 future_mark (SCM ptr
) {
208 return SCM_FUTURE_DATA (ptr
);
212 future_print (SCM exp
, SCM port
, scm_print_state
*pstate
)
214 int writingp
= SCM_WRITINGP (pstate
);
215 scm_puts ("#<future ", port
);
216 SCM_SET_WRITINGP (pstate
, 1);
217 scm_iprin1 (SCM_FUTURE_DATA (exp
), port
, pstate
);
218 SCM_SET_WRITINGP (pstate
, writingp
);
219 scm_putc ('>', port
);
223 SCM_DEFINE (scm_future_ref
, "future-ref", 1, 0, 0,
225 "If the future @var{x} has not been computed yet, compute and\n"
226 "return @var{x}, otherwise just return the previously computed\n"
228 #define FUNC_NAME s_scm_future_ref
231 SCM_VALIDATE_FUTURE (1, future
);
232 scm_i_scm_pthread_mutex_lock (SCM_FUTURE_MUTEX (future
));
233 if (SCM_FUTURE_STATUS (future
) != SCM_FUTURE_COMPUTING
)
235 SCM_SET_FUTURE_STATUS (future
, SCM_FUTURE_SIGNAL_ME
);
236 scm_i_scm_pthread_cond_wait (SCM_FUTURE_COND (future
),
237 SCM_FUTURE_MUTEX (future
));
239 if (!SCM_FUTURE_ALIVE_P (future
))
241 scm_i_pthread_mutex_unlock (SCM_FUTURE_MUTEX (future
));
242 SCM_MISC_ERROR ("requesting result from failed future ~A",
243 scm_list_1 (future
));
245 res
= SCM_FUTURE_DATA (future
);
246 scm_i_pthread_mutex_unlock (SCM_FUTURE_MUTEX (future
));
252 kill_futures (SCM victims
)
254 while (!scm_is_null (victims
))
257 UNLINK (victims
, future
);
258 kill_future (future
);
259 scm_i_pthread_cond_signal (SCM_FUTURE_COND (future
));
266 SCM next
= undead
, *nextloc
= &undead
;
267 while (!scm_is_null (next
))
269 if (scm_i_pthread_mutex_trylock (SCM_FUTURE_MUTEX (next
)))
271 else if (SCM_FUTURE_ALIVE_P (next
))
273 scm_i_pthread_cond_signal (SCM_FUTURE_COND (next
));
274 scm_i_pthread_mutex_unlock (SCM_FUTURE_MUTEX (next
));
276 SCM_SET_GC_MARK (next
);
277 nextloc
= SCM_FUTURE_NEXTLOC (next
);
283 UNLINK (next
, future
);
284 scm_i_pthread_mutex_unlock (SCM_FUTURE_MUTEX (future
));
285 cleanup (SCM_FUTURE (future
));
292 mark_futures (SCM futures
)
294 while (!scm_is_null (futures
))
296 SCM_SET_GC_MARK (futures
);
297 futures
= SCM_FUTURE_NEXT (futures
);
302 scan_futures (void *dummy1
, void *dummy2
, void *dummy3
)
306 long now
= scm_c_get_internal_run_time ();
307 if (now
- last_switch
> SCM_TIME_UNITS_PER_SECOND
)
309 /* switch out old (> 1 sec), unused futures */
316 mark_futures (young
);
320 while (!scm_is_null (next
))
322 if (!SCM_GC_MARK_P (next
))
325 nextloc
= SCM_FUTURE_NEXTLOC (next
);
329 while (!scm_is_null (next
))
331 if (SCM_GC_MARK_P (next
))
339 UNLINK (next
, future
);
340 SCM_SET_GC_MARK (future
);
341 LINK (young
, future
);
351 scm_t_bits scm_tc16_future
;
356 last_switch
= scm_c_get_internal_run_time ();
358 scm_loc_sys_thread_handler
359 = SCM_VARIABLE_LOC (scm_c_define ("%thread-handler", SCM_BOOL_F
));
361 scm_tc16_future
= scm_make_smob_type ("future", 0);
362 scm_set_smob_mark (scm_tc16_future
, future_mark
);
363 scm_set_smob_print (scm_tc16_future
, future_print
);
365 scm_c_hook_add (&scm_before_sweep_c_hook
, scan_futures
, 0, 0);
366 #include "libguile/futures.x"