proc.c 18 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_value posix_fork(void),
  23. posix_exec(s48_value program, s48_value lookup_p,
  24. s48_value env, s48_value args),
  25. posix_enter_pid(s48_value pid),
  26. posix_waitpid(void),
  27. posix_integer_to_signal(s48_value sig_int),
  28. posix_initialize_named_signals(void),
  29. posix_request_interrupts(s48_value int_number),
  30. posix_cancel_interrupt_request(s48_value sch_signal),
  31. posix_kill(s48_value sch_pid, s48_value sch_signal);
  32. static s48_value enter_signal(int signal);
  33. static int extract_signal(s48_value 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_value 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_value child_pids = S48_NULL;
  49. static s48_value unnamed_signals = S48_NULL;
  50. static s48_value lookup_record(s48_value *list_loc, int offset, s48_value key);
  51. /*
  52. * Record types imported from Scheme.
  53. */
  54. static s48_value posix_process_id_type_binding = S48_FALSE;
  55. static s48_value posix_named_signal_type_binding = S48_FALSE;
  56. static s48_value posix_unnamed_signal_type_binding = S48_FALSE;
  57. /*
  58. * Vector of Scheme signal objects imported from Scheme, and a marker that
  59. * is put in unnamed signals.
  60. */
  61. static s48_value posix_signals_vector_binding = S48_FALSE;
  62. static s48_value posix_unnamed_signal_marker_binding = S48_FALSE;
  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. S48_GC_PROTECT_GLOBAL(posix_process_id_type_binding);
  83. posix_process_id_type_binding =
  84. s48_get_imported_binding("posix-process-id-type");
  85. S48_GC_PROTECT_GLOBAL(posix_named_signal_type_binding);
  86. posix_named_signal_type_binding =
  87. s48_get_imported_binding("posix-named-signal-type");
  88. S48_GC_PROTECT_GLOBAL(posix_unnamed_signal_type_binding);
  89. posix_unnamed_signal_type_binding =
  90. s48_get_imported_binding("posix-unnamed-signal-type");
  91. S48_GC_PROTECT_GLOBAL(posix_signals_vector_binding);
  92. posix_signals_vector_binding =
  93. s48_get_imported_binding("posix-signals-vector");
  94. S48_GC_PROTECT_GLOBAL(posix_unnamed_signal_marker_binding);
  95. posix_unnamed_signal_marker_binding =
  96. s48_get_imported_binding("posix-unnamed-signal-marker");
  97. S48_GC_PROTECT_GLOBAL(child_pids);
  98. S48_GC_PROTECT_GLOBAL(unnamed_signals);
  99. signal_map_init();
  100. }
  101. void
  102. s48_uninit_posix_proc(void)
  103. {
  104. /* this will lose our signal handlers without reinstalling them; too bad */
  105. cancel_interrupt_requests();
  106. signal_map_uninit();
  107. }
  108. /*
  109. * Box a process id in a Scheme record.
  110. */
  111. static s48_value
  112. make_pid(pid_t c_pid)
  113. {
  114. s48_value weak;
  115. s48_value sch_pid = s48_make_record(posix_process_id_type_binding);
  116. S48_UNSAFE_RECORD_SET(sch_pid, 0, s48_enter_fixnum(c_pid));
  117. S48_UNSAFE_RECORD_SET(sch_pid, 1, S48_FALSE); /* return status */
  118. S48_UNSAFE_RECORD_SET(sch_pid, 2, S48_FALSE); /* terminating signal */
  119. S48_UNSAFE_RECORD_SET(sch_pid, 3, S48_FALSE); /* placeholder for waiting threads */
  120. weak = s48_make_weak_pointer(sch_pid);
  121. child_pids = s48_cons(weak, child_pids);
  122. return sch_pid;
  123. }
  124. /*
  125. * Lookup a pid in the list of same. We clear out any dropped weak pointers
  126. * on the way.
  127. */
  128. static s48_value
  129. lookup_pid(pid_t c_pid)
  130. {
  131. return lookup_record(&child_pids, 0, s48_enter_fixnum(c_pid));
  132. }
  133. /*
  134. * Lookup a record on a list of weak pointers to same. We get a value and
  135. * the record offset at which to look for the value. Any dropped pointers
  136. * are cleared out along the way. If any have been seen we walk the entire
  137. * list to clear them all out.
  138. *
  139. * This is too much C code! It should all be done in Scheme.
  140. */
  141. static s48_value
  142. lookup_record(s48_value *the_list_loc, int offset, s48_value key)
  143. {
  144. int cleanup_p = 0;
  145. s48_value the_list = *the_list_loc;
  146. /* Clear out initial dropped weaks */
  147. while (the_list != S48_NULL &&
  148. S48_UNSAFE_WEAK_POINTER_REF(S48_UNSAFE_CAR(the_list)) == S48_FALSE)
  149. the_list = S48_UNSAFE_CDR(the_list);
  150. if (the_list != *the_list_loc) {
  151. *the_list_loc = the_list;
  152. cleanup_p = 1; }
  153. if (the_list == S48_NULL)
  154. return S48_FALSE; /* Nothing */
  155. {
  156. s48_value first = S48_UNSAFE_WEAK_POINTER_REF(S48_UNSAFE_CAR(the_list));
  157. if (key == S48_UNSAFE_RECORD_REF(first, offset))
  158. /* Found it first thing. We skip the cleanup, but so what. */
  159. return first;
  160. {
  161. /* Loop down. */
  162. s48_value found = S48_FALSE;
  163. s48_value prev = the_list;
  164. s48_value next = S48_UNSAFE_CDR(prev);
  165. for(; next != S48_NULL && found == S48_FALSE;
  166. next = S48_UNSAFE_CDR(prev)) {
  167. s48_value first = S48_UNSAFE_WEAK_POINTER_REF(S48_UNSAFE_CAR(next));
  168. if (first == S48_FALSE) {
  169. S48_UNSAFE_SET_CDR(prev, S48_UNSAFE_CDR(next));
  170. cleanup_p = 1; }
  171. else if (key == S48_UNSAFE_RECORD_REF(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(; next != S48_NULL; next = S48_UNSAFE_CDR(next)) {
  178. s48_value first = S48_UNSAFE_WEAK_POINTER_REF(S48_UNSAFE_CAR(next));
  179. if (first == S48_FALSE)
  180. S48_UNSAFE_SET_CDR(prev, S48_UNSAFE_CDR(next)); } }
  181. return found; } }
  182. }
  183. /*
  184. * If we already have this process, return it, else make a new one.
  185. */
  186. s48_value
  187. s48_enter_pid(pid_t c_pid)
  188. {
  189. s48_value sch_pid = lookup_pid(c_pid);
  190. return sch_pid == S48_FALSE ? make_pid(c_pid) : sch_pid;
  191. }
  192. /*
  193. * Version of above for calling from Scheme.
  194. */
  195. static s48_value
  196. posix_enter_pid(s48_value sch_pid)
  197. {
  198. return s48_enter_pid(s48_extract_fixnum(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_value
  208. posix_waitpid(void)
  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;
  216. else if (errno != EINTR)
  217. s48_raise_os_error(errno);
  218. }
  219. else {
  220. s48_value sch_pid = lookup_pid(c_pid);
  221. s48_value temp = S48_UNSPECIFIC;
  222. S48_DECLARE_GC_PROTECT(2);
  223. S48_GC_PROTECT_2(sch_pid, temp);
  224. if (sch_pid != S48_FALSE) {
  225. if (WIFEXITED(stat))
  226. S48_UNSAFE_RECORD_SET(sch_pid, 1, s48_enter_fixnum(WEXITSTATUS(stat)));
  227. else {
  228. temp = enter_signal(WTERMSIG(stat));
  229. S48_UNSAFE_RECORD_SET(sch_pid, 2, temp);
  230. }
  231. S48_GC_UNPROTECT();
  232. return sch_pid;
  233. }
  234. else
  235. S48_GC_UNPROTECT();
  236. }
  237. }
  238. }
  239. /*
  240. * Fork and exec.
  241. */
  242. static s48_value
  243. posix_fork(void)
  244. {
  245. pid_t child_pid = fork();
  246. if (child_pid < 0)
  247. s48_raise_os_error(errno);
  248. if (child_pid == 0)
  249. return S48_FALSE;
  250. else
  251. return make_pid(child_pid);
  252. }
  253. /*
  254. * The environment is an array of strings of the form "name=value", where
  255. * `name' cannot contain `='.
  256. *
  257. * It is a nuisance that given three binary choices (arguments explicit or
  258. * in a vector, path lookup or not, explicit or implicit environment) Posix
  259. * only gives six functions. The two calls that have an explict environment
  260. * both do path lookup. We work around this by adding `./' to the beginning
  261. * of the program, if it does not already contain a `/'.
  262. */
  263. static s48_value
  264. posix_exec(s48_value program, s48_value lookup_p,
  265. s48_value env, s48_value args)
  266. {
  267. char **c_args = enter_byte_vector_array(args);
  268. char *c_program, *real_c_program;
  269. int status;
  270. c_program = s48_extract_byte_vector(program);
  271. s48_stop_alarm_interrupts();
  272. if (env == S48_FALSE)
  273. if (lookup_p == S48_FALSE)
  274. status = execv(c_program, c_args);
  275. else {
  276. status = execvp(c_program, c_args);
  277. }
  278. else {
  279. char **c_env = enter_byte_vector_array(env);
  280. if (NULL == strchr(c_program, '/'))
  281. real_c_program = add_dot_slash(c_program);
  282. else
  283. real_c_program = c_program;
  284. status = execve(c_program, c_args, c_env);
  285. free(c_env);
  286. if (real_c_program != c_program)
  287. free(real_c_program); }
  288. /* If we get here, then something has gone wrong. */
  289. free(c_args);
  290. s48_start_alarm_interrupts();
  291. s48_raise_os_error(errno);
  292. /* appease gcc -Wall */
  293. return S48_FALSE;
  294. }
  295. /*
  296. * Convert a list of byte vectors into an array of char pointers.
  297. */
  298. static char **
  299. enter_byte_vector_array(s48_value vectors)
  300. {
  301. int length = S48_UNSAFE_EXTRACT_FIXNUM(s48_length(vectors));
  302. char **result = (char **)malloc((length + 1) * sizeof(char *));
  303. int i;
  304. if (result == NULL)
  305. s48_raise_out_of_memory_error();
  306. for(i = 0; i < length; i++, vectors = S48_UNSAFE_CDR(vectors)) {
  307. s48_value vector = S48_UNSAFE_CAR(vectors);
  308. if (! S48_BYTE_VECTOR_P(vector)) {
  309. free(result);
  310. s48_raise_argument_type_error(vector); }
  311. result[i] = S48_UNSAFE_EXTRACT_BYTE_VECTOR(vector); }
  312. result[length] = NULL;
  313. return result;
  314. }
  315. /*
  316. * Add `./' to the beginning of `name'.
  317. */
  318. static char *
  319. add_dot_slash(char *name)
  320. {
  321. int len = strlen(name);
  322. char *new_name = (char *)malloc((len + 1) * sizeof(char));
  323. if (new_name == NULL)
  324. s48_raise_out_of_memory_error();
  325. new_name[0] = '.';
  326. new_name[1] = '/';
  327. strcpy(new_name + 2, name);
  328. return new_name;
  329. }
  330. /*
  331. * Signals
  332. */
  333. /*
  334. * Simple front for kill(). We have to retry if interrupted.
  335. */
  336. s48_value
  337. posix_kill(s48_value sch_pid, s48_value sch_signal)
  338. {
  339. int status;
  340. s48_check_record_type(sch_pid, posix_process_id_type_binding);
  341. RETRY_OR_RAISE_NEG(status,
  342. kill(s48_extract_fixnum(S48_UNSAFE_RECORD_REF(sch_pid, 0)),
  343. extract_signal(sch_signal)));
  344. return S48_UNSPECIFIC;
  345. }
  346. /*
  347. * This is an array that maps our `canonical' signal numbers to the local
  348. * OS's numbers. The initialization is done via an include file written
  349. * by a Scheme program. The include file first calls signal_count_is()
  350. * with the number of named signals and then adds the named signals supported
  351. * by the current os to `signal_map'.
  352. */
  353. static int *signal_map, signal_map_size;
  354. static void
  355. signal_count_is(int count)
  356. {
  357. int i;
  358. signal_map_size = count;
  359. signal_map = (int *) malloc(count * sizeof(int));
  360. if (signal_map == NULL) {
  361. fprintf(stderr, "ran out of memory during initialization\n");
  362. exit(1); }
  363. for (i = 0; i < count; i++)
  364. signal_map[i] = -1;
  365. }
  366. static void
  367. signal_map_init()
  368. {
  369. #include "s48_signals.h"
  370. }
  371. static void
  372. signal_map_uninit(void)
  373. {
  374. free(signal_map);
  375. }
  376. /*
  377. * Converts from an OS signal to a canonical signal number.
  378. * We return -1 if there is no matching named signal.
  379. */
  380. static int
  381. lookup_signal(int c_signal) {
  382. int i = 0;
  383. for (i = 0; i < signal_map_size; i++)
  384. if (signal_map[i] == c_signal)
  385. return i;
  386. return -1;
  387. }
  388. /*
  389. * Use the signal map to set the os-number slot in each named signal to
  390. * its value in the current OS.
  391. */
  392. static s48_value
  393. posix_initialize_named_signals(void)
  394. {
  395. int i, length;
  396. s48_value named_signals;
  397. S48_SHARED_BINDING_CHECK(posix_signals_vector_binding);
  398. named_signals = S48_SHARED_BINDING_REF(posix_signals_vector_binding);
  399. if(! S48_VECTOR_P(named_signals))
  400. s48_raise_argument_type_error(named_signals);
  401. length = S48_UNSAFE_VECTOR_LENGTH(named_signals);
  402. for(i = 0; i < length; i++) {
  403. s48_value signal = S48_UNSAFE_VECTOR_REF(named_signals, i);
  404. int canonical = s48_extract_fixnum(S48_UNSAFE_RECORD_REF(signal, 1));
  405. int c_signal = signal_map[canonical];
  406. s48_value scm_signal = (c_signal == -1) ?
  407. S48_FALSE :
  408. s48_enter_fixnum(c_signal);
  409. S48_UNSAFE_RECORD_SET(signal, 2, scm_signal); }
  410. return S48_UNSPECIFIC;
  411. }
  412. /*
  413. * Make a new unnamed signal containing `fx_signal' and add it to the weak
  414. * list of unnamed signals.
  415. */
  416. static s48_value
  417. make_unnamed_signal(s48_value fx_signal)
  418. {
  419. s48_value weak = S48_UNSPECIFIC;
  420. s48_value unnamed = s48_make_record(posix_unnamed_signal_type_binding);
  421. S48_DECLARE_GC_PROTECT(1);
  422. S48_GC_PROTECT_1(weak);
  423. S48_UNSAFE_RECORD_SET(unnamed,
  424. 0,
  425. S48_UNSAFE_SHARED_BINDING_REF(
  426. posix_unnamed_signal_marker_binding));
  427. S48_UNSAFE_RECORD_SET(unnamed, 1, fx_signal);
  428. S48_UNSAFE_RECORD_SET(unnamed, 2, S48_NULL); /* No queues */
  429. weak = s48_make_weak_pointer(unnamed);
  430. unnamed_signals = s48_cons(weak, unnamed_signals);
  431. S48_GC_UNPROTECT();
  432. return unnamed;
  433. }
  434. /*
  435. * Returns a signal record for `signal'. Unnamed signals are looked up in
  436. * the weak list of same; if none is found we make one. Scheme records for
  437. * named signals are retrieved from a vector sent down by the Scheme code.
  438. */
  439. static s48_value
  440. enter_signal(int c_signal)
  441. {
  442. int canonical = lookup_signal(c_signal);
  443. if (canonical == -1) {
  444. s48_value fx_signal = s48_enter_fixnum(c_signal);
  445. s48_value unnamed = lookup_record(&unnamed_signals, 1, fx_signal);
  446. if (unnamed != S48_FALSE)
  447. return unnamed;
  448. else
  449. return make_unnamed_signal(fx_signal); }
  450. else
  451. return S48_VECTOR_REF(S48_SHARED_BINDING_REF(posix_signals_vector_binding),
  452. canonical);
  453. }
  454. /*
  455. * Wrapper for enter_signal() for calling from Scheme.
  456. */
  457. static s48_value
  458. posix_integer_to_signal(s48_value signal_int)
  459. {
  460. if (S48_FIXNUM_P(signal_int))
  461. return enter_signal(s48_extract_fixnum(signal_int));
  462. else
  463. /* really should do an integer? test here */
  464. return S48_FALSE;
  465. }
  466. /*
  467. * Go from a signal back to the local integer. For named signals we extract
  468. * the canonical signal to use as an index into the signal map. Unnamed signals
  469. * contain the local signal already.
  470. */
  471. static int
  472. extract_signal(s48_value sch_signal)
  473. {
  474. s48_value type;
  475. if (! S48_RECORD_P(sch_signal))
  476. s48_raise_argument_type_error(sch_signal);
  477. type = S48_UNSAFE_RECORD_TYPE(sch_signal);
  478. if (type == S48_UNSAFE_SHARED_BINDING_REF(posix_named_signal_type_binding)) {
  479. int canonical = s48_extract_fixnum(S48_UNSAFE_RECORD_REF(sch_signal, 1));
  480. if ((0 <= canonical) && (canonical < signal_map_size)
  481. && signal_map[canonical] != -1)
  482. return signal_map[canonical];
  483. else
  484. s48_raise_argument_type_error(sch_signal); }
  485. else if (type ==
  486. S48_UNSAFE_SHARED_BINDING_REF(posix_unnamed_signal_type_binding))
  487. return s48_extract_fixnum(S48_UNSAFE_RECORD_REF(sch_signal, 1));
  488. else
  489. s48_raise_argument_type_error(sch_signal);
  490. }
  491. /*
  492. * Queue the interrupt. For SIGINT and SIGALRM we call the event-system's
  493. * handler as well.
  494. */
  495. static void
  496. generic_interrupt_catcher(int signum)
  497. {
  498. extern void s48_add_os_signal(long);
  499. s48_add_os_signal(signum);
  500. switch (signum) {
  501. case SIGINT: {
  502. s48_when_keyboard_interrupt(0);
  503. break; }
  504. case SIGALRM: {
  505. s48_when_alarm_interrupt(0);
  506. break; }
  507. case SIG_EXTERNAL_EVENT: {
  508. s48_when_external_event_interrupt(0);
  509. break; }
  510. default:
  511. NOTE_EVENT; }
  512. return;
  513. }
  514. /*
  515. * Array of actions to be restored when we no longer listen for a signal.
  516. */
  517. #define MAX_SIGNAL 1023 /* Just a guess. */
  518. struct sigaction *saved_actions[MAX_SIGNAL + 1] = {NULL};
  519. /*
  520. * If there is a saved action then our handler is already in place and
  521. * we need do nothing. Otherwise we save the current action and install
  522. * our own.
  523. */
  524. s48_value
  525. posix_request_interrupts(s48_value sch_signum)
  526. {
  527. int signum = s48_extract_fixnum(sch_signum);
  528. struct sigaction sa;
  529. if (saved_actions[signum] == NULL) {
  530. struct sigaction * old = (struct sigaction *)
  531. malloc(sizeof(struct sigaction));
  532. if (old == NULL)
  533. s48_raise_out_of_memory_error();
  534. sa.sa_handler = generic_interrupt_catcher;
  535. sigfillset(&sa.sa_mask);
  536. sa.sa_flags = 0;
  537. if (sigaction(signum, &sa, old) != 0) {
  538. free(old);
  539. s48_raise_os_error(errno); }
  540. saved_actions[signum] = old; }
  541. return S48_UNSPECIFIC;
  542. }
  543. /*
  544. * The reverse of the above. If there is a saved action then we install it
  545. * and remove it from the saved_action array.
  546. */
  547. static void
  548. cancel_interrupt_request(int signum)
  549. {
  550. struct sigaction * old = saved_actions[signum];
  551. if (old != NULL)
  552. {
  553. if (sigaction(signum, old, (struct sigaction *) NULL) != 0)
  554. s48_raise_os_error(errno);
  555. free(old);
  556. saved_actions[signum] = NULL;
  557. }
  558. }
  559. s48_value
  560. posix_cancel_interrupt_request(s48_value sch_signum)
  561. {
  562. cancel_interrupt_request(s48_extract_fixnum(sch_signum));
  563. return S48_UNSPECIFIC;
  564. }
  565. static void
  566. cancel_interrupt_requests(void)
  567. {
  568. int signum = 0;
  569. while (signum <= MAX_SIGNAL)
  570. {
  571. cancel_interrupt_request(signum);
  572. ++signum;
  573. }
  574. }