futures.c 8.9 KB

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