proc.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. /* Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees.
  2. See file COPYING. */
  3. /*
  4. * Scheme 48/POSIX process environment interface
  5. */
  6. #include <stdio.h>
  7. #include <errno.h>
  8. #include <string.h>
  9. #include <signal.h>
  10. #include <unistd.h>
  11. #include <stdlib.h>
  12. #include <sys/types.h>
  13. #include <sys/wait.h>
  14. #include "c-mods.h"
  15. #include "scheme48.h"
  16. #include "scheme48vm.h"
  17. #include "event.h"
  18. #include "posix.h"
  19. #include "unix.h"
  20. extern void s48_init_posix_proc(void),
  21. s48_uninit_posix_proc(void);
  22. static s48_ref_t posix_fork(s48_call_t call),
  23. posix_exec(s48_call_t call, s48_ref_t program, s48_ref_t lookup_p,
  24. s48_ref_t env, s48_ref_t args),
  25. posix_enter_pid(s48_call_t call, s48_ref_t pid),
  26. posix_waitpid(s48_call_t call),
  27. posix_integer_to_signal(s48_call_t call, s48_ref_t sig_int),
  28. posix_initialize_named_signals(s48_call_t call),
  29. posix_request_interrupts(s48_call_t call, s48_ref_t int_number),
  30. posix_cancel_interrupt_request(s48_call_t call, s48_ref_t sch_signal),
  31. posix_kill(s48_call_t call, s48_ref_t sch_pid, s48_ref_t sch_signal);
  32. static s48_ref_t enter_signal(s48_call_t call, int signal);
  33. static int extract_signal(s48_call_t call, s48_ref_t sch_signal);
  34. static void signal_map_init(void);
  35. static void signal_map_uninit(void);
  36. static void cancel_interrupt_requests(void);
  37. static char **enter_byte_vector_array(s48_call_t call, s48_ref_t strings),
  38. *add_dot_slash(char *name);
  39. /*
  40. * Two lists, one with all the child process ids and the other with all the
  41. * unnamed signals. Each CAR is a weak pointer to the actual object.
  42. *
  43. * We also have a handy procedure for lookup up values in the lists.
  44. *
  45. * These are in C instead of Scheme to prevent them from being written out in
  46. * images.
  47. */
  48. static s48_ref_t child_pids;
  49. static s48_ref_t unnamed_signals;
  50. s48_ref_t s48_lookup_record(s48_call_t call, s48_ref_t *list_loc, int offset, s48_ref_t key);
  51. /*
  52. * Record types imported from Scheme.
  53. */
  54. static s48_ref_t posix_process_id_type_binding;
  55. static s48_ref_t posix_named_signal_type_binding;
  56. static s48_ref_t posix_unnamed_signal_type_binding;
  57. /*
  58. * Vector of Scheme signal objects imported from Scheme, and a marker that
  59. * is put in unnamed signals.
  60. */
  61. static s48_ref_t posix_signals_vector_binding;
  62. static s48_ref_t posix_unnamed_signal_marker_binding;
  63. /*
  64. * Queue of received interrupts that need to be passed on to Scheme.
  65. * Kept in a finite array to avoid consing.
  66. */
  67. /*
  68. * Install all exported functions in Scheme48.
  69. */
  70. void
  71. s48_init_posix_proc(void)
  72. {
  73. S48_EXPORT_FUNCTION(posix_fork);
  74. S48_EXPORT_FUNCTION(posix_exec);
  75. S48_EXPORT_FUNCTION(posix_enter_pid);
  76. S48_EXPORT_FUNCTION(posix_waitpid);
  77. S48_EXPORT_FUNCTION(posix_integer_to_signal);
  78. S48_EXPORT_FUNCTION(posix_initialize_named_signals);
  79. S48_EXPORT_FUNCTION(posix_request_interrupts);
  80. S48_EXPORT_FUNCTION(posix_cancel_interrupt_request);
  81. S48_EXPORT_FUNCTION(posix_kill);
  82. posix_process_id_type_binding =
  83. s48_get_imported_binding_2("posix-process-id-type");
  84. posix_named_signal_type_binding =
  85. s48_get_imported_binding_2("posix-named-signal-type");
  86. posix_unnamed_signal_type_binding =
  87. s48_get_imported_binding_2("posix-unnamed-signal-type");
  88. posix_signals_vector_binding =
  89. s48_get_imported_binding_2("posix-signals-vector");
  90. posix_unnamed_signal_marker_binding =
  91. s48_get_imported_binding_2("posix-unnamed-signal-marker");
  92. child_pids = s48_make_global_ref(_s48_value_null);
  93. unnamed_signals = s48_make_global_ref(_s48_value_null);
  94. signal_map_init();
  95. }
  96. void
  97. s48_uninit_posix_proc(void)
  98. {
  99. /* this will lose our signal handlers without reinstalling them; too bad */
  100. cancel_interrupt_requests();
  101. signal_map_uninit();
  102. }
  103. /*
  104. * Box a process id in a Scheme record.
  105. */
  106. static s48_ref_t
  107. make_pid(s48_call_t call, pid_t c_pid)
  108. {
  109. s48_ref_t weak, temp;
  110. s48_ref_t sch_pid = s48_make_record_2(call, posix_process_id_type_binding);
  111. s48_unsafe_record_set_2(call, sch_pid, 0, s48_enter_long_2(call, c_pid));
  112. s48_unsafe_record_set_2(call, sch_pid, 1, s48_false_2(call)); /* return status */
  113. s48_unsafe_record_set_2(call, sch_pid, 2, s48_false_2(call)); /* terminating signal */
  114. s48_unsafe_record_set_2(call, sch_pid, 3, s48_false_2(call)); /* placeholder for waiting threads */
  115. weak = s48_make_weak_pointer_2(call, sch_pid);
  116. temp = child_pids;
  117. child_pids = s48_local_to_global_ref(s48_cons_2(call, weak, child_pids));
  118. s48_free_global_ref(temp);
  119. return sch_pid;
  120. }
  121. /*
  122. * Lookup a pid in the list of same. We clear out any dropped weak pointers
  123. * on the way.
  124. */
  125. static s48_ref_t
  126. lookup_pid(s48_call_t call, pid_t c_pid)
  127. {
  128. return s48_lookup_record(call, &child_pids, 0, s48_enter_long_2(call, c_pid));
  129. }
  130. /*
  131. * Lookup a record on a list of weak pointers to same. We get a value and
  132. * the record offset at which to look for the value. Any dropped pointers
  133. * are cleared out along the way. If any have been seen we walk the entire
  134. * list to clear them all out.
  135. *
  136. * This is too much C code! It should all be done in Scheme.
  137. */
  138. s48_ref_t
  139. s48_lookup_record(s48_call_t call, s48_ref_t *the_list_loc, int offset, s48_ref_t key)
  140. {
  141. int cleanup_p = 0;
  142. s48_ref_t the_list = *the_list_loc;
  143. /* Clear out initial dropped weaks */
  144. while (!s48_null_p_2(call, the_list) &&
  145. s48_false_p_2(call,
  146. s48_unsafe_weak_pointer_ref_2(call, s48_unsafe_car_2(call, the_list))))
  147. the_list = s48_unsafe_cdr_2(call, the_list);
  148. if (the_list != *the_list_loc) {
  149. s48_free_global_ref(*the_list_loc);
  150. the_list = s48_local_to_global_ref(the_list);
  151. *the_list_loc = the_list;
  152. cleanup_p = 1; }
  153. if (s48_null_p_2(call, the_list))
  154. return s48_false_2(call); /* Nothing */
  155. {
  156. s48_ref_t first = s48_unsafe_weak_pointer_ref_2(call, s48_unsafe_car_2(call, the_list));
  157. if (s48_eq_p_2(call, key, s48_unsafe_record_ref_2(call, first, offset)))
  158. /* Found it first thing. We skip the cleanup, but so what. */
  159. return first;
  160. {
  161. /* Loop down. */
  162. s48_ref_t found = s48_false_2(call);
  163. s48_ref_t prev = the_list;
  164. s48_ref_t next = s48_unsafe_cdr_2(call, prev);
  165. for(; !s48_null_p_2(call, next) && s48_false_p_2(call, found);
  166. next = s48_unsafe_cdr_2(call, prev)) {
  167. s48_ref_t first = s48_unsafe_weak_pointer_ref_2(call, s48_unsafe_car_2(call, next));
  168. if (s48_false_p_2(call, first)) {
  169. s48_unsafe_set_cdr_2(call, prev, s48_unsafe_cdr_2(call, next));
  170. cleanup_p = 1; }
  171. else if (s48_eq_p_2(call, key, s48_unsafe_record_ref_2(call, first, offset)))
  172. found = first;
  173. else
  174. prev = next; }
  175. /* If we found any empty weaks we check the entire list for them. */
  176. if (cleanup_p) {
  177. for(; !s48_null_p_2(call, next); next = s48_unsafe_cdr_2(call, next)) {
  178. s48_ref_t first = s48_unsafe_weak_pointer_ref_2(call, s48_unsafe_car_2(call, next));
  179. if (s48_false_p_2(call, first))
  180. s48_unsafe_set_cdr_2(call, prev, s48_unsafe_cdr_2(call, next)); } }
  181. return found; } }
  182. }
  183. /*
  184. * If we already have this process, return it, else make a new one.
  185. */
  186. s48_ref_t
  187. s48_enter_pid(s48_call_t call, pid_t c_pid)
  188. {
  189. s48_ref_t sch_pid = lookup_pid(call, c_pid);
  190. return s48_false_p_2(call, sch_pid) ? make_pid(call, c_pid) : sch_pid;
  191. }
  192. /*
  193. * Version of above for calling from Scheme.
  194. */
  195. static s48_ref_t
  196. posix_enter_pid(s48_call_t call, s48_ref_t sch_pid)
  197. {
  198. return s48_enter_pid(call, s48_extract_long_2(call, sch_pid));
  199. }
  200. /*
  201. * Waiting for children. We get finished pid's until we reach one for which
  202. * there is a Scheme pid record. The exit status or terminating signal is
  203. * saved in the record which is then returned.
  204. *
  205. * This does not looked for stopped children, only terminated ones.
  206. */
  207. static s48_ref_t
  208. posix_waitpid(s48_call_t call)
  209. {
  210. while(1==1) {
  211. int stat;
  212. pid_t c_pid = waitpid(-1, &stat, WNOHANG);
  213. if (c_pid == -1) {
  214. if (errno == ECHILD) /* no one left to wait for */
  215. return s48_false_2(call);
  216. else if (errno != EINTR)
  217. s48_os_error_2(call, "posix_waitpid", errno, 0);
  218. }
  219. else {
  220. s48_ref_t sch_pid = lookup_pid(call, c_pid);
  221. s48_ref_t temp = s48_unspecific_2(call);
  222. if (!s48_false_p_2(call, sch_pid)) {
  223. if (WIFEXITED(stat))
  224. s48_unsafe_record_set_2(call, sch_pid, 1, s48_enter_long_2(call, WEXITSTATUS(stat)));
  225. else {
  226. temp = enter_signal(call, WTERMSIG(stat));
  227. s48_unsafe_record_set_2(call, sch_pid, 2, temp);
  228. }
  229. return sch_pid;
  230. }
  231. }
  232. }
  233. }
  234. /*
  235. * Fork and exec.
  236. */
  237. static s48_ref_t
  238. posix_fork(s48_call_t call)
  239. {
  240. pid_t child_pid = fork();
  241. if (child_pid < 0)
  242. s48_os_error_2(call, "posix_fork", errno, 0);
  243. if (child_pid == 0)
  244. return s48_false_2(call);
  245. else
  246. return make_pid(call, child_pid);
  247. }
  248. /*
  249. * The environment is an array of strings of the form "name=value", where
  250. * `name' cannot contain `='.
  251. *
  252. * It is a nuisance that given three binary choices (arguments explicit or
  253. * in a vector, path lookup or not, explicit or implicit environment) Posix
  254. * only gives six functions. The two calls that have an explict environment
  255. * both do path lookup. We work around this by adding `./' to the beginning
  256. * of the program, if it does not already contain a `/'.
  257. */
  258. static s48_ref_t
  259. posix_exec(s48_call_t call, s48_ref_t program, s48_ref_t lookup_p,
  260. s48_ref_t env, s48_ref_t args)
  261. {
  262. char **c_args = enter_byte_vector_array(call, args);
  263. char *c_program, *real_c_program;
  264. int status;
  265. c_program = s48_extract_byte_vector_readonly_2(call, program);
  266. s48_stop_alarm_interrupts();
  267. if (s48_false_p_2(call, env))
  268. if (s48_false_p_2(call, lookup_p))
  269. status = execv(c_program, c_args);
  270. else {
  271. status = execvp(c_program, c_args);
  272. }
  273. else {
  274. char **c_env = enter_byte_vector_array(call, env);
  275. if (NULL == strchr(c_program, '/'))
  276. real_c_program = add_dot_slash(c_program);
  277. else
  278. real_c_program = c_program;
  279. status = execve(c_program, c_args, c_env);
  280. free(c_env);
  281. if (real_c_program != c_program)
  282. free(real_c_program); }
  283. /* If we get here, then something has gone wrong. */
  284. free(c_args);
  285. s48_start_alarm_interrupts();
  286. s48_os_error_2(call, "posix_exec", errno, 0);
  287. /* appease gcc -Wall */
  288. return s48_false_2(call);
  289. }
  290. /*
  291. * Convert a list of byte vectors into an array of char pointers.
  292. */
  293. static char **
  294. enter_byte_vector_array(s48_call_t call, s48_ref_t vectors)
  295. {
  296. int length = s48_unsafe_extract_long_2(call, s48_length_2(call, vectors));
  297. char **result = (char **)malloc((length + 1) * sizeof(char *));
  298. int i;
  299. if (result == NULL)
  300. s48_out_of_memory_error();
  301. for(i = 0; i < length; i++, vectors = s48_unsafe_cdr_2(call, vectors)) {
  302. s48_ref_t vector = s48_unsafe_car_2(call, vectors);
  303. if (! s48_byte_vector_p_2(call, vector)) {
  304. free(result);
  305. s48_assertion_violation_2(call, NULL, "not a byte vector", 1, vector); }
  306. result[i] = s48_extract_byte_vector_readonly_2(call, vector); }
  307. result[length] = NULL;
  308. return result;
  309. }
  310. /*
  311. * Add `./' to the beginning of `name'.
  312. */
  313. static char *
  314. add_dot_slash(char *name)
  315. {
  316. int len = strlen(name);
  317. char *new_name = (char *)malloc((len + 1) * sizeof(char));
  318. if (new_name == NULL)
  319. s48_out_of_memory_error();
  320. new_name[0] = '.';
  321. new_name[1] = '/';
  322. strcpy(new_name + 2, name);
  323. return new_name;
  324. }
  325. /*
  326. * Signals
  327. */
  328. /*
  329. * Simple front for kill(). We have to retry if interrupted.
  330. */
  331. s48_ref_t
  332. posix_kill(s48_call_t call, s48_ref_t sch_pid, s48_ref_t sch_signal)
  333. {
  334. int status;
  335. s48_check_record_type_2(call, sch_pid, posix_process_id_type_binding);
  336. RETRY_OR_RAISE_NEG(status,
  337. kill(s48_extract_long_2(call, s48_unsafe_record_ref_2(call, sch_pid, 0)),
  338. extract_signal(call, sch_signal)));
  339. return s48_unspecific_2(call);
  340. }
  341. /*
  342. * This is an array that maps our `canonical' signal numbers to the local
  343. * OS's numbers. The initialization is done via an include file written
  344. * by a Scheme program. The include file first calls signal_count_is()
  345. * with the number of named signals and then adds the named signals supported
  346. * by the current os to `signal_map'.
  347. */
  348. static int *signal_map, signal_map_size;
  349. static void
  350. signal_count_is(int count)
  351. {
  352. int i;
  353. signal_map_size = count;
  354. signal_map = (int *) malloc(count * sizeof(int));
  355. if (signal_map == NULL) {
  356. fprintf(stderr, "ran out of memory during initialization\n");
  357. exit(1); }
  358. for (i = 0; i < count; i++)
  359. signal_map[i] = -1;
  360. }
  361. static void
  362. signal_map_init()
  363. {
  364. #include "s48_signals.h"
  365. }
  366. static void
  367. signal_map_uninit(void)
  368. {
  369. free(signal_map);
  370. }
  371. /*
  372. * Converts from an OS signal to a canonical signal number.
  373. * We return -1 if there is no matching named signal.
  374. */
  375. static int
  376. lookup_signal(int c_signal) {
  377. int i = 0;
  378. for (i = 0; i < signal_map_size; i++)
  379. if (signal_map[i] == c_signal)
  380. return i;
  381. return -1;
  382. }
  383. /*
  384. * Use the signal map to set the os-number slot in each named signal to
  385. * its value in the current OS.
  386. */
  387. static s48_ref_t
  388. posix_initialize_named_signals(s48_call_t call)
  389. {
  390. int i, length;
  391. s48_ref_t named_signals;
  392. s48_shared_binding_check_2(call, posix_signals_vector_binding);
  393. named_signals = s48_shared_binding_ref_2(call, posix_signals_vector_binding);
  394. if(! s48_vector_p_2(call, named_signals))
  395. s48_assertion_violation_2(call,
  396. "posix_initialize_named_signals", "not a vector", 1,
  397. named_signals);
  398. length = s48_unsafe_vector_length_2(call, named_signals);
  399. for(i = 0; i < length; i++) {
  400. s48_ref_t signal = s48_unsafe_vector_ref_2(call, named_signals, i);
  401. int canonical = s48_extract_long_2(call, s48_unsafe_record_ref_2(call, signal, 1));
  402. int c_signal = signal_map[canonical];
  403. s48_ref_t scm_signal = (c_signal == -1) ?
  404. s48_false_2(call) :
  405. s48_enter_long_2(call, c_signal);
  406. s48_unsafe_record_set_2(call, signal, 2, scm_signal); }
  407. return s48_unspecific_2(call);
  408. }
  409. /*
  410. * Make a new unnamed signal containing `fx_signal' and add it to the weak
  411. * list of unnamed signals.
  412. */
  413. static s48_ref_t
  414. make_unnamed_signal(s48_call_t call, s48_ref_t fx_signal)
  415. {
  416. s48_ref_t weak, temp;
  417. s48_ref_t unnamed = s48_make_record_2(call, posix_unnamed_signal_type_binding);
  418. s48_unsafe_record_set_2(call,
  419. unnamed,
  420. 0,
  421. s48_unsafe_shared_binding_ref_2(call,
  422. posix_unnamed_signal_marker_binding));
  423. s48_unsafe_record_set_2(call, unnamed, 1, fx_signal);
  424. s48_unsafe_record_set_2(call, unnamed, 2, s48_null_2(call)); /* No queues */
  425. weak = s48_make_weak_pointer_2(call, unnamed);
  426. temp = unnamed_signals;
  427. unnamed_signals = s48_local_to_global_ref(s48_cons_2(call, weak, unnamed_signals));
  428. s48_free_global_ref(temp);
  429. return unnamed;
  430. }
  431. /*
  432. * Returns a signal record for `signal'. Unnamed signals are looked up in
  433. * the weak list of same; if none is found we make one. Scheme records for
  434. * named signals are retrieved from a vector sent down by the Scheme code.
  435. */
  436. static s48_ref_t
  437. enter_signal(s48_call_t call, int c_signal)
  438. {
  439. int canonical = lookup_signal(c_signal);
  440. if (canonical == -1) {
  441. s48_ref_t fx_signal = s48_enter_long_2(call, c_signal);
  442. s48_ref_t unnamed = s48_lookup_record(call, &unnamed_signals, 1, fx_signal);
  443. if (!s48_false_p_2(call, unnamed))
  444. return unnamed;
  445. else
  446. return make_unnamed_signal(call, fx_signal); }
  447. else
  448. return s48_vector_ref_2(call,
  449. s48_shared_binding_ref_2(call, posix_signals_vector_binding),
  450. canonical);
  451. }
  452. /*
  453. * Wrapper for enter_signal() for calling from Scheme.
  454. */
  455. static s48_ref_t
  456. posix_integer_to_signal(s48_call_t call, s48_ref_t signal_int)
  457. {
  458. if (s48_fixnum_p_2(call, signal_int))
  459. return enter_signal(call, s48_extract_long_2(call, signal_int));
  460. else
  461. /* really should do an integer? test here */
  462. return s48_false_2(call);
  463. }
  464. /*
  465. * Go from a signal back to the local integer. For named signals we extract
  466. * the canonical signal to use as an index into the signal map. Unnamed signals
  467. * contain the local signal already.
  468. */
  469. static int
  470. extract_signal(s48_call_t call, s48_ref_t sch_signal)
  471. {
  472. s48_ref_t type;
  473. if (! s48_record_p_2(call, sch_signal))
  474. s48_assertion_violation_2(call, NULL, "not a record", 1, sch_signal);
  475. type = s48_unsafe_record_type_2(call, sch_signal);
  476. if (s48_eq_p_2(call, type, s48_unsafe_shared_binding_ref_2(call, posix_named_signal_type_binding))) {
  477. int canonical = s48_extract_long_2(call, s48_unsafe_record_ref_2(call, sch_signal, 1));
  478. if ((0 <= canonical) && (canonical < signal_map_size)
  479. && signal_map[canonical] != -1)
  480. return signal_map[canonical];
  481. else
  482. s48_assertion_violation_2(call, NULL, "not a valid signal index", 1, sch_signal); }
  483. else if (s48_eq_p_2(call, type,
  484. s48_unsafe_shared_binding_ref_2(call, posix_unnamed_signal_type_binding)))
  485. return s48_extract_long_2(call, s48_unsafe_record_ref_2(call, sch_signal, 1));
  486. else
  487. s48_assertion_violation_2(call, NULL, "not a signal", 1, sch_signal);
  488. }
  489. /*
  490. * Queue the interrupt. For SIGINT and SIGALRM we call the event-system's
  491. * handler as well.
  492. */
  493. static void
  494. generic_interrupt_catcher(int signum)
  495. {
  496. extern void s48_add_os_signal(long);
  497. s48_add_os_signal(signum);
  498. switch (signum) {
  499. case SIGINT: {
  500. s48_when_keyboard_interrupt(0);
  501. break; }
  502. case SIGALRM: {
  503. s48_when_alarm_interrupt(0);
  504. break; }
  505. case SIG_EXTERNAL_EVENT: {
  506. s48_when_external_event_interrupt(0);
  507. break; }
  508. default:
  509. NOTE_EVENT; }
  510. return;
  511. }
  512. /*
  513. * Array of actions to be restored when we no longer listen for a signal.
  514. */
  515. #define MAX_SIGNAL 1023 /* Just a guess. */
  516. struct sigaction *saved_actions[MAX_SIGNAL + 1] = {NULL};
  517. /*
  518. * If there is a saved action then our handler is already in place and
  519. * we need do nothing. Otherwise we save the current action and install
  520. * our own.
  521. */
  522. s48_ref_t
  523. posix_request_interrupts(s48_call_t call, s48_ref_t sch_signum)
  524. {
  525. int signum = s48_extract_long_2(call, sch_signum);
  526. struct sigaction sa;
  527. if (saved_actions[signum] == NULL) {
  528. struct sigaction * old = (struct sigaction *)
  529. malloc(sizeof(struct sigaction));
  530. if (old == NULL)
  531. s48_out_of_memory_error();
  532. sa.sa_handler = generic_interrupt_catcher;
  533. sigfillset(&sa.sa_mask);
  534. sa.sa_flags = 0;
  535. if (sigaction(signum, &sa, old) != 0) {
  536. free(old);
  537. s48_os_error_2(call, "posix_request_interrupts", errno, 1, sch_signum); }
  538. saved_actions[signum] = old; }
  539. return s48_unspecific_2(call);
  540. }
  541. /*
  542. * The reverse of the above. If there is a saved action then we install it
  543. * and remove it from the saved_action array.
  544. */
  545. static void
  546. cancel_interrupt_request(int signum)
  547. {
  548. struct sigaction * old = saved_actions[signum];
  549. if (old != NULL)
  550. {
  551. if (sigaction(signum, old, (struct sigaction *) NULL) != 0)
  552. /* THIS IS STILL OLD FFI! FIX THIS! */
  553. s48_os_error_2(NULL, NULL, errno, 1, s48_enter_fixnum(signum));
  554. free(old);
  555. saved_actions[signum] = NULL;
  556. }
  557. }
  558. s48_ref_t
  559. posix_cancel_interrupt_request(s48_call_t call, s48_ref_t sch_signum)
  560. {
  561. cancel_interrupt_request(s48_extract_long_2(call, sch_signum));
  562. return s48_unspecific_2(call);
  563. }
  564. static void
  565. cancel_interrupt_requests(void)
  566. {
  567. int signum = 0;
  568. while (signum <= MAX_SIGNAL)
  569. {
  570. cancel_interrupt_request(signum);
  571. ++signum;
  572. }
  573. }