fluids.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. /* Copyright (C) 1996,1997,2000,2001, 2004, 2006, 2007, 2008, 2009, 2010,
  2. * 2011, 2012, 2013 Free Software Foundation, Inc.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public License
  6. * as published by the Free Software Foundation; either version 3 of
  7. * the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301 USA
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. # include <config.h>
  21. #endif
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include "libguile/_scm.h"
  25. #include "libguile/print.h"
  26. #include "libguile/dynwind.h"
  27. #include "libguile/fluids.h"
  28. #include "libguile/alist.h"
  29. #include "libguile/eval.h"
  30. #include "libguile/ports.h"
  31. #include "libguile/deprecation.h"
  32. #include "libguile/validate.h"
  33. #include "libguile/bdw-gc.h"
  34. /* Number of additional slots to allocate when ALLOCATED_FLUIDS is full. */
  35. #define FLUID_GROW 128
  36. /* Vector of allocated fluids indexed by fluid numbers. Access is protected by
  37. FLUID_ADMIN_MUTEX. */
  38. static void **allocated_fluids = NULL;
  39. static size_t allocated_fluids_len = 0;
  40. static scm_i_pthread_mutex_t fluid_admin_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
  41. #define IS_FLUID(x) SCM_FLUID_P (x)
  42. #define FLUID_NUM(x) SCM_I_FLUID_NUM (x)
  43. #define IS_DYNAMIC_STATE(x) SCM_I_DYNAMIC_STATE_P (x)
  44. #define DYNAMIC_STATE_FLUIDS(x) SCM_I_DYNAMIC_STATE_FLUIDS (x)
  45. #define SET_DYNAMIC_STATE_FLUIDS(x, y) SCM_SET_CELL_WORD_1 ((x), (SCM_UNPACK (y)))
  46. /* Grow STATE so that it can hold up to ALLOCATED_FLUIDS_LEN fluids. This may
  47. be more than necessary since ALLOCATED_FLUIDS is sparse and the current
  48. thread may not access all the fluids anyway. Memory usage could be improved
  49. by using a 2-level array as is done in glibc for pthread keys (TODO). */
  50. static void
  51. grow_dynamic_state (SCM state)
  52. {
  53. SCM new_fluids;
  54. SCM old_fluids = DYNAMIC_STATE_FLUIDS (state);
  55. size_t i, len, old_len = SCM_SIMPLE_VECTOR_LENGTH (old_fluids);
  56. /* Assume the assignment below is atomic. */
  57. len = allocated_fluids_len;
  58. new_fluids = scm_c_make_vector (len, SCM_UNDEFINED);
  59. for (i = 0; i < old_len; i++)
  60. SCM_SIMPLE_VECTOR_SET (new_fluids, i,
  61. SCM_SIMPLE_VECTOR_REF (old_fluids, i));
  62. SET_DYNAMIC_STATE_FLUIDS (state, new_fluids);
  63. }
  64. void
  65. scm_i_fluid_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
  66. {
  67. scm_puts_unlocked ("#<fluid ", port);
  68. scm_intprint ((int) FLUID_NUM (exp), 10, port);
  69. scm_putc_unlocked ('>', port);
  70. }
  71. void
  72. scm_i_dynamic_state_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
  73. {
  74. scm_puts_unlocked ("#<dynamic-state ", port);
  75. scm_intprint (SCM_UNPACK (exp), 16, port);
  76. scm_putc_unlocked ('>', port);
  77. }
  78. /* Return a new fluid. */
  79. static SCM
  80. new_fluid (SCM init)
  81. {
  82. SCM fluid;
  83. size_t trial, n;
  84. /* Fluids hold the type tag and the fluid number in the first word,
  85. and the default value in the second word. */
  86. fluid = scm_cell (scm_tc7_fluid, SCM_UNPACK (init));
  87. SCM_SET_CELL_TYPE (fluid, scm_tc7_fluid);
  88. scm_dynwind_begin (0);
  89. scm_i_dynwind_pthread_mutex_lock (&fluid_admin_mutex);
  90. for (trial = 0; trial < 2; trial++)
  91. {
  92. /* Look for a free fluid number. */
  93. for (n = 0; n < allocated_fluids_len; n++)
  94. /* TODO: Use `__sync_bool_compare_and_swap' where available. */
  95. if (allocated_fluids[n] == NULL)
  96. break;
  97. if (trial == 0 && n >= allocated_fluids_len && allocated_fluids_len)
  98. /* All fluid numbers are in use. Run a GC and retry. Explicitly
  99. running the GC is costly and bad-style. We only do this because
  100. dynamic state fluid vectors would grow unreasonably if fluid numbers
  101. weren't reused. */
  102. scm_i_gc ("fluids");
  103. }
  104. if (n >= allocated_fluids_len)
  105. {
  106. /* Grow the vector of allocated fluids. */
  107. void **new_allocated_fluids =
  108. scm_gc_malloc_pointerless ((allocated_fluids_len + FLUID_GROW)
  109. * sizeof (*allocated_fluids),
  110. "allocated fluids");
  111. /* Copy over old values and initialize rest. GC can not run
  112. during these two operations since there is no safe point in
  113. them. */
  114. memcpy (new_allocated_fluids, allocated_fluids,
  115. allocated_fluids_len * sizeof (*allocated_fluids));
  116. memset (new_allocated_fluids + allocated_fluids_len, 0,
  117. FLUID_GROW * sizeof (*allocated_fluids));
  118. n = allocated_fluids_len;
  119. /* Update the vector of allocated fluids. Dynamic states will
  120. eventually be lazily grown to accomodate the new value of
  121. ALLOCATED_FLUIDS_LEN in `fluid-ref' and `fluid-set!'. */
  122. allocated_fluids = new_allocated_fluids;
  123. allocated_fluids_len += FLUID_GROW;
  124. }
  125. allocated_fluids[n] = SCM_UNPACK_POINTER (fluid);
  126. SCM_SET_CELL_WORD_0 (fluid, (scm_tc7_fluid | (n << 8)));
  127. GC_GENERAL_REGISTER_DISAPPEARING_LINK (&allocated_fluids[n],
  128. SCM2PTR (fluid));
  129. scm_dynwind_end ();
  130. /* Now null out values. We could (and probably should) do this when
  131. the fluid is collected instead of now. */
  132. scm_i_reset_fluid (n);
  133. return fluid;
  134. }
  135. SCM
  136. scm_make_fluid (void)
  137. {
  138. return new_fluid (SCM_BOOL_F);
  139. }
  140. SCM_DEFINE (scm_make_fluid_with_default, "make-fluid", 0, 1, 0,
  141. (SCM dflt),
  142. "Return a newly created fluid, whose initial value is @var{dflt},\n"
  143. "or @code{#f} if @var{dflt} is not given.\n"
  144. "Fluids are objects that can hold one\n"
  145. "value per dynamic state. That is, modifications to this value are\n"
  146. "only visible to code that executes with the same dynamic state as\n"
  147. "the modifying code. When a new dynamic state is constructed, it\n"
  148. "inherits the values from its parent. Because each thread normally executes\n"
  149. "with its own dynamic state, you can use fluids for thread local storage.")
  150. #define FUNC_NAME s_scm_make_fluid_with_default
  151. {
  152. return new_fluid (SCM_UNBNDP (dflt) ? SCM_BOOL_F : dflt);
  153. }
  154. #undef FUNC_NAME
  155. SCM_DEFINE (scm_make_unbound_fluid, "make-unbound-fluid", 0, 0, 0,
  156. (),
  157. "Make a fluid that is initially unbound.")
  158. #define FUNC_NAME s_scm_make_unbound_fluid
  159. {
  160. return new_fluid (SCM_UNDEFINED);
  161. }
  162. #undef FUNC_NAME
  163. SCM_DEFINE (scm_fluid_p, "fluid?", 1, 0, 0,
  164. (SCM obj),
  165. "Return @code{#t} iff @var{obj} is a fluid; otherwise, return\n"
  166. "@code{#f}.")
  167. #define FUNC_NAME s_scm_fluid_p
  168. {
  169. return scm_from_bool (IS_FLUID (obj));
  170. }
  171. #undef FUNC_NAME
  172. int
  173. scm_is_fluid (SCM obj)
  174. {
  175. return IS_FLUID (obj);
  176. }
  177. /* Does not check type of `fluid'! */
  178. static SCM
  179. fluid_ref (SCM fluid)
  180. {
  181. SCM ret;
  182. SCM fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
  183. if (SCM_UNLIKELY (FLUID_NUM (fluid) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
  184. {
  185. /* Lazily grow the current thread's dynamic state. */
  186. grow_dynamic_state (SCM_I_CURRENT_THREAD->dynamic_state);
  187. fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
  188. }
  189. ret = SCM_SIMPLE_VECTOR_REF (fluids, FLUID_NUM (fluid));
  190. if (SCM_UNBNDP (ret))
  191. return SCM_I_FLUID_DEFAULT (fluid);
  192. else
  193. return ret;
  194. }
  195. SCM_DEFINE (scm_fluid_ref, "fluid-ref", 1, 0, 0,
  196. (SCM fluid),
  197. "Return the value associated with @var{fluid} in the current\n"
  198. "dynamic root. If @var{fluid} has not been set, then return\n"
  199. "@code{#f}.")
  200. #define FUNC_NAME s_scm_fluid_ref
  201. {
  202. SCM val;
  203. SCM_VALIDATE_FLUID (1, fluid);
  204. val = fluid_ref (fluid);
  205. if (SCM_UNBNDP (val))
  206. SCM_MISC_ERROR ("unbound fluid: ~S",
  207. scm_list_1 (fluid));
  208. return val;
  209. }
  210. #undef FUNC_NAME
  211. SCM_DEFINE (scm_fluid_set_x, "fluid-set!", 2, 0, 0,
  212. (SCM fluid, SCM value),
  213. "Set the value associated with @var{fluid} in the current dynamic root.")
  214. #define FUNC_NAME s_scm_fluid_set_x
  215. {
  216. SCM fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
  217. SCM_VALIDATE_FLUID (1, fluid);
  218. if (SCM_UNLIKELY (FLUID_NUM (fluid) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
  219. {
  220. /* Lazily grow the current thread's dynamic state. */
  221. grow_dynamic_state (SCM_I_CURRENT_THREAD->dynamic_state);
  222. fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
  223. }
  224. SCM_SIMPLE_VECTOR_SET (fluids, FLUID_NUM (fluid), value);
  225. return SCM_UNSPECIFIED;
  226. }
  227. #undef FUNC_NAME
  228. SCM_DEFINE (scm_fluid_unset_x, "fluid-unset!", 1, 0, 0,
  229. (SCM fluid),
  230. "Unset the value associated with @var{fluid}.")
  231. #define FUNC_NAME s_scm_fluid_unset_x
  232. {
  233. /* FIXME: really unset the default value, too? The current test
  234. suite demands it, but I would prefer not to. */
  235. SCM_SET_CELL_OBJECT_1 (fluid, SCM_UNDEFINED);
  236. return scm_fluid_set_x (fluid, SCM_UNDEFINED);
  237. }
  238. #undef FUNC_NAME
  239. SCM_DEFINE (scm_fluid_bound_p, "fluid-bound?", 1, 0, 0,
  240. (SCM fluid),
  241. "Return @code{#t} iff @var{fluid} is bound to a value.\n"
  242. "Throw an error if @var{fluid} is not a fluid.")
  243. #define FUNC_NAME s_scm_fluid_bound_p
  244. {
  245. SCM val;
  246. SCM_VALIDATE_FLUID (1, fluid);
  247. val = fluid_ref (fluid);
  248. return scm_from_bool (! (SCM_UNBNDP (val)));
  249. }
  250. #undef FUNC_NAME
  251. static SCM
  252. apply_thunk (void *thunk)
  253. {
  254. return scm_call_0 (SCM_PACK (thunk));
  255. }
  256. void
  257. scm_swap_fluid (SCM fluid, SCM value_box, SCM dynstate)
  258. {
  259. SCM fluid_vector, tmp;
  260. size_t fluid_num;
  261. fluid_num = FLUID_NUM (fluid);
  262. fluid_vector = DYNAMIC_STATE_FLUIDS (dynstate);
  263. if (SCM_UNLIKELY (fluid_num >= SCM_SIMPLE_VECTOR_LENGTH (fluid_vector)))
  264. {
  265. /* Lazily grow the current thread's dynamic state. */
  266. grow_dynamic_state (dynstate);
  267. fluid_vector = DYNAMIC_STATE_FLUIDS (dynstate);
  268. }
  269. tmp = SCM_SIMPLE_VECTOR_REF (fluid_vector, fluid_num);
  270. SCM_SIMPLE_VECTOR_SET (fluid_vector, fluid_num, SCM_VARIABLE_REF (value_box));
  271. SCM_VARIABLE_SET (value_box, tmp);
  272. }
  273. SCM_DEFINE (scm_with_fluids, "with-fluids*", 3, 0, 0,
  274. (SCM fluids, SCM values, SCM thunk),
  275. "Set @var{fluids} to @var{values} temporary, and call @var{thunk}.\n"
  276. "@var{fluids} must be a list of fluids and @var{values} must be the same\n"
  277. "number of their values to be applied. Each substitution is done\n"
  278. "one after another. @var{thunk} must be a procedure with no argument.")
  279. #define FUNC_NAME s_scm_with_fluids
  280. {
  281. return scm_c_with_fluids (fluids, values,
  282. apply_thunk, (void *) SCM_UNPACK (thunk));
  283. }
  284. #undef FUNC_NAME
  285. SCM
  286. scm_c_with_fluids (SCM fluids, SCM values, SCM (*cproc) (), void *cdata)
  287. #define FUNC_NAME "scm_c_with_fluids"
  288. {
  289. SCM ans;
  290. long flen, vlen, i;
  291. scm_i_thread *thread = SCM_I_CURRENT_THREAD;
  292. SCM_VALIDATE_LIST_COPYLEN (1, fluids, flen);
  293. SCM_VALIDATE_LIST_COPYLEN (2, values, vlen);
  294. if (flen != vlen)
  295. scm_out_of_range (s_scm_with_fluids, values);
  296. for (i = 0; i < flen; i++)
  297. {
  298. scm_dynstack_push_fluid (&thread->dynstack,
  299. SCM_CAR (fluids), SCM_CAR (values),
  300. thread->dynamic_state);
  301. fluids = SCM_CDR (fluids);
  302. values = SCM_CDR (values);
  303. }
  304. ans = cproc (cdata);
  305. for (i = 0; i < flen; i++)
  306. scm_dynstack_unwind_fluid (&thread->dynstack, thread->dynamic_state);
  307. return ans;
  308. }
  309. #undef FUNC_NAME
  310. SCM
  311. scm_with_fluid (SCM fluid, SCM value, SCM thunk)
  312. {
  313. return scm_c_with_fluid (fluid, value,
  314. apply_thunk, (void *) SCM_UNPACK (thunk));
  315. }
  316. SCM
  317. scm_c_with_fluid (SCM fluid, SCM value, SCM (*cproc) (), void *cdata)
  318. #define FUNC_NAME "scm_c_with_fluid"
  319. {
  320. SCM ans;
  321. scm_i_thread *thread = SCM_I_CURRENT_THREAD;
  322. scm_dynstack_push_fluid (&thread->dynstack, fluid, value,
  323. thread->dynamic_state);
  324. ans = cproc (cdata);
  325. scm_dynstack_unwind_fluid (&thread->dynstack, thread->dynamic_state);
  326. return ans;
  327. }
  328. #undef FUNC_NAME
  329. static void
  330. swap_fluid (SCM data)
  331. {
  332. SCM f = SCM_CAR (data);
  333. SCM t = fluid_ref (f);
  334. scm_fluid_set_x (f, SCM_CDR (data));
  335. SCM_SETCDR (data, t);
  336. }
  337. void
  338. scm_dynwind_fluid (SCM fluid, SCM value)
  339. {
  340. SCM data = scm_cons (fluid, value);
  341. scm_dynwind_rewind_handler_with_scm (swap_fluid, data, SCM_F_WIND_EXPLICITLY);
  342. scm_dynwind_unwind_handler_with_scm (swap_fluid, data, SCM_F_WIND_EXPLICITLY);
  343. }
  344. SCM
  345. scm_i_make_initial_dynamic_state ()
  346. {
  347. SCM fluids = scm_c_make_vector (allocated_fluids_len, SCM_BOOL_F);
  348. return scm_cell (scm_tc7_dynamic_state, SCM_UNPACK (fluids));
  349. }
  350. SCM_DEFINE (scm_make_dynamic_state, "make-dynamic-state", 0, 1, 0,
  351. (SCM parent),
  352. "Return a copy of the dynamic state object @var{parent}\n"
  353. "or of the current dynamic state when @var{parent} is omitted.")
  354. #define FUNC_NAME s_scm_make_dynamic_state
  355. {
  356. SCM fluids;
  357. if (SCM_UNBNDP (parent))
  358. parent = scm_current_dynamic_state ();
  359. SCM_ASSERT (IS_DYNAMIC_STATE (parent), parent, SCM_ARG1, FUNC_NAME);
  360. fluids = scm_vector_copy (DYNAMIC_STATE_FLUIDS (parent));
  361. return scm_cell (scm_tc7_dynamic_state, SCM_UNPACK (fluids));
  362. }
  363. #undef FUNC_NAME
  364. SCM_DEFINE (scm_dynamic_state_p, "dynamic-state?", 1, 0, 0,
  365. (SCM obj),
  366. "Return @code{#t} if @var{obj} is a dynamic state object;\n"
  367. "return @code{#f} otherwise")
  368. #define FUNC_NAME s_scm_dynamic_state_p
  369. {
  370. return scm_from_bool (IS_DYNAMIC_STATE (obj));
  371. }
  372. #undef FUNC_NAME
  373. int
  374. scm_is_dynamic_state (SCM obj)
  375. {
  376. return IS_DYNAMIC_STATE (obj);
  377. }
  378. SCM_DEFINE (scm_current_dynamic_state, "current-dynamic-state", 0, 0, 0,
  379. (),
  380. "Return the current dynamic state object.")
  381. #define FUNC_NAME s_scm_current_dynamic_state
  382. {
  383. return SCM_I_CURRENT_THREAD->dynamic_state;
  384. }
  385. #undef FUNC_NAME
  386. SCM_DEFINE (scm_set_current_dynamic_state, "set-current-dynamic-state", 1,0,0,
  387. (SCM state),
  388. "Set the current dynamic state object to @var{state}\n"
  389. "and return the previous current dynamic state object.")
  390. #define FUNC_NAME s_scm_set_current_dynamic_state
  391. {
  392. scm_i_thread *t = SCM_I_CURRENT_THREAD;
  393. SCM old = t->dynamic_state;
  394. SCM_ASSERT (IS_DYNAMIC_STATE (state), state, SCM_ARG1, FUNC_NAME);
  395. t->dynamic_state = state;
  396. return old;
  397. }
  398. #undef FUNC_NAME
  399. static void
  400. swap_dynamic_state (SCM loc)
  401. {
  402. SCM_SETCAR (loc, scm_set_current_dynamic_state (SCM_CAR (loc)));
  403. }
  404. void
  405. scm_dynwind_current_dynamic_state (SCM state)
  406. {
  407. SCM loc = scm_cons (state, SCM_EOL);
  408. SCM_ASSERT (IS_DYNAMIC_STATE (state), state, SCM_ARG1, NULL);
  409. scm_dynwind_rewind_handler_with_scm (swap_dynamic_state, loc,
  410. SCM_F_WIND_EXPLICITLY);
  411. scm_dynwind_unwind_handler_with_scm (swap_dynamic_state, loc,
  412. SCM_F_WIND_EXPLICITLY);
  413. }
  414. void *
  415. scm_c_with_dynamic_state (SCM state, void *(*func)(void *), void *data)
  416. {
  417. void *result;
  418. scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
  419. scm_dynwind_current_dynamic_state (state);
  420. result = func (data);
  421. scm_dynwind_end ();
  422. return result;
  423. }
  424. SCM_DEFINE (scm_with_dynamic_state, "with-dynamic-state", 2, 0, 0,
  425. (SCM state, SCM proc),
  426. "Call @var{proc} while @var{state} is the current dynamic\n"
  427. "state object.")
  428. #define FUNC_NAME s_scm_with_dynamic_state
  429. {
  430. SCM result;
  431. scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
  432. scm_dynwind_current_dynamic_state (state);
  433. result = scm_call_0 (proc);
  434. scm_dynwind_end ();
  435. return result;
  436. }
  437. #undef FUNC_NAME
  438. void
  439. scm_init_fluids ()
  440. {
  441. #include "libguile/fluids.x"
  442. }
  443. /*
  444. Local Variables:
  445. c-file-style: "gnu"
  446. End:
  447. */