futures.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /* Copyright (C) 1995,1996,1997,1998,2000,2001, 2002, 2003, 2006, 2008 Free Software Foundation, Inc.
  2. *
  3. * This library is free software; you can redistribute it and/or
  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.
  7. *
  8. * This library is distributed in the hope that it will be useful, but
  9. * 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.
  12. *
  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
  16. * 02110-1301 USA
  17. */
  18. #if 0
  19. /* This whole file is not being compiled. See futures.h for the
  20. reason.
  21. */
  22. #ifdef HAVE_CONFIG_H
  23. # include <config.h>
  24. #endif
  25. #include "libguile/_scm.h"
  26. #include "libguile/eval.h"
  27. #include "libguile/ports.h"
  28. #include "libguile/validate.h"
  29. #include "libguile/stime.h"
  30. #include "libguile/threads.h"
  31. #include "libguile/futures.h"
  32. #define LINK(list, obj) \
  33. do { \
  34. SCM_SET_FUTURE_NEXT (obj, list); \
  35. list = obj; \
  36. } while (0)
  37. #define UNLINK(list, obj) \
  38. do { \
  39. obj = list; \
  40. list = SCM_FUTURE_NEXT (list); \
  41. } while (0)
  42. scm_i_pthread_mutex_t future_admin_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
  43. static SCM futures = SCM_EOL;
  44. static SCM young = SCM_EOL;
  45. static SCM old = SCM_EOL;
  46. static SCM undead = SCM_EOL;
  47. static long last_switch;
  48. #ifdef SCM_FUTURES_DEBUG
  49. static int n_dead = 0;
  50. static SCM
  51. count (SCM ls)
  52. {
  53. int n = 0;
  54. while (!scm_is_null (ls))
  55. {
  56. ++n;
  57. ls = SCM_FUTURE_NEXT (ls);
  58. }
  59. return scm_from_int (n);
  60. }
  61. extern SCM scm_future_cache_status (void);
  62. SCM_DEFINE (scm_future_cache_status, "future-cache-status", 0, 0, 0,
  63. (),
  64. "Return a list containing number of futures, youngs, olds, undeads and deads.")
  65. #define FUNC_NAME s_scm_future_cache_status
  66. {
  67. int nd = n_dead;
  68. n_dead = 0;
  69. return scm_list_5 (count (futures),
  70. count (young),
  71. count (old),
  72. count (undead),
  73. scm_from_int (nd));
  74. }
  75. #undef FUNC_NAME
  76. #endif
  77. SCM *scm_loc_sys_thread_handler;
  78. SCM_DEFINE (scm_make_future, "make-future", 1, 0, 0,
  79. (SCM thunk),
  80. "Make a future evaluating THUNK.")
  81. #define FUNC_NAME s_scm_make_future
  82. {
  83. SCM_VALIDATE_THUNK (1, thunk);
  84. return scm_i_make_future (thunk);
  85. }
  86. #undef FUNC_NAME
  87. static char *s_future = "future";
  88. static void
  89. cleanup (scm_t_future *future)
  90. {
  91. scm_i_pthread_mutex_destroy (&future->mutex);
  92. scm_i_pthread_cond_destroy (&future->cond);
  93. scm_gc_free (future, sizeof (*future), s_future);
  94. #ifdef SCM_FUTURES_DEBUG
  95. ++n_dead;
  96. #endif
  97. }
  98. static SCM
  99. future_loop (scm_t_future *future)
  100. {
  101. scm_i_scm_pthread_mutex_lock (&future->mutex);
  102. do {
  103. if (future->status == SCM_FUTURE_SIGNAL_ME)
  104. scm_i_pthread_cond_broadcast (&future->cond);
  105. future->status = SCM_FUTURE_COMPUTING;
  106. future->data = (SCM_CLOSUREP (future->data)
  107. ? scm_i_call_closure_0 (future->data)
  108. : scm_call_0 (future->data));
  109. scm_i_scm_pthread_cond_wait (&future->cond, &future->mutex);
  110. } while (!future->die_p);
  111. future->status = SCM_FUTURE_DEAD;
  112. scm_i_pthread_mutex_unlock (&future->mutex);
  113. return SCM_UNSPECIFIED;
  114. }
  115. static SCM
  116. future_handler (scm_t_future *future, SCM key, SCM args)
  117. {
  118. future->status = SCM_FUTURE_DEAD;
  119. scm_i_pthread_mutex_unlock (&future->mutex);
  120. return scm_apply_1 (*scm_loc_sys_thread_handler, key, args);
  121. }
  122. static SCM
  123. alloc_future (SCM thunk)
  124. {
  125. scm_t_future *f = scm_gc_malloc (sizeof (*f), s_future);
  126. SCM future;
  127. f->data = SCM_BOOL_F;
  128. scm_i_pthread_mutex_init (&f->mutex, NULL);
  129. scm_i_pthread_cond_init (&f->cond, NULL);
  130. f->die_p = 0;
  131. f->status = SCM_FUTURE_TASK_ASSIGNED;
  132. scm_i_scm_pthread_mutex_lock (&future_admin_mutex);
  133. SCM_NEWSMOB2 (future, scm_tc16_future, futures, f);
  134. SCM_SET_FUTURE_DATA (future, thunk);
  135. futures = future;
  136. scm_i_pthread_mutex_unlock (&future_admin_mutex);
  137. scm_spawn_thread ((scm_t_catch_body) future_loop,
  138. SCM_FUTURE (future),
  139. (scm_t_catch_handler) future_handler,
  140. SCM_FUTURE (future));
  141. return future;
  142. }
  143. static void
  144. kill_future (SCM future)
  145. {
  146. SCM_FUTURE (future)->die_p = 1;
  147. LINK (undead, future);
  148. }
  149. SCM
  150. scm_i_make_future (SCM thunk)
  151. {
  152. SCM future;
  153. scm_i_scm_pthread_mutex_lock (&future_admin_mutex);
  154. while (1)
  155. {
  156. if (!scm_is_null (old))
  157. UNLINK (old, future);
  158. else if (!scm_is_null (young))
  159. UNLINK (young, future);
  160. else
  161. {
  162. scm_i_pthread_mutex_unlock (&future_admin_mutex);
  163. return alloc_future (thunk);
  164. }
  165. if (scm_i_pthread_mutex_trylock (SCM_FUTURE_MUTEX (future)))
  166. kill_future (future);
  167. else if (!SCM_FUTURE_ALIVE_P (future))
  168. {
  169. scm_i_pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
  170. cleanup (SCM_FUTURE (future));
  171. }
  172. else
  173. break;
  174. }
  175. LINK (futures, future);
  176. scm_i_pthread_mutex_unlock (&future_admin_mutex);
  177. SCM_SET_FUTURE_DATA (future, thunk);
  178. SCM_SET_FUTURE_STATUS (future, SCM_FUTURE_TASK_ASSIGNED);
  179. scm_i_pthread_cond_signal (SCM_FUTURE_COND (future));
  180. scm_i_pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
  181. return future;
  182. }
  183. static SCM
  184. future_mark (SCM ptr) {
  185. return SCM_FUTURE_DATA (ptr);
  186. }
  187. static int
  188. future_print (SCM exp, SCM port, scm_print_state *pstate)
  189. {
  190. int writingp = SCM_WRITINGP (pstate);
  191. scm_puts ("#<future ", port);
  192. SCM_SET_WRITINGP (pstate, 1);
  193. scm_iprin1 (SCM_FUTURE_DATA (exp), port, pstate);
  194. SCM_SET_WRITINGP (pstate, writingp);
  195. scm_putc ('>', port);
  196. return !0;
  197. }
  198. SCM_DEFINE (scm_future_ref, "future-ref", 1, 0, 0,
  199. (SCM future),
  200. "If the future @var{x} has not been computed yet, compute and\n"
  201. "return @var{x}, otherwise just return the previously computed\n"
  202. "value.")
  203. #define FUNC_NAME s_scm_future_ref
  204. {
  205. SCM res;
  206. SCM_VALIDATE_FUTURE (1, future);
  207. scm_i_scm_pthread_mutex_lock (SCM_FUTURE_MUTEX (future));
  208. if (SCM_FUTURE_STATUS (future) != SCM_FUTURE_COMPUTING)
  209. {
  210. SCM_SET_FUTURE_STATUS (future, SCM_FUTURE_SIGNAL_ME);
  211. scm_i_scm_pthread_cond_wait (SCM_FUTURE_COND (future),
  212. SCM_FUTURE_MUTEX (future));
  213. }
  214. if (!SCM_FUTURE_ALIVE_P (future))
  215. {
  216. scm_i_pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
  217. SCM_MISC_ERROR ("requesting result from failed future ~A",
  218. scm_list_1 (future));
  219. }
  220. res = SCM_FUTURE_DATA (future);
  221. scm_i_pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
  222. return res;
  223. }
  224. #undef FUNC_NAME
  225. static void
  226. kill_futures (SCM victims)
  227. {
  228. while (!scm_is_null (victims))
  229. {
  230. SCM future;
  231. UNLINK (victims, future);
  232. kill_future (future);
  233. scm_i_pthread_cond_signal (SCM_FUTURE_COND (future));
  234. }
  235. }
  236. static void
  237. cleanup_undead ()
  238. {
  239. SCM next = undead, *nextloc = &undead;
  240. while (!scm_is_null (next))
  241. {
  242. if (scm_i_pthread_mutex_trylock (SCM_FUTURE_MUTEX (next)))
  243. goto next;
  244. else if (SCM_FUTURE_ALIVE_P (next))
  245. {
  246. scm_i_pthread_cond_signal (SCM_FUTURE_COND (next));
  247. scm_i_pthread_mutex_unlock (SCM_FUTURE_MUTEX (next));
  248. next:
  249. SCM_SET_GC_MARK (next);
  250. nextloc = SCM_FUTURE_NEXTLOC (next);
  251. next = *nextloc;
  252. }
  253. else
  254. {
  255. SCM future;
  256. UNLINK (next, future);
  257. scm_i_pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
  258. cleanup (SCM_FUTURE (future));
  259. *nextloc = next;
  260. }
  261. }
  262. }
  263. static void
  264. mark_futures (SCM futures)
  265. {
  266. while (!scm_is_null (futures))
  267. {
  268. SCM_SET_GC_MARK (futures);
  269. futures = SCM_FUTURE_NEXT (futures);
  270. }
  271. }
  272. static void *
  273. scan_futures (void *dummy1, void *dummy2, void *dummy3)
  274. {
  275. SCM next, *nextloc;
  276. long now = scm_c_get_internal_run_time ();
  277. if (now - last_switch > SCM_TIME_UNITS_PER_SECOND)
  278. {
  279. /* switch out old (> 1 sec), unused futures */
  280. kill_futures (old);
  281. old = young;
  282. young = SCM_EOL;
  283. last_switch = now;
  284. }
  285. else
  286. mark_futures (young);
  287. next = futures;
  288. nextloc = &futures;
  289. while (!scm_is_null (next))
  290. {
  291. if (!SCM_GC_MARK_P (next))
  292. goto free;
  293. keep:
  294. nextloc = SCM_FUTURE_NEXTLOC (next);
  295. next = *nextloc;
  296. }
  297. goto exit;
  298. while (!scm_is_null (next))
  299. {
  300. if (SCM_GC_MARK_P (next))
  301. {
  302. *nextloc = next;
  303. goto keep;
  304. }
  305. free:
  306. {
  307. SCM future;
  308. UNLINK (next, future);
  309. SCM_SET_GC_MARK (future);
  310. LINK (young, future);
  311. }
  312. }
  313. *nextloc = SCM_EOL;
  314. exit:
  315. cleanup_undead ();
  316. mark_futures (old);
  317. return 0;
  318. }
  319. scm_t_bits scm_tc16_future;
  320. void
  321. scm_init_futures ()
  322. {
  323. last_switch = scm_c_get_internal_run_time ();
  324. scm_loc_sys_thread_handler
  325. = SCM_VARIABLE_LOC (scm_c_define ("%thread-handler", SCM_BOOL_F));
  326. scm_tc16_future = scm_make_smob_type ("future", 0);
  327. scm_set_smob_mark (scm_tc16_future, future_mark);
  328. scm_set_smob_print (scm_tc16_future, future_print);
  329. scm_c_hook_add (&scm_before_sweep_c_hook, scan_futures, 0, 0);
  330. #include "libguile/futures.x"
  331. }
  332. #endif
  333. /*
  334. Local Variables:
  335. c-file-style: "gnu"
  336. End:
  337. */