home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / games / volume13 / diph / part01 < prev    next >
Encoding:
Internet Message Format  |  1992-02-10  |  53.2 KB

  1. Path: uunet!zephyr.ens.tek.com!master!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v13i026:  diph - the game of dining philosophers, Part01/01
  5. Message-ID: <2345@masterCNA.TEK.COM>
  6. Date: 25 Jan 92 01:33:46 GMT
  7. Sender: news@masterCNA.TEK.COM
  8. Lines: 2217
  9. Approved: billr@saab.CNA.TEK.COM
  10.  
  11. Submitted-by: brnstnd@KRAMDEN.ACF.NYU.EDU
  12. Posting-number: Volume 13, Issue 26
  13. Archive-name: diph/Part01
  14. Environment: BSD Unix
  15.  
  16.     [Somewhat unusual game in that it is really just a showcase for
  17.      the underlying library routines, but it does work.  -br]
  18.  
  19. #! /bin/sh
  20. # This is a shell archive.  Remove anything before this line, then unpack
  21. # it by saving it into a file and typing "sh file".  To overwrite existing
  22. # files, type "sh file -c".  You can also feed this as standard input via
  23. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  24. # will see the following message at the end:
  25. #        "End of archive 1 (of 1)."
  26. # Contents:  README MANIFEST config config/fdsettrouble.h diph.6 diph.c
  27. #   ralloc.c ralloc.h sigsched.3 sigsched.c sigsched.h sod.h timer.c
  28. #   timer.h
  29. # Wrapped by billr@saab on Fri Jan 24 17:31:54 1992
  30. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  31. if test -f 'README' -a "${1}" != "-c" ; then 
  32.   echo shar: Will not clobber existing file \"'README'\"
  33. else
  34. echo shar: Extracting \"'README'\" \(741 characters\)
  35. sed "s/^X//" >'README' <<'END_OF_FILE'
  36. XThey say that to make computer scientists like a multitasking model, you
  37. Xhave to show them how you solve the dining philosophers problem under
  38. Xthat model. Okay, then: the point of this package is to show off my
  39. Xsigsched library, which lets you do signal-schedule programming, aka
  40. Xevent programming, aka non-preemptive threads, on any BSD system. Also
  41. Xincluded here is my timer library, which defines real, virtual, and
  42. Xprofiling time events. Anyway, the dining philosophers simulation here
  43. Xis sufficiently slapstick to deserve being called a game, though not a
  44. Xfantastically deep game. Set the philosophers loose and watch them
  45. Xinteract for a while. No Makefile necessary---just compile all the .c
  46. Xfiles together into diph and run.
  47. X
  48. X---Dan
  49. X
  50. END_OF_FILE
  51. if test 741 -ne `wc -c <'README'`; then
  52.     echo shar: \"'README'\" unpacked with wrong size!
  53. fi
  54. # end of 'README'
  55. fi
  56. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  57.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  58. else
  59. echo shar: Extracting \"'MANIFEST'\" \(548 characters\)
  60. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  61. X   File Name        Archive #    Description
  62. X-----------------------------------------------------------
  63. X MANIFEST                   1    This shipping list
  64. X README                     1    
  65. X config                     1    
  66. X config/fdsettrouble.h      1    
  67. X diph.6                     1    
  68. X diph.c                     1    
  69. X ralloc.c                   1    
  70. X ralloc.h                   1    
  71. X sigsched.3                 1    
  72. X sigsched.c                 1    
  73. X sigsched.h                 1    
  74. X sod.h                      1    
  75. X timer.c                    1    
  76. X timer.h                    1    
  77. END_OF_FILE
  78. if test 548 -ne `wc -c <'MANIFEST'`; then
  79.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  80. fi
  81. # end of 'MANIFEST'
  82. fi
  83. if test ! -d 'config' ; then
  84.     echo shar: Creating directory \"'config'\"
  85.     mkdir 'config'
  86. fi
  87. if test -f 'config/fdsettrouble.h' -a "${1}" != "-c" ; then 
  88.   echo shar: Will not clobber existing file \"'config/fdsettrouble.h'\"
  89. else
  90. echo shar: Extracting \"'config/fdsettrouble.h'\" \(180 characters\)
  91. sed "s/^X//" >'config/fdsettrouble.h' <<'END_OF_FILE'
  92. X#ifndef CONFIG_FD_SET_TROUBLE_H
  93. X#define CONFIG_FD_SET_TROUBLE_H
  94. X
  95. X#undef LACKING_FD_ZERO
  96. X#undef DESPERATE_FD_SET
  97. X
  98. X/* sysconf expects lines 4 and 5 */
  99. X
  100. X/* XXX: deprecated */
  101. X
  102. X#endif
  103. END_OF_FILE
  104. if test 180 -ne `wc -c <'config/fdsettrouble.h'`; then
  105.     echo shar: \"'config/fdsettrouble.h'\" unpacked with wrong size!
  106. fi
  107. # end of 'config/fdsettrouble.h'
  108. fi
  109. if test -f 'diph.6' -a "${1}" != "-c" ; then 
  110.   echo shar: Will not clobber existing file \"'diph.6'\"
  111. else
  112. echo shar: Extracting \"'diph.6'\" \(369 characters\)
  113. sed "s/^X//" >'diph.6' <<'END_OF_FILE'
  114. X.TH diph 6
  115. X.SH NAME
  116. Xdiph \- dining philosophers simulation
  117. X.SH SYNTAX
  118. X.B diph
  119. X.SH DESCRIPTION
  120. X.B diph
  121. Xis a somewhat slapstick simulation of the
  122. Xdining philosophers problem.
  123. XInstructions are printed at the beginning of each run.
  124. X.SH VERSION
  125. Xdiph version 1.0, 7/27/91.
  126. X.SH AUTHOR
  127. XPlaced into the public domain by Daniel J. Bernstein.
  128. X.SH "SEE ALSO"
  129. Xsigsched(3),
  130. Xtimer(3)
  131. END_OF_FILE
  132. if test 369 -ne `wc -c <'diph.6'`; then
  133.     echo shar: \"'diph.6'\" unpacked with wrong size!
  134. fi
  135. # end of 'diph.6'
  136. fi
  137. if test -f 'diph.c' -a "${1}" != "-c" ; then 
  138.   echo shar: Will not clobber existing file \"'diph.c'\"
  139. else
  140. echo shar: Extracting \"'diph.c'\" \(7332 characters\)
  141. sed "s/^X//" >'diph.c' <<'END_OF_FILE'
  142. X/* diph.c: the game of dining philosophers
  143. XDaniel J. Bernstein, brnstnd@nyu.edu.
  144. XDepends on sigsched.h, timer.h, ralloc.h.
  145. XRequires UNIX.
  146. X1/8/92: Took advantage of rallocneverfail().
  147. X7/27/91: Baseline. diph 1.0, public domain.
  148. XNo known patent problems.
  149. X
  150. XA colorful implementation of dining philosophers using signal-schedule
  151. Xprogramming. Notice how easy signal-schedule makes synchronization. You
  152. Xdon't have to worry about locks. You don't have to worry about the order
  153. Xof bringing semaphores up and down. All you have to do is make sure that
  154. Xno thread can get into an infinite loop, and that's trivial.
  155. X
  156. XWhen a philosopher wants to eat, if a fork isn't available, he glares at
  157. Xthe neighbor using the fork. When that neighbor finishes eating, he
  158. Xpunches the one who glared at him.
  159. X
  160. XWe use the timer library to schedule eating and end-of-eating in real
  161. Xtime. Each philosopher thinks for 1 to 10 seconds, then eats for 2 to 5
  162. Xseconds, then goes back to thinking.
  163. X
  164. XThe solution really requires only 5 bits of state (though more bits, of
  165. Xcourse, are stored inside sigsched): whether forks are up and down.
  166. XEverything else is added for amusement value.
  167. X
  168. XPhilosophers 0 through 4 have these bits:
  169. X  eating
  170. X  thinking (aka not hungry)
  171. X  glaring to the left
  172. X  glaring to the right
  173. X
  174. XPhilosopher i uses forks i and i + 1. In the program output, forks are
  175. Xdisplayed as the numbers of the philosophers who can use them: 01, 12,
  176. X23, 34, 40.
  177. X
  178. X*/
  179. X
  180. X#include <stdio.h>
  181. X#include <signal.h>
  182. X#include "sigsched.h"
  183. X#include "timer.h"
  184. X#include "ralloc.h" /* just for rcount() statistics */
  185. X
  186. Xint myrandom()
  187. X{
  188. X return getpid() + rand(); /* XXX: good enough for a demonstration program */
  189. X}
  190. X
  191. Xvoid choose_eattime(when)
  192. Xtimer_clock *when;
  193. X{
  194. X timer_clock now;
  195. X timer_clock diff;
  196. X timer_now(TIMER_REAL,&now);
  197. X diff.sec = 1 + (myrandom() % 9);
  198. X diff.usec = 1 + (myrandom() % 1000000);
  199. X timer_sum(&now,&diff,when);
  200. X}
  201. X
  202. Xvoid choose_doneeattime(when)
  203. Xtimer_clock *when;
  204. X{
  205. X timer_clock now;
  206. X timer_clock diff;
  207. X timer_now(TIMER_REAL,&now);
  208. X diff.sec = 2 + (myrandom() % 3);
  209. X diff.usec = 1 + (myrandom() % 1000000);
  210. X timer_sum(&now,&diff,when);
  211. X}
  212. X
  213. X#define next(i) (((i) + 1) % 5)
  214. X#define prev(i) (((i) + 4) % 5)
  215. X
  216. Xint timeseaten[5];
  217. Xint usecseaten[5];
  218. Xint usecshungry[5];
  219. X
  220. Xint eating[5];
  221. Xint thinking[5];
  222. Xint prevglaring[5];
  223. Xint nextglaring[5];
  224. X
  225. Xint forkup[5];
  226. X
  227. Xtimer_sig wakeup[5];
  228. Xtimer_clock when[5];
  229. Xtimer_clock beganeating[5];
  230. X
  231. Xmeasurehungry(i)
  232. Xint i;
  233. X{
  234. X timer_clock diff;
  235. X timer_now(TIMER_REAL,beganeating + i);
  236. X if (timer_diff(beganeating + i,when + i,&diff) < 0)
  237. X   ; /* XXX: aack! timer error! */
  238. X else
  239. X   usecshungry[i] += diff.sec * 1000000 + diff.usec;
  240. X}
  241. X
  242. Xmeasureeating(i)
  243. Xint i;
  244. X{
  245. X timer_clock diff;
  246. X timer_clock now;
  247. X timer_now(TIMER_REAL,&now);
  248. X if (timer_diff(&now,beganeating + i,&diff) < 0)
  249. X   ; /* XXX: aack! time warp! */
  250. X else
  251. X   usecseaten[i] += diff.sec * 1000000 + diff.usec;
  252. X}
  253. X
  254. Xstopthinking(i)
  255. Xint i;
  256. X{
  257. X printf("%d's stomach rumbles.\n",i); fflush(stdout);
  258. X thinking[i] = 0;
  259. X eat(i);
  260. X}
  261. X
  262. Xstopeating(i)
  263. Xint i;
  264. X{
  265. X printf("%d stops eating and lowers forks %d%d and %d%d.\n"
  266. X     ,i,prev(i),i,i,next(i)); fflush(stdout);
  267. X ++timeseaten[i];
  268. X measureeating(i);
  269. X eating[i] = 0;
  270. X forkup[i] = 0;
  271. X forkup[next(i)] = 0;
  272. X if (prevglaring[next(i)])
  273. X   punch(i,next(i));
  274. X if (nextglaring[prev(i)])
  275. X   punch(i,prev(i));
  276. X printf("%d sinks into meditation.\n",i); fflush(stdout);
  277. X thinking[i] = 1;
  278. X choose_eattime(when + i);
  279. X timer_setsig(wakeup + i,TIMER_REAL,when + i);
  280. X ss_schedonce(&(wakeup[i].sig),stopthinking,i);
  281. X}
  282. X
  283. Xstopprevglare(i)
  284. Xint i;
  285. X{
  286. X printf("%d stops glaring at %d.\n",i,prev(i)); fflush(stdout);
  287. X prevglaring[i] = 0;
  288. X}
  289. X
  290. Xstopnextglare(i)
  291. Xint i;
  292. X{
  293. X printf("%d stops glaring at %d.\n",i,next(i)); fflush(stdout);
  294. X nextglaring[i] = 0;
  295. X}
  296. X
  297. Xglareprev(i)
  298. Xint i;
  299. X{
  300. X if (prevglaring[i])
  301. X   printf("%d continues glaring at %d.\n",i,prev(i));
  302. X else
  303. X   printf("%d glares at %d.\n",i,prev(i));
  304. X fflush(stdout);
  305. X prevglaring[i] = 1;
  306. X}
  307. X
  308. Xglarenext(i)
  309. Xint i;
  310. X{
  311. X if (nextglaring[i])
  312. X   printf("%d continues glaring at %d.\n",i,next(i));
  313. X else
  314. X   printf("%d glares at %d.\n",i,next(i));
  315. X fflush(stdout);
  316. X nextglaring[i] = 1;
  317. X}
  318. X
  319. Xeat(i)
  320. Xint i;
  321. X{
  322. X ss_unsched(ss_asap(),eat,i);
  323. X if (!forkup[i] && prevglaring[i])
  324. X   stopprevglare(i);
  325. X if (!forkup[next(i)] && nextglaring[i])
  326. X   stopnextglare(i);
  327. X if (forkup[i])
  328. X   glareprev(i);
  329. X if (forkup[next(i)])
  330. X   glarenext(i);
  331. X if (!forkup[i] && !forkup[next(i)])
  332. X  {
  333. X   printf("%d grabs forks %d%d and %d%d and begins eating.\n"
  334. X     ,i,prev(i),i,i,next(i)); fflush(stdout);
  335. X   measurehungry(i);
  336. X   forkup[i] = 1;
  337. X   forkup[next(i)] = 1;
  338. X   eating[i] = 1;
  339. X   choose_doneeattime(when + i);
  340. X   timer_setsig(wakeup + i,TIMER_REAL,when + i);
  341. X   ss_schedonce(&(wakeup[i].sig),stopeating,i);
  342. X  }
  343. X}
  344. X
  345. Xpunch(i,j)
  346. Xint i;
  347. Xint j;
  348. X{
  349. X printf("%d punches %d.\n",i,j); fflush(stdout);
  350. X ss_unsched(ss_asap(),eat,j);
  351. X ss_schedwait(ss_asap(),eat,j,1);
  352. X}
  353. X
  354. Xstatistics(n)
  355. Xint n;
  356. X{
  357. X int i;
  358. X
  359. X /* Normally, you can't use stdio inside signal handlers. */
  360. X /* Not only could output get awfully intermixed, but */
  361. X /* stdio's internal state could become really fouled up. */
  362. X /* Under sigsched, such worries simply vanish. */
  363. X printf("\n");
  364. X
  365. X printf("These forks are up:");
  366. X for (i = 0;i < 5;++i)
  367. X   if (forkup[i])
  368. X     printf(" %d%d",prev(i),i);
  369. X
  370. X printf("\n");
  371. X for (i = 0;i < 5;++i)
  372. X   if (thinking[i])
  373. X     printf("Philosopher %d is thinking.\n",i);
  374. X   else
  375. X     if (eating[i])
  376. X       printf("Philosopher %d is eating with forks %d%d and %d%d.\n"
  377. X         ,i,prev(i),i,i,next(i));
  378. X     else
  379. X      {
  380. X       printf("Philosopher %d is hungry",i);
  381. X       if (prevglaring[i] && nextglaring[i])
  382. X     printf(", glaring at %d, and glaring at %d",prev(i),next(i));
  383. X       else if (prevglaring[i])
  384. X     printf(" and glaring at %d",prev(i));
  385. X       else if (nextglaring[i])
  386. X     printf(" and glaring at %d",next(i));
  387. X       printf(".\n");
  388. X      }
  389. X
  390. X for (i = 0;i < 5;++i)
  391. X  {
  392. X   printf("Philosopher %d ate %d time",i,timeseaten[i]);
  393. X   if (timeseaten[i] != 1) printf("s");
  394. X   printf(" for %.2f secs avg, %.2f secs avg hungry.\n"
  395. X     ,usecseaten[i] * 0.000001 / (timeseaten[i] + 0.000001)
  396. X     ,usecshungry[i] * 0.000001 / (timeseaten[i] + eating[i] + 0.000001)
  397. X       /* + eating[i] is to count eating in progress */
  398. X       /* 0.000001 is fudge to avoid dividing by 0 */
  399. X    );
  400. X  }
  401. X
  402. X printf("ralloc reports %d memory segments in use.\n",rcount());
  403. X
  404. X printkeys();
  405. X printf("\n");
  406. X fflush(stdout);
  407. X}
  408. X
  409. Xdie(n)
  410. Xint n;
  411. X{
  412. X exit(n);
  413. X}
  414. X
  415. Xvoid outofmem(n)
  416. Xint n;
  417. X{
  418. X printf("Aack! Out of memory.\n");
  419. X printf("The philosophers suddenly forget what they were doing.\n");
  420. X printf("They get up and walk away from the table aimlessly.\n");
  421. X die(2);
  422. X}
  423. X
  424. Xprintkeys()
  425. X{
  426. X printf("(Type ^C for statistics, ^\\ to quit.)\n");
  427. X}
  428. X
  429. Xmain()
  430. X{
  431. X int i;
  432. X
  433. X rallocneverfail(outofmem);
  434. X printkeys();
  435. X timer_init();
  436. X for (i = 0;i < 5;++i)
  437. X   timeseaten[i] = eating[i] = prevglaring[i] = nextglaring[i] = forkup[i] = 0;
  438. X for (i = 0;i < 5;++i)
  439. X   usecseaten[i] = usecshungry[i] = 0;
  440. X for (i = 0;i < 5;++i)
  441. X  {
  442. X   printf("%d grabs a chair, sits down, and thinks.\n",i);
  443. X   fflush(stdout);
  444. X   thinking[i] = 1;
  445. X   choose_eattime(when + i);
  446. X   timer_setsig(wakeup + i,TIMER_REAL,when + i);
  447. X   ss_schedonce(&(wakeup[i].sig),stopthinking,i);
  448. X  }
  449. X ss_addsig(SIGINT);
  450. X ss_addsig(SIGQUIT);
  451. X ss_sched(ss_signal(SIGINT),statistics,0);
  452. X ss_sched(ss_signal(SIGQUIT),die,0);
  453. X ss_exec();
  454. X /* from this there is no return */
  455. X}
  456. END_OF_FILE
  457. if test 7332 -ne `wc -c <'diph.c'`; then
  458.     echo shar: \"'diph.c'\" unpacked with wrong size!
  459. fi
  460. # end of 'diph.c'
  461. fi
  462. if test -f 'ralloc.c' -a "${1}" != "-c" ; then 
  463.   echo shar: Will not clobber existing file \"'ralloc.c'\"
  464. else
  465. echo shar: Extracting \"'ralloc.c'\" \(3779 characters\)
  466. sed "s/^X//" >'ralloc.c' <<'END_OF_FILE'
  467. X/* ralloc.c, ralloc.h: recovering alloc
  468. XDaniel J. Bernstein, brnstnd@nyu.edu.
  469. XDepends on sod.h.
  470. XRequires malloc/free.
  471. X8/26/91: Changed exit() to _exit().
  472. X8/26/91: Made rallocneverfail() overwrite any previous handler.
  473. X7/24/91: Added rallocneverfail().
  474. X7/18/91: Baseline. ralloc 1.0, public domain.
  475. XNo known patent problems.
  476. X
  477. XLots of library routines allocate space for temporary objects: compiled
  478. Xregular expressions, for example. They don't destroy the objects between
  479. Xeach call---wouldn't it be a waste to reallocate and recompile those
  480. Xregular expressions on every single pattern match? But when space gets
  481. Xtight, you don't want all those temporary objects cluttering the heap.
  482. XYou've got to deallocate them as soon as possible. Sure, library X might
  483. Xhave some deallocation routines---but if X is hidden below library Y and
  484. Xseparate library A runs out of space, do you expect A to know about X
  485. Xand call X's routines? Of course not. How can A and X coordinate?
  486. X
  487. XThe solution is ralloc. ralloc works just like malloc, except that when
  488. Xit runs out of memory, it tries to recover space from anyone who's
  489. Xwilling to give a little slack. If f is a deallocation function, you can
  490. Xcall rallocinstall(f), and ralloc(n) will call f() if there aren't n
  491. Xbytes free. f() should return a non-zero integer if it could free some
  492. Xmemory, 0 if not. Several libraries can rallocinstall their deallocation
  493. Xroutines, and ralloc will cycle between all of them. Make sure that f
  494. Xactually frees some memory if it returns non-zero---otherwise ralloc()
  495. Xwill loop, trying f again and again and wondering why malloc() never has
  496. Xenough space. (In a future implementation I might add a loop counter and
  497. Xhave ralloc give up after trying f enough times.)
  498. X
  499. XAccording to John F. Haugh, ralloc is a Bad Thing, because it inherently
  500. Xrequires static variables, hence can't be put into a ``pure'' shared
  501. Xlibrary. Face it, John: ralloc() solves a real problem, and if you can't
  502. Xput it in a shared library, it's not because ralloc() is somehow evil.
  503. XIt's because your shared libraries aren't good enough.
  504. X
  505. X*/
  506. X
  507. X#include "ralloc.h"
  508. X#include "sod.h"
  509. Xextern char *malloc(); /*XXXX*/
  510. Xextern void free();
  511. X
  512. Xtypedef int (*foo)();
  513. X
  514. XSODdecl(funlist,foo);
  515. X
  516. Xstatic funlist funhead = 0;
  517. Xstatic funlist funlast = 0; /* last fun to successfully recover */
  518. X
  519. Xstatic int ralloccount = 0;
  520. X
  521. Xint rcount()
  522. X{
  523. X return ralloccount;
  524. X}
  525. X
  526. Xvoid rfree(s)
  527. Xchar *s;
  528. X{
  529. X /* This is for completeness, and for another reason: so that you only */
  530. X /* have to modify this file if you want a debugging malloc-free. */
  531. X --ralloccount; /* for instance */
  532. X free(s);
  533. X}
  534. X
  535. Xstatic int crit = 0; /* just to be safe */
  536. X
  537. Xstatic int (*neverfail)() = 0;
  538. X
  539. Xstatic void die(n)
  540. Xunsigned n;
  541. X{
  542. X if (neverfail)
  543. X   neverfail(n);
  544. X _exit(1); /*XXX*/
  545. X}
  546. X
  547. Xchar *ralloc(n)
  548. Xunsigned n;
  549. X{
  550. X char *t;
  551. X funlist fun;
  552. X
  553. X if(t = malloc(n))
  554. X  {
  555. X   ++ralloccount;
  556. X   return t;
  557. X  }
  558. X if (crit)
  559. X   if (neverfail)
  560. X     die(n);
  561. X   else
  562. X     return 0;
  563. X if (!funhead)
  564. X   if (neverfail)
  565. X     die(n);
  566. X   else
  567. X     return 0;
  568. X crit = 1;
  569. X fun = (funlast ? SODnext(funlast) : funhead);
  570. X do
  571. X  {
  572. X   if(!fun)
  573. X     fun = funhead;
  574. X   if((*SODdata(fun))()) /* XXX: can we make use of args or return code? */
  575. X     funlast = fun;
  576. X   else
  577. X     if(fun == funlast)
  578. X      {
  579. X       crit = 0;
  580. X       if (neverfail)
  581. X     die(n);
  582. X       else
  583. X         return 0; /* gaack! */
  584. X      }
  585. X   fun = SODnext(fun);
  586. X   t = malloc(n);
  587. X  }
  588. X while(!t);
  589. X ++ralloccount;
  590. X crit = 0;
  591. X return t;
  592. X}
  593. X
  594. Xvoid rallocneverfail(f)
  595. Xint (*f)();
  596. X{
  597. X neverfail = f; /* possibly overwriting previous handler */
  598. X}
  599. X
  600. X#define malloc ralloc
  601. X
  602. Xint rallocinstall(f)
  603. Xint (*f)();
  604. X{
  605. X funlist fun;
  606. X
  607. X fun = SODalloc(funlist,fun,ralloc);
  608. X if(!fun)
  609. X   return -1;
  610. X SODdata(fun) = f;
  611. X SODpush(funhead,fun);
  612. X
  613. X funlast = funhead; /* need to set it to something */
  614. X
  615. X return 0;
  616. X}
  617. END_OF_FILE
  618. if test 3779 -ne `wc -c <'ralloc.c'`; then
  619.     echo shar: \"'ralloc.c'\" unpacked with wrong size!
  620. fi
  621. # end of 'ralloc.c'
  622. fi
  623. if test -f 'ralloc.h' -a "${1}" != "-c" ; then 
  624.   echo shar: Will not clobber existing file \"'ralloc.h'\"
  625. else
  626. echo shar: Extracting \"'ralloc.h'\" \(257 characters\)
  627. sed "s/^X//" >'ralloc.h' <<'END_OF_FILE'
  628. X#ifndef RALLOC_H
  629. X#define RALLOC_H
  630. X
  631. Xextern char *ralloc();
  632. Xextern void rfree();
  633. Xextern int rcount();
  634. Xextern int rallocinstall();
  635. Xextern void rallocneverfail();
  636. X
  637. X#define RFREE(x) rfree((char *) (x))
  638. X#define RALLOC(t,x) ((t *) ralloc((x) * sizeof(t)))
  639. X
  640. X#endif
  641. END_OF_FILE
  642. if test 257 -ne `wc -c <'ralloc.h'`; then
  643.     echo shar: \"'ralloc.h'\" unpacked with wrong size!
  644. fi
  645. # end of 'ralloc.h'
  646. fi
  647. if test -f 'sigsched.3' -a "${1}" != "-c" ; then 
  648.   echo shar: Will not clobber existing file \"'sigsched.3'\"
  649. else
  650. echo shar: Extracting \"'sigsched.3'\" \(10068 characters\)
  651. sed "s/^X//" >'sigsched.3' <<'END_OF_FILE'
  652. X.TH sigsched 3
  653. X.SH NAME
  654. Xsigsched \- signal-schedule (non-preemptive threads) library
  655. X.SH SYNTAX
  656. X.B #include <sigsched.h>
  657. X
  658. Xss_sig *\fBss_asap()\fR;
  659. X.br
  660. Xss_sig *\fBss_signal(\fIsigno\fB)\fR;
  661. X.br
  662. Xss_sig *\fBss_sigread(\fIfd\fB)\fR;
  663. X.br
  664. Xss_sig *\fBss_sigwrite(\fIfd\fB)\fR;
  665. X.br
  666. Xss_sig *\fBss_sigexcept(\fIfd\fB)\fR;
  667. X
  668. Xint \fBss_addsig(\fIsigno\fB)\fR;
  669. X
  670. Xint \fBss_schedvwait(\fIsig,t,flagi,i,p,wait\fB)\fR;
  671. X.br
  672. Xint \fBss_schedwait(\fIsig,t,i,wait\fB)\fR;
  673. X.br
  674. Xint \fBss_sched(\fIsig,t,i\fB)\fR;
  675. X
  676. Xint \fBss_schedonce(\fIsig,t,i\fB)\fR;
  677. X
  678. Xint \fBss_unschedv(\fIsig,t,flagi,i,p\fB)\fR;
  679. X.br
  680. Xint \fBss_unsched(\fIsig,t,i\fB)\fR;
  681. X
  682. Xvoid \fBss_externsetsig(\fIsig,x\fB)\fR;
  683. X
  684. Xint \fBss_exec()\fR;
  685. X
  686. Xvoid \fBss_forcewait()\fR;
  687. X.br
  688. Xvoid \fBss_unforcewait()\fR;
  689. X
  690. Xss_thread \fI*t\fP;
  691. X.br
  692. Xss_sig \fI*sig\fP;
  693. X.br
  694. Xss_extern \fI*x\fP;
  695. X.br
  696. Xint \fIflagi\fP;
  697. X.br
  698. Xint \fIsigno\fP;
  699. X.br
  700. Xint \fIfd\fP;
  701. X.br
  702. Xss_id \fIi\fP;
  703. X.br
  704. Xss_idptr \fIp\fP;
  705. X.br
  706. Xint \fIwait\fP;
  707. X.SH DESCRIPTION
  708. X.B sigsched
  709. Ximplements the signal-schedule programming model,
  710. Xotherwise known as non-preemptive threads,
  711. Xotherwise known as event-based programming.
  712. XA thread is scheduled to execute upon receipt of a signal
  713. X(occurrence of an event).
  714. XSeparate threads do not interrupt each other.
  715. XAll they can do is schedule more threads.
  716. X
  717. X.B sigsched
  718. Xsupports far more flexible signals than C normally provides
  719. Xunder UNIX.
  720. X``File descriptor 2 is writable'' is a signal, for example.
  721. XFurthermore, threads do not have to be written to handle a
  722. Xsignal at any moment, so code written to use
  723. X.B sigsched
  724. Xcan be fully optimized.
  725. XIn contrast, preemptive thread models (including
  726. XUNIX's usual signal handling) prevent optimizations involving global
  727. Xvariables.
  728. X
  729. XIn general, a ``signal'' is any persistent condition.
  730. XThe ``file descriptor 2 is writable'' signal starts when the pipe
  731. Xis created, persists at least until the next I/O, finishes when the pipe is
  732. Xwritten to capacity, restarts when the pipe is read, and so on.
  733. XUNIX signals are examples of
  734. X.I thread-lowered signals.
  735. XFor example, SIGINT starts (is raised) when some process executes
  736. Xkill(pid,SIGINT),
  737. Xand finishes (is lowered) just before process pid calls the appropriate
  738. Xsignal handler (thread).
  739. XNote that if another process calls
  740. Xkill(pid,SIGINT)
  741. Xbefore the first one is delivered,
  742. Xthe signal merely persists.
  743. XIt is not delivered twice, as after the first delivery the
  744. Xsignal condition has been turned off and can't be redelivered.
  745. XAny number of kill()s may be absorbed into
  746. Xone delivery in this way.
  747. X
  748. XWith
  749. X.B sigsched,
  750. Xthe program can schedule a thread to execute upon receipt of a signal.
  751. X.B ss_schedvwait()
  752. Xand
  753. X.B ss_unschedv()
  754. Xschedule and unschedule threads.
  755. X.B ss_exec()
  756. Xthen executes one scheduled thread after another, as described below.
  757. XIt exits when there are no ``important'' threads left to execute.
  758. X
  759. X.B ss_schedvwait(\fIsig,t,flagi,i,p,wait\fB)
  760. Xschedules the thread
  761. X.I t
  762. Xto execute with integer identifier
  763. X.I i
  764. Xor pointer identifier
  765. X.I p
  766. Xas soon as condition
  767. X.I sig
  768. Xexists.
  769. XThis is an ``important'' thread if
  770. X.I wait
  771. Xis nonzero.
  772. X.I sig
  773. Xis of type
  774. X.B ss_sig *;
  775. Xvarious functions produce signals of this type.
  776. X.I t
  777. Xis of type
  778. X.B ss_thread *,
  779. Xdefined as a function returning void;
  780. Xit is called as
  781. X.I t(i)
  782. Xif
  783. X.I flagi
  784. Xis nonzero,
  785. Xor
  786. X.I t(p)
  787. Xif
  788. X.I flagi
  789. Xis zero.
  790. X.I i
  791. Xis an integer,
  792. Xwhich must be zero if
  793. X.I flagi
  794. Xis;
  795. X.I p
  796. Xis a character pointer,
  797. Xwhich must be a null pointer if
  798. X.I flagi
  799. Xis nonzero.
  800. X.B <sigsched.h>
  801. Xdefines the
  802. X.B ss_sig
  803. Xand
  804. X.B ss_thread
  805. Xtypes;
  806. Xit also abbreviates
  807. Xint as
  808. X.B ss_id
  809. Xand char * as
  810. X.B ss_idptr.
  811. X.B ss_schedvwait
  812. Xnormally returns 0, but will return -1
  813. Xin case of a memory allocation failure.
  814. X
  815. X.B ss_unschedv(\fIsig,t,flagi,i,p\fB)
  816. Xunschedules the thread
  817. X.I t
  818. Xpreviously scheduled to execute with identifier
  819. X.I i
  820. Xor
  821. X.I p
  822. Xas soon as condition
  823. X.I sig
  824. Xexisted.
  825. X.I flagi,
  826. X.I i,
  827. Xand
  828. X.I p
  829. Xmust follow the same rules as above.
  830. X.B ss_unschedv
  831. Xreturns 0 if the unschedule was successful,
  832. X1 if there was no such thread.
  833. XThe effects are currently undefined if a thread is scheduled
  834. Xmore than once for the same signal with the same identifier.
  835. X
  836. X.B ss_exec()
  837. Xexecutes one thread after another, with no interruptions.
  838. XIt calls
  839. X.I t(id)
  840. Xonly if, for some signal
  841. X.I sig,
  842. X(1)
  843. X.I t(id)
  844. Xis scheduled to execute upon
  845. X.I sig;
  846. X(2) condition
  847. X.I sig
  848. Xhas existed sometime between the end of the last call
  849. Xof a thread scheduled upon
  850. X.I sig
  851. Xand the beginning of this call to
  852. X.I t(id).
  853. XIf a
  854. Xthread has just finished executing and
  855. X.B ss_exec
  856. Xcan call one or more
  857. Xthreads under the above restrictions, it will choose one and call that,
  858. Xunless every scheduled thread has a wait value of 0
  859. X(i.e., there are no important threads scheduled).
  860. XIn the latter case
  861. X(including, for example, when there are no threads scheduled at all),
  862. X.B ss_exec()
  863. Ximmediately returns 0.
  864. XIt returns -1 in case of a memory allocation
  865. Xfailure; in that case its internal structures may be permanently
  866. Xcorrupted, and
  867. X.B ss_exec
  868. Xmay not be called again in the same program.
  869. X
  870. XIf no threads can execute at a given moment,
  871. Xbut if some thread is
  872. Xscheduled with a non-zero wait value,
  873. X.B ss_exec
  874. Xhas to wait for a signal
  875. Xto arrive.
  876. XAs an optimization,
  877. Xit will block the process until some
  878. Xthread can execute,
  879. Xrather than actively polling the set of signals.
  880. X
  881. XNote that if several threads are scheduled to execute upon one signal,
  882. Xand the signal suddenly exists, one of the threads will execute.
  883. XIf the
  884. Xsignal turns off before the end of that thread, the other threads
  885. Xscheduled upon the signal will not execute.
  886. XThis is always true for
  887. Xthread-lowered signals.
  888. XThis behavior stands in
  889. Xmarked contrast to the behavior of interrupts---upon an interrupt,
  890. Xall the scheduled threads would be executed.
  891. X
  892. XEach signal provides its own scheduling guarantees.
  893. XFor instance, under
  894. Xthis implementation,
  895. Xany (waiting) thread scheduled on the signal
  896. X.I ss_asap()
  897. Xwill in fact execute at some point, provided that no thread
  898. Xblocks or loops forever.
  899. XThere is no way to keep pushing 
  900. X.I ss_asap()
  901. Xfarther and farther into the future by scheduling other threads.
  902. XOn the other hand,
  903. X.I ss_asap()
  904. Xwill never flush out the other builtin signals.
  905. X
  906. X.B sigsched
  907. Xprovides several builtin signals:
  908. X.B ss_asap()
  909. Xreturns a (pointer to a) signal which always exists.
  910. X.B ss_signal(\fIsigno\fB)
  911. Xreturns a thread-lowered signal which is true when UNIX signal
  912. X.I signo
  913. Xis received.
  914. X.B ss_sigread(\fIfd\fB)
  915. Xreturns a signal which is true when
  916. X.I fd
  917. Xis open and readable, as defined by
  918. X.I select();
  919. Xsimilarly for
  920. X.B ss_sigwrite
  921. Xand
  922. X.B ss_sigexcept.
  923. X
  924. XIn order for
  925. X.B sigsched
  926. Xto handle UNIX signal
  927. X.I signo,
  928. Xyou must call
  929. X.B ss_addsig(\fIsigno\fB)
  930. Xbefore calling
  931. X.B ss_exec().
  932. X.B ss_addsig
  933. Xwill discard the old signal handler;
  934. Xlater,
  935. X.B ss_exec
  936. Xwill not restore the handler upon exiting, and may
  937. Xleave the signal blocked or unblocked.
  938. X.B ss_addsig
  939. Xwill return 0 normally,
  940. X-1 if
  941. X.I signo
  942. Xis not in the right range for signals.
  943. XIf another library makes use of
  944. X.B ss_signal
  945. Xwith
  946. X.B sigsched,
  947. Xit should provide a mandatory initialization routine
  948. Xwhich calls
  949. X.B ss_addsig.
  950. X
  951. X.B ss_schedvwait
  952. Xand
  953. X.B ss_unschedv
  954. Xcan be abbreviated in common cases.
  955. X.B ss_schedwait(\fIsig,t,i,wait\fB)
  956. Xis the same as
  957. X.B ss_schedvwait(\fIsig,t,1,i,(ss_idptr)0,wait\fB).
  958. X.B ss_sched(\fIsig,t,i\fB)
  959. Xis the same with
  960. X.I wait
  961. Xset to 0; it is commonly used for
  962. Xhandling user signals.
  963. X.B ss_unsched(\fIsig,t,i\fB)
  964. Xis the same as
  965. X.B ss_unschedv(\fIsig,t,1,i,(ss_idptr)0\fB).
  966. X
  967. X.B ss_schedonce(\fIsig,t,i\fB)
  968. Xis similar to
  969. X.B ss_sched
  970. Xbut is in fact implemented on top of
  971. X.B ss_schedvwait
  972. Xwith an independent mechanism.
  973. XEach call to
  974. X.B ss_schedonce
  975. Xschedules
  976. X.I t
  977. Xupon a new signal which starts when
  978. X.I sig
  979. Xdoes and exists only until
  980. X.I t(i)
  981. Xis executed.
  982. XAfter the first execution the new signal disappears.
  983. XThe new signal cannot be unscheduled.
  984. X
  985. X.B ss_forcewait()
  986. Xtells
  987. X.B sigsched
  988. Xthat something important is going on outside
  989. X.B sigsched
  990. Xand that
  991. X.B ss_exec
  992. Xshould not exit.
  993. X.B ss_unforcewait()
  994. Xnegates a previous
  995. X.B ss_forcewait().
  996. X.B ss_forcewait()
  997. Xand
  998. X.B ss_unforcewait()
  999. Xcontrol a counter, not a flag, so independent
  1000. Xlibraries can use them, but each library should
  1001. Xbe careful to use as many of one call as of the other.
  1002. XThese functions must not be used outside
  1003. X.B ss_exec().
  1004. X
  1005. X.B ss_externsetsig(sig,x)
  1006. Xcreates a new signal
  1007. Xin the
  1008. X.B ss_sig
  1009. Xpointed to by
  1010. X.I sig.
  1011. X.I x
  1012. Xpoints to an
  1013. X.B ss_extern,
  1014. Xwhich is defined as follows in
  1015. X.B <sigsched.h>:
  1016. X.PP
  1017. X.EX
  1018. Xtypedef struct {
  1019. X  int (*sched)();
  1020. X  int (*unsched)();
  1021. X  union { int n; char *c; } u;
  1022. X} ss_extern;
  1023. X.EE
  1024. X.PP
  1025. X.I sched
  1026. Xmust be filled in with a scheduling function,
  1027. Xwhich is called as
  1028. X.I (*sched)(x,t,flagi,i,p,wait)
  1029. Xwhenever
  1030. X.B ss_schedvwait(\fIsig,t,flagi,i,p,wait\fB)
  1031. Xis called;
  1032. Xsimilarly for
  1033. X.I unsched.
  1034. XUse of
  1035. X.I u
  1036. Xis up to the caller.
  1037. X.I sched
  1038. Xand
  1039. X.I unsched
  1040. Xmust observe the same rules as
  1041. X.B ss_schedvwait
  1042. Xand
  1043. X.B ss_unschedv
  1044. Xon any other signals: i.e., they must schedule threads upon
  1045. Xa persistent condition, make sure that
  1046. X.I ss_exec
  1047. Xdoes not exit if
  1048. Xany important threads are scheduled, etc.
  1049. XNote that
  1050. X.B ss_externsetsig
  1051. Xrecords
  1052. X.I x
  1053. Xin
  1054. X.I sig,
  1055. Xso
  1056. X.I x
  1057. Xmust point either to static memory or to
  1058. Xmemory which remains allocated as long as
  1059. Xany thread is scheduled or executing upon
  1060. X.I sig.
  1061. XMemory management of the
  1062. X.I sig
  1063. Xstructure itself is up to the caller.
  1064. X
  1065. XIt is recommended that library
  1066. X.I foo
  1067. Xdefine a
  1068. X.B foo_sig
  1069. Xstructure, which contains
  1070. X.B ss_sig
  1071. X.I sig,
  1072. X.B ss_extern
  1073. X.I x,
  1074. Xand any other necessary information for the signals defined by
  1075. X.I foo.
  1076. XThen
  1077. X.B foo_setsig(\fI&fsig,otherinfo\fB),
  1078. Xwhere
  1079. X.I fsig
  1080. Xis a
  1081. X.B foo_sig,
  1082. Xshould set up the
  1083. X.I otherinfo,
  1084. Xset
  1085. X.I fsig.x.u.c
  1086. Xto
  1087. X.I &fsig,
  1088. Xset
  1089. X.I fsig.x.sched
  1090. Xand
  1091. X.I fsig.x.unsched
  1092. Xappropriately,
  1093. Xand
  1094. Xfinish with
  1095. X.B ss_externsetsig(&fsig.sig,&fsig.x).
  1096. XThat way the user can use
  1097. X.I &fsig.sig
  1098. Xas the signal argument to
  1099. X.B sigsched
  1100. Xfunctions,
  1101. Xand when
  1102. X.I foo's
  1103. Xscheduling routines are passed
  1104. X.I &fsig.x
  1105. Xas a first argument,
  1106. Xthey can get to
  1107. X.I otherinfo
  1108. Xthrough
  1109. X.I fsig.x.u.c.
  1110. X
  1111. X.B sigsched
  1112. Xuses
  1113. X.B ralloc
  1114. Xfor all allocation.
  1115. X.SH VERSION
  1116. Xsigsched 1.1, August 25, 1991.
  1117. X.SH AUTHOR
  1118. XPlaced into the public domain by Daniel J. Bernstein.
  1119. X.SH "SEE ALSO"
  1120. Xselect(2),
  1121. Xsigvec(2),
  1122. Xralloc(3)
  1123. X
  1124. END_OF_FILE
  1125. if test 10068 -ne `wc -c <'sigsched.3'`; then
  1126.     echo shar: \"'sigsched.3'\" unpacked with wrong size!
  1127. fi
  1128. # end of 'sigsched.3'
  1129. fi
  1130. if test -f 'sigsched.c' -a "${1}" != "-c" ; then 
  1131.   echo shar: Will not clobber existing file \"'sigsched.c'\"
  1132. else
  1133. echo shar: Extracting \"'sigsched.c'\" \(13289 characters\)
  1134. sed "s/^X//" >'sigsched.c' <<'END_OF_FILE'
  1135. X/* sigsched.c, sigsched.h: signal-schedule thread library
  1136. XDaniel J. Bernstein, brnstnd@nyu.edu.
  1137. XDepends on ralloc.h, sod.h, config/fdsettrouble.h.
  1138. XRequires BSDish environment: reliable signals, sig{vec,block,setmask}, select.
  1139. X9/1/91: Added worst-case fdset, FD_ZERO, etc. definitions.
  1140. X8/25/91: sigsched 1.1, public domain.
  1141. X8/25/91: Fixed bug that sigs[sched->blah].r didn't force instant timeout.
  1142. X8/25/91: Fixed bug that if select() returned -1 then fds were still checked.
  1143. X7/21/91: Changed forever to a 1-hour wakeup.
  1144. X7/19/91: Added isopen() to fix bug in case of bad descriptor.
  1145. X7/18/91: Baseline. sigsched 1.0, public domain.
  1146. XNo known patent problems.
  1147. X
  1148. XDocumentation in sigsched.3.
  1149. X
  1150. XXXX: how well do we clean up upon ss_exec() exit?
  1151. X
  1152. X*/
  1153. X
  1154. X#include <sys/types.h>
  1155. X#include <sys/param.h>
  1156. X#include <sys/time.h>
  1157. X#include <signal.h>
  1158. X#include <errno.h>
  1159. X#include <fcntl.h>
  1160. Xextern int errno;
  1161. X#include "config/fdsettrouble.h"
  1162. X#include "sigsched.h"
  1163. X#include "ralloc.h"
  1164. X#include "sod.h"
  1165. X
  1166. X/* XXX: should restore signal set exactly after ss_exec returns */
  1167. X
  1168. Xtypedef int sigc_set; /*XXX */
  1169. X
  1170. X#define sigc_ismember(x,i) (*(x) & (1 << ((i) - 1)))
  1171. X#define sigc_addset(x,i) (*(x) |= (1 << ((i) - 1)))
  1172. X#define sigc_emptyset(x) (*(x) = 0)
  1173. X
  1174. X/*       sigprocmask(SIG_UNBLOCK,xxxx,(sigc_set *) 0); */
  1175. X#define sigc_unblock(x) (sigsetmask(sigblock(0) & ~*(x)))
  1176. X/*       sigprocmask(SIG_BLOCK,xxxx,(sigc_set *) 0); */
  1177. X#define sigc_block(x) (sigblock(*(x)))
  1178. X
  1179. X#ifndef NSIG
  1180. X#define NSIG 64 /* it's not as if any sane system has more than 32 */
  1181. X#endif
  1182. X
  1183. X#define NUMSIGS NSIG
  1184. X
  1185. X#ifndef FD_SETSIZE
  1186. X#define FD_SETSIZE 256
  1187. X#endif
  1188. X
  1189. X#define NUMFDS FD_SETSIZE /* if select() can't handle it, we can't either */
  1190. X
  1191. X#ifdef LACKING_FD_ZERO
  1192. X#define NFDBITS    (sizeof(fd_mask) * NBBY)
  1193. X#define    FD_SET(n,p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  1194. X#define    FD_ISSET(n,p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  1195. X#define FD_ZERO(p) bzero((caddr_t)(p),sizeof(*(p)))
  1196. X#endif
  1197. X
  1198. X#ifdef DESPERATION_FD_SET
  1199. X#undef NFDBITS
  1200. X#undef FD_SET
  1201. X#undef FD_ISSET
  1202. X#undef FD_ZERO
  1203. X#undef fd_set
  1204. X#define fd_set long
  1205. X#define FD_SET(n,p) ((*p) |= (1 << (n)))
  1206. X#define FD_ISSET(n,p) ((*p) & (1 << (n)))
  1207. X#define FD_ZERO(p) (*p = 0L)
  1208. X#endif
  1209. X
  1210. X#define ASAP 1
  1211. X#define SIGNAL 2
  1212. X#define READ 3
  1213. X#define WRITE 4
  1214. X#define EXCEPT 5
  1215. X#define JUNK 6
  1216. X#define EXTERN 7
  1217. X
  1218. Xtypedef struct { ss_sig s; int r; } ss_sigplus;
  1219. X
  1220. Xstatic ss_sigplus asap;
  1221. Xstatic ss_sigplus sigs[NUMSIGS];
  1222. Xstatic ss_sigplus reads[NUMFDS];
  1223. Xstatic ss_sigplus writes[NUMFDS];
  1224. Xstatic ss_sigplus excepts[NUMFDS];
  1225. Xstatic ss_sigplus junk; /* special case for internal use */
  1226. X
  1227. Xstatic void initsigs()
  1228. X{
  1229. X int i;
  1230. X asap.s.type = ASAP; asap.s.u.n = 0; asap.r = 0;
  1231. X for (i = 0;i < NUMSIGS;++i)
  1232. X  { sigs[i].s.type = SIGNAL; sigs[i].s.u.n = i; sigs[i].r = 0; }
  1233. X for (i = 0;i < NUMFDS;++i)
  1234. X  { reads[i].s.type = READ; reads[i].s.u.n = i; reads[i].r = 0; }
  1235. X for (i = 0;i < NUMFDS;++i)
  1236. X  { writes[i].s.type = WRITE; writes[i].s.u.n = i; writes[i].r = 0; }
  1237. X for (i = 0;i < NUMFDS;++i)
  1238. X  { excepts[i].s.type = EXCEPT; excepts[i].s.u.n = i; excepts[i].r = 0; }
  1239. X junk.s.type = JUNK; junk.s.u.n = 0; junk.r = 0;
  1240. X}
  1241. X
  1242. Xss_sig *ss_asap()
  1243. X{ return &(asap.s); }
  1244. X#define OKsig(i) ((i >= 0) && (i < NUMSIGS))
  1245. Xss_sig *ss_signal(i) int i;
  1246. X{ if (!OKsig(i)) return 0; return &(sigs[i].s); }
  1247. X#define OKfd(fd) ((fd >= 0) && (fd < NUMFDS))
  1248. Xss_sig *ss_sigread(fd) int fd;
  1249. X{ if (!OKfd(fd)) return 0; return &(reads[fd].s); }
  1250. Xss_sig *ss_sigwrite(fd) int fd;
  1251. X{ if (!OKfd(fd)) return 0; return &(writes[fd].s); }
  1252. Xss_sig *ss_sigexcept(fd) int fd;
  1253. X{ if (!OKfd(fd)) return 0; return &(excepts[fd].s); }
  1254. X
  1255. Xvoid ss_externsetsig(sig,x)
  1256. Xss_sig *sig;
  1257. Xss_extern *x;
  1258. X{
  1259. X sig->type = EXTERN;
  1260. X sig->u.c = (char *) x;
  1261. X}
  1262. X
  1263. Xstruct sched
  1264. X {
  1265. X  ss_sig *sig;
  1266. X  ss_thread *t;
  1267. X  union { ss_id i; ss_idptr p; } id;
  1268. X  int flagi;
  1269. X  int wait;
  1270. X }
  1271. X;
  1272. X
  1273. XSODdecl(schedlist,struct sched);
  1274. X
  1275. Xstatic schedlist schedhead = 0;
  1276. Xstatic int schednum = 0;
  1277. Xstatic int schedjunked = 0;
  1278. Xstatic int numwait = 0;
  1279. X
  1280. Xvoid ss_forcewait()
  1281. X{
  1282. X ++numwait;
  1283. X}
  1284. X
  1285. Xvoid ss_unforcewait()
  1286. X{
  1287. X --numwait;
  1288. X}
  1289. X
  1290. Xint ss_schedvwait(sig,t,flagi,i,p,wait)
  1291. Xss_sig *sig;
  1292. Xss_thread *t;
  1293. Xint flagi;
  1294. Xss_id i;
  1295. Xss_idptr p;
  1296. Xint wait;
  1297. X{
  1298. X schedlist s;
  1299. X
  1300. X if (sig->type == EXTERN)
  1301. X  {
  1302. X   ss_extern *x;
  1303. X   x = (ss_extern *) sig->u.c;
  1304. X   return x->sched(x,t,flagi,i,p,wait);
  1305. X  }
  1306. X s = SODalloc(schedlist,s,ralloc);
  1307. X if (!s)
  1308. X   return -1;
  1309. X SODdata(s).sig = sig;
  1310. X SODdata(s).t = t;
  1311. X if (SODdata(s).flagi = flagi)
  1312. X   SODdata(s).id.i = i;
  1313. X else
  1314. X   SODdata(s).id.p = p;
  1315. X SODdata(s).wait = wait;
  1316. X SODpush(schedhead,s);
  1317. X ++schednum;
  1318. X if (wait)
  1319. X   ++numwait;
  1320. X return 0;
  1321. X}
  1322. X
  1323. Xint ss_schedwait(sig,t,i,wait)
  1324. Xss_sig *sig;
  1325. Xss_thread *t;
  1326. Xss_id i;
  1327. Xint wait;
  1328. X{
  1329. X return ss_schedvwait(sig,t,1,i,(ss_idptr) 0,wait);
  1330. X}
  1331. X
  1332. Xint ss_sched(sig,t,i)
  1333. Xss_sig *sig;
  1334. Xss_thread *t;
  1335. Xss_id i;
  1336. X{
  1337. X return ss_schedvwait(sig,t,1,i,(ss_idptr) 0,0);
  1338. X}
  1339. X
  1340. Xstruct oncestuff { ss_sig *sig; ss_thread *t; ss_id i; } ;
  1341. X/* XXX: this is the same as some other struct */
  1342. X
  1343. Xstatic void once(p)
  1344. Xss_idptr p;
  1345. X{
  1346. X struct oncestuff *os;
  1347. X os = (struct oncestuff *) p;
  1348. X if (ss_unschedv(os->sig,once,0,0,p) == -1)
  1349. X   ; /* impossible */
  1350. X os->t(os->i);
  1351. X RFREE(os);
  1352. X}
  1353. X
  1354. Xint ss_schedonce(sig,t,i)
  1355. Xss_sig *sig;
  1356. Xss_thread *t;
  1357. Xss_id i;
  1358. X{
  1359. X struct oncestuff *os;
  1360. X
  1361. X os = (struct oncestuff *) ralloc(sizeof(struct oncestuff));
  1362. X if (!os)
  1363. X   return -1;
  1364. X os->sig = sig; os->t = t; os->i = i;
  1365. X return ss_schedvwait(sig,once,0,0,(ss_idptr) os,1);
  1366. X}
  1367. X
  1368. X/* XXX: could rallocinstall() this, if it has the recvhead() test */
  1369. X
  1370. Xstatic int schedcleanup()
  1371. X{
  1372. X schedlist s;
  1373. X schedlist t;
  1374. X schedlist sprev;
  1375. X
  1376. X/*  if (recvhead) return 0;  XXX: needs recvhead in scope */
  1377. X
  1378. X if (!schedjunked)
  1379. X   return 0;
  1380. X
  1381. X sprev = 0;
  1382. X s = schedhead;
  1383. X while (s)
  1384. X  {
  1385. X   if (SODdata(s).sig == &(junk.s))
  1386. X    {
  1387. X     if (sprev)
  1388. X      {
  1389. X       SODpop(SODnext(sprev),t); /* XXX: not part of official sod interface */
  1390. X       s = SODnext(sprev);
  1391. X      }
  1392. X     else
  1393. X      {
  1394. X       SODpop(s,t);
  1395. X       schedhead = s;
  1396. X      }
  1397. X     SODfree(t,rfree);
  1398. X     --schednum;
  1399. X     --schedjunked;
  1400. X    }
  1401. X   else
  1402. X    {
  1403. X     sprev = s;
  1404. X     s = SODnext(s);
  1405. X    }
  1406. X  }
  1407. X
  1408. X/* schednum -= schedjunked; now done dynamically inside loop */
  1409. X/* schedjunked = 0; */
  1410. X return 1;
  1411. X}
  1412. X
  1413. Xstatic void nothing(id)
  1414. Xss_id id;
  1415. X{
  1416. X ;
  1417. X}
  1418. X
  1419. Xint ss_unschedv(sig,t,flagi,i,p)
  1420. Xss_sig *sig;
  1421. Xss_thread *t;
  1422. Xint flagi;
  1423. Xss_id i;
  1424. Xss_idptr p;
  1425. X{
  1426. X schedlist s;
  1427. X
  1428. X if (sig->type == EXTERN)
  1429. X  {
  1430. X   ss_extern *x;
  1431. X   x = (ss_extern *) sig->u.c;
  1432. X   return x->unsched(x,t,flagi,i,p);
  1433. X  }
  1434. X for (s = schedhead;s;s = SODnext(s))
  1435. X   if (SODdata(s).sig == sig && SODdata(s).t == t)
  1436. X     if (SODdata(s).flagi == flagi)
  1437. X       if (flagi ? (SODdata(s).id.i == i) : (SODdata(s).id.p == p))
  1438. X        {
  1439. X         SODdata(s).sig = &(junk.s);
  1440. X         SODdata(s).t = nothing; /* just in case */
  1441. X         if (SODdata(s).wait)
  1442. X           --numwait;
  1443. X         SODdata(s).wait = 0;
  1444. X         ++schedjunked;
  1445. X         return 0;
  1446. X        }
  1447. X return 1;
  1448. X}
  1449. X
  1450. Xint ss_unsched(sig,t,i)
  1451. Xss_sig *sig;
  1452. Xss_thread *t;
  1453. Xss_id i;
  1454. X{
  1455. X return ss_unschedv(sig,t,1,i,(ss_idptr) 0);
  1456. X}
  1457. X
  1458. Xstatic struct timeval timeout;
  1459. Xstatic struct timeval instant = { 0, 0 };
  1460. Xstatic struct timeval forever = { 3600, 0 };
  1461. X  /* XXX: talk to me */
  1462. X
  1463. Xstatic void handle(i)
  1464. Xint i;
  1465. X{
  1466. X timeout = instant; /* XXX: structure copying */
  1467. X sigs[i].r = 1;
  1468. X}
  1469. X
  1470. Xstatic sigc_set sigstorage;
  1471. Xstatic sigc_set *xxxx = 0;
  1472. X
  1473. Xint ss_addsig(i)
  1474. Xint i;
  1475. X{
  1476. X if (!OKsig(i))
  1477. X   return -1;
  1478. X if (!xxxx)
  1479. X  {
  1480. X   xxxx = &sigstorage;
  1481. X   sigc_emptyset(xxxx);
  1482. X  }
  1483. X sigc_addset(xxxx,i);
  1484. X return 0;
  1485. X}
  1486. X
  1487. Xstatic int isopen(fd)
  1488. Xint fd;
  1489. X{
  1490. X /* XXX: should call this only if select() fails */
  1491. X return fcntl(fd,F_GETFL,0) != -1;
  1492. X}
  1493. X
  1494. XSODdecl(recvlist,schedlist);
  1495. X
  1496. Xint ss_exec()
  1497. X{
  1498. X int i;
  1499. X struct sigvec sv;
  1500. X recvlist recvhead;
  1501. X recvlist temp;
  1502. X schedlist sch;
  1503. X
  1504. X initsigs();
  1505. X
  1506. X if (xxxx)
  1507. X  {
  1508. X   sigc_block(xxxx);
  1509. X
  1510. X   sv.sv_handler = handle;
  1511. X   sv.sv_mask = *xxxx; /* so handle won't interrupt itself */
  1512. X   sv.sv_flags = 0;
  1513. X
  1514. X   /* XXX: Does anyone but me find it absolutely idiotic that POSIX
  1515. X      doesn't provide a way to get each member of a signal set in turn? */
  1516. X   for (i = 0;i < NUMSIGS;i++)
  1517. X    {
  1518. X     if (sigc_ismember(xxxx,i))
  1519. X       if (sigvec(i,&sv,(struct sigvec *) 0) == -1) /*XXX: really trash orig? */
  1520. X     ; /* not our problem */
  1521. X    }
  1522. X  }
  1523. X
  1524. X recvhead = 0;
  1525. X
  1526. X while (numwait)
  1527. X  {
  1528. X   if (recvhead)
  1529. X    {
  1530. X     int w;
  1531. X     SODpop(recvhead,temp);
  1532. X     sch = SODdata(temp);
  1533. X
  1534. X/* This is the only section where we call user code. */
  1535. X#define DOIT \
  1536. Xif (SODdata(sch).flagi) \
  1537. X  SODdata(sch).t(SODdata(sch).id.i); \
  1538. Xelse \
  1539. X  SODdata(sch).t(SODdata(sch).id.p);
  1540. X
  1541. X     switch(SODdata(sch).sig->type)
  1542. X      {
  1543. X       case JUNK:
  1544. X     break; /* has been unscheduled while waiting on the receive list */
  1545. X       case ASAP:
  1546. X     DOIT
  1547. X     break;
  1548. X       case READ:
  1549. X     if (reads[w = SODdata(sch).sig->u.n].r)
  1550. X       DOIT
  1551. X     reads[w].r = 0;
  1552. X     break;
  1553. X       case WRITE:
  1554. X     if (writes[w = SODdata(sch).sig->u.n].r)
  1555. X       DOIT
  1556. X     writes[w].r = 0;
  1557. X     break;
  1558. X       case EXCEPT:
  1559. X     if (excepts[w = SODdata(sch).sig->u.n].r)
  1560. X       DOIT
  1561. X     excepts[w].r = 0;
  1562. X     break;
  1563. X       case SIGNAL:
  1564. X     if (sigs[w = SODdata(sch).sig->u.n].r)
  1565. X       DOIT
  1566. X     sigs[w].r = 0;
  1567. X       /* ``after the end of the last...'' */
  1568. X     break;
  1569. X       case EXTERN:
  1570. X     /* by definition, an external library handles this */
  1571. X     break;
  1572. X       default: /* XXX: huh? */
  1573. X     ;
  1574. X      }
  1575. X     SODfree(temp,rfree);
  1576. X    }
  1577. X   else
  1578. X    {
  1579. X     schedlist sp;
  1580. X     static fd_set rfds;
  1581. X     static fd_set wfds;
  1582. X     static fd_set efds;
  1583. X     static int maxfd;
  1584. X     int r;
  1585. X
  1586. X     if (schedjunked > 100)
  1587. X       if (schednum / schedjunked < 3)
  1588. X         (void) schedcleanup(); /* now's as good a time as any */
  1589. X
  1590. X     timeout = forever;
  1591. X     FD_ZERO(&rfds);
  1592. X     FD_ZERO(&wfds);
  1593. X     FD_ZERO(&efds);
  1594. X     maxfd = -1;
  1595. X
  1596. X     for (sp = schedhead;sp;sp = SODnext(sp))
  1597. X      {
  1598. X       switch(SODdata(sp).sig->type)
  1599. X    {
  1600. X     case JUNK:
  1601. X       break;
  1602. X     case ASAP:
  1603. X       timeout = instant;
  1604. X       break;
  1605. X     case SIGNAL:
  1606. X       if (sigs[SODdata(sp).sig->u.n].r)
  1607. X         timeout = instant;
  1608. X       break;
  1609. X     case READ:
  1610. X       if (isopen(SODdata(sp).sig->u.n))
  1611. X         FD_SET(SODdata(sp).sig->u.n,&rfds);
  1612. X       if (SODdata(sp).sig->u.n > maxfd)
  1613. X         maxfd = SODdata(sp).sig->u.n;
  1614. X       break;
  1615. X     case WRITE:
  1616. X       if (isopen(SODdata(sp).sig->u.n))
  1617. X         FD_SET(SODdata(sp).sig->u.n,&wfds);
  1618. X       if (SODdata(sp).sig->u.n > maxfd)
  1619. X         maxfd = SODdata(sp).sig->u.n;
  1620. X       break;
  1621. X     case EXCEPT:
  1622. X       if (isopen(SODdata(sp).sig->u.n))
  1623. X         FD_SET(SODdata(sp).sig->u.n,&efds);
  1624. X       if (SODdata(sp).sig->u.n > maxfd)
  1625. X         maxfd = SODdata(sp).sig->u.n;
  1626. X       break;
  1627. X     case EXTERN:
  1628. X       break;
  1629. X     default: /*XXX: huh? */
  1630. X       break;
  1631. X    }
  1632. X      }
  1633. X
  1634. X     if (xxxx)
  1635. X       sigc_unblock(xxxx);
  1636. X     /* This is the only section where handle() can be called. */
  1637. X     /* XXX: If maxfd == -1, this select functions as a pause. */
  1638. X     /* XXX: If maxfd == -1 and timeout is instant, should skip select. */
  1639. X     /* XXX: Random bug of note: Real BSD systems will say that the
  1640. X        fd is writable as soon as a network connect() fails. The first
  1641. X    I/O will show the error (though it's rather stupid that you
  1642. X    can't find out the error without doing I/O). What does Ultrix
  1643. X    4.1 do? It pauses for 75 seconds. Dolts. */
  1644. X     r = select(maxfd + 1,&rfds,&wfds,&efds,&timeout);
  1645. X       /* XXX: does this necessarily prevent timeout race conditions? */
  1646. X     if (xxxx)
  1647. X       sigc_block(xxxx);
  1648. X
  1649. X     if (r == -1)
  1650. X      {
  1651. X       FD_ZERO(&rfds);
  1652. X       FD_ZERO(&wfds);
  1653. X       FD_ZERO(&efds);
  1654. X       switch(errno)
  1655. X        {
  1656. X         case EINTR: /* fine, this will happen on any signal */ break;
  1657. X         case EBADF: /* who knows? */ break;
  1658. X         case EINVAL: /* simply impossible */ break;
  1659. X         default: /*XXX*/ ;
  1660. X     /* well, that was real useful */
  1661. X        }
  1662. X      }
  1663. X
  1664. X     for (sp = schedhead;sp;sp = SODnext(sp))
  1665. X      {
  1666. X       switch(SODdata(sp).sig->type) 
  1667. X    {
  1668. X     case JUNK:
  1669. X       break;
  1670. X     case ASAP:
  1671. X           temp = SODalloc(recvlist,temp,ralloc);
  1672. X           if (!temp)
  1673. X             return -1; /*XXX*/
  1674. X       SODdata(temp) = sp;
  1675. X           SODpush(recvhead,temp);
  1676. X       break;
  1677. X     case SIGNAL:
  1678. X       if (sigs[SODdata(sp).sig->u.n].r)
  1679. X        {
  1680. X             temp = SODalloc(recvlist,temp,ralloc);
  1681. X             if (!temp)
  1682. X               return -1; /*XXX*/
  1683. X         SODdata(temp) = sp;
  1684. X             SODpush(recvhead,temp);
  1685. X        }
  1686. X       break;
  1687. X     case READ:
  1688. X       if (FD_ISSET(SODdata(sp).sig->u.n,&rfds))
  1689. X        {
  1690. X         FD_CLR(SODdata(sp).sig->u.n,&rfds);
  1691. X         reads[SODdata(sp).sig->u.n].r = 1;
  1692. X             temp = SODalloc(recvlist,temp,ralloc);
  1693. X             if (!temp)
  1694. X               return -1; /*XXX*/
  1695. X         SODdata(temp) = sp;
  1696. X             SODpush(recvhead,temp);
  1697. X        }
  1698. X       break;
  1699. X     case WRITE:
  1700. X       if (FD_ISSET(SODdata(sp).sig->u.n,&wfds))
  1701. X        {
  1702. X         FD_CLR(SODdata(sp).sig->u.n,&wfds);
  1703. X         writes[SODdata(sp).sig->u.n].r = 1;
  1704. X             temp = SODalloc(recvlist,temp,ralloc);
  1705. X             if (!temp)
  1706. X               return -1; /*XXX*/
  1707. X         SODdata(temp) = sp;
  1708. X             SODpush(recvhead,temp);
  1709. X        }
  1710. X       break;
  1711. X     case EXCEPT:
  1712. X       if (FD_ISSET(SODdata(sp).sig->u.n,&efds))
  1713. X        {
  1714. X         FD_CLR(SODdata(sp).sig->u.n,&efds);
  1715. X         excepts[SODdata(sp).sig->u.n].r = 1;
  1716. X             temp = SODalloc(recvlist,temp,ralloc);
  1717. X             if (!temp)
  1718. X               return -1; /*XXX*/
  1719. X         SODdata(temp) = sp;
  1720. X             SODpush(recvhead,temp);
  1721. X        }
  1722. X       break;
  1723. X     case EXTERN:
  1724. X       break;
  1725. X     default:
  1726. X       break;
  1727. X    }
  1728. X      }
  1729. X    }
  1730. X  }
  1731. X if (xxxx)
  1732. X   sigc_unblock(xxxx);
  1733. X   /* XXX: should put this at other returns as well */
  1734. X return 0;
  1735. X}
  1736. END_OF_FILE
  1737. if test 13289 -ne `wc -c <'sigsched.c'`; then
  1738.     echo shar: \"'sigsched.c'\" unpacked with wrong size!
  1739. fi
  1740. # end of 'sigsched.c'
  1741. fi
  1742. if test -f 'sigsched.h' -a "${1}" != "-c" ; then 
  1743.   echo shar: Will not clobber existing file \"'sigsched.h'\"
  1744. else
  1745. echo shar: Extracting \"'sigsched.h'\" \(732 characters\)
  1746. sed "s/^X//" >'sigsched.h' <<'END_OF_FILE'
  1747. X#ifndef SIGSCHED_H
  1748. X#define SIGSCHED_H
  1749. X
  1750. Xtypedef struct
  1751. X {
  1752. X  int type;
  1753. X  union { int n; char *c; } u;
  1754. X }
  1755. Xss_sig;
  1756. X
  1757. Xtypedef struct
  1758. X {
  1759. X  int (*sched)();
  1760. X  int (*unsched)();
  1761. X  union { int n; char *c; } u;
  1762. X }
  1763. Xss_extern;
  1764. X
  1765. Xtypedef void ss_thread();
  1766. Xtypedef int ss_id;
  1767. Xtypedef char *ss_idptr;
  1768. X
  1769. Xextern ss_sig *ss_asap();
  1770. Xextern ss_sig *ss_signal();
  1771. Xextern ss_sig *ss_sigread();
  1772. Xextern ss_sig *ss_sigwrite();
  1773. Xextern ss_sig *ss_sigexcept();
  1774. X
  1775. Xextern int ss_addsig();
  1776. X
  1777. Xextern void ss_externsetsig();
  1778. X
  1779. Xextern int ss_schedvwait();
  1780. Xextern int ss_schedwait();
  1781. Xextern int ss_sched();
  1782. Xextern int ss_schedonce();
  1783. Xextern int ss_unschedv();
  1784. Xextern int ss_unsched();
  1785. X
  1786. Xextern void ss_forcewait();
  1787. Xextern void ss_unforcewait();
  1788. X
  1789. Xextern int ss_exec();
  1790. X
  1791. X#endif
  1792. END_OF_FILE
  1793. if test 732 -ne `wc -c <'sigsched.h'`; then
  1794.     echo shar: \"'sigsched.h'\" unpacked with wrong size!
  1795. fi
  1796. # end of 'sigsched.h'
  1797. fi
  1798. if test -f 'sod.h' -a "${1}" != "-c" ; then 
  1799.   echo shar: Will not clobber existing file \"'sod.h'\"
  1800. else
  1801. echo shar: Extracting \"'sod.h'\" \(508 characters\)
  1802. sed "s/^X//" >'sod.h' <<'END_OF_FILE'
  1803. X#ifndef SOD_H
  1804. X#define SOD_H
  1805. X
  1806. X/* a half-hearted attempt at a generic stack library */
  1807. X
  1808. X#define SODdecl(foostack,foo) \
  1809. Xtypedef struct foostack { struct foostack *next; foo data; } *foostack
  1810. X  /* note that user must supply semicolon */
  1811. X
  1812. X#define SODnext(x) ((x)->next)
  1813. X#define SODdata(x) ((x)->data)
  1814. X#define SODalloc(t,x,ralloc) ((t) ((ralloc)(sizeof(*x))))
  1815. X#define SODpush(x,y) ((y)->next = (x),(x) = (y))
  1816. X#define SODpop(x,y) ((y) = (x),(x) = (x)->next)
  1817. X#define SODfree(u,rfree) ((rfree)((char *)(u)))
  1818. X
  1819. X#endif
  1820. END_OF_FILE
  1821. if test 508 -ne `wc -c <'sod.h'`; then
  1822.     echo shar: \"'sod.h'\" unpacked with wrong size!
  1823. fi
  1824. # end of 'sod.h'
  1825. fi
  1826. if test -f 'timer.c' -a "${1}" != "-c" ; then 
  1827.   echo shar: Will not clobber existing file \"'timer.c'\"
  1828. else
  1829. echo shar: Extracting \"'timer.c'\" \(7815 characters\)
  1830. sed "s/^X//" >'timer.c' <<'END_OF_FILE'
  1831. X/* timer.c, timer.h: timer libraries
  1832. XDaniel J. Bernstein, brnstnd@nyu.edu.
  1833. XDepends on sigsched.h, ralloc.h, sod.h.
  1834. XRequires BSD (interval timers, PROF and VTALRM signals, gettimeofday, etc.).
  1835. X7/27/91: Baseline. timer 1.0, public domain.
  1836. XNo known patent problems.
  1837. X
  1838. XAll signals defined here are thread-lowered signals.
  1839. X
  1840. XNote that we use timer_clock instead of struct timeval since
  1841. Xtimer_clock has at least a prayer of being portable.
  1842. XThis implementation, however, is BSD-only.
  1843. X*/
  1844. X
  1845. X#include <sys/types.h>
  1846. X#include <sys/time.h>
  1847. X#include <sys/times.h>
  1848. X#include <signal.h>
  1849. Xextern long times();
  1850. X#include "sigsched.h"
  1851. X#include "sod.h"
  1852. X#include "timer.h"
  1853. X#include "ralloc.h"
  1854. X#ifndef HZ
  1855. X#define HZ 60 /*XXX*/
  1856. X#endif
  1857. X
  1858. Xint timer_now(t,result)
  1859. Xtimer_type t;
  1860. Xtimer_clock *result;
  1861. X{
  1862. X struct tms tms;
  1863. X struct timeval tv;
  1864. X
  1865. X switch(t)
  1866. X  {
  1867. X   case TIMER_REAL:
  1868. X     if (gettimeofday(&tv,(struct timezone *) 0) == -1)
  1869. X       return -1;
  1870. X     result->sec = tv.tv_sec;
  1871. X     result->usec = tv.tv_usec;
  1872. X     break;
  1873. X   case TIMER_VIRTUAL:
  1874. X     times(&tms);
  1875. X     result->sec = tms.tms_utime / HZ;
  1876. X     result->usec = ((tms.tms_utime % HZ) * 1000000) / HZ;
  1877. X     break;
  1878. X   case TIMER_PROF:
  1879. X     times(&tms);
  1880. X     result->sec = (tms.tms_utime + tms.tms_stime) / HZ;
  1881. X     result->usec = (((tms.tms_utime + tms.tms_stime) % HZ) * 1000000) / HZ;
  1882. X     break;
  1883. X   default:
  1884. X     return -1;
  1885. X  }
  1886. X return 0;
  1887. X}
  1888. X
  1889. Xvoid timer_sum(one,two,result)
  1890. Xtimer_clock *one;
  1891. Xtimer_clock *two;
  1892. Xtimer_clock *result;
  1893. X{
  1894. X result->sec = one->sec + two->sec;
  1895. X if ((result->usec = one->usec + two->usec) >= 1000000)
  1896. X  {
  1897. X   result->sec += 1;
  1898. X   result->usec -= 1000000;
  1899. X  }
  1900. X}
  1901. X
  1902. Xint timer_diff(one,two,result)
  1903. Xtimer_clock *one;
  1904. Xtimer_clock *two;
  1905. Xtimer_clock *result;
  1906. X{
  1907. X if (one->sec > two->sec)
  1908. X  {
  1909. X   result->sec = one->sec - two->sec;
  1910. X   if (one->usec >= two->usec)
  1911. X     result->usec = one->usec - two->usec;
  1912. X   else
  1913. X    { --result->sec; result->usec = 1000000 - (two->usec - one->usec); }
  1914. X   return 1;
  1915. X  }
  1916. X if (one->sec < two->sec)
  1917. X  {
  1918. X   result->sec = two->sec - one->sec;
  1919. X   if (two->usec >= one->usec)
  1920. X     result->usec = two->usec - one->usec;
  1921. X   else
  1922. X    { --result->sec; result->usec = 1000000 - (one->usec - two->usec); }
  1923. X   return -1;
  1924. X  }
  1925. X if (one->usec > two->usec)
  1926. X  {
  1927. X   result->sec = 0;
  1928. X   result->usec = one->usec - two->usec;
  1929. X   return 1;
  1930. X  }
  1931. X if (one->usec < two->usec)
  1932. X  {
  1933. X   result->sec = 0;
  1934. X   result->usec = two->usec - one->usec;
  1935. X   return 1;
  1936. X  }
  1937. X result->sec = 0;
  1938. X result->usec = 0;
  1939. X return 0;
  1940. X}
  1941. X
  1942. X/* Basic idea: For each kind of timer, keep a list of all scheduled */
  1943. X/* events. Set the interval timers to go off at the first events. */
  1944. X
  1945. Xstruct kaboom { timer_clock when; ss_thread *t; int flagi; ss_id i; ss_idptr p; int wait; } ;
  1946. X
  1947. XSODdecl(kaboomlist,struct kaboom);
  1948. X
  1949. X/* XXX: should use priority queues here */
  1950. X
  1951. Xstatic int numwait = 0;
  1952. X
  1953. X/* XXX: all these will have to change if TIMER_NUM changes */
  1954. Xstatic kaboomlist thead[TIMER_NUM] = { 0, 0, 0 };
  1955. Xstatic int tgoing[TIMER_NUM] = { 0, 0, 0 };
  1956. Xstatic timer_clock twhen[TIMER_NUM];
  1957. Xstatic int t2sig[TIMER_NUM] = { SIGALRM, SIGVTALRM, SIGPROF };
  1958. Xstatic int t2it[TIMER_NUM] = { ITIMER_REAL, ITIMER_VIRTUAL, ITIMER_PROF };
  1959. X
  1960. Xstatic void kaboomcleanup()
  1961. X{
  1962. X kaboomlist newhead;
  1963. X kaboomlist k;
  1964. X timer_type i;
  1965. X
  1966. X for (i = 0;i < TIMER_NUM;++i)
  1967. X  {
  1968. X   newhead = 0;
  1969. X   while (thead[i])
  1970. X    {
  1971. X     SODpop(thead[i],k);
  1972. X     if (SODdata(k).t) SODpush(newhead,k); else SODfree(k,rfree);
  1973. X    }
  1974. X   thead[i] = newhead;
  1975. X  }
  1976. X}
  1977. X
  1978. Xstatic void kaboom(t)
  1979. Xtimer_type t;
  1980. X{
  1981. X kaboomlist k;
  1982. X timer_clock dummy;
  1983. X ss_thread *thread;
  1984. X
  1985. X ss_unsched(ss_signal(t2sig[t]),kaboom,t);
  1986. X tgoing[t] = 0; /* timer's out */
  1987. X for (k = thead[t];k;k = SODnext(k))
  1988. X   if (timer_diff(&(SODdata(k).when),twhen + t,&dummy) <= 0)
  1989. X    {
  1990. X     thread = SODdata(k).t; SODdata(k).t = 0;
  1991. X     if (SODdata(k).wait) --numwait; SODdata(k).wait = 0;
  1992. X     if (thread)
  1993. X       if (SODdata(k).flagi)
  1994. X     thread(SODdata(k).i);
  1995. X       else
  1996. X     thread(SODdata(k).p);
  1997. X     /* k may now be invalid. alternative: ss_schedonce(ss_asap(),...) */
  1998. X     break; /* important! */
  1999. X    }
  2000. X kaboomcleanup();
  2001. X if (kaboomresched(t) == -1)
  2002. X   ; /* XXXXXX: uh-oh */
  2003. X}
  2004. X
  2005. Xstatic int set_it(t,when)
  2006. Xtimer_type t;
  2007. Xtimer_clock *when;
  2008. X{
  2009. X struct itimerval it;
  2010. X timer_clock now;
  2011. X timer_clock diff;
  2012. X
  2013. X if (timer_now(t,&now) == -1)
  2014. X   return -1;
  2015. X if (timer_diff(when,&now,&diff) <= 0)
  2016. X  {
  2017. X   diff.sec = 0;
  2018. X   diff.usec = 1;
  2019. X  }
  2020. X it.it_value.tv_sec = diff.sec; it.it_interval.tv_sec = 0;
  2021. X it.it_value.tv_usec = diff.usec; it.it_interval.tv_usec = 0;
  2022. X if (setitimer(t2it[t],&it,(struct itimerval *) 0) == -1)
  2023. X   return -1;
  2024. X return 0;
  2025. X}
  2026. X
  2027. Xstatic int kaboomresched(t) /* XXX: implicit-static */
  2028. Xtimer_type t;
  2029. X{
  2030. X timer_clock dummy;
  2031. X kaboomlist k;
  2032. X int resched;
  2033. X
  2034. X if (thead[t])
  2035. X  {
  2036. X   resched = 0;
  2037. X   for (k = thead[t];k;k = SODnext(k))
  2038. X     if (SODdata(k).t)
  2039. X       if (!tgoing[t] || timer_diff(&SODdata(k).when,twhen + t,&dummy) < 0)
  2040. X    {
  2041. X     resched = 1;
  2042. X     twhen[t] = SODdata(k).when; /*XXX: structure copying*/
  2043. X    }
  2044. X   if (resched)
  2045. X    {
  2046. X     if (tgoing[t])
  2047. X       ss_unsched(ss_signal(t2sig[t]),kaboom,t);
  2048. X     tgoing[t] = 1;
  2049. X     if (ss_schedwait(ss_signal(t2sig[t]),kaboom,t,numwait) == -1)
  2050. X       return -1; /*XXX*/
  2051. X     if (set_it(t,twhen + t) == -1)
  2052. X       return -1; /*XXX*/
  2053. X    }
  2054. X  }
  2055. X return 0;
  2056. X}
  2057. X
  2058. Xstatic int timer_sched(x,t,flagi,i,p,wait)
  2059. Xss_extern *x;
  2060. Xss_thread *t;
  2061. Xint flagi;
  2062. Xss_id i;
  2063. Xss_idptr p;
  2064. Xint wait;
  2065. X{
  2066. X timer_sig *tsig;
  2067. X kaboomlist k;
  2068. X int resched;
  2069. X timer_clock dummy;
  2070. X
  2071. X k = SODalloc(kaboomlist,k,ralloc);
  2072. X if (!k)
  2073. X   return -1;
  2074. X tsig = (timer_sig *) x->u.c;
  2075. X SODdata(k).when.sec = tsig->when.sec;
  2076. X SODdata(k).when.usec = tsig->when.usec;
  2077. X SODdata(k).t = t;
  2078. X SODdata(k).flagi = flagi;
  2079. X SODdata(k).i = i;
  2080. X SODdata(k).p = p;
  2081. X SODdata(k).wait = wait;
  2082. X
  2083. X resched = 0;
  2084. X if (wait)
  2085. X   if (!numwait++)
  2086. X     resched = 1;
  2087. X SODpush(thead[tsig->t],k);
  2088. X if (!tgoing[tsig->t] || (timer_diff(&(SODdata(k).when),twhen + tsig->t,&dummy) < 0))
  2089. X   resched |= 2;
  2090. X if (resched)
  2091. X  {
  2092. X   if (tgoing[tsig->t])
  2093. X     ss_unsched(ss_signal(t2sig[tsig->t]),kaboom,tsig->t);
  2094. X   if (ss_schedwait(ss_signal(t2sig[tsig->t]),kaboom,tsig->t,numwait) == -1)
  2095. X     return -1;
  2096. X   tgoing[tsig->t] = 1;
  2097. X   if (resched & 2) twhen[tsig->t] = SODdata(k).when; /*XXX: struct copying*/
  2098. X   if (set_it(tsig->t,twhen + tsig->t) == -1)
  2099. X     return -1;
  2100. X  }
  2101. X return 0;
  2102. X}
  2103. X
  2104. Xstatic int timer_unsched(x,t,flagi,i,p)
  2105. Xss_extern *x;
  2106. Xss_thread *t;
  2107. Xint flagi;
  2108. Xss_id i;
  2109. Xss_idptr p;
  2110. X{
  2111. X timer_sig *tsig;
  2112. X kaboomlist k;
  2113. X struct kaboom *sk;
  2114. X
  2115. X tsig = (timer_sig *) x->u.c;
  2116. X for (k = thead[tsig->t];k;k = SODnext(k))
  2117. X  {
  2118. X   sk = &(SODdata(k));
  2119. X   if ((sk->t == t) && (sk->flagi == flagi) && (sk->i == i) && (sk->p == p))
  2120. X     if ((sk->when.usec == tsig->when.usec) && (sk->when.sec == tsig->when.usec))
  2121. X      {
  2122. X       sk->t = 0;
  2123. X       if (sk->wait)
  2124. X     --numwait;
  2125. X       sk->wait = 0;
  2126. X      }
  2127. X  }
  2128. X kaboomcleanup();
  2129. X if (kaboomresched(tsig->t) == -1)
  2130. X   return -1;
  2131. X return 0;
  2132. X}
  2133. X
  2134. Xvoid timer_setsig(tsig,t,when)
  2135. Xtimer_sig *tsig;
  2136. Xtimer_type t;
  2137. Xtimer_clock *when;
  2138. X{
  2139. X tsig->x.sched = timer_sched;
  2140. X tsig->x.unsched = timer_unsched;
  2141. X tsig->x.u.c = (char *) tsig; /* my, aren't we the clever ones today */
  2142. X tsig->t = t;
  2143. X tsig->when.sec = when->sec;
  2144. X tsig->when.usec = when->usec;
  2145. X ss_externsetsig(&(tsig->sig),&(tsig->x));
  2146. X}
  2147. X
  2148. Xstatic int init = 0;
  2149. X
  2150. Xint timer_init()
  2151. X{
  2152. X struct itimerval it;
  2153. X it.it_value.tv_sec = 0; it.it_value.tv_usec = 0;
  2154. X it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 0;
  2155. X if (init)
  2156. X   return 0;
  2157. X init = 1;
  2158. X if (ss_addsig(SIGALRM) == -1)
  2159. X   return -1;
  2160. X if (setitimer(ITIMER_REAL,&it,(struct itimerval *) 0) == -1)
  2161. X   return -1;
  2162. X if (ss_addsig(SIGPROF) == -1)
  2163. X   return -1;
  2164. X if (setitimer(ITIMER_PROF,&it,(struct itimerval *) 0) == -1)
  2165. X   return -1;
  2166. X if (ss_addsig(SIGVTALRM) == -1)
  2167. X   return -1;
  2168. X if (setitimer(ITIMER_VIRTUAL,&it,(struct itimerval *) 0) == -1)
  2169. X   return -1;
  2170. X /* we may end up receiving up to one of each signal, but that's okay */
  2171. X return 0;
  2172. X}
  2173. END_OF_FILE
  2174. if test 7815 -ne `wc -c <'timer.c'`; then
  2175.     echo shar: \"'timer.c'\" unpacked with wrong size!
  2176. fi
  2177. # end of 'timer.c'
  2178. fi
  2179. if test -f 'timer.h' -a "${1}" != "-c" ; then 
  2180.   echo shar: Will not clobber existing file \"'timer.h'\"
  2181. else
  2182. echo shar: Extracting \"'timer.h'\" \(521 characters\)
  2183. sed "s/^X//" >'timer.h' <<'END_OF_FILE'
  2184. X#ifndef TIMER_H
  2185. X#define TIMER_H
  2186. X
  2187. X#include "sigsched.h"
  2188. X
  2189. X#define TIMER_REAL ((timer_type) 0)
  2190. X#define TIMER_VIRTUAL ((timer_type) 1)
  2191. X#define TIMER_PROF ((timer_type) 2)
  2192. X#define TIMER_NUM ((timer_type) 3)
  2193. X
  2194. Xtypedef int timer_type;
  2195. Xtypedef struct { unsigned long sec; unsigned long usec; } timer_clock;
  2196. Xtypedef struct { ss_sig sig; ss_extern x; timer_type t; timer_clock when; } timer_sig;
  2197. X
  2198. Xextern int timer_now();
  2199. Xextern void timer_sum();
  2200. Xextern int timer_diff();
  2201. Xextern void timer_setsig();
  2202. Xextern int timer_init();
  2203. X
  2204. X#endif
  2205. END_OF_FILE
  2206. if test 521 -ne `wc -c <'timer.h'`; then
  2207.     echo shar: \"'timer.h'\" unpacked with wrong size!
  2208. fi
  2209. # end of 'timer.h'
  2210. fi
  2211. echo shar: End of archive 1 \(of 1\).
  2212. cp /dev/null ark1isdone
  2213. MISSING=""
  2214. for I in 1 ; do
  2215.     if test ! -f ark${I}isdone ; then
  2216.     MISSING="${MISSING} ${I}"
  2217.     fi
  2218. done
  2219. if test "${MISSING}" = "" ; then
  2220.     echo You have the archive.
  2221.     rm -f ark[1-9]isdone
  2222. else
  2223.     echo You still need to unpack the following archives:
  2224.     echo "        " ${MISSING}
  2225. fi
  2226. ##  End of shell archive.
  2227. exit 0
  2228.