PageRenderTime 75ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/src/racket/src/thread.c

http://github.com/gmarceau/PLT
C | 7989 lines | 6099 code | 1374 blank | 516 comment | 1097 complexity | 53b08be251330184d36c3e02c55b6546 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. Racket
  3. Copyright (c) 2004-2011 PLT Scheme Inc.
  4. Copyright (c) 1995-2001 Matthew Flatt
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public
  7. License as published by the Free Software Foundation; either
  8. version 2 of the License, or (at your option) any later version.
  9. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with this library; if not, write to the Free
  15. Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  16. Boston, MA 02110-1301 USA.
  17. */
  18. /* This file implements Racket threads.
  19. Usually, Racket threads are implemented by copying the stack.
  20. The scheme_thread_block() function is called occasionally by the
  21. evaluator so that the current thread can be swapped out.
  22. do_swap_thread() performs the actual swap. Threads can also be
  23. implemented by the OS; the bottom part of this file contains
  24. OS-specific thread code.
  25. Much of the work in thread management is knowning when to go to
  26. sleep, to be nice to the OS outside of Racket. The rest of the
  27. work is implementing custodians (called "custodians" in the code),
  28. parameters, and wills. */
  29. /* Some copilers don't like re-def of GC_malloc in schemef.h: */
  30. #ifndef MZ_PRECISE_GC
  31. # define SCHEME_NO_GC_PROTO
  32. #endif
  33. #include "schpriv.h"
  34. #include "schmach.h"
  35. #include "schgc.h"
  36. #ifdef MZ_USE_FUTURES
  37. # include "future.h"
  38. #endif
  39. #ifndef PALMOS_STUFF
  40. # include <time.h>
  41. #endif
  42. #ifdef FILES_HAVE_FDS
  43. # include <sys/types.h>
  44. # include <sys/time.h>
  45. # ifdef SELECT_INCLUDE
  46. # include <sys/select.h>
  47. # endif
  48. # ifdef USE_BEOS_SOCKET_INCLUDE
  49. # include <be/net/socket.h>
  50. # endif
  51. #endif
  52. #ifdef USE_WINSOCK_TCP
  53. # ifdef USE_TCP
  54. # include <winsock.h>
  55. # endif
  56. #endif
  57. #ifdef USE_BEOS_PORT_THREADS
  58. # include <be/net/socket.h>
  59. #endif
  60. #ifdef USE_STACKAVAIL
  61. # include <malloc.h>
  62. #endif
  63. #ifdef UNISTD_INCLUDE
  64. # include <unistd.h>
  65. #endif
  66. #ifndef SIGNMZTHREAD
  67. # define SIGMZTHREAD SIGUSR2
  68. #endif
  69. #if defined(WINDOWS_PROCESSES) || defined(WINDOWS_FILE_HANDLES)
  70. # include <windows.h>
  71. THREAD_LOCAL_DECL(extern void *scheme_break_semaphore;)
  72. #endif
  73. #if defined(FILES_HAVE_FDS) \
  74. || defined(USE_BEOS_PORT_THREADS) \
  75. || (defined(USE_WINSOCK_TCP) && defined(USE_TCP)) \
  76. || (defined(WINDOWS_PROCESSES) || defined(WINDOWS_FILE_HANDLES))
  77. # define USING_FDS
  78. # if (!defined(USE_WINSOCK_TCP) || !defined(USE_TCP)) && !defined(FILES_HAVE_FDS)
  79. # include <sys/types.h>
  80. # endif
  81. #endif
  82. #include "schfd.h"
  83. #define DEFAULT_INIT_STACK_SIZE 1000
  84. #define MAX_INIT_STACK_SIZE 100000
  85. #ifdef SGC_STD_DEBUGGING
  86. # define SENORA_GC_NO_FREE
  87. #endif
  88. /* If a finalization callback invokes Scheme code,
  89. we can end up with a thread swap in the middle of a thread
  90. swap (where the outer swap was interrupted by GC). The
  91. following is a debugging flag to help detect and fix
  92. such problems. */
  93. #define WATCH_FOR_NESTED_SWAPS 0
  94. #if WATCH_FOR_NESTED_SWAPS
  95. static int swapping = 0;
  96. #endif
  97. extern void scheme_gmp_tls_init(intptr_t *s);
  98. extern void *scheme_gmp_tls_load(intptr_t *s);
  99. extern void scheme_gmp_tls_unload(intptr_t *s, void *p);
  100. extern void scheme_gmp_tls_snapshot(intptr_t *s, intptr_t *save);
  101. extern void scheme_gmp_tls_restore_snapshot(intptr_t *s, void *data, intptr_t *save, int do_free);
  102. static void check_ready_break();
  103. THREAD_LOCAL_DECL(extern int scheme_num_read_syntax_objects);
  104. THREAD_LOCAL_DECL(extern intptr_t scheme_hash_request_count);
  105. THREAD_LOCAL_DECL(extern intptr_t scheme_hash_iteration_count);
  106. THREAD_LOCAL_DECL(extern intptr_t scheme_code_page_total);
  107. #ifdef MZ_USE_JIT
  108. extern int scheme_jit_malloced;
  109. #else
  110. # define scheme_jit_malloced 0
  111. #endif
  112. /*========================================================================*/
  113. /* local variables and prototypes */
  114. /*========================================================================*/
  115. #define INIT_TB_SIZE 20
  116. #ifndef MZ_THREAD_QUANTUM_USEC
  117. # define MZ_THREAD_QUANTUM_USEC 10000
  118. #endif
  119. THREAD_LOCAL_DECL(static int buffer_init_size);
  120. THREAD_LOCAL_DECL(Scheme_Thread *scheme_current_thread = NULL);
  121. THREAD_LOCAL_DECL(Scheme_Thread *scheme_main_thread = NULL);
  122. THREAD_LOCAL_DECL(Scheme_Thread *scheme_first_thread = NULL);
  123. XFORM_NONGCING Scheme_Thread *scheme_get_current_thread() { return scheme_current_thread; }
  124. XFORM_NONGCING intptr_t scheme_get_multiple_count() { return scheme_current_thread->ku.multiple.count; }
  125. XFORM_NONGCING Scheme_Object **scheme_get_multiple_array() { return scheme_current_thread->ku.multiple.array; }
  126. XFORM_NONGCING void scheme_set_current_thread_ran_some() { scheme_current_thread->ran_some = 1; }
  127. THREAD_LOCAL_DECL(Scheme_Thread_Set *scheme_thread_set_top);
  128. THREAD_LOCAL_DECL(static int num_running_threads); /* not counting original */
  129. #ifdef LINK_EXTENSIONS_BY_TABLE
  130. Scheme_Thread **scheme_current_thread_ptr;
  131. volatile int *scheme_fuel_counter_ptr;
  132. #endif
  133. THREAD_LOCAL_DECL(static int swap_no_setjmp = 0);
  134. THREAD_LOCAL_DECL(static int thread_swap_count);
  135. THREAD_LOCAL_DECL(int scheme_did_gc_count);
  136. SHARED_OK static int init_load_on_demand = 1;
  137. #ifdef RUNSTACK_IS_GLOBAL
  138. THREAD_LOCAL_DECL(Scheme_Object **scheme_current_runstack_start);
  139. THREAD_LOCAL_DECL(Scheme_Object **scheme_current_runstack);
  140. THREAD_LOCAL_DECL(MZ_MARK_STACK_TYPE scheme_current_cont_mark_stack);
  141. THREAD_LOCAL_DECL(MZ_MARK_POS_TYPE scheme_current_cont_mark_pos);
  142. #endif
  143. THREAD_LOCAL_DECL(static Scheme_Custodian *main_custodian);
  144. THREAD_LOCAL_DECL(static Scheme_Custodian *last_custodian);
  145. THREAD_LOCAL_DECL(static Scheme_Hash_Table *limited_custodians = NULL);
  146. READ_ONLY static Scheme_Object *initial_inspector;
  147. #ifndef MZ_PRECISE_GC
  148. static int cust_box_count, cust_box_alloc;
  149. static Scheme_Custodian_Box **cust_boxes;
  150. # ifndef USE_SENORA_GC
  151. extern int GC_is_marked(void *);
  152. # endif
  153. #endif
  154. READ_ONLY Scheme_At_Exit_Proc replacement_at_exit;
  155. ROSYM Scheme_Object *scheme_parameterization_key;
  156. ROSYM Scheme_Object *scheme_exn_handler_key;
  157. ROSYM Scheme_Object *scheme_break_enabled_key;
  158. THREAD_LOCAL_DECL(intptr_t scheme_total_gc_time);
  159. THREAD_LOCAL_DECL(static intptr_t start_this_gc_time);
  160. THREAD_LOCAL_DECL(static intptr_t end_this_gc_time);
  161. static void get_ready_for_GC(void);
  162. static void done_with_GC(void);
  163. #ifdef MZ_PRECISE_GC
  164. static void inform_GC(int master_gc, int major_gc, intptr_t pre_used, intptr_t post_used,
  165. intptr_t pre_admin, intptr_t post_admin);
  166. #endif
  167. THREAD_LOCAL_DECL(static volatile short delayed_break_ready);
  168. THREAD_LOCAL_DECL(static Scheme_Thread *main_break_target_thread);
  169. THREAD_LOCAL_DECL(Scheme_Sleep_Proc scheme_place_sleep);
  170. HOOK_SHARED_OK void (*scheme_sleep)(float seconds, void *fds);
  171. HOOK_SHARED_OK void (*scheme_notify_multithread)(int on);
  172. HOOK_SHARED_OK void (*scheme_wakeup_on_input)(void *fds);
  173. HOOK_SHARED_OK int (*scheme_check_for_break)(void);
  174. HOOK_SHARED_OK Scheme_On_Atomic_Timeout_Proc scheme_on_atomic_timeout;
  175. HOOK_SHARED_OK static int atomic_timeout_auto_suspend;
  176. HOOK_SHARED_OK static int atomic_timeout_atomic_level;
  177. THREAD_LOCAL_DECL(struct Scheme_GC_Pre_Post_Callback_Desc *gc_prepost_callback_descs);
  178. ROSYM static Scheme_Object *read_symbol, *write_symbol, *execute_symbol, *delete_symbol, *exists_symbol;
  179. ROSYM static Scheme_Object *client_symbol, *server_symbol;
  180. THREAD_LOCAL_DECL(static int do_atomic = 0);
  181. THREAD_LOCAL_DECL(static int missed_context_switch = 0);
  182. THREAD_LOCAL_DECL(static int have_activity = 0);
  183. THREAD_LOCAL_DECL(int scheme_active_but_sleeping = 0);
  184. THREAD_LOCAL_DECL(static int thread_ended_with_activity);
  185. THREAD_LOCAL_DECL(int scheme_no_stack_overflow);
  186. THREAD_LOCAL_DECL(int all_breaks_disabled = 0);
  187. THREAD_LOCAL_DECL(static int needs_sleep_cancelled);
  188. THREAD_LOCAL_DECL(static double needs_sleep_time_end); /* back-door result */
  189. THREAD_LOCAL_DECL(static int tls_pos = 0);
  190. /* On swap, put target in a static variable, instead of on the stack,
  191. so that the swapped-out thread is less likely to have a pointer
  192. to the target thread. */
  193. THREAD_LOCAL_DECL(static Scheme_Thread *swap_target);
  194. THREAD_LOCAL_DECL(static Scheme_Object *scheduled_kills);
  195. THREAD_LOCAL_DECL(static Scheme_Object *the_nested_exn_handler);
  196. THREAD_LOCAL_DECL(static Scheme_Object *cust_closers);
  197. THREAD_LOCAL_DECL(static Scheme_Object *thread_swap_callbacks);
  198. THREAD_LOCAL_DECL(static Scheme_Object *thread_swap_out_callbacks);
  199. THREAD_LOCAL_DECL(static Scheme_Object *recycle_cell);
  200. THREAD_LOCAL_DECL(static Scheme_Object *maybe_recycle_cell);
  201. THREAD_LOCAL_DECL(static int recycle_cc_count);
  202. THREAD_LOCAL_DECL(struct Scheme_Hash_Table *place_local_misc_table);
  203. #if defined(MZ_PRECISE_GC) && defined(MZ_USE_PLACES)
  204. extern intptr_t GC_is_place();
  205. #endif
  206. #ifdef MZ_PRECISE_GC
  207. extern intptr_t GC_get_memory_use(void *c);
  208. #else
  209. extern MZ_DLLIMPORT long GC_get_memory_use();
  210. #endif
  211. typedef struct Thread_Cell {
  212. Scheme_Object so;
  213. char inherited, assigned;
  214. Scheme_Object *def_val;
  215. /* A thread's thread_cell table maps cells to keys weakly.
  216. This table maps keys to values weakly. The two weak
  217. levels ensure that thread cells are properly GCed
  218. when the value of a thread cell references the thread
  219. cell. */
  220. Scheme_Bucket_Table *vals;
  221. } Thread_Cell;
  222. #ifdef MZ_PRECISE_GC
  223. /* This is a trick to get the types right. Note that
  224. the layout of the weak box is defined by the
  225. GC spec. */
  226. typedef struct {
  227. short type;
  228. short hash_key;
  229. Scheme_Custodian *val;
  230. } Scheme_Custodian_Weak_Box;
  231. # define MALLOC_MREF() (Scheme_Custodian_Reference *)scheme_make_late_weak_box(NULL)
  232. # define CUSTODIAN_FAM(x) ((Scheme_Custodian_Weak_Box *)x)->val
  233. # define xCUSTODIAN_FAM(x) SCHEME_BOX_VAL(x)
  234. #else
  235. # define MALLOC_MREF() MALLOC_ONE_WEAK(Scheme_Custodian_Reference)
  236. # define CUSTODIAN_FAM(x) (*(x))
  237. # define xCUSTODIAN_FAM(x) (*(x))
  238. #endif
  239. typedef struct Proc_Global_Rec {
  240. const char *key;
  241. void *val;
  242. struct Proc_Global_Rec *next;
  243. } Proc_Global_Rec;
  244. SHARED_OK static Proc_Global_Rec *process_globals;
  245. #if defined(MZ_USE_MZRT)
  246. static mzrt_mutex *process_global_lock;
  247. #endif
  248. #ifdef MZ_PRECISE_GC
  249. static void register_traversers(void);
  250. #endif
  251. static Scheme_Object *custodian_require_mem(int argc, Scheme_Object *args[]);
  252. static Scheme_Object *custodian_limit_mem(int argc, Scheme_Object *args[]);
  253. static Scheme_Object *custodian_can_mem(int argc, Scheme_Object *args[]);
  254. static Scheme_Object *new_tracking_fun(int argc, Scheme_Object *args[]);
  255. static Scheme_Object *union_tracking_val(int argc, Scheme_Object *args[]);
  256. static Scheme_Object *collect_garbage(int argc, Scheme_Object *args[]);
  257. static Scheme_Object *current_memory_use(int argc, Scheme_Object *args[]);
  258. static Scheme_Object *sch_thread(int argc, Scheme_Object *args[]);
  259. static Scheme_Object *sch_thread_nokill(int argc, Scheme_Object *args[]);
  260. static Scheme_Object *sch_sleep(int argc, Scheme_Object *args[]);
  261. static Scheme_Object *thread_p(int argc, Scheme_Object *args[]);
  262. static Scheme_Object *thread_running_p(int argc, Scheme_Object *args[]);
  263. static Scheme_Object *thread_dead_p(int argc, Scheme_Object *args[]);
  264. static Scheme_Object *thread_wait(int argc, Scheme_Object *args[]);
  265. static Scheme_Object *sch_current(int argc, Scheme_Object *args[]);
  266. static Scheme_Object *kill_thread(int argc, Scheme_Object *args[]);
  267. static Scheme_Object *break_thread(int argc, Scheme_Object *args[]);
  268. static Scheme_Object *thread_suspend(int argc, Scheme_Object *args[]);
  269. static Scheme_Object *thread_resume(int argc, Scheme_Object *args[]);
  270. static Scheme_Object *make_thread_suspend(int argc, Scheme_Object *args[]);
  271. static Scheme_Object *make_thread_resume(int argc, Scheme_Object *args[]);
  272. static Scheme_Object *make_thread_dead(int argc, Scheme_Object *args[]);
  273. static void register_thread_sync();
  274. static Scheme_Object *sch_sync(int argc, Scheme_Object *args[]);
  275. static Scheme_Object *sch_sync_timeout(int argc, Scheme_Object *args[]);
  276. static Scheme_Object *sch_sync_enable_break(int argc, Scheme_Object *args[]);
  277. static Scheme_Object *sch_sync_timeout_enable_break(int argc, Scheme_Object *args[]);
  278. static Scheme_Object *evt_p(int argc, Scheme_Object *args[]);
  279. static Scheme_Object *evts_to_evt(int argc, Scheme_Object *args[]);
  280. static Scheme_Object *make_custodian(int argc, Scheme_Object *argv[]);
  281. static Scheme_Object *make_custodian_from_main(int argc, Scheme_Object *argv[]);
  282. static Scheme_Object *custodian_p(int argc, Scheme_Object *argv[]);
  283. static Scheme_Object *custodian_close_all(int argc, Scheme_Object *argv[]);
  284. static Scheme_Object *custodian_to_list(int argc, Scheme_Object *argv[]);
  285. static Scheme_Object *current_custodian(int argc, Scheme_Object *argv[]);
  286. static Scheme_Object *make_custodian_box(int argc, Scheme_Object *argv[]);
  287. static Scheme_Object *custodian_box_value(int argc, Scheme_Object *argv[]);
  288. static Scheme_Object *custodian_box_p(int argc, Scheme_Object *argv[]);
  289. static Scheme_Object *call_as_nested_thread(int argc, Scheme_Object *argv[]);
  290. static Scheme_Object *current_namespace(int argc, Scheme_Object *args[]);
  291. static Scheme_Object *namespace_p(int argc, Scheme_Object *args[]);
  292. static Scheme_Object *parameter_p(int argc, Scheme_Object *args[]);
  293. static Scheme_Object *parameter_procedure_eq(int argc, Scheme_Object *args[]);
  294. static Scheme_Object *make_parameter(int argc, Scheme_Object *args[]);
  295. static Scheme_Object *make_derived_parameter(int argc, Scheme_Object *args[]);
  296. static Scheme_Object *extend_parameterization(int argc, Scheme_Object *args[]);
  297. static Scheme_Object *parameterization_p(int argc, Scheme_Object *args[]);
  298. static Scheme_Object *reparameterize(int argc, Scheme_Object **argv);
  299. static Scheme_Object *make_thread_cell(int argc, Scheme_Object *args[]);
  300. static Scheme_Object *thread_cell_p(int argc, Scheme_Object *args[]);
  301. static Scheme_Object *thread_cell_get(int argc, Scheme_Object *args[]);
  302. static Scheme_Object *thread_cell_set(int argc, Scheme_Object *args[]);
  303. static Scheme_Object *thread_cell_values(int argc, Scheme_Object *args[]);
  304. static Scheme_Object *make_security_guard(int argc, Scheme_Object *argv[]);
  305. static Scheme_Object *security_guard_p(int argc, Scheme_Object *argv[]);
  306. static Scheme_Object *current_security_guard(int argc, Scheme_Object *argv[]);
  307. static Scheme_Object *make_thread_set(int argc, Scheme_Object *argv[]);
  308. static Scheme_Object *thread_set_p(int argc, Scheme_Object *argv[]);
  309. static Scheme_Object *current_thread_set(int argc, Scheme_Object *argv[]);
  310. static Scheme_Object *current_thread_initial_stack_size(int argc, Scheme_Object *argv[]);
  311. static void adjust_custodian_family(void *pr, void *ignored);
  312. static Scheme_Object *make_will_executor(int argc, Scheme_Object *args[]);
  313. static Scheme_Object *will_executor_p(int argc, Scheme_Object *args[]);
  314. static Scheme_Object *register_will(int argc, Scheme_Object *args[]);
  315. static Scheme_Object *will_executor_try(int argc, Scheme_Object *args[]);
  316. static Scheme_Object *will_executor_go(int argc, Scheme_Object *args[]);
  317. static Scheme_Object *will_executor_sema(Scheme_Object *w, int *repost);
  318. static Scheme_Object *check_break_now(int argc, Scheme_Object *args[]);
  319. static int syncing_ready(Scheme_Object *s, Scheme_Schedule_Info *sinfo);
  320. static void make_initial_config(Scheme_Thread *p);
  321. static int do_kill_thread(Scheme_Thread *p);
  322. static void suspend_thread(Scheme_Thread *p);
  323. static int check_sleep(int need_activity, int sleep_now);
  324. static void remove_thread(Scheme_Thread *r);
  325. static void exit_or_escape(Scheme_Thread *p);
  326. static int resume_suspend_ready(Scheme_Object *o, Scheme_Schedule_Info *sinfo);
  327. static int dead_ready(Scheme_Object *o, Scheme_Schedule_Info *sinfo);
  328. static int cust_box_ready(Scheme_Object *o);
  329. static int can_break_param(Scheme_Thread *p);
  330. static int post_system_idle();
  331. static Scheme_Object *current_stats(int argc, Scheme_Object *args[]);
  332. SHARED_OK static Scheme_Object **config_map;
  333. typedef struct {
  334. MZTAG_IF_REQUIRED
  335. short is_derived;
  336. Scheme_Object *key;
  337. Scheme_Object *guard;
  338. Scheme_Object *extract_guard;
  339. Scheme_Object *defcell;
  340. } ParamData;
  341. enum {
  342. CONFIG_DIRECT,
  343. CONFIG_INDIRECT
  344. };
  345. typedef struct Scheme_Thread_Custodian_Hop {
  346. Scheme_Object so;
  347. Scheme_Thread *p; /* really an indirection with precise gc */
  348. } Scheme_Thread_Custodian_Hop;
  349. SHARED_OK static Scheme_Custodian_Extractor *extractors;
  350. #define SETJMP(p) scheme_setjmpup(&p->jmpup_buf, p, p->stack_start)
  351. #define LONGJMP(p) scheme_longjmpup(&p->jmpup_buf)
  352. #define RESETJMP(p) scheme_reset_jmpup_buf(&p->jmpup_buf)
  353. #ifdef WIN32_THREADS
  354. /* Only set up for Boehm GC that thinks it's a DLL: */
  355. # define GC_THINKS_ITS_A_DLL_BUT_ISNT
  356. # ifdef GC_THINKS_ITS_A_DLL_BUT_ISNT
  357. extern BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved);
  358. # endif
  359. #endif
  360. #ifndef MZ_PRECISE_GC
  361. # define scheme_thread_hop_type scheme_thread_type
  362. #endif
  363. #ifdef MZ_PRECISE_GC
  364. uintptr_t scheme_get_current_thread_stack_start(void);
  365. #endif
  366. SHARED_OK Scheme_Object *initial_cmdline_vec;
  367. /*========================================================================*/
  368. /* initialization */
  369. /*========================================================================*/
  370. void scheme_init_thread(Scheme_Env *env)
  371. {
  372. #ifdef MZ_PRECISE_GC
  373. register_traversers();
  374. #endif
  375. REGISTER_SO(read_symbol);
  376. REGISTER_SO(write_symbol);
  377. REGISTER_SO(execute_symbol);
  378. REGISTER_SO(delete_symbol);
  379. REGISTER_SO(exists_symbol);
  380. REGISTER_SO(client_symbol);
  381. REGISTER_SO(server_symbol);
  382. read_symbol = scheme_intern_symbol("read");
  383. write_symbol = scheme_intern_symbol("write");
  384. execute_symbol = scheme_intern_symbol("execute");
  385. delete_symbol = scheme_intern_symbol("delete");
  386. exists_symbol = scheme_intern_symbol("exists");
  387. client_symbol = scheme_intern_symbol("client");
  388. server_symbol = scheme_intern_symbol("server");
  389. GLOBAL_PRIM_W_ARITY("dump-memory-stats" , scheme_dump_gc_stats, 0, -1, env);
  390. GLOBAL_PRIM_W_ARITY("vector-set-performance-stats!", current_stats , 1, 2, env);
  391. GLOBAL_PRIM_W_ARITY("make-empty-namespace", scheme_make_namespace, 0, 0, env);
  392. GLOBAL_PRIM_W_ARITY("thread" , sch_thread , 1, 1, env);
  393. GLOBAL_PRIM_W_ARITY("thread/suspend-to-kill", sch_thread_nokill , 1, 1, env);
  394. GLOBAL_PRIM_W_ARITY("sleep" , sch_sleep , 0, 1, env);
  395. GLOBAL_FOLDING_PRIM("thread?" , thread_p , 1, 1, 1, env);
  396. GLOBAL_PRIM_W_ARITY("thread-running?" , thread_running_p , 1, 1, env);
  397. GLOBAL_PRIM_W_ARITY("thread-dead?" , thread_dead_p , 1, 1, env);
  398. GLOBAL_PRIM_W_ARITY("thread-wait" , thread_wait , 1, 1, env);
  399. GLOBAL_PRIM_W_ARITY("current-thread" , sch_current , 0, 0, env);
  400. GLOBAL_PRIM_W_ARITY("kill-thread" , kill_thread , 1, 1, env);
  401. GLOBAL_PRIM_W_ARITY("break-thread" , break_thread , 1, 1, env);
  402. GLOBAL_PRIM_W_ARITY("thread-suspend" , thread_suspend , 1, 1, env);
  403. GLOBAL_PRIM_W_ARITY("thread-resume" , thread_resume , 1, 2, env);
  404. GLOBAL_PRIM_W_ARITY("thread-resume-evt" , make_thread_resume , 1, 1, env);
  405. GLOBAL_PRIM_W_ARITY("thread-suspend-evt" , make_thread_suspend, 1, 1, env);
  406. GLOBAL_PRIM_W_ARITY("thread-dead-evt" , make_thread_dead , 1, 1, env);
  407. register_thread_sync();
  408. scheme_add_evt(scheme_thread_suspend_type, (Scheme_Ready_Fun)resume_suspend_ready, NULL, NULL, 1);
  409. scheme_add_evt(scheme_thread_resume_type, (Scheme_Ready_Fun)resume_suspend_ready, NULL, NULL, 1);
  410. scheme_add_evt(scheme_thread_dead_type, (Scheme_Ready_Fun)dead_ready, NULL, NULL, 1);
  411. scheme_add_evt(scheme_cust_box_type, cust_box_ready, NULL, NULL, 0);
  412. GLOBAL_PARAMETER("current-custodian" , current_custodian , MZCONFIG_CUSTODIAN, env);
  413. GLOBAL_PRIM_W_ARITY("make-custodian" , make_custodian , 0, 1, env);
  414. GLOBAL_FOLDING_PRIM("custodian?" , custodian_p , 1, 1, 1 , env);
  415. GLOBAL_PRIM_W_ARITY("custodian-shutdown-all", custodian_close_all , 1, 1, env);
  416. GLOBAL_PRIM_W_ARITY("custodian-managed-list", custodian_to_list , 2, 2, env);
  417. GLOBAL_PRIM_W_ARITY("make-custodian-box" , make_custodian_box , 2, 2, env);
  418. GLOBAL_PRIM_W_ARITY("custodian-box-value" , custodian_box_value , 1, 1, env);
  419. GLOBAL_FOLDING_PRIM("custodian-box?" , custodian_box_p , 1, 1, 1 , env);
  420. GLOBAL_PRIM_W_ARITY("call-in-nested-thread" , call_as_nested_thread, 1, 2, env);
  421. GLOBAL_PARAMETER("current-namespace" , current_namespace, MZCONFIG_ENV, env);
  422. GLOBAL_PRIM_W_ARITY("namespace?" , namespace_p , 1, 1, env);
  423. GLOBAL_PRIM_W_ARITY("security-guard?" , security_guard_p , 1, 1, env);
  424. GLOBAL_PRIM_W_ARITY("make-security-guard", make_security_guard, 3, 4, env);
  425. GLOBAL_PARAMETER("current-security-guard", current_security_guard, MZCONFIG_SECURITY_GUARD, env);
  426. GLOBAL_PRIM_W_ARITY("thread-group?" , thread_set_p , 1, 1, env);
  427. GLOBAL_PRIM_W_ARITY("make-thread-group", make_thread_set, 0, 1, env);
  428. GLOBAL_PARAMETER("current-thread-group", current_thread_set, MZCONFIG_THREAD_SET, env);
  429. GLOBAL_PRIM_W_ARITY("parameter?" , parameter_p , 1, 1, env);
  430. GLOBAL_PRIM_W_ARITY("make-parameter" , make_parameter , 1, 2, env);
  431. GLOBAL_PRIM_W_ARITY("make-derived-parameter", make_derived_parameter, 3, 3, env);
  432. GLOBAL_PRIM_W_ARITY("parameter-procedure=?" , parameter_procedure_eq, 2, 2, env);
  433. GLOBAL_PRIM_W_ARITY("parameterization?" , parameterization_p , 1, 1, env);
  434. GLOBAL_PRIM_W_ARITY("thread-cell?" , thread_cell_p , 1, 1, env);
  435. GLOBAL_PRIM_W_ARITY("make-thread-cell" , make_thread_cell , 1, 2, env);
  436. GLOBAL_PRIM_W_ARITY("thread-cell-ref" , thread_cell_get , 1, 1, env);
  437. GLOBAL_PRIM_W_ARITY("thread-cell-set!" , thread_cell_set , 2, 2, env);
  438. GLOBAL_PRIM_W_ARITY("current-preserved-thread-cell-values", thread_cell_values, 0, 1, env);
  439. GLOBAL_PRIM_W_ARITY("make-will-executor", make_will_executor, 0, 0, env);
  440. GLOBAL_PRIM_W_ARITY("will-executor?" , will_executor_p , 1, 1, env);
  441. GLOBAL_PRIM_W_ARITY("will-register" , register_will , 3, 3, env);
  442. GLOBAL_PRIM_W_ARITY("will-try-execute" , will_executor_try , 1, 1, env);
  443. GLOBAL_PRIM_W_ARITY("will-execute" , will_executor_go , 1, 1, env);
  444. scheme_add_evt_through_sema(scheme_will_executor_type, will_executor_sema, NULL);
  445. GLOBAL_PRIM_W_ARITY("collect-garbage" , collect_garbage , 0, 0, env);
  446. GLOBAL_PRIM_W_ARITY("current-memory-use" , current_memory_use , 0, 1, env);
  447. GLOBAL_PRIM_W_ARITY("custodian-require-memory" , custodian_require_mem, 3, 3, env);
  448. GLOBAL_PRIM_W_ARITY("custodian-limit-memory" , custodian_limit_mem , 2, 3, env);
  449. GLOBAL_PRIM_W_ARITY("custodian-memory-accounting-available?", custodian_can_mem , 0, 0, env);
  450. GLOBAL_FOLDING_PRIM("evt?" , evt_p , 1, 1 , 1, env);
  451. GLOBAL_PRIM_W_ARITY2("sync" , sch_sync , 1, -1, 0, -1, env);
  452. GLOBAL_PRIM_W_ARITY2("sync/timeout" , sch_sync_timeout , 2, -1, 0, -1, env);
  453. GLOBAL_PRIM_W_ARITY2("sync/enable-break" , sch_sync_enable_break , 1, -1, 0, -1, env);
  454. GLOBAL_PRIM_W_ARITY2("sync/timeout/enable-break", sch_sync_timeout_enable_break, 2, -1, 0, -1, env);
  455. GLOBAL_PRIM_W_ARITY("choice-evt" , evts_to_evt , 0, -1, env);
  456. GLOBAL_PARAMETER("current-thread-initial-stack-size", current_thread_initial_stack_size, MZCONFIG_THREAD_INIT_STACK_SIZE, env);
  457. }
  458. void scheme_init_thread_places(void) {
  459. buffer_init_size = INIT_TB_SIZE;
  460. REGISTER_SO(recycle_cell);
  461. REGISTER_SO(maybe_recycle_cell);
  462. REGISTER_SO(gc_prepost_callback_descs);
  463. REGISTER_SO(place_local_misc_table);
  464. }
  465. void scheme_init_memtrace(Scheme_Env *env)
  466. {
  467. Scheme_Object *v;
  468. Scheme_Env *newenv;
  469. v = scheme_intern_symbol("#%memtrace");
  470. newenv = scheme_primitive_module(v, env);
  471. v = scheme_make_symbol("memory-trace-continuation-mark");
  472. scheme_add_global("memory-trace-continuation-mark", v , newenv);
  473. v = scheme_make_prim_w_arity(new_tracking_fun,
  474. "new-memtrace-tracking-function", 1, 1);
  475. scheme_add_global("new-memtrace-tracking-function", v, newenv);
  476. v = scheme_make_prim_w_arity(union_tracking_val,
  477. "unioned-memtrace-tracking-value", 1, 1);
  478. scheme_add_global("unioned-memtrace-tracking-value", v, newenv);
  479. scheme_finish_primitive_module(newenv);
  480. }
  481. void scheme_init_inspector() {
  482. REGISTER_SO(initial_inspector);
  483. initial_inspector = scheme_make_initial_inspectors();
  484. /* Keep the initial inspector in case someone resets Scheme (by
  485. calling scheme_basic_env() a second time. Using the same
  486. inspector after a reset lets us use the same initial module
  487. instances. */
  488. }
  489. Scheme_Object *scheme_get_current_inspector()
  490. XFORM_SKIP_PROC
  491. {
  492. Scheme_Config *c;
  493. if (scheme_defining_primitives)
  494. return initial_inspector;
  495. c = scheme_current_config();
  496. return scheme_get_param(c, MZCONFIG_INSPECTOR);
  497. }
  498. Scheme_Object *scheme_get_initial_inspector(void)
  499. {
  500. return initial_inspector;
  501. }
  502. void scheme_init_parameterization()
  503. {
  504. REGISTER_SO(scheme_exn_handler_key);
  505. REGISTER_SO(scheme_parameterization_key);
  506. REGISTER_SO(scheme_break_enabled_key);
  507. scheme_exn_handler_key = scheme_make_symbol("exnh");
  508. scheme_parameterization_key = scheme_make_symbol("paramz");
  509. scheme_break_enabled_key = scheme_make_symbol("break-on?");
  510. }
  511. void scheme_init_paramz(Scheme_Env *env)
  512. {
  513. Scheme_Object *v;
  514. Scheme_Env *newenv;
  515. v = scheme_intern_symbol("#%paramz");
  516. newenv = scheme_primitive_module(v, env);
  517. scheme_add_global_constant("exception-handler-key", scheme_exn_handler_key , newenv);
  518. scheme_add_global_constant("parameterization-key" , scheme_parameterization_key, newenv);
  519. scheme_add_global_constant("break-enabled-key" , scheme_break_enabled_key , newenv);
  520. GLOBAL_PRIM_W_ARITY("extend-parameterization" , extend_parameterization , 1, -1, newenv);
  521. GLOBAL_PRIM_W_ARITY("check-for-break" , check_break_now , 0, 0, newenv);
  522. GLOBAL_PRIM_W_ARITY("reparameterize" , reparameterize , 1, 1, newenv);
  523. GLOBAL_PRIM_W_ARITY("make-custodian-from-main", make_custodian_from_main, 0, 0, newenv);
  524. scheme_finish_primitive_module(newenv);
  525. scheme_protect_primitive_provide(newenv, NULL);
  526. }
  527. static Scheme_Object *collect_garbage(int c, Scheme_Object *p[])
  528. {
  529. scheme_collect_garbage();
  530. return scheme_void;
  531. }
  532. static Scheme_Object *current_memory_use(int argc, Scheme_Object *args[])
  533. {
  534. Scheme_Object *arg = NULL;
  535. intptr_t retval = 0;
  536. if (argc) {
  537. if(SAME_TYPE(SCHEME_TYPE(args[0]), scheme_custodian_type)) {
  538. arg = args[0];
  539. } else if(SCHEME_PROCP(args[0])) {
  540. arg = args[0];
  541. } else {
  542. scheme_wrong_type("current-memory-use",
  543. "custodian or memory-trace-function",
  544. 0, argc, args);
  545. }
  546. }
  547. #ifdef MZ_PRECISE_GC
  548. retval = GC_get_memory_use(arg);
  549. #else
  550. retval = GC_get_memory_use();
  551. #endif
  552. return scheme_make_integer_value(retval);
  553. }
  554. /*========================================================================*/
  555. /* custodians */
  556. /*========================================================================*/
  557. static void adjust_limit_table(Scheme_Custodian *c)
  558. {
  559. /* If a custodian has a limit and any object or children, then it
  560. must not be collected and merged with its parent. To prevent
  561. collection, we register the custodian in the `limite_custodians'
  562. table. */
  563. if (c->has_limit) {
  564. if (c->elems || CUSTODIAN_FAM(c->children)) {
  565. if (!c->recorded) {
  566. c->recorded = 1;
  567. if (!limited_custodians)
  568. limited_custodians = scheme_make_hash_table(SCHEME_hash_ptr);
  569. scheme_hash_set(limited_custodians, (Scheme_Object *)c, scheme_true);
  570. }
  571. } else if (c->recorded) {
  572. c->recorded = 0;
  573. if (limited_custodians)
  574. scheme_hash_set(limited_custodians, (Scheme_Object *)c, NULL);
  575. }
  576. }
  577. }
  578. static Scheme_Object *custodian_require_mem(int argc, Scheme_Object *args[])
  579. {
  580. intptr_t lim;
  581. Scheme_Custodian *c1, *c2, *cx;
  582. if(NOT_SAME_TYPE(SCHEME_TYPE(args[0]), scheme_custodian_type)) {
  583. scheme_wrong_type("custodian-require-memory", "custodian", 0, argc, args);
  584. return NULL;
  585. }
  586. if (SCHEME_INTP(args[1]) && (SCHEME_INT_VAL(args[1]) > 0)) {
  587. lim = SCHEME_INT_VAL(args[1]);
  588. } else if (SCHEME_BIGNUMP(args[1]) && SCHEME_BIGPOS(args[1])) {
  589. lim = 0x3fffffff; /* more memory than we actually have */
  590. } else {
  591. scheme_wrong_type("custodian-require-memory", "positive exact integer", 1, argc, args);
  592. return NULL;
  593. }
  594. if(NOT_SAME_TYPE(SCHEME_TYPE(args[2]), scheme_custodian_type)) {
  595. scheme_wrong_type("custodian-require-memory", "custodian", 2, argc, args);
  596. return NULL;
  597. }
  598. c1 = (Scheme_Custodian *)args[0];
  599. c2 = (Scheme_Custodian *)args[2];
  600. /* Check whether c1 is super to c2: */
  601. if (c1 == c2) {
  602. cx = NULL;
  603. } else {
  604. for (cx = c2; cx && NOT_SAME_OBJ(cx, c1); ) {
  605. cx = CUSTODIAN_FAM(cx->parent);
  606. }
  607. }
  608. if (!cx) {
  609. scheme_raise_exn(MZEXN_FAIL_CONTRACT,
  610. "custodian-require-memory: second custodian is not a sub-custodian of the first custodian");
  611. }
  612. #ifdef MZ_PRECISE_GC
  613. if (GC_set_account_hook(MZACCT_REQUIRE, c1, lim, c2))
  614. return scheme_void;
  615. #endif
  616. scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED,
  617. "custodian-require-memory: not supported");
  618. return NULL; /* doesn't get here */
  619. }
  620. static Scheme_Object *custodian_limit_mem(int argc, Scheme_Object *args[])
  621. {
  622. intptr_t lim;
  623. if (NOT_SAME_TYPE(SCHEME_TYPE(args[0]), scheme_custodian_type)) {
  624. scheme_wrong_type("custodian-limit-memory", "custodian", 0, argc, args);
  625. return NULL;
  626. }
  627. if (SCHEME_INTP(args[1]) && (SCHEME_INT_VAL(args[1]) > 0)) {
  628. lim = SCHEME_INT_VAL(args[1]);
  629. } else if (SCHEME_BIGNUMP(args[1]) && SCHEME_BIGPOS(args[1])) {
  630. lim = 0x3fffffff; /* more memory than we actually have */
  631. } else {
  632. scheme_wrong_type("custodian-limit-memory", "positive exact integer", 1, argc, args);
  633. return NULL;
  634. }
  635. if (argc > 2) {
  636. if (NOT_SAME_TYPE(SCHEME_TYPE(args[2]), scheme_custodian_type)) {
  637. scheme_wrong_type("custodian-require-memory", "custodian", 2, argc, args);
  638. return NULL;
  639. }
  640. }
  641. ((Scheme_Custodian *)args[0])->has_limit = 1;
  642. adjust_limit_table((Scheme_Custodian *)args[0]);
  643. if (argc > 2) {
  644. ((Scheme_Custodian *)args[2])->has_limit = 1;
  645. adjust_limit_table((Scheme_Custodian *)args[2]);
  646. }
  647. #ifdef MZ_PRECISE_GC
  648. if (GC_set_account_hook(MZACCT_LIMIT, args[0], lim, (argc > 2) ? args[2] : args[0]))
  649. return scheme_void;
  650. #endif
  651. scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED,
  652. "custodian-limit-memory: not supported");
  653. return NULL; /* doesn't get here */
  654. }
  655. static Scheme_Object *custodian_can_mem(int argc, Scheme_Object *args[])
  656. {
  657. #ifdef MZ_PRECISE_GC
  658. return (GC_accouting_enabled() ? scheme_true : scheme_false);
  659. #else
  660. return scheme_false;
  661. #endif
  662. }
  663. static Scheme_Object *new_tracking_fun(int argc, Scheme_Object *args[])
  664. {
  665. int retval = 0;
  666. #ifdef MZ_PRECISE_GC
  667. retval = GC_mtrace_new_id(args[0]);
  668. #endif
  669. return scheme_make_integer(retval);
  670. }
  671. static Scheme_Object *union_tracking_val(int argc, Scheme_Object *args[])
  672. {
  673. int retval = 0;
  674. #ifdef MZ_PRECISE_GC
  675. retval = GC_mtrace_union_current_with(SCHEME_INT_VAL(args[0]));
  676. #endif
  677. return scheme_make_integer(retval);
  678. }
  679. static void ensure_custodian_space(Scheme_Custodian *m, int k)
  680. {
  681. int i;
  682. if (m->count + k >= m->alloc) {
  683. Scheme_Object ***naya_boxes;
  684. Scheme_Custodian_Reference **naya_mrefs;
  685. Scheme_Close_Custodian_Client **naya_closers;
  686. void **naya_data;
  687. m->alloc = (m->alloc ? (2 * m->alloc) : 4);
  688. if (m->alloc < k)
  689. m->alloc += k;
  690. naya_boxes = MALLOC_N(Scheme_Object**, m->alloc);
  691. naya_closers = MALLOC_N(Scheme_Close_Custodian_Client*, m->alloc);
  692. naya_data = MALLOC_N(void*, m->alloc);
  693. naya_mrefs = MALLOC_N(Scheme_Custodian_Reference*, m->alloc);
  694. for (i = m->count; i--; ) {
  695. naya_boxes[i] = m->boxes[i];
  696. m->boxes[i] = NULL;
  697. naya_closers[i] = m->closers[i];
  698. m->closers[i] = NULL;
  699. naya_data[i] = m->data[i];
  700. m->data[i] = NULL;
  701. naya_mrefs[i] = m->mrefs[i];
  702. m->mrefs[i] = NULL;
  703. }
  704. m->boxes = naya_boxes;
  705. m->closers = naya_closers;
  706. m->data = naya_data;
  707. m->mrefs = naya_mrefs;
  708. }
  709. }
  710. static void add_managed_box(Scheme_Custodian *m,
  711. Scheme_Object **box, Scheme_Custodian_Reference *mref,
  712. Scheme_Close_Custodian_Client *f, void *data)
  713. {
  714. int i;
  715. for (i = m->count; i--; ) {
  716. if (!m->boxes[i]) {
  717. m->boxes[i] = box;
  718. m->closers[i] = f;
  719. m->data[i] = data;
  720. m->mrefs[i] = mref;
  721. m->elems++;
  722. adjust_limit_table(m);
  723. return;
  724. }
  725. }
  726. ensure_custodian_space(m, 1);
  727. m->boxes[m->count] = box;
  728. m->closers[m->count] = f;
  729. m->data[m->count] = data;
  730. m->mrefs[m->count] = mref;
  731. m->elems++;
  732. adjust_limit_table(m);
  733. m->count++;
  734. }
  735. static void remove_managed(Scheme_Custodian_Reference *mr, Scheme_Object *o,
  736. Scheme_Close_Custodian_Client **old_f, void **old_data)
  737. {
  738. Scheme_Custodian *m;
  739. int i;
  740. if (!mr)
  741. return;
  742. m = CUSTODIAN_FAM(mr);
  743. if (!m)
  744. return;
  745. for (i = m->count; i--; ) {
  746. if (m->boxes[i] && SAME_OBJ((xCUSTODIAN_FAM(m->boxes[i])), o)) {
  747. xCUSTODIAN_FAM(m->boxes[i]) = 0;
  748. m->boxes[i] = NULL;
  749. CUSTODIAN_FAM(m->mrefs[i]) = 0;
  750. m->mrefs[i] = NULL;
  751. if (old_f)
  752. *old_f = m->closers[i];
  753. if (old_data)
  754. *old_data = m->data[i];
  755. m->data[i] = NULL;
  756. --m->elems;
  757. adjust_limit_table(m);
  758. break;
  759. }
  760. }
  761. while (m->count && !m->boxes[m->count - 1]) {
  762. --m->count;
  763. }
  764. }
  765. static void adjust_custodian_family(void *mgr, void *skip_move)
  766. {
  767. /* Threads note: because this function is only called as a
  768. finalization callback, it is automatically syncronized by the GC
  769. locks. And it is synchronized against all finalizations, so a
  770. managee can't try to unregister while we're shuffling its
  771. custodian. */
  772. Scheme_Custodian *r = (Scheme_Custodian *)mgr, *parent, *m;
  773. int i;
  774. parent = CUSTODIAN_FAM(r->parent);
  775. if (parent) {
  776. /* Remove from parent's list of children: */
  777. if (CUSTODIAN_FAM(parent->children) == r) {
  778. CUSTODIAN_FAM(parent->children) = CUSTODIAN_FAM(r->sibling);
  779. } else {
  780. m = CUSTODIAN_FAM(parent->children);
  781. while (m && CUSTODIAN_FAM(m->sibling) != r) {
  782. m = CUSTODIAN_FAM(m->sibling);
  783. }
  784. if (m)
  785. CUSTODIAN_FAM(m->sibling) = CUSTODIAN_FAM(r->sibling);
  786. }
  787. /* Remove from global list: */
  788. if (CUSTODIAN_FAM(r->global_next))
  789. CUSTODIAN_FAM(CUSTODIAN_FAM(r->global_next)->global_prev) = CUSTODIAN_FAM(r->global_prev);
  790. else
  791. last_custodian = CUSTODIAN_FAM(r->global_prev);
  792. CUSTODIAN_FAM(CUSTODIAN_FAM(r->global_prev)->global_next) = CUSTODIAN_FAM(r->global_next);
  793. /* Add children to parent's list: */
  794. for (m = CUSTODIAN_FAM(r->children); m; ) {
  795. Scheme_Custodian *next = CUSTODIAN_FAM(m->sibling);
  796. CUSTODIAN_FAM(m->parent) = parent;
  797. CUSTODIAN_FAM(m->sibling) = CUSTODIAN_FAM(parent->children);
  798. CUSTODIAN_FAM(parent->children) = m;
  799. m = next;
  800. }
  801. adjust_limit_table(parent);
  802. /* Add remaining managed items to parent: */
  803. if (!skip_move) {
  804. for (i = 0; i < r->count; i++) {
  805. if (r->boxes[i]) {
  806. CUSTODIAN_FAM(r->mrefs[i]) = parent;
  807. add_managed_box(parent, r->boxes[i], r->mrefs[i], r->closers[i], r->data[i]);
  808. #ifdef MZ_PRECISE_GC
  809. {
  810. Scheme_Object *o;
  811. o = xCUSTODIAN_FAM(r->boxes[i]);
  812. if (SAME_TYPE(SCHEME_TYPE(o), scheme_thread_hop_type)) {
  813. o = WEAKIFIED(((Scheme_Thread_Custodian_Hop *)o)->p);
  814. if (o)
  815. GC_register_thread(o, parent);
  816. }
  817. }
  818. #endif
  819. }
  820. }
  821. }
  822. }
  823. CUSTODIAN_FAM(r->parent) = NULL;
  824. CUSTODIAN_FAM(r->sibling) = NULL;
  825. if (!skip_move)
  826. CUSTODIAN_FAM(r->children) = NULL;
  827. CUSTODIAN_FAM(r->global_prev) = NULL;
  828. CUSTODIAN_FAM(r->global_next) = NULL;
  829. }
  830. void insert_custodian(Scheme_Custodian *m, Scheme_Custodian *parent)
  831. {
  832. /* insert into parent's list: */
  833. CUSTODIAN_FAM(m->parent) = parent;
  834. if (parent) {
  835. CUSTODIAN_FAM(m->sibling) = CUSTODIAN_FAM(parent->children);
  836. CUSTODIAN_FAM(parent->children) = m;
  837. } else
  838. CUSTODIAN_FAM(m->sibling) = NULL;
  839. /* Insert into global chain. A custodian is always inserted
  840. directly after its parent, so families stay together, and
  841. the local list stays in the same order as the sibling list. */
  842. if (parent) {
  843. Scheme_Custodian *next;
  844. next = CUSTODIAN_FAM(parent->global_next);
  845. CUSTODIAN_FAM(m->global_next) = next;
  846. CUSTODIAN_FAM(m->global_prev) = parent;
  847. CUSTODIAN_FAM(parent->global_next) = m;
  848. if (next)
  849. CUSTODIAN_FAM(next->global_prev) = m;
  850. else
  851. last_custodian = m;
  852. } else {
  853. CUSTODIAN_FAM(m->global_next) = NULL;
  854. CUSTODIAN_FAM(m->global_prev) = NULL;
  855. }
  856. if (parent)
  857. adjust_limit_table(parent);
  858. }
  859. Scheme_Custodian *scheme_make_custodian(Scheme_Custodian *parent)
  860. {
  861. Scheme_Custodian *m;
  862. Scheme_Custodian_Reference *mw;
  863. if (!parent)
  864. parent = main_custodian; /* still NULL if we're creating main; that's ok */
  865. m = MALLOC_ONE_TAGGED(Scheme_Custodian);
  866. m->so.type = scheme_custodian_type;
  867. m->alloc = m->count = 0;
  868. mw = MALLOC_MREF();
  869. m->parent = mw;
  870. mw = MALLOC_MREF();
  871. m->children = mw;
  872. mw = MALLOC_MREF();
  873. m->sibling = mw;
  874. mw = MALLOC_MREF();
  875. m->global_next = mw;
  876. mw = MALLOC_MREF();
  877. m->global_prev = mw;
  878. CUSTODIAN_FAM(m->children) = NULL;
  879. insert_custodian(m, parent);
  880. scheme_add_finalizer(m, adjust_custodian_family, NULL);
  881. return m;
  882. }
  883. static void rebox_willdone_object(void *o, void *mr)
  884. {
  885. Scheme_Custodian *m = CUSTODIAN_FAM((Scheme_Custodian_Reference *)mr);
  886. Scheme_Close_Custodian_Client *f;
  887. void *data;
  888. /* Still needs management? */
  889. if (m) {
  890. #ifdef MZ_PRECISE_GC
  891. Scheme_Object *b;
  892. #else
  893. Scheme_Object **b;
  894. #endif
  895. remove_managed(mr, o, &f, &data);
  896. #ifdef MZ_PRECISE_GC
  897. b = scheme_box(NULL);
  898. #else
  899. b = MALLOC_ONE(Scheme_Object*); /* not atomic this time */
  900. #endif
  901. xCUSTODIAN_FAM(b) = o;
  902. /* Put the custodian back: */
  903. CUSTODIAN_FAM((Scheme_Custodian_Reference *)mr) = m;
  904. add_managed_box(m, (Scheme_Object **)b, (Scheme_Custodian_Reference *)mr, f, data);
  905. }
  906. }
  907. static void managed_object_gone(void *o, void *mr)
  908. {
  909. Scheme_Custodian *m = CUSTODIAN_FAM((Scheme_Custodian_Reference *)mr);
  910. /* Still has management? */
  911. if (m)
  912. remove_managed(mr, o, NULL, NULL);
  913. }
  914. int scheme_custodian_is_available(Scheme_Custodian *m) XFORM_SKIP_PROC
  915. /* may be called from a future thread */
  916. {
  917. if (m->shut_down)
  918. return 0;
  919. return 1;
  920. }
  921. void scheme_custodian_check_available(Scheme_Custodian *m, const char *who, const char *what)
  922. {
  923. if (!m)
  924. m = (Scheme_Custodian *)scheme_get_param(scheme_current_config(), MZCONFIG_CUSTODIAN);
  925. if (!scheme_custodian_is_available(m))
  926. scheme_arg_mismatch(who, "the custodian has been shut down: ",
  927. (Scheme_Object *)m);
  928. }
  929. Scheme_Custodian_Reference *scheme_add_managed(Scheme_Custodian *m, Scheme_Object *o,
  930. Scheme_Close_Custodian_Client *f, void *data,
  931. int must_close)
  932. {
  933. #ifdef MZ_PRECISE_GC
  934. Scheme_Object *b;
  935. #else
  936. Scheme_Object **b;
  937. #endif
  938. Scheme_Custodian_Reference *mr;
  939. if (!m)
  940. m = (Scheme_Custodian *)scheme_get_param(scheme_current_config(), MZCONFIG_CUSTODIAN);
  941. if (m->shut_down) {
  942. /* The custodian was shut down in the time that it took
  943. to allocate o. This situation should be avoided if at
  944. all possible, but here's the fail-safe. */
  945. if (f)
  946. f(o, data);
  947. return NULL;
  948. }
  949. #ifdef MZ_PRECISE_GC
  950. b = scheme_make_late_weak_box(NULL);
  951. #else
  952. b = MALLOC_ONE_WEAK(Scheme_Object*);
  953. #endif
  954. xCUSTODIAN_FAM(b) = o;
  955. mr = MALLOC_MREF();
  956. CUSTODIAN_FAM(mr) = m;
  957. /* The atomic link via the box `b' allows the execution of wills for
  958. o. After this, we should either drop the object or we have to
  959. hold on to the object strongly (for when custodian-close-all is
  960. called). */
  961. if (must_close)
  962. scheme_add_finalizer(o, rebox_willdone_object, mr);
  963. else
  964. scheme_add_finalizer(o, managed_object_gone, mr);
  965. add_managed_box(m, (Scheme_Object **)b, mr, f, data);
  966. return mr;
  967. }
  968. void scheme_remove_managed(Scheme_Custodian_Reference *mr, Scheme_Object *o)
  969. {
  970. /* Is this a good idea? I'm not sure: */
  971. scheme_subtract_finalizer(o, managed_object_gone, mr);
  972. scheme_subtract_finalizer(o, rebox_willdone_object, mr);
  973. remove_managed(mr, o, NULL, NULL);
  974. }
  975. Scheme_Thread *scheme_do_close_managed(Scheme_Custodian *m, Scheme_Exit_Closer_Func cf)
  976. {
  977. Scheme_Thread *kill_self = NULL;
  978. Scheme_Custodian *c, *start, *next_m;
  979. int i, is_thread;
  980. Scheme_Thread *the_thread;
  981. Scheme_Object *o;
  982. Scheme_Close_Custodian_Client *f;
  983. void *data;
  984. if (!m)
  985. m = main_custodian;
  986. if (m->shut_down)
  987. return NULL;
  988. m->shut_down = 1;
  989. /* Need to kill children first, transitively, so find
  990. last decendent. The family will be the global-list from
  991. m to this last decendent, inclusive. */
  992. for (c = m; CUSTODIAN_FAM(c->children); ) {
  993. for (c = CUSTODIAN_FAM(c->children); CUSTODIAN_FAM(c->sibling); ) {
  994. c = CUSTODIAN_FAM(c->sibling);
  995. }
  996. }
  997. start = m;
  998. m = c;
  999. while (1) {
  1000. /* It matters that this loop starts at the top. See
  1001. the m->count = i assignment below. */
  1002. for (i = m->count; i--; ) {
  1003. if (m->boxes[i]) {
  1004. o = xCUSTODIAN_FAM(m->boxes[i]);
  1005. f = m->closers[i];
  1006. data = m->data[i];
  1007. if (!cf && (SAME_TYPE(SCHEME_TYPE(o), scheme_thread_hop_type))) {
  1008. /* We've added an indirection and made it weak. See mr_hop note above. */
  1009. is_thread = 1;
  1010. the_thread = (Scheme_Thread *)WEAKIFIED(((Scheme_Thread_Custodian_Hop *)o)->p);
  1011. } else {
  1012. is_thread = 0;
  1013. the_thread = NULL;
  1014. }
  1015. xCUSTODIAN_FAM(m->boxes[i]) = NULL;
  1016. CUSTODIAN_FAM(m->mrefs[i]) = NULL;
  1017. /* Set m->count to i in case a GC happens while
  1018. the closer is running. If there's a GC, then
  1019. for_each_managed will be called. */
  1020. m->count = i;
  1021. if (is_thread && !the_thread) {
  1022. /* Thread is already collected, so skip */
  1023. } else if (cf) {
  1024. cf(o, f, data);
  1025. } else {
  1026. if (is_thread) {
  1027. if (the_thread) {
  1028. /* Only kill the thread if it has no other custodians */
  1029. if (SCHEME_NULLP(the_thread->extra_mrefs)) {
  1030. if (do_kill_thread(the_thread))
  1031. kill_self = the_thread;
  1032. } else {
  1033. Scheme_Custodian_Reference *mref;
  1034. mref = m->mrefs[i];
  1035. if (mref == the_thread->mref) {
  1036. /* Designate a new main custodian for the thread */
  1037. mref = (Scheme_Custodian_Reference *)SCHEME_CAR(the_thread->extra_mrefs);
  1038. the_thread->mref = mref;
  1039. the_thread->extra_mrefs = SCHEME_CDR(the_thread->extra_mrefs);
  1040. #ifdef MZ_PRECISE_GC
  1041. GC_register_thread(the_thread, CUSTODIAN_FAM(mref));
  1042. #endif
  1043. } else {
  1044. /* Just remove mref from the list of extras */
  1045. Scheme_Object *l, *prev = NULL;
  1046. for (l = the_thread->extra_mrefs; 1; l = SCHEME_CDR(l)) {
  1047. if (SAME_OBJ(SCHEME_CAR(l), (Scheme_Object *)mref)) {
  1048. if (prev)
  1049. SCHEME_CDR(prev) = SCHEME_CDR(l);
  1050. else
  1051. the_thread->extra_mrefs = SCHEME_CDR(l);
  1052. break;
  1053. }
  1054. prev = l;
  1055. }
  1056. }
  1057. }
  1058. }
  1059. } else {
  1060. f(o, data);
  1061. }
  1062. }
  1063. }
  1064. }
  1065. #ifdef MZ_PRECISE_GC
  1066. {
  1067. Scheme_Object *pr = m->cust_boxes, *wb;
  1068. Scheme_Custodian_Box *cb;
  1069. while (pr) {
  1070. wb = SCHEME_CAR(pr);
  1071. cb = (Scheme_Custodian_Box *)SCHEME_BOX_VAL(wb);
  1072. if (cb) cb->v = NULL;
  1073. pr = SCHEME_CDR(pr);
  1074. }
  1075. m->cust_boxes = NULL;
  1076. }
  1077. #endif
  1078. m->count = 0;
  1079. m->alloc = 0;
  1080. m->elems = 0;
  1081. m->boxes = NULL;
  1082. m->closers = NULL;
  1083. m->data = NULL;
  1084. m->mrefs = NULL;
  1085. m->shut_down = 1;
  1086. if (SAME_OBJ(m, start))
  1087. break;
  1088. next_m = CUSTODIAN_FAM(m->global_prev);
  1089. /* Remove this custodian from its parent */
  1090. adjust_custodian_family(m, m);
  1091. adjust_limit_table(m);
  1092. m = next_m;
  1093. }
  1094. #ifdef MZ_USE_FUTURES
  1095. scheme_future_check_custodians();
  1096. #endif
  1097. return kill_self;
  1098. }
  1099. typedef void (*Scheme_For_Each_Func)(Scheme_Object *);
  1100. static void for_each_managed(Scheme_Type type, Scheme_For_Each_Func cf)
  1101. XFORM_SKIP_PROC
  1102. /* This function must not allocate. */
  1103. {
  1104. Scheme_Custodian *m;
  1105. int i;
  1106. if (SAME_TYPE(type, scheme_thread_type))
  1107. type = scheme_thread_hop_type;
  1108. /* back to front so children are first: */
  1109. m = last_custodian;
  1110. while (m) {
  1111. for (i = m->count; i--; ) {
  1112. if (m->boxes[i]) {
  1113. Scheme_Object *o;
  1114. o = xCUSTODIAN_FAM(m->boxes[i]);
  1115. if (SAME_TYPE(SCHEME_TYPE(o), type)) {
  1116. if (SAME_TYPE(type, scheme_thread_hop_type)) {
  1117. /* We've added an indirection and made it weak. See mr_hop note above. */
  1118. Scheme_Thread *t;
  1119. t = (Scheme_Thread *)WEAKIFIED(((Scheme_Thread_Custodian_Hop *)o)->p);
  1120. if (!t) {
  1121. /* The thread is already collected */
  1122. continue;
  1123. } else if (SAME_OBJ(t->mref, m->mrefs[i]))
  1124. o = (Scheme_Object *)t;
  1125. else {
  1126. /* The main custodian for this thread is someone else */
  1127. continue;
  1128. }
  1129. }
  1130. cf(o);
  1131. }
  1132. }
  1133. }
  1134. m = CUSTODIAN_FAM(m->global_prev);
  1135. }
  1136. }
  1137. static void do_close_managed(Scheme_Custodian *m)
  1138. /* The trick is that we may need to kill the thread
  1139. that is running us. If so, delay it to the very
  1140. end. */
  1141. {
  1142. if (scheme_do_close_managed(m, NULL)) {
  1143. /* Kill/suspend self */
  1144. if (scheme_current_thread->suspend_to_kill)
  1145. suspend_thread(scheme_current_thread);
  1146. else
  1147. scheme_thread_block(0.0);
  1148. }
  1149. }
  1150. void scheme_close_managed(Scheme_Custodian *m)
  1151. {
  1152. do_close_managed(m);
  1153. /* Give killed threads time to die: */
  1154. scheme_thread_block(0);
  1155. scheme_current_thread->ran_some = 1;
  1156. }
  1157. static Scheme_Object *make_custodian(int argc, Scheme_Object *argv[])
  1158. {
  1159. Scheme_Custodian *m;
  1160. if (argc) {
  1161. if (!SCHEME_CUSTODIANP(argv[0]))
  1162. scheme_wrong_type("make-custodian", "custodian", 0, argc, argv);
  1163. m = (Scheme_Custodian *)argv[0];
  1164. } else
  1165. m = (Scheme_Custodian *)scheme_get_param(scheme_current_config(), MZCONFIG_CUSTODIAN);
  1166. if (m->shut_down)
  1167. scheme_arg_mismatch("make-custodian",
  1168. "the custodian has been shut down: ",
  1169. (Scheme_Object *)m);
  1170. return (Scheme_Object *)scheme_make_custodian(m);
  1171. }
  1172. static Scheme_Object *make_custodian_from_main(int argc, Scheme_Object *argv[])
  1173. {
  1174. return (Scheme_Object *)scheme_make_custodian(NULL);
  1175. }
  1176. static Scheme_Object *custodian_p(int argc, Scheme_Object *argv[])
  1177. {
  1178. return SCHEME_CUSTODIANP(argv[0]) ? scheme_true : scheme_false;
  1179. }
  1180. static Scheme_Object *custodian_close_all(int argc, Scheme_Object *argv[])
  1181. {
  1182. if (!SCHEME_CUSTODIANP(argv[0]))
  1183. scheme_wrong_type("custodian-shutdown-all", "custodian", 0, argc, argv);
  1184. scheme_close_managed((Scheme_Custodian *)argv[0]);
  1185. return scheme_void;
  1186. }
  1187. Scheme_Custodian* scheme_custodian_extract_reference(Scheme_Custodian_Reference *mr)
  1188. {
  1189. return CUSTODIAN_FAM(mr);
  1190. }
  1191. int scheme_custodian_is_shut_down(Scheme_Custodian* c)
  1192. {
  1193. return c->shut_down;
  1194. }
  1195. static Scheme_Object *extract_thread(Scheme_Object *o)
  1196. {
  1197. return (Scheme_Object *)WEAKIFIED(((Scheme_Thread_Custodian_Hop *)o)->p);
  1198. }
  1199. void scheme_init_custodian_extractors()
  1200. {
  1201. if (!extractors) {
  1202. int n;
  1203. n = scheme_num_types();
  1204. REGISTER_SO(extractors);
  1205. extractors = MALLOC_N_ATOMIC(Scheme_Custodian_Extractor, n);
  1206. memset(extractors, 0, sizeof(Scheme_Custodian_Extractor) * n);
  1207. extractors[scheme_thread_hop_type] = extract_thread;
  1208. }
  1209. }
  1210. void scheme_add_custodian_extractor(Scheme_Type t, Scheme_Custodian_Extractor e)
  1211. {
  1212. if (t) {
  1213. extractors[t] = e;
  1214. }
  1215. }
  1216. static Scheme_Object *custodian_to_list(int argc, Scheme_Object *argv[])
  1217. {
  1218. Scheme_Custodian *m, *m2, *c;
  1219. Scheme_Object **hold, *o;
  1220. int i, j, cnt, kids;
  1221. Scheme_Type type;
  1222. Scheme_Custodian_Extractor ex;
  1223. if (!SCHEME_CUSTODIANP(argv[0]))
  1224. scheme_wrong_type("custodian-managed-list", "custodian", 0, argc, argv);
  1225. if (!SCHEME_CUSTODIANP(argv[1]))
  1226. scheme_wrong_type("custodian-managed-list", "custodian", 1, argc, argv);
  1227. m = (Scheme_Custodian *)argv[0];
  1228. m2 = (Scheme_Custodian *)argv[1];
  1229. /* Check that the second manages the first: */
  1230. c = CUSTODIAN_FAM(m->parent);
  1231. while (c && NOT_SAME_OBJ(m2, c)) {
  1232. c = CUSTODIAN_FAM(c->parent);
  1233. }
  1234. if (!c) {
  1235. scheme_arg_mismatch("custodian-managed-list",
  1236. "the second custodian does not "
  1237. "manage the first custodian: ",
  1238. argv[0]);
  1239. }
  1240. /* Init extractors: */
  1241. scheme_add_custodian_extractor(0, NULL);
  1242. /* Count children: */
  1243. kids = 0;
  1244. for (c = CUSTODIAN_FAM(m->children); c; c = CUSTODIAN_FAM(c->sibling)) {
  1245. kids++;
  1246. }
  1247. /* Do all allocation first, since custodian links are weak.
  1248. Furthermore, allocation may trigger collection of an otherwise
  1249. unreferenced custodian, folding its items into this one,
  1250. so loop until we've allocated enough. */
  1251. do {
  1252. cnt = m->count;
  1253. hold = MALLOC_N(Scheme_Object *, cnt + kids);
  1254. } while (cnt < m->count);
  1255. /* Put managed items into hold array: */
  1256. for (i = m->count, j = 0; i--; ) {
  1257. if (m->boxes[i]) {
  1258. o = xCUSTODIAN_FAM(m->boxes[i]);
  1259. type = SCHEME_TYPE(o);
  1260. ex = extractors[type];
  1261. if (ex) {
  1262. o = ex(o);
  1263. }
  1264. if (o) {
  1265. hold[j] = o;
  1266. j++;
  1267. }
  1268. }
  1269. }
  1270. /* Add kids: */
  1271. for (c = CUSTODIAN_FAM(m->children); c; c = CUSTODIAN_FAM(c->sibling)) {
  1272. hold[j] = (Scheme_Object *)c;
  1273. j++;

Large files files are truncated, but you can click here to view the full file