|
|
1.1 root 1: /*
2:
1.1.1.3 root 3: Copyright 1990,1991,1992 Eric R. Smith.
4:
1.1.1.5 ! root 5: Copyright 1992,1993,1994 Atari Corporation.
1.1.1.3 root 6:
7: All rights reserved.
1.1 root 8:
9: */
10:
11:
12:
13: #include "mint.h"
14:
15:
16:
17: /*
18:
19: * We initialize proc_clock to a very large value so that we don't have
20:
21: * to worry about unexpected process switches while starting up
22:
23: */
24:
25:
26:
27: short proc_clock = 0x7fff;
28:
29:
30:
31: /* used by filesystems for time/date stamps; updated once per second */
32:
33: short timestamp, datestamp;
34:
35:
36:
37: extern short in_kernel; /* in main.c */
38:
39:
40:
41: static void unnapme P_((PROC *));
42:
1.1.1.5 ! root 43: static TIMEOUT *newtimeout P_((short));
1.1 root 44:
1.1.1.5 ! root 45: static void disposetimeout P_((TIMEOUT *));
1.1 root 46:
1.1.1.5 ! root 47: static void inserttimeout P_ ((TIMEOUT *, long));
1.1 root 48:
49:
50:
1.1.1.5 ! root 51: #define TIMEOUTS 20 /* # of static timeout structs */
1.1 root 52:
1.1.1.5 ! root 53: #define TIMEOUT_USED 0x01 /* timeout struct is in use */
1.1 root 54:
1.1.1.5 ! root 55: #define TIMEOUT_STATIC 0x02 /* this is a static timeout */
1.1 root 56:
1.1.1.5 ! root 57:
! 58:
! 59: /* This gets implizitly initialized to zero, thus the flags are
! 60:
! 61: * set up correctly.
1.1 root 62:
63: */
64:
1.1.1.5 ! root 65: static TIMEOUT timeouts[TIMEOUTS] = { { 0, }, };
1.1 root 66:
1.1.1.5 ! root 67: TIMEOUT *tlist = NULL;
1.1 root 68:
1.1.1.5 ! root 69: TIMEOUT *expire_list = NULL;
1.1 root 70:
71:
72:
1.1.1.5 ! root 73: /* Number of ticks after that an expired timeout is considered to be old
1.1 root 74:
1.1.1.5 ! root 75: and disposed automatically. */
1.1 root 76:
1.1.1.5 ! root 77: #define TIMEOUT_EXPIRE_LIMIT 400 /* 2 secs */
1.1 root 78:
79:
80:
1.1.1.5 ! root 81: static TIMEOUT *
1.1 root 82:
1.1.1.5 ! root 83: newtimeout(fromlist)
1.1 root 84:
1.1.1.5 ! root 85: short fromlist;
1.1 root 86:
87: {
88:
1.1.1.5 ! root 89: TIMEOUT *t;
1.1 root 90:
1.1.1.5 ! root 91: short i, sr;
1.1 root 92:
93:
94:
1.1.1.5 ! root 95: if (!fromlist) {
1.1 root 96:
1.1.1.5 ! root 97: t = kmalloc(SIZEOF(TIMEOUT));
1.1 root 98:
1.1.1.5 ! root 99: if (t) {
1.1 root 100:
1.1.1.5 ! root 101: t->flags = 0;
1.1 root 102:
1.1.1.5 ! root 103: t->arg = 0;
1.1 root 104:
1.1.1.5 ! root 105: return t;
1.1 root 106:
1.1.1.5 ! root 107: }
1.1 root 108:
1.1.1.5 ! root 109: }
1.1 root 110:
1.1.1.5 ! root 111: sr = spl7();
1.1 root 112:
1.1.1.5 ! root 113: for (i = 0; i < TIMEOUTS; ++i) {
! 114:
! 115: if (!(timeouts[i].flags & TIMEOUT_USED)) {
! 116:
! 117: timeouts[i].flags |= (TIMEOUT_STATIC|TIMEOUT_USED);
! 118:
! 119: spl(sr);
! 120:
! 121: timeouts[i].arg = 0;
! 122:
! 123: return &timeouts[i];
! 124:
! 125: }
! 126:
! 127: }
! 128:
! 129: spl(sr);
! 130:
! 131: return 0;
! 132:
! 133: }
! 134:
! 135:
! 136:
! 137: static void
! 138:
! 139: disposetimeout(t)
! 140:
! 141: TIMEOUT *t;
! 142:
! 143: {
! 144:
! 145: if (t->flags & TIMEOUT_STATIC) t->flags &= ~TIMEOUT_USED;
! 146:
! 147: else kfree(t);
! 148:
! 149: }
! 150:
! 151:
! 152:
! 153: static void
! 154:
! 155: dispose_old_timeouts ()
! 156:
! 157: {
! 158:
! 159: TIMEOUT *t, **prev, *old;
! 160:
! 161: long now = *(long *) 0x4ba;
! 162:
! 163: short sr = spl7 ();
! 164:
! 165:
! 166:
! 167: for (prev = &expire_list, t = *prev; t; prev = &t->next, t = *prev)
! 168:
! 169: {
! 170:
! 171: if (t->when < now)
! 172:
! 173: {
! 174:
! 175: /* This and the following timeouts are too old. Throw them away. */
! 176:
! 177: *prev = 0;
! 178:
! 179: spl (sr);
! 180:
! 181: while (t)
! 182:
! 183: {
! 184:
! 185: old = t;
! 186:
! 187: t = t->next;
! 188:
! 189: disposetimeout (old);
! 190:
! 191: }
! 192:
! 193: return;
! 194:
! 195: }
! 196:
! 197: }
! 198:
! 199: spl (sr);
! 200:
! 201: }
! 202:
! 203:
! 204:
! 205: static void
! 206:
! 207: inserttimeout(t, delta)
! 208:
! 209: TIMEOUT *t;
! 210:
! 211: long delta;
! 212:
! 213: {
! 214:
! 215: TIMEOUT **prev, *cur;
! 216:
! 217: short sr = spl7();
1.1 root 218:
219:
220:
221: cur = tlist;
222:
223: prev = &tlist;
224:
225: while (cur) {
226:
227: if (cur->when >= delta) {
228:
229: cur->when -= delta;
230:
231: t->next = cur;
232:
233: t->when = delta;
234:
235: *prev = t;
236:
1.1.1.5 ! root 237: spl(sr);
! 238:
! 239: return;
1.1 root 240:
241: }
242:
243: delta -= cur->when;
244:
245: prev = &cur->next;
246:
247: cur = cur->next;
248:
249: }
250:
251: assert(delta >= 0);
252:
253: t->when = delta;
254:
255: t->next = cur;
256:
257: *prev = t;
258:
1.1.1.5 ! root 259: spl(sr);
! 260:
! 261: }
! 262:
! 263:
! 264:
! 265: /*
! 266:
! 267: * addtimeout(long delta, void (*func)()): schedule a timeout for the current
! 268:
! 269: * process, to take place in "delta" milliseconds. "func" specifies a
! 270:
! 271: * function to be called at that time; the function is passed as a parameter
! 272:
! 273: * the process for which the timeout was specified (i.e. the value of
! 274:
! 275: * curproc at the time addtimeout() was called; note that this is probably
! 276:
! 277: * *not* the current process when the timeout occurs).
! 278:
! 279: *
! 280:
! 281: * NOTE: if kernel memory is low, newtimeout() will try to get a statically
! 282:
! 283: * allocated timeout struct (fallback method).
! 284:
! 285: */
! 286:
! 287:
! 288:
! 289: TIMEOUT * ARGS_ON_STACK
! 290:
! 291: addtimeout(delta, func)
! 292:
! 293: long delta;
! 294:
! 295: void (*func) P_((PROC *));
! 296:
! 297: {
! 298:
! 299: TIMEOUT *t;
! 300:
! 301: TIMEOUT **prev;
! 302:
! 303: short sr;
! 304:
! 305:
! 306:
! 307: /* Try to reuse an already expired timeout that had the
! 308:
! 309: same function attached */
! 310:
! 311: sr = spl7();
! 312:
! 313: prev = &expire_list;
! 314:
! 315: for (t = *prev; t != NULL; prev = &t->next, t = *prev)
! 316:
! 317: if (t->proc == curproc && t->func == func)
! 318:
! 319: {
! 320:
! 321: *prev = t->next;
! 322:
! 323: break;
! 324:
! 325: }
! 326:
! 327:
! 328:
! 329: spl(sr);
! 330:
! 331: if (t == NULL)
! 332:
! 333: t = newtimeout(0);
! 334:
! 335:
! 336:
! 337: /* BUG: we should have some fallback mechanism for timeouts when the
! 338:
! 339: kernel memory is exhausted
! 340:
! 341: */
! 342:
! 343: assert(t);
! 344:
! 345:
! 346:
! 347: t->proc = curproc;
! 348:
! 349: t->func = func;
! 350:
! 351: inserttimeout(t, delta);
! 352:
! 353: return t;
! 354:
! 355: }
! 356:
! 357:
! 358:
! 359: /*
! 360:
! 361: * addroottimeout(long delta, void (*)(PROC *), short flags);
! 362:
! 363: * Same as addtimeout(), except that the timeout is attached to Pid 0 (MiNT).
! 364:
! 365: * This means the timeout won't be cancelled if the process which was
! 366:
! 367: * running at the time addroottimeout() was called exits.
! 368:
! 369: *
! 370:
! 371: * Currently only bit 0 of `flags' is used. Meaning:
! 372:
! 373: * Bit 0 set: Call from interrupt (cannot use kmalloc, use statically
! 374:
! 375: * allocated `struct timeout' instead).
! 376:
! 377: * Bit 0 clear: Not called from interrupt, can use kmalloc.
! 378:
! 379: *
! 380:
! 381: * Thus addroottimeout() can be called from interrupts (bit 0 of flags set),
! 382:
! 383: * which makes it *extremly* useful for device drivers.
! 384:
! 385: * A serial device driver would make an addroottimeout(0, check_keys, 1)
! 386:
! 387: * if some bytes have arrived.
! 388:
! 389: * check_keys() is then called at the next context switch, can use all
! 390:
! 391: * the kernel functions and can do time cosuming jobs.
! 392:
! 393: */
! 394:
! 395:
! 396:
! 397: TIMEOUT * ARGS_ON_STACK
! 398:
! 399: addroottimeout(delta, func, flags)
! 400:
! 401: long delta;
! 402:
! 403: void (*func) P_((PROC *));
! 404:
! 405: short flags;
! 406:
! 407: {
! 408:
! 409: TIMEOUT *t;
! 410:
! 411: TIMEOUT **prev;
! 412:
! 413: short sr;
! 414:
! 415:
! 416:
! 417: /* Try to reuse an already expired timeout that had the
! 418:
! 419: same function attached */
! 420:
! 421: sr = spl7();
! 422:
! 423: prev = &expire_list;
! 424:
! 425: for (t = *prev; t != NULL; t = *prev)
! 426:
! 427: {
! 428:
! 429: if (t->proc == rootproc && t->func == func)
! 430:
! 431: {
! 432:
! 433: *prev = t->next;
! 434:
! 435: break;
! 436:
! 437: }
! 438:
! 439: prev = &t->next;
! 440:
! 441: }
! 442:
! 443: spl(sr);
! 444:
! 445:
! 446:
! 447: if (!t)
! 448:
! 449: t = newtimeout(flags & 1);
! 450:
! 451:
! 452:
! 453: if (!t) return NULL;
! 454:
! 455: t->proc = rootproc;
! 456:
! 457: t->func = func;
! 458:
! 459: inserttimeout(t, delta);
! 460:
1.1 root 461: return t;
462:
463: }
464:
465:
466:
467: /*
468:
469: * cancelalltimeouts(): cancels all pending timeouts for the current
470:
471: * process
472:
473: */
474:
475:
476:
1.1.1.4 root 477: void ARGS_ON_STACK
1.1 root 478:
479: cancelalltimeouts()
480:
481: {
482:
483: TIMEOUT *cur, **prev, *old;
484:
485: long delta;
486:
1.1.1.5 ! root 487: short sr = spl7 ();
! 488:
1.1 root 489:
490:
491: cur = tlist;
492:
493: prev = &tlist;
494:
495: while (cur) {
496:
497: if (cur->proc == curproc) {
498:
499: delta = cur->when;
500:
501: old = cur;
502:
503: *prev = cur = cur->next;
504:
505: if (cur) cur->when += delta;
506:
1.1.1.5 ! root 507: spl(sr);
! 508:
1.1 root 509: disposetimeout(old);
510:
1.1.1.5 ! root 511: sr = spl7();
! 512:
! 513: /* ++kay: just in case an interrupt handler installed a
! 514:
! 515: * timeout right after `prev' and before `cur' */
! 516:
! 517: cur = *prev;
! 518:
1.1 root 519: }
520:
521: else {
522:
523: prev = &cur->next;
524:
525: cur = cur->next;
526:
527: }
528:
529: }
530:
1.1.1.5 ! root 531: prev = &expire_list;
! 532:
! 533: for (cur = *prev; cur; cur = *prev)
! 534:
! 535: {
! 536:
! 537: if (cur->proc == curproc)
! 538:
! 539: {
! 540:
! 541: *prev = cur->next;
! 542:
! 543: spl (sr);
! 544:
! 545: disposetimeout (cur);
! 546:
! 547: sr = spl7 ();
! 548:
! 549: }
! 550:
! 551: else
! 552:
! 553: prev = &cur->next;
! 554:
! 555: }
! 556:
! 557: spl (sr);
! 558:
1.1 root 559: }
560:
561:
562:
563: /*
564:
565: * Cancel a specific timeout. If the timeout isn't on the list, or isn't
566:
567: * for this process, we do nothing; otherwise, we cancel the time out
568:
569: * and then free the memory it used. *NOTE*: it's very possible (indeed
570:
571: * likely) that "this" was already removed from the list and disposed of
572:
573: * by the timeout processing routines, so it's important that we check
574:
575: * for it's presence in the list and do absolutely nothing if we don't
576:
577: * find it there!
578:
579: */
580:
581:
582:
1.1.1.4 root 583: void ARGS_ON_STACK
1.1 root 584:
585: canceltimeout(this)
586:
587: TIMEOUT *this;
588:
589: {
590:
591: TIMEOUT *cur, **prev;
592:
1.1.1.5 ! root 593: short sr = spl7();
! 594:
! 595:
! 596:
! 597: /* First look at the list of expired timeouts */
! 598:
! 599: prev = &expire_list;
! 600:
! 601: for (cur = *prev; cur; cur = *prev)
! 602:
! 603: {
! 604:
! 605: if (cur == this && cur->proc == curproc)
! 606:
! 607: {
! 608:
! 609: *prev = cur->next;
! 610:
! 611: spl (sr);
! 612:
! 613: disposetimeout (this);
! 614:
! 615: return;
! 616:
! 617: }
! 618:
! 619: prev = &cur->next;
! 620:
! 621: }
! 622:
1.1 root 623:
624:
625: prev = &tlist;
626:
627: for (cur = tlist; cur; cur = cur->next) {
628:
629: if (cur == this && cur->proc == curproc) {
630:
631: *prev = cur->next;
632:
633: if (cur->next) {
634:
635: cur->next->when += this->when;
636:
637: }
638:
1.1.1.5 ! root 639: spl (sr);
! 640:
1.1 root 641: disposetimeout(this);
642:
1.1.1.5 ! root 643: return;
1.1 root 644:
645: }
646:
647: prev = &cur->next;
648:
649: }
650:
1.1.1.5 ! root 651: spl(sr);
! 652:
! 653: }
! 654:
! 655:
! 656:
! 657: void ARGS_ON_STACK
! 658:
! 659: cancelroottimeout(this)
! 660:
! 661: TIMEOUT *this;
! 662:
! 663: {
! 664:
! 665: TIMEOUT *cur, **prev;
! 666:
! 667: short sr = spl7();
! 668:
! 669:
! 670:
! 671: /* First look at the list of expired timeouts */
! 672:
! 673: prev = &expire_list;
! 674:
! 675: for (cur = *prev; cur; cur = *prev)
! 676:
! 677: {
! 678:
! 679: if (cur == this && cur->proc == rootproc)
! 680:
! 681: {
! 682:
! 683: *prev = cur->next;
! 684:
! 685: spl (sr);
! 686:
! 687: disposetimeout (this);
! 688:
! 689: return;
! 690:
! 691: }
! 692:
! 693: prev = &cur->next;
! 694:
! 695: }
! 696:
! 697:
! 698:
! 699: prev = &tlist;
! 700:
! 701: for (cur = tlist; cur; cur = cur->next) {
! 702:
! 703: if (cur == this && (cur->proc == rootproc)) {
! 704:
! 705: *prev = cur->next;
! 706:
! 707: if (cur->next) {
! 708:
! 709: cur->next->when += this->when;
! 710:
! 711: }
! 712:
! 713: spl (sr);
! 714:
! 715: disposetimeout(this);
! 716:
! 717: return;
! 718:
! 719: }
! 720:
! 721: prev = &cur->next;
! 722:
! 723: }
! 724:
! 725: spl(sr);
! 726:
1.1 root 727: }
728:
729:
730:
731: /*
732:
733: * timeout: called every 20 ms or so by GEMDOS, this routine
734:
735: * is responsible for maintaining process times and such.
736:
737: * it should also decrement the "proc_clock" variable, but
738:
739: * should *not* take any action when it reaches 0 (the state of the
740:
741: * stack is too uncertain, and time is too critical). Instead,
742:
743: * a vbl routine checks periodically and if "proc_clock" is 0
744:
745: * suspends the current process
746:
747: */
748:
749:
750:
751: volatile int our_clock = 1000;
752:
753:
754:
1.1.1.5 ! root 755: /* variables for monitoring the keyboard */
! 756:
! 757: extern IOREC_T *keyrec; /* keyboard i/o record pointer */
! 758:
! 759: extern short kintr; /* keyboard interrupt pending (see intr.s) */
! 760:
! 761:
! 762:
1.1.1.2 root 763: void ARGS_ON_STACK
1.1 root 764:
765: timeout()
766:
767: {
768:
769: int ms; /* time between ticks */
770:
771:
772:
1.1.1.5 ! root 773: kintr = keyrec->head != keyrec->tail;
! 774:
! 775:
! 776:
1.1 root 777: ms = *((short *)0x442L);
778:
779: if (proc_clock > 0)
780:
781: proc_clock--;
782:
783:
784:
785: our_clock -= ms;
786:
787: if (tlist) {
788:
789: tlist->when -= ms;
790:
791: }
792:
793: }
794:
795:
796:
797: /*
798:
799: * sleep() calls this routine to check on alarms and other sorts
800:
801: * of time-outs on every context switch.
802:
803: */
804:
805:
806:
807: void
808:
809: checkalarms()
810:
811: {
812:
813: extern long searchtime; /* in dosdir.c */
814:
815: PROC *p;
816:
817: long delta;
818:
1.1.1.5 ! root 819: void (*evnt) P_((PROC *, long arg));
1.1 root 820:
821: TIMEOUT *old;
822:
1.1.1.5 ! root 823: short sr;
! 824:
! 825: long arg;
! 826:
1.1 root 827:
828:
829: /* do the once per second things */
830:
831: while (our_clock < 0) {
832:
833: our_clock += 1000;
834:
835: timestamp = Tgettime();
836:
837: datestamp = Tgetdate();
838:
839: searchtime++;
840:
841: reset_priorities();
842:
843: }
844:
845:
846:
1.1.1.5 ! root 847: sr = spl7();
! 848:
1.1 root 849: /* see if there are outstanding timeout requests to do */
850:
851: while (tlist && ((delta = tlist->when) <= 0)) {
852:
853: p = tlist->proc;
854:
1.1.1.5 ! root 855: /* hack: pass an extra long as arg, those intrested in it will need
1.1 root 856:
1.1.1.5 ! root 857: * a cast and have to place it in t->arg themselves but that way
1.1 root 858:
1.1.1.5 ! root 859: * everything else still works without change -nox */
1.1 root 860:
1.1.1.5 ! root 861: arg = tlist->arg;
1.1 root 862:
1.1.1.5 ! root 863: evnt = (void (*)P_((PROC *, long)))tlist->func;
1.1 root 864:
1.1.1.5 ! root 865: old = tlist;
1.1 root 866:
1.1.1.5 ! root 867: tlist = tlist->next;
1.1 root 868:
1.1.1.5 ! root 869: /* if delta < 0, it's possible that the time has come for the next timeout
1.1 root 870:
1.1.1.5 ! root 871: * to occur.
1.1 root 872:
1.1.1.5 ! root 873: * ++kay: moved this before the timeout fuction is called, in case the
1.1 root 874:
1.1.1.5 ! root 875: * timeout function installes a new timeout. */
1.1 root 876:
877: if (tlist)
878:
879: tlist->when += delta;
880:
1.1.1.5 ! root 881: old->next = expire_list;
! 882:
! 883: old->when = *(long *) 0x4ba + TIMEOUT_EXPIRE_LIMIT;
! 884:
! 885: expire_list = old;
! 886:
! 887: spl(sr);
! 888:
! 889: /* ++kay: debug output at spl7 hangs the system, so moved it here */
! 890:
! 891: TRACE(("doing timeout code for pid %d", p->pid));
! 892:
! 893:
! 894:
! 895: /* call the timeout function */
! 896:
! 897: (*evnt)(p, arg);
! 898:
! 899: sr = spl7();
! 900:
1.1 root 901: }
902:
1.1.1.5 ! root 903: spl(sr);
! 904:
! 905: /* Now look at the expired timeouts if some are getting old */
! 906:
! 907: dispose_old_timeouts ();
! 908:
1.1 root 909: }
910:
911:
912:
913: /*
914:
915: * nap(n): nap for n milliseconds. Used in loops where we're waiting for
916:
917: * an event. If we expect the event *very* soon, we should use yield
918:
919: * instead.
920:
921: * NOTE: we may not sleep for exactly n milliseconds; signals can wake
922:
923: * us earlier, and the vagaries of process scheduling may cause us to
924:
925: * oversleep...
926:
927: */
928:
929:
930:
931: static void
932:
933: unnapme(p)
934:
935: PROC *p;
936:
937: {
938:
1.1.1.2 root 939: if (p->wait_q == SELECT_Q && p->wait_cond == (long)nap) {
1.1 root 940:
1.1.1.3 root 941: short sr = spl7();
942:
1.1 root 943: rm_q(SELECT_Q, p);
944:
945: add_q(READY_Q, p);
946:
1.1.1.3 root 947: spl(sr);
948:
1.1 root 949: p->wait_cond = 0;
950:
951: }
952:
953: }
954:
955:
956:
1.1.1.2 root 957: void ARGS_ON_STACK
1.1 root 958:
959: nap(n)
960:
961: unsigned n;
962:
963: {
964:
965: TIMEOUT *t;
966:
967:
968:
969: t = addtimeout((long)n, unnapme);
970:
1.1.1.2 root 971: sleep(SELECT_Q, (long)nap);
1.1 root 972:
973: canceltimeout(t);
974:
975: }
976:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.