event.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. /* Copyright (c) 1993-2005 by Richard Kelsey and Jonathan Rees.
  2. See file COPYING. */
  3. #include <signal.h> /* for sigaction() (POSIX.1) */
  4. #include <stdlib.h>
  5. #include <unistd.h>
  6. #include <stdio.h>
  7. #include <sys/types.h>
  8. #include <sys/time.h>
  9. #include <sys/times.h>
  10. #include <errno.h> /* for errno, (POSIX?/ANSI) */
  11. #include <string.h> /* FD_ZERO sometimes needs this */
  12. #include "sysdep.h"
  13. #include "c-mods.h"
  14. #include "scheme48vm.h"
  15. #include "event.h"
  16. /* turning interrupts and I/O readiness into events */
  17. #define block_interrupts()
  18. #define allow_interrupts()
  19. void s48_when_keyboard_interrupt(int ign);
  20. void s48_when_alarm_interrupt(int ign);
  21. static void when_sigpipe_interrupt(int ign);
  22. psbool s48_setcatcher(int signum, void (*catcher)(int));
  23. void s48_start_alarm_interrupts(void);
  24. void
  25. s48_sysdep_init(void)
  26. {
  27. if (!s48_setcatcher(SIGINT, s48_when_keyboard_interrupt)
  28. || !s48_setcatcher(SIGALRM, s48_when_alarm_interrupt)
  29. || !s48_setcatcher(SIGPIPE, when_sigpipe_interrupt)) {
  30. fprintf(stderr,
  31. "Failed to install signal handlers, errno = %d\n",
  32. errno);
  33. exit(1);
  34. }
  35. s48_start_alarm_interrupts();
  36. }
  37. /*
  38. * Unless a signal is being ignored, set up the handler.
  39. * If we return PSFALSE, something went wrong and errno is set to what.
  40. */
  41. psbool
  42. s48_setcatcher(int signum, void (*catcher)(int))
  43. {
  44. struct sigaction sa;
  45. if (sigaction(signum, (struct sigaction *)NULL, &sa) != 0)
  46. return (PSFALSE);
  47. if (sa.sa_handler == SIG_IGN)
  48. return (PSTRUE);
  49. sa.sa_handler = catcher;
  50. sigemptyset(&sa.sa_mask);
  51. sa.sa_flags = 0;
  52. if (sigaction(signum, &sa, (struct sigaction *)NULL) != 0)
  53. return (PSFALSE);
  54. return (PSTRUE);
  55. }
  56. static long keyboard_interrupt_count = 0;
  57. void
  58. s48_when_keyboard_interrupt(int ign)
  59. {
  60. keyboard_interrupt_count += 1;
  61. NOTE_EVENT;
  62. return;
  63. }
  64. /*
  65. We turn off SIGPIPE interrupts by installing a handler that does nothing.
  66. Turning them off affects exec()'ed programs, so we don't want to do that.
  67. Any actual pipe problems are caught when we try to read or write to them.
  68. We thank Olin Shivers for this hack.
  69. */
  70. static void
  71. when_sigpipe_interrupt(int ign)
  72. {
  73. return;
  74. }
  75. /* ticks since last timer-interrupt request */
  76. long s48_current_time = 0;
  77. static long alarm_time = -1;
  78. static long poll_time = -1;
  79. static long poll_interval = 5;
  80. void
  81. s48_when_alarm_interrupt(int ign)
  82. {
  83. s48_current_time += 1;
  84. /* fprintf(stderr, "[tick]"); */
  85. if ((alarm_time >= 0 && alarm_time <= s48_current_time) ||
  86. (poll_time >= 0 && poll_time <= s48_current_time)) {
  87. NOTE_EVENT;
  88. };
  89. return;
  90. }
  91. #define USEC_PER_POLL (1000000 / POLLS_PER_SECOND)
  92. /* delta is in ticks, 0 cancels current alarm */
  93. long
  94. s48_schedule_alarm_interrupt(long delta)
  95. {
  96. long old;
  97. /*
  98. fprintf(stderr, "<scheduling alarm for %ld + %ld>\n", s48_current_time,
  99. delta/TICKS_PER_POLL); */
  100. /* get remaining time */
  101. if (alarm_time == -1)
  102. old = -1;
  103. else
  104. old = (alarm_time - s48_current_time) * TICKS_PER_POLL;
  105. /* decrement poll_time and reset current_time */
  106. if (poll_time != -1)
  107. poll_time -= s48_current_time;
  108. s48_current_time = 0;
  109. /* set alarm_time */
  110. if (delta == 0) {
  111. NOTE_EVENT;
  112. alarm_time = 0; }
  113. else
  114. alarm_time = delta / TICKS_PER_POLL;
  115. return old;
  116. }
  117. /* The next two procedures return times in seconds and ticks */
  118. long
  119. s48_real_time(long *ticks)
  120. {
  121. struct timeval tv;
  122. static struct timeval tv_orig;
  123. static int initp = PSFALSE;
  124. if (!initp) {
  125. gettimeofday(&tv_orig, NULL);
  126. initp = PSTRUE;
  127. };
  128. gettimeofday(&tv, NULL);
  129. *ticks = (tv.tv_usec - tv_orig.tv_usec)/(1000000/TICKS_PER_SECOND);
  130. return tv.tv_sec - tv_orig.tv_sec;
  131. }
  132. long
  133. s48_run_time(long *ticks)
  134. {
  135. struct tms time_buffer;
  136. static long clock_tick = 0;
  137. long cpu_time;
  138. if (clock_tick == 0)
  139. clock_tick = sysconf(_SC_CLK_TCK); /* POSIX.1, POSIX.2 */
  140. times(&time_buffer); /* On Sun, getrusage() would be better */
  141. cpu_time = time_buffer.tms_utime + time_buffer.tms_stime;
  142. *ticks = (cpu_time % clock_tick) * TICKS_PER_SECOND / clock_tick;
  143. return cpu_time / clock_tick;
  144. }
  145. void
  146. s48_start_alarm_interrupts(void)
  147. {
  148. struct itimerval newv, old;
  149. newv.it_value.tv_sec = 0;
  150. newv.it_value.tv_usec = USEC_PER_POLL;
  151. newv.it_interval.tv_sec = 0;
  152. newv.it_interval.tv_usec = USEC_PER_POLL;
  153. if (0 != setitimer(ITIMER_REAL, &newv, &old)) {
  154. perror("setitimer");
  155. exit(-1); }
  156. }
  157. void
  158. s48_stop_alarm_interrupts(void)
  159. {
  160. struct itimerval newv, old;
  161. newv.it_value.tv_sec = 0;
  162. newv.it_value.tv_usec = 0;
  163. newv.it_interval.tv_sec = 0;
  164. newv.it_interval.tv_usec = 0;
  165. if (0 != setitimer(ITIMER_REAL, &newv, &old)) {
  166. perror("setitimer");
  167. exit(-1); }
  168. }
  169. /*
  170. * ; Scheme version of the get-next-event procedure
  171. * ;
  172. * ; 1. If there has been a keyboard interrupt, return it.
  173. * ; 2. Check for ready ports if enough time has passed since the last check.
  174. * ; 3. If there is a ready port, return it.
  175. * ; 4. If an alarm is due, return it.
  176. * ; 5. If no events are pending, clear the event flags.
  177. * (define (get-next-event)
  178. * (cond ((> *keyboard-interrupt-count* 0)
  179. * (without-interrupts
  180. * (lambda ()
  181. * (set! *keyboard-interrupt-count*
  182. * (- *keyboard-interrupt-count* 1))))
  183. * (values (enum event-type keyboard-interrupt) #f #f))
  184. * (else
  185. * (cond ((>= *current_time* *poll-time*)
  186. * (queue-ready-ports)
  187. * (set! *poll-time* (+ *time* *poll-interval*))))
  188. * (cond ((not (queue-empty? ready-ports))
  189. * (values (enum event-type i/o-completion)
  190. * (dequeue! ready-ports)))
  191. * ((>= *current_time* *alarm-time*)
  192. * (set! *alarm-time* max-integer)
  193. * (values (enum event-type alarm-interrupt) #f))
  194. * (else
  195. * (without-interrupts
  196. * (lambda ()
  197. * (if (and (= *keyboard-interrupt-count* 0)
  198. * (> *alarm-time* *current_time*)
  199. * (> *poll-time* *current_time*))
  200. * (set! *pending-event?* #f))))
  201. * (values (enum event-type no-event) #f))))))
  202. */
  203. static psbool there_are_ready_ports(void);
  204. static int next_ready_port(void);
  205. static int queue_ready_ports(psbool wait, long seconds, long ticks);
  206. int
  207. s48_get_next_event(long *ready_fd, long *status)
  208. {
  209. extern int s48_os_signal_pending(void);
  210. int io_poll_status;
  211. /*
  212. fprintf(stderr, "[poll at %d (waiting for %d)]\n", s48_current_time, alarm_time);
  213. */
  214. if (keyboard_interrupt_count > 0) {
  215. block_interrupts();
  216. --keyboard_interrupt_count;
  217. allow_interrupts();
  218. /* fprintf(stderr, "[keyboard interrupt]\n"); */
  219. return (KEYBOARD_INTERRUPT_EVENT);
  220. }
  221. if (poll_time != -1 && s48_current_time >= poll_time) {
  222. io_poll_status = queue_ready_ports(PSFALSE, 0, 0);
  223. if (io_poll_status == NO_ERRORS)
  224. poll_time = s48_current_time + poll_interval;
  225. else {
  226. *status = io_poll_status;
  227. return (ERROR_EVENT);
  228. }
  229. }
  230. if (there_are_ready_ports()) {
  231. *ready_fd = next_ready_port();
  232. *status = 0; /* chars read or written */
  233. /* fprintf(stderr, "[i/o completion]\n"); */
  234. return (IO_COMPLETION_EVENT);
  235. }
  236. if (alarm_time != -1 && s48_current_time >= alarm_time) {
  237. alarm_time = -1;
  238. /* fprintf(stderr, "[alarm %ld]\n", ticks); */
  239. return (ALARM_EVENT);
  240. }
  241. if (s48_os_signal_pending())
  242. return (OS_SIGNAL_EVENT);
  243. block_interrupts();
  244. if ((keyboard_interrupt_count == 0)
  245. && (alarm_time == -1 || s48_current_time < alarm_time)
  246. && (poll_time == -1 || s48_current_time < poll_time))
  247. s48_Spending_eventsPS = PSFALSE;
  248. allow_interrupts();
  249. return (NO_EVENT);
  250. }
  251. /*
  252. * We keep two queues of ports: those that have a pending operation, and
  253. * those whose operation has completed. Periodically, we call select() on
  254. * the pending ports and move any that are ready onto the other queue and
  255. * signal an event.
  256. */
  257. #define FD_QUIESCENT 0 /* idle */
  258. #define FD_READY 1 /* I/O ready to be performed */
  259. #define FD_PENDING 2 /* waiting */
  260. typedef struct fd_struct {
  261. int fd, /* file descriptor */
  262. status; /* one of the FD_* constants */
  263. psbool is_input; /* iff input */
  264. struct fd_struct *next; /* next on same queue */
  265. } fd_struct;
  266. /*
  267. * A queue of fd_structs is empty iff the first field is NULL. In
  268. * that case, lastp points to first.
  269. */
  270. typedef struct fdque {
  271. fd_struct *first,
  272. **lastp;
  273. } fdque;
  274. static fd_struct *fds[FD_SETSIZE];
  275. static fdque ready = {
  276. NULL,
  277. &ready.first
  278. },
  279. pending = {
  280. NULL,
  281. &pending.first
  282. };
  283. static void findrm(fd_struct *entry, fdque *que);
  284. static fd_struct *rmque(fd_struct **link, fdque *que);
  285. static void addque(fd_struct *entry, fdque *que);
  286. static fd_struct *add_fd(int fd, psbool is_input);
  287. /*
  288. * Find a fd_struct in a queue, and remove it.
  289. */
  290. static void
  291. findrm(fd_struct *entry, fdque *que)
  292. {
  293. fd_struct **fp,
  294. *f;
  295. for (fp = &que->first; (f = *fp) != entry; fp = &f->next)
  296. if (f == NULL) {
  297. fprintf(stderr, "ERROR: findrm fd %d, status %d not on queue.\n",
  298. entry->fd, entry->status);
  299. return;
  300. }
  301. rmque(fp, que);
  302. }
  303. /*
  304. * Given a pointer to the link of a fd_struct, and a pointer to
  305. * the queue it is on, remove the entry from the queue.
  306. * The entry removed is returned.
  307. */
  308. static fd_struct *
  309. rmque(fd_struct **link, fdque *que)
  310. {
  311. fd_struct *res;
  312. res = *link;
  313. *link = res->next;
  314. if (res->next == NULL)
  315. que->lastp = link;
  316. return (res);
  317. }
  318. /*
  319. * Add a fd_struct to a queue.
  320. */
  321. static void
  322. addque(fd_struct *entry, fdque *que)
  323. {
  324. *que->lastp = entry;
  325. entry->next = NULL;
  326. que->lastp = &entry->next;
  327. }
  328. static psbool
  329. there_are_ready_ports(void)
  330. {
  331. return (ready.first != NULL);
  332. }
  333. static int
  334. next_ready_port(void)
  335. {
  336. fd_struct *p;
  337. p = rmque(&ready.first, &ready);
  338. p->status = FD_QUIESCENT;
  339. return (p->fd);
  340. }
  341. /*
  342. * Put fd on to the queue of ports with pending operations.
  343. * Return PSTRUE if successful, and PSFALSE otherwise.
  344. */
  345. psbool
  346. s48_add_pending_fd(int fd, psbool is_input)
  347. {
  348. fd_struct *data;
  349. if (! (0 <= fd && fd < FD_SETSIZE)) {
  350. fprintf(stderr, "ERROR: add_pending fd %d not in [0, %d)\n",
  351. fd,
  352. FD_SETSIZE);
  353. return (PSFALSE);
  354. }
  355. data = fds[fd];
  356. if (data == NULL) {
  357. data = add_fd(fd, is_input);
  358. if (data == NULL)
  359. return (PSFALSE); } /* no more memory */
  360. data->is_input = is_input;
  361. if (data->status == FD_PENDING)
  362. return (PSTRUE); /* fd is already pending */
  363. if (data->status == FD_READY)
  364. findrm(data, &ready);
  365. data->status = FD_PENDING;
  366. addque(data, &pending);
  367. if (poll_time == -1)
  368. poll_time = s48_current_time + poll_interval;
  369. return PSTRUE;
  370. }
  371. /*
  372. * Add a new fd_struct for fd.
  373. */
  374. static fd_struct *
  375. add_fd(int fd, psbool is_input)
  376. {
  377. struct fd_struct *new_fd;
  378. new_fd = (struct fd_struct *)malloc(sizeof(struct fd_struct));
  379. if (new_fd != NULL) {
  380. new_fd->fd = fd;
  381. new_fd->status = FD_QUIESCENT;
  382. new_fd->is_input = is_input;
  383. new_fd->next = NULL;
  384. fds[fd] = new_fd;
  385. }
  386. return (new_fd);
  387. }
  388. /*
  389. * Remove fd from any queues it is on. Returns true if the FD was on a queue
  390. * and false if it wasn't.
  391. */
  392. psbool
  393. s48_remove_fd(int fd)
  394. {
  395. struct fd_struct *data;
  396. if (! (0 <= fd && fd < FD_SETSIZE)) {
  397. fprintf(stderr, "ERROR: s48_remove_fd fd %d not in [0, %d)\n",
  398. fd,
  399. FD_SETSIZE);
  400. return PSFALSE;
  401. }
  402. data = fds[fd];
  403. if (data == NULL)
  404. return PSFALSE;
  405. if (data->status == FD_PENDING) {
  406. findrm(data, &pending);
  407. if (pending.first == NULL)
  408. poll_time = -1;
  409. } else if (data->status == FD_READY)
  410. findrm(data, &ready);
  411. free((void *)data);
  412. fds[fd] = NULL;
  413. return PSTRUE;
  414. }
  415. int
  416. s48_wait_for_event(long max_wait, psbool is_minutes)
  417. {
  418. int status;
  419. long seconds,
  420. ticks;
  421. /* fprintf(stderr, "[waiting]\n"); */
  422. s48_stop_alarm_interrupts();
  423. ticks = 0;
  424. if (max_wait == -1)
  425. seconds = -1;
  426. else if (is_minutes)
  427. seconds = max_wait * 60;
  428. else {
  429. seconds = max_wait / TICKS_PER_SECOND;
  430. ticks = max_wait % TICKS_PER_SECOND;
  431. }
  432. if (keyboard_interrupt_count > 0)
  433. status = NO_ERRORS;
  434. else {
  435. status = queue_ready_ports(PSTRUE, seconds, ticks);
  436. if (there_are_ready_ports())
  437. NOTE_EVENT;
  438. }
  439. s48_start_alarm_interrupts();
  440. return (status);
  441. }
  442. /*
  443. * Call select() on the pending ports and move any ready ones to the ready
  444. * queue. If wait is true, seconds is either -1 (wait forever) or the
  445. * maximum number of seconds to wait (with ticks any additional ticks).
  446. * The returned value is a status code.
  447. */
  448. static int
  449. queue_ready_ports(psbool wait, long seconds, long ticks)
  450. {
  451. fd_set reads,
  452. writes,
  453. alls;
  454. int limfd;
  455. fd_struct *fdp,
  456. **fdpp;
  457. int left;
  458. struct timeval tv,
  459. *tvp;
  460. if ((! wait)
  461. && (pending.first == NULL))
  462. return (NO_ERRORS);
  463. FD_ZERO(&reads);
  464. FD_ZERO(&writes);
  465. FD_ZERO(&alls);
  466. limfd = 0;
  467. for (fdp = pending.first; fdp != NULL; fdp = fdp->next) {
  468. FD_SET(fdp->fd, fdp->is_input ? &reads : &writes);
  469. FD_SET(fdp->fd, &alls);
  470. if (limfd <= fdp->fd)
  471. limfd = fdp->fd + 1;
  472. }
  473. tvp = &tv;
  474. if (wait)
  475. if (seconds == -1)
  476. tvp = NULL;
  477. else {
  478. tv.tv_sec = seconds;
  479. tv.tv_usec = ticks * (1000000 / TICKS_PER_SECOND);
  480. }
  481. else
  482. timerclear(&tv);
  483. while(1) {
  484. left = select(limfd, &reads, &writes, &alls, tvp);
  485. if (left > 0) {
  486. fdpp = &pending.first;
  487. while (left > 0 && (fdp = *fdpp) != NULL)
  488. if ((FD_ISSET(fdp->fd, &alls))
  489. || (FD_ISSET(fdp->fd, fdp->is_input ? &reads : &writes))) {
  490. --left;
  491. rmque(fdpp, &pending);
  492. fdp->status = FD_READY;
  493. addque(fdp, &ready);
  494. } else
  495. fdpp = &fdp->next;
  496. if (pending.first == NULL)
  497. poll_time = -1;
  498. return NO_ERRORS;
  499. }
  500. else if (left == 0)
  501. return NO_ERRORS;
  502. else if (errno == EINTR) {
  503. tvp = &tv; /* turn off blocking and try again */
  504. timerclear(tvp);
  505. }
  506. else
  507. return errno;
  508. }
  509. }