kernel.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:14k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /* Non pre-empting synchronization kernel, machine-independent portion
  2.  * Copyright 1992 Phil Karn, KA9Q
  3.  */
  4. #if defined(PROCLOG) || defined(PROCTRACE)
  5. #include <stdio.h>
  6. #endif
  7. #include <dos.h>
  8. #include <setjmp.h>
  9. #include "global.h"
  10. #include "mbuf.h"
  11. #include "proc.h"
  12. #include "timer.h"
  13. #include "socket.h"
  14. #include "daemon.h"
  15. #include "hardware.h"
  16. #include "display.h"
  17. #ifdef PROCLOG
  18. FILE *proclog;
  19. FILE *proctrace;
  20. #endif
  21. int Stkchk = 0;
  22. struct proc *Curproc; /* Currently running process */
  23. struct proc *Rdytab; /* Processes ready to run (not including curproc) */
  24. struct proc *Waittab[PHASH]; /* Waiting process list */
  25. struct proc *Susptab; /* Suspended processes */
  26. static struct mbuf *Killq;
  27. struct ksig Ksig;
  28. int Kdebug; /* Control display of current task on screen */
  29. static void addproc(struct proc *entry);
  30. static void delproc(struct proc *entry);
  31. static void ksig(void *event,int n);
  32. static int procsigs(void);
  33. /* Create a process descriptor for the main function. Must be actually
  34.  * called from the main function, and must be called before any other
  35.  * tasking functions are called!
  36.  *
  37.  * Note that standard I/O is NOT set up here.
  38.  */
  39. struct proc *
  40. mainproc(char *name)
  41. {
  42. register struct proc *pp;
  43. /* Create process descriptor */
  44. pp = (struct proc *)callocw(1,sizeof(struct proc));
  45. /* Create name */
  46. pp->name = strdup(name);
  47. #ifndef AMIGA
  48. pp->stksize = 0;
  49. #else
  50. init_psetup(pp);
  51. #endif
  52. /* Make current */
  53. pp->flags.suspend = pp->flags.waiting = 0;
  54. Curproc = pp;
  55. #ifdef PROCLOG
  56. proclog = fopen("proclog",APPEND_TEXT);
  57. proctrace = fopen("proctrace",APPEND_TEXT);
  58. #endif
  59. return pp;
  60. }
  61. /* Create a new, ready process and return pointer to descriptor.
  62.  * The general registers are not initialized, but optional args are pushed
  63.  * on the stack so they can be seen by a C function.
  64.  */
  65. struct proc *
  66. newproc(
  67. char *name, /* Arbitrary user-assigned name string */
  68. unsigned int stksize, /* Stack size in words to allocate */
  69. void (*pc)(), /* Initial execution address */
  70. int iarg, /* Integer argument (argc) */
  71. void *parg1, /* Generic pointer argument #1 (argv) */
  72. void *parg2, /* Generic pointer argument #2 (session ptr) */
  73. int freeargs /* If set, free arg list on parg1 at termination */
  74. ){
  75. register struct proc *pp;
  76. int i;
  77. if(Stkchk)
  78. chkstk();
  79. /* Create process descriptor */
  80. pp = (struct proc *)callocw(1,sizeof(struct proc));
  81. /* Create name */
  82. pp->name = strdup(name);
  83. /* Allocate stack */
  84. #ifdef AMIGA
  85. stksize += SIGQSIZE0; /* DOS overhead */
  86. #endif
  87. pp->stksize = stksize;
  88. if((pp->stack = (uint16 *)malloc(sizeof(uint16)*stksize)) == NULL){
  89. free(pp->name);
  90. free(pp);
  91. return NULL;
  92. }
  93. /* Initialize stack for high-water check */
  94. for(i=0;i<stksize;i++)
  95. pp->stack[i] = STACKPAT;
  96. /* Do machine-dependent initialization of stack */
  97. psetup(pp,iarg,parg1,parg2,pc);
  98. pp->flags.freeargs = freeargs;
  99. pp->iarg = iarg;
  100. pp->parg1 = parg1;
  101. pp->parg2 = parg2;
  102. /* Inherit creator's input and output sockets */
  103. pp->input = fdup(stdin);
  104. pp->output = fdup(stdout);
  105. /* Add to ready process table */
  106. pp->flags.suspend = pp->flags.waiting = 0;
  107. addproc(pp);
  108. return pp;
  109. }
  110. /* Free resources allocated to specified process. If a process wants to kill
  111.  * itself, the reaper is called to do the dirty work. This avoids some
  112.  * messy situations that would otherwise occur, like freeing your own stack.
  113.  */
  114. void
  115. killproc(struct proc *pp)
  116. {
  117. char **argv;
  118. if(pp == NULL)
  119. return;
  120. /* Don't check the stack here! Will cause infinite recursion if
  121.  * called from a stack error
  122.  */
  123. if(pp == Curproc)
  124. killself(); /* Doesn't return */
  125. fclose(pp->input);
  126. fclose(pp->output);
  127. /* Stop alarm clock in case it's running */
  128. stop_timer(&pp->alarm);
  129. /* Alert everyone waiting for this proc to die */
  130. ksignal(pp,0);
  131. /* Remove from appropriate table */
  132. delproc(pp);
  133. #ifdef PROCLOG
  134. fprintf(proclog,"id %p name %s stack %u/%un",pp,
  135. pp->name,stkutil(pp),pp->stksize);
  136. fclose(proclog);
  137. proclog = fopen("proclog",APPEND_TEXT);
  138. proctrace = fopen("proctrace",APPEND_TEXT);
  139. #endif
  140. /* Free allocated memory resources */
  141. if(pp->flags.freeargs){
  142. argv = pp->parg1;
  143. while(pp->iarg-- != 0)
  144. free(*argv++);
  145. free(pp->parg1);
  146. }
  147. free(pp->name);
  148. free(pp->stack);
  149. free(pp);
  150. }
  151. /* Terminate current process by sending a request to the killer process.
  152.  * Automatically called when a process function returns. Does not return.
  153.  */
  154. void
  155. killself(void)
  156. {
  157. struct mbuf *bp = NULL;
  158. pushdown(&bp,&Curproc,sizeof(Curproc));
  159. enqueue(&Killq,&bp);
  160. /* "Wait for me; I will be merciful and quick." */
  161. for(;;)
  162. kwait(NULL);
  163. }
  164. /* Process used by processes that want to kill themselves */
  165. void
  166. killer(int i,void *v1,void *v2)
  167. {
  168. struct proc *pp;
  169. struct mbuf *bp;
  170. for(;;){
  171. while(Killq == NULL)
  172. kwait(&Killq);
  173. bp = dequeue(&Killq);
  174. pullup(&bp,&pp,sizeof(pp));
  175. free_p(&bp);
  176. if(pp != Curproc) /* We're immortal */
  177. killproc(pp);
  178. }
  179. }
  180. /* Inhibit a process from running */
  181. void
  182. suspend(struct proc *pp)
  183. {
  184. if(pp == NULL)
  185. return;
  186. if(pp != Curproc)
  187. delproc(pp); /* Running process isn't on any list */
  188. pp->flags.suspend = 1;
  189. if(pp != Curproc)
  190. addproc(pp); /* kwait will do it for us */
  191. else
  192. kwait(NULL);
  193. }
  194. /* Restart suspended process */
  195. void
  196. resume(struct proc *pp)
  197. {
  198. if(pp == NULL)
  199. return;
  200. delproc(pp); /* Can't be Curproc! */
  201. pp->flags.suspend = 0;
  202. addproc(pp);
  203. }
  204. /* Wakeup waiting process, regardless of event it's waiting for. The process
  205.  * will see a return value of "val" from its kwait() call. Must not be
  206.  * called from an interrupt handler.
  207.  */
  208. void
  209. alert(struct proc *pp,int val)
  210. {
  211. if(pp == NULL)
  212. return;
  213. #ifdef notdef
  214. if(pp->flags.waiting == 0)
  215. return;
  216. #endif
  217. #ifdef PROCTRACE
  218. logmsg(-1,"alert(%p,%u) [%s]",pp,val,pp->name);
  219. #endif
  220. if(pp != Curproc)
  221. delproc(pp);
  222. pp->flags.waiting = 0;
  223. pp->retval = val;
  224. pp->event = NULL;
  225. if(pp != Curproc)
  226. addproc(pp);
  227. }
  228. /* Post a wait on a specified event and give up the CPU until it happens. The
  229.  * null event is special: it means "I don't want to block on an event, but let
  230.  * somebody else run for a while". It can also mean that the present process
  231.  * is terminating; in this case the wait never returns.
  232.  *
  233.  * Pwait() returns 0 if the event was signaled; otherwise it returns the
  234.  * arg in an alert() call. Pwait must not be called from interrupt level.
  235.  *
  236.  * Before waiting and after giving up the CPU, kwait() processes the signal
  237.  * queue containing events signaled when interrupts were off. This means
  238.  * the process queues are no longer modified by interrupt handlers,
  239.  * so it is no longer necessary to run with interrupts disabled here. This
  240.  * greatly improves interrupt latencies.
  241.  */
  242. int
  243. kwait(void *event)
  244. {
  245. register struct proc *oldproc;
  246. int tmp;
  247. int i_state;
  248. if(!istate()){
  249. stktrace();
  250. }
  251. Ksig.kwaits++;
  252. if(intcontext() == 1){
  253. /* Pwait must not be called from interrupt context */
  254. Ksig.kwaitints++;
  255. return 0;
  256. }
  257. /* Enable interrupts, after saving the current state.
  258.  * This minimizes interrupt latency since we may have a lot
  259.  * of work to do. This seems safe, since care has been taken
  260.  * here to ensure that signals from interrupt level are not lost, e.g.,
  261.  * if we're waiting on an event, we post it before we scan the
  262.  * signal queue.
  263.  */
  264. i_state = istate();
  265. enable();
  266. if(Stkchk)
  267. chkstk();
  268. if(event != NULL){
  269. /* Post a wait for the specified event */
  270. Curproc->event = event;
  271. Curproc->flags.waiting = 1;
  272. addproc(Curproc); /* Put us on the wait list */
  273. }
  274. /* If the signal queue contains a signal for the event that we're
  275.  * waiting for, this will wake us back up
  276.  */
  277. procsigs();
  278. if(event == NULL){
  279. /* We remain runnable */
  280. if(Rdytab == NULL){
  281. /* Nothing else is ready, so just return */
  282. Ksig.kwaitnops++;
  283. restore(i_state);
  284. return 0;
  285. }
  286. addproc(Curproc); /* Put us on the end of the ready list */
  287. }
  288. /* Look for a ready process and run it. If there are none,
  289.  * loop or halt until an interrupt makes something ready.
  290.  */
  291. while(Rdytab == NULL){
  292. /* Give system back to upper-level multitasker, if any.
  293.  * Note that this function enables interrupts internally
  294.  * to prevent deadlock, but it restores our state
  295.  * before returning.
  296.  */
  297. if(Kdebug)
  298. debug("              ");
  299. giveup();
  300. /* Process signals that occurred during the giveup() */
  301. procsigs();
  302. }
  303. /* Remove first entry from ready list */
  304. oldproc = Curproc;
  305. Curproc = Rdytab;
  306. delproc(Curproc);
  307. if(Kdebug)
  308. debug(Curproc->name);
  309. /* Now do the context switch.
  310.  * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
  311.  *
  312.  * First save the current process's state. Then if
  313.  * this is still the old process, load the new environment. Since the
  314.  * new task will "think" it's returning from the setjmp() with a return
  315.  * value of 1, the comparison with 0 will bypass the longjmp(), which
  316.  * would otherwise cause an infinite loop.
  317.  */
  318. #ifdef PROCTRACE
  319. if(strcmp(oldproc->name,Curproc->name) != 0){
  320. logmsg(-1,"-> %s(%d)",Curproc->name,Curproc->flags.istate);
  321. }
  322. #endif
  323. /* Save old state */
  324. oldproc->flags.istate = 0;
  325. if(i_state)
  326. oldproc->flags.istate = 1;
  327. if(setjmp(oldproc->env) == 0){
  328. /* We're still running in the old task; load new task context.
  329.  * The interrupt state is restored here in case longjmp
  330.  * doesn't do it (e.g., systems other than Turbo-C).
  331.  */
  332. restore(Curproc->flags.istate);
  333. longjmp(Curproc->env,1);
  334. }
  335. /* At this point, we're running in the newly dispatched task */
  336. tmp = Curproc->retval;
  337. Curproc->retval = 0;
  338. /* Also restore the true interrupt state here, in case the longjmp
  339.  * DOES restore the interrupt state saved at the time of the setjmp().
  340.  * This is the case with Turbo-C's setjmp/longjmp.
  341.  */
  342. restore(Curproc->flags.istate);
  343. /* If an exception signal was sent and we're prepared, take it */
  344. if((Curproc->flags.sset) && tmp == Curproc->signo)
  345. longjmp(Curproc->sig,1);
  346. /* Otherwise return normally to the new task */
  347. return tmp;
  348. }
  349. void
  350. ksignal(void *event,int n)
  351. {
  352. static void *lastevent;
  353. if(istate()){
  354. /* Interrupts are on, just call ksig directly after
  355.  * processing the previously queued signals
  356.  */
  357. procsigs();
  358. ksig(event,n);
  359. return;
  360. }
  361. /* Interrupts are off, so quickly queue event */
  362. Ksig.ksigsqueued++;
  363.   /* Ignore duplicate signals to protect against a mad device driver
  364.  * overflowing the signal queue
  365.  */
  366. if(event == lastevent && Ksig.nentries != 0){
  367. Ksig.duksigs++;
  368. return; 
  369. }
  370. if(Ksig.nentries == SIGQSIZE){
  371. /* It's hard to handle this gracefully */
  372. Ksig.lostsigs++;
  373. return;
  374. }
  375. lastevent = Ksig.wp->event = event;
  376. Ksig.wp->n = n;
  377. if(++Ksig.wp >= &Ksig.entry[SIGQSIZE])
  378. Ksig.wp = Ksig.entry;
  379. Ksig.nentries++;
  380. }
  381. static int
  382. procsigs(void)
  383. {
  384. int cnt = 0;
  385. int tmp;
  386. int i_state;
  387. for(;;){
  388. /* Atomic read and decrement of entry count */
  389. i_state = dirps();
  390. tmp = Ksig.nentries;
  391. if(tmp != 0)
  392. Ksig.nentries--;
  393. restore(i_state);
  394. if(tmp == 0)
  395. break;
  396. ksig(Ksig.rp->event,Ksig.rp->n);
  397. if(++Ksig.rp >= &Ksig.entry[SIGQSIZE])
  398. Ksig.rp = Ksig.entry;
  399. cnt++;
  400. }
  401. if(cnt > Ksig.maxentries)
  402. Ksig.maxentries = cnt; /* Record high water mark */
  403. return cnt;
  404. }
  405. /* Make ready the first 'n' processes waiting for a given event. The ready
  406.  * processes will see a return value of 0 from kwait().  Note that they don't
  407.  * actually get control until we explicitly give up the CPU ourselves through
  408.  * a kwait(). ksig is now called from pwait, which is never called at
  409.  * interrupt time, so it is no longer necessary to protect the proc queues
  410.  * against interrupts. This also helps interrupt latencies considerably.
  411.  */
  412. static void
  413. ksig(
  414. void *event, /* Event to signal */
  415. int n /* Max number of processes to wake up */
  416. ){
  417. register struct proc *pp;
  418. struct proc *pnext;
  419. unsigned int hashval;
  420. int cnt = 0;
  421. Ksig.ksigs++;
  422. if(Stkchk)
  423. chkstk();
  424. if(event == NULL){
  425. Ksig.ksignops++;
  426. return; /* Null events are invalid */
  427. }
  428. /* n == 0 means "signal everybody waiting for this event" */
  429. if(n == 0)
  430. n = 65535;
  431. hashval = phash(event);
  432. for(pp = Waittab[hashval];n != 0 && pp != NULL;pp = pnext){
  433. pnext = pp->next;
  434. if(pp->event == event){
  435. #ifdef PROCTRACE
  436. logmsg(-1,"ksignal(%p,%u) wake %p [%s]",event,n,
  437.  pp,pp->name);
  438. #endif
  439. delproc(pp);
  440. pp->flags.waiting = 0;
  441. pp->retval = 0;
  442. pp->event = NULL;
  443. addproc(pp);
  444. n--;
  445. cnt++;
  446. }
  447. }
  448. for(pp = Susptab;n != 0 && pp != NULL;pp = pnext){
  449. pnext = pp->next;
  450. if(pp->event == event){
  451. #ifdef PROCTRACE
  452. logmsg(-1,"ksignal(%p,%u) wake %p [%s]",event,n,
  453.  pp,pp->name);
  454. #endif /* PROCTRACE */
  455. delproc(pp);
  456. pp->flags.waiting = 0;
  457. pp->event = 0;
  458. pp->retval = 0;
  459. addproc(pp);
  460. n--;
  461. cnt++;
  462. }
  463. }
  464. if(cnt == 0)
  465. Ksig.ksignops++;
  466. else
  467. Ksig.ksigwakes += cnt;
  468. }
  469. /* Rename a process */
  470. void
  471. chname(struct proc *pp,char *newname)
  472. {
  473. free(pp->name);
  474. pp->name = strdup(newname);
  475. }
  476. /* Remove a process entry from the appropriate table */
  477. static void
  478. delproc(struct proc *entry) /* Pointer to entry */
  479. {
  480. if(entry == NULL)
  481. return;
  482. if(entry->next != NULL)
  483. entry->next->prev = entry->prev;
  484. if(entry->prev != NULL){
  485. entry->prev->next = entry->next;
  486. } else {
  487. if(entry->flags.suspend){
  488. Susptab = entry->next;
  489. } else if(entry->flags.waiting){
  490. Waittab[phash(entry->event)] = entry->next;
  491. } else { /* Ready */
  492. Rdytab = entry->next;
  493. }
  494. }
  495. }
  496. /* Append proc entry to end of appropriate list */
  497. static void
  498. addproc(struct proc *entry) /* Pointer to entry */
  499. {
  500. register struct proc *pp;
  501. struct proc **head;
  502. if(entry == NULL)
  503. return;
  504. if(entry->flags.suspend){
  505. head = &Susptab;
  506. } else if(entry->flags.waiting){
  507. head = &Waittab[phash(entry->event)];
  508. } else { /* Ready */
  509. head = &Rdytab;
  510. }
  511. entry->next = NULL;
  512. if(*head == NULL){
  513. /* Empty list, stick at beginning */
  514. entry->prev = NULL;
  515. *head = entry;
  516. } else {
  517. /* Find last entry on list */
  518. for(pp = *head;pp->next != NULL;pp = pp->next)
  519. ;
  520. pp->next = entry;
  521. entry->prev = pp;
  522. }
  523. }