async.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. /* Copyright (C) 1995,1996,1997,1998,2000,2001 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., 51 Franklin Street, Fifth Floor,
  16. * Boston, MA 02110-1301 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. #include <signal.h>
  42. #include "libguile/_scm.h"
  43. #include "libguile/eval.h"
  44. #include "libguile/throw.h"
  45. #include "libguile/root.h"
  46. #include "libguile/smob.h"
  47. #include "libguile/validate.h"
  48. #include "libguile/async.h"
  49. #ifdef HAVE_STRING_H
  50. #include <string.h>
  51. #endif
  52. #ifdef HAVE_UNISTD_H
  53. #include <unistd.h>
  54. #endif
  55. /* {Asynchronous Events}
  56. *
  57. *
  58. * Async == thunk + mark.
  59. *
  60. * Setting the mark guarantees future execution of the thunk. More
  61. * than one set may be satisfied by a single execution.
  62. *
  63. * scm_tick_clock decremented once per SCM_ALLOW_INTS.
  64. * Async execution triggered by SCM_ALLOW_INTS when scm_tick_clock drops to 0.
  65. * Async execution prevented by scm_mask_ints != 0.
  66. *
  67. * If the clock reaches 0 when scm_mask_ints != 0, then reset the clock
  68. * to 1.
  69. *
  70. * If the clock reaches 0 any other time, run marked asyncs.
  71. *
  72. * From a unix signal handler, mark a corresponding async and set the clock
  73. * to 1. Do SCM_REDEFER_INTS;/SCM_REALLOW_INTS so that if the signal handler is not
  74. * called in the dynamic scope of a critical section, it is excecuted immediately.
  75. *
  76. * Overall, closely timed signals of a particular sort may be combined. Pending signals
  77. * are delivered in a fixed priority order, regardless of arrival order.
  78. *
  79. */
  80. /* True between SCM_DEFER_INTS and SCM_ALLOW_INTS, and
  81. * when the interpreter is not running at all.
  82. */
  83. int scm_ints_disabled = 1;
  84. unsigned int scm_mask_ints = 1;
  85. #ifdef GUILE_OLD_ASYNC_CLICK
  86. unsigned int scm_async_clock = 20;
  87. static unsigned int scm_async_rate = 20;
  88. static unsigned int scm_tick_clock = 0;
  89. static unsigned int scm_tick_rate = 0;
  90. static unsigned int scm_desired_tick_rate = 0;
  91. static unsigned int scm_switch_clock = 0;
  92. static unsigned int scm_switch_rate = 0;
  93. static unsigned int scm_desired_switch_rate = 0;
  94. #else
  95. int scm_asyncs_pending_p = 0;
  96. #endif
  97. static scm_t_bits tc16_async;
  98. /* cmm: this has SCM_ prefix because SCM_MAKE_VALIDATE expects it.
  99. this is ugly. */
  100. #define SCM_ASYNCP(X) SCM_TYP16_PREDICATE (tc16_async, X)
  101. #define VALIDATE_ASYNC(pos,a) SCM_MAKE_VALIDATE(pos, a, ASYNCP)
  102. #define ASYNC_GOT_IT(X) (SCM_CELL_WORD_0 (X) >> 16)
  103. #define SET_ASYNC_GOT_IT(X, V) (SCM_SET_CELL_WORD_0 ((X), SCM_TYP16 (X) | ((V) << 16)))
  104. #define ASYNC_THUNK(X) SCM_CELL_OBJECT_1 (X)
  105. #ifdef GUILE_OLD_ASYNC_CLICK
  106. int
  107. scm_asyncs_pending ()
  108. {
  109. SCM pos;
  110. pos = scm_asyncs;
  111. while (!SCM_NULLP (pos))
  112. {
  113. SCM a = SCM_CAR (pos);
  114. if (ASYNC_GOT_IT (a))
  115. return 1;
  116. pos = SCM_CDR (pos);
  117. }
  118. return 0;
  119. }
  120. void
  121. scm_async_click ()
  122. {
  123. int owe_switch;
  124. int owe_tick;
  125. if (!scm_switch_rate)
  126. {
  127. owe_switch = 0;
  128. scm_switch_clock = scm_switch_rate = scm_desired_switch_rate;
  129. scm_desired_switch_rate = 0;
  130. }
  131. else
  132. {
  133. owe_switch = (scm_async_rate >= scm_switch_clock);
  134. if (owe_switch)
  135. {
  136. if (scm_desired_switch_rate)
  137. {
  138. scm_switch_clock = scm_switch_rate = scm_desired_switch_rate;
  139. scm_desired_switch_rate = 0;
  140. }
  141. else
  142. scm_switch_clock = scm_switch_rate;
  143. }
  144. else
  145. {
  146. if (scm_desired_switch_rate)
  147. {
  148. scm_switch_clock = scm_switch_rate = scm_desired_switch_rate;
  149. scm_desired_switch_rate = 0;
  150. }
  151. else
  152. scm_switch_clock -= scm_async_rate;
  153. }
  154. }
  155. if (scm_mask_ints)
  156. {
  157. if (owe_switch)
  158. scm_switch ();
  159. scm_async_clock = 1;
  160. return;;
  161. }
  162. if (!scm_tick_rate)
  163. {
  164. unsigned int r;
  165. owe_tick = 0;
  166. r = scm_desired_tick_rate;
  167. if (r)
  168. {
  169. scm_desired_tick_rate = 0;
  170. scm_tick_rate = r;
  171. scm_tick_clock = r;
  172. }
  173. }
  174. else
  175. {
  176. owe_tick = (scm_async_rate >= scm_tick_clock);
  177. if (owe_tick)
  178. {
  179. scm_tick_clock = scm_tick_rate = scm_desired_tick_rate;
  180. scm_desired_tick_rate = 0;
  181. }
  182. else
  183. {
  184. if (scm_desired_tick_rate)
  185. {
  186. scm_tick_clock = scm_tick_rate = scm_desired_tick_rate;
  187. scm_desired_tick_rate = 0;
  188. }
  189. else
  190. scm_tick_clock -= scm_async_rate;
  191. }
  192. }
  193. SCM_DEFER_INTS;
  194. if (scm_tick_rate && scm_switch_rate)
  195. {
  196. scm_async_rate = min (scm_tick_clock, scm_switch_clock);
  197. scm_async_clock = scm_async_rate;
  198. }
  199. else if (scm_tick_rate)
  200. {
  201. scm_async_clock = scm_async_rate = scm_tick_clock;
  202. }
  203. else if (scm_switch_rate)
  204. {
  205. scm_async_clock = scm_async_rate = scm_switch_clock;
  206. }
  207. else
  208. scm_async_clock = scm_async_rate = 1 << 16;
  209. SCM_ALLOW_INTS_ONLY;
  210. tail:
  211. scm_run_asyncs (scm_asyncs);
  212. SCM_DEFER_INTS;
  213. if (scm_asyncs_pending ())
  214. {
  215. SCM_ALLOW_INTS_ONLY;
  216. goto tail;
  217. }
  218. SCM_ALLOW_INTS;
  219. if (owe_switch)
  220. scm_switch ();
  221. }
  222. void
  223. scm_switch ()
  224. {
  225. #if 0 /* Thread switching code should probably reside here, but the
  226. async switching code doesn't seem to work, so it's put in the
  227. SCM_DEFER_INTS macro instead. /mdj */
  228. SCM_THREAD_SWITCHING_CODE;
  229. #endif
  230. }
  231. #else
  232. void
  233. scm_async_click ()
  234. {
  235. if (!scm_mask_ints)
  236. do
  237. scm_run_asyncs (scm_asyncs);
  238. while (scm_asyncs_pending_p);
  239. }
  240. #endif
  241. static SCM
  242. async_mark (SCM obj)
  243. {
  244. return ASYNC_THUNK (obj);
  245. }
  246. SCM_DEFINE (scm_async, "async", 1, 0, 0,
  247. (SCM thunk),
  248. "Create a new async for the procedure @var{thunk}.")
  249. #define FUNC_NAME s_scm_async
  250. {
  251. SCM_RETURN_NEWSMOB (tc16_async, SCM_UNPACK (thunk));
  252. }
  253. #undef FUNC_NAME
  254. SCM_DEFINE (scm_system_async, "system-async", 1, 0, 0,
  255. (SCM thunk),
  256. "Create a new async for the procedure @var{thunk}. Also\n"
  257. "add it to the system's list of active async objects.")
  258. #define FUNC_NAME s_scm_system_async
  259. {
  260. SCM it = scm_async (thunk);
  261. scm_asyncs = scm_cons (it, scm_asyncs);
  262. return it;
  263. }
  264. #undef FUNC_NAME
  265. SCM_DEFINE (scm_async_mark, "async-mark", 1, 0, 0,
  266. (SCM a),
  267. "Mark the async @var{a} for future execution.")
  268. #define FUNC_NAME s_scm_async_mark
  269. {
  270. VALIDATE_ASYNC (1, a);
  271. #ifdef GUILE_OLD_ASYNC_CLICK
  272. SET_ASYNC_GOT_IT (a, 1);
  273. #else
  274. SET_ASYNC_GOT_IT (a, scm_asyncs_pending_p = 1);
  275. #endif
  276. return SCM_UNSPECIFIED;
  277. }
  278. #undef FUNC_NAME
  279. SCM_DEFINE (scm_system_async_mark, "system-async-mark", 1, 0, 0,
  280. (SCM a),
  281. "Mark the async @var{a} for future execution.")
  282. #define FUNC_NAME s_scm_system_async_mark
  283. {
  284. VALIDATE_ASYNC (1, a);
  285. SCM_REDEFER_INTS;
  286. #ifdef GUILE_OLD_ASYNC_CLICK
  287. SET_ASYNC_GOT_IT (a, 1);
  288. scm_async_rate = 1 + scm_async_rate - scm_async_clock;
  289. scm_async_clock = 1;
  290. #else
  291. SET_ASYNC_GOT_IT (a, scm_asyncs_pending_p = 1);
  292. #endif
  293. SCM_REALLOW_INTS;
  294. return SCM_UNSPECIFIED;
  295. }
  296. #undef FUNC_NAME
  297. SCM_DEFINE (scm_run_asyncs, "run-asyncs", 1, 0, 0,
  298. (SCM list_of_a),
  299. "Execute all thunks from the asyncs of the list @var{list_of_a}.")
  300. #define FUNC_NAME s_scm_run_asyncs
  301. {
  302. #ifdef GUILE_OLD_ASYNC_CLICK
  303. if (scm_mask_ints)
  304. return SCM_BOOL_F;
  305. #else
  306. scm_asyncs_pending_p = 0;
  307. #endif
  308. while (! SCM_NULLP (list_of_a))
  309. {
  310. SCM a;
  311. SCM_VALIDATE_CONS (1, list_of_a);
  312. a = SCM_CAR (list_of_a);
  313. VALIDATE_ASYNC (SCM_ARG1, a);
  314. scm_mask_ints = 1;
  315. if (ASYNC_GOT_IT (a))
  316. {
  317. SET_ASYNC_GOT_IT (a, 0);
  318. scm_call_0 (ASYNC_THUNK (a));
  319. }
  320. scm_mask_ints = 0;
  321. list_of_a = SCM_CDR (list_of_a);
  322. }
  323. return SCM_BOOL_T;
  324. }
  325. #undef FUNC_NAME
  326. SCM_DEFINE (scm_noop, "noop", 0, 0, 1,
  327. (SCM args),
  328. "Do nothing. When called without arguments, return @code{#f},\n"
  329. "otherwise return the first argument.")
  330. #define FUNC_NAME s_scm_noop
  331. {
  332. SCM_VALIDATE_REST_ARGUMENT (args);
  333. return (SCM_NULLP (args) ? SCM_BOOL_F : SCM_CAR (args));
  334. }
  335. #undef FUNC_NAME
  336. #ifdef GUILE_OLD_ASYNC_CLICK
  337. SCM_DEFINE (scm_set_tick_rate, "set-tick-rate", 1, 0, 0,
  338. (SCM n),
  339. "Set the rate of async ticks to @var{n}. Return the old rate\n"
  340. "value.")
  341. #define FUNC_NAME s_scm_set_tick_rate
  342. {
  343. unsigned int old_n = scm_tick_rate;
  344. SCM_VALIDATE_INUM (1, n);
  345. scm_desired_tick_rate = SCM_INUM (n);
  346. scm_async_rate = 1 + scm_async_rate - scm_async_clock;
  347. scm_async_clock = 1;
  348. return SCM_MAKINUM (old_n);
  349. }
  350. #undef FUNC_NAME
  351. SCM_DEFINE (scm_set_switch_rate, "set-switch-rate", 1, 0, 0,
  352. (SCM n),
  353. "Set the async switch rate to @var{n}. Return the old value\n"
  354. "of the switch rate.")
  355. #define FUNC_NAME s_scm_set_switch_rate
  356. {
  357. unsigned int old_n = scm_switch_rate;
  358. SCM_VALIDATE_INUM (1, n);
  359. scm_desired_switch_rate = SCM_INUM (n);
  360. scm_async_rate = 1 + scm_async_rate - scm_async_clock;
  361. scm_async_clock = 1;
  362. return SCM_MAKINUM (old_n);
  363. }
  364. #undef FUNC_NAME
  365. #endif
  366. SCM_DEFINE (scm_unmask_signals, "unmask-signals", 0, 0, 0,
  367. (),
  368. "Unmask signals. The returned value is not specified.")
  369. #define FUNC_NAME s_scm_unmask_signals
  370. {
  371. scm_mask_ints = 0;
  372. return SCM_UNSPECIFIED;
  373. }
  374. #undef FUNC_NAME
  375. SCM_DEFINE (scm_mask_signals, "mask-signals", 0, 0, 0,
  376. (),
  377. "Mask signals. The returned value is not specified.")
  378. #define FUNC_NAME s_scm_mask_signals
  379. {
  380. scm_mask_ints = 1;
  381. return SCM_UNSPECIFIED;
  382. }
  383. #undef FUNC_NAME
  384. void
  385. scm_init_async ()
  386. {
  387. scm_asyncs = SCM_EOL;
  388. tc16_async = scm_make_smob_type ("async", 0);
  389. scm_set_smob_mark (tc16_async, async_mark);
  390. #include "libguile/async.x"
  391. }
  392. /*
  393. Local Variables:
  394. c-file-style: "gnu"
  395. End:
  396. */