home *** CD-ROM | disk | FTP | other *** search
- /* Non pre-empting synchronization kernel, machine-independent portion
- * Copyright 1991 Phil Karn, KA9Q
- */
-
- #define SUSPEND_PROC 1
-
- #if defined(PROCLOG) || defined(PROCTRACE)
- #include <stdio.h>
- #endif
- #include <dos.h>
- #include <setjmp.h>
- #include "global.h"
- #include "mbuf.h"
- #include "proc.h"
- #include "timer.h"
- #include "socket.h"
- #include "daemon.h"
- #include "hardware.h"
-
- #ifdef PROCLOG
- FILE *proclog;
- FILE *proctrace;
- #endif
- int Stkchk = 1;
- struct proc *Curproc; /* Currently running process */
- struct proc *Rdytab; /* Processes ready to run (not including curproc) */
- struct proc *Waittab[PHASH]; /* Waiting process list */
- struct proc *Susptab; /* Suspended processes */
- static struct mbuf *Killq;
-
- static void addproc __ARGS((struct proc *entry));
- static void delproc __ARGS((struct proc *entry));
-
- /* Create a process descriptor for the main function. Must be actually
- * called from the main function!
- * Note that standard I/O is NOT set up here.
- */
- struct proc *
- mainproc(name)
- char *name;
- {
- register struct proc *pp;
-
- /* Create process descriptor */
- pp = (struct proc *)callocw(1,sizeof(struct proc));
-
- /* Create name */
- pp->name = strdup(name);
- #ifndef AMIGA
- pp->stksize = 0;
- #else
- init_psetup(pp);
- #endif
- /* Make current */
- pp->state = READY;
- Curproc = pp;
-
- #ifdef PROCLOG
- proclog = fopen("proclog",APPEND_TEXT);
- proctrace = fopen("proctrace",APPEND_TEXT);
- #endif
- return pp;
- }
- /* Create a new, ready process and return pointer to descriptor.
- * The general registers are not initialized, but optional args are pushed
- * on the stack so they can be seen by a C function.
- */
- struct proc *
- newproc(name,stksize,pc,iarg,parg1,parg2,freeargs)
- char *name; /* Arbitrary user-assigned name string */
- unsigned int stksize; /* Stack size in words to allocate */
- void (*pc)(); /* Initial execution address */
- int iarg; /* Integer argument (argc) */
- void *parg1; /* Generic pointer argument #1 (argv) */
- void *parg2; /* Generic pointer argument #2 (session ptr) */
- int freeargs; /* If set, free arg list on parg1 at termination */
- {
- register struct proc *pp;
- int i;
-
- if(Stkchk)
- chkstk();
-
- /* Create process descriptor */
- pp = (struct proc *)callocw(1,sizeof(struct proc));
-
- /* Create name */
- pp->name = strdup(name);
-
- /* Allocate stack */
- #ifdef AMIGA
- stksize += 2000; /* DOS overhead */
- #endif
- pp->stksize = stksize;
- if((pp->stack = (int16 *)malloc(sizeof(int16)*stksize)) == NULL){
- free(pp->name);
- free((char *)pp);
- return NULLPROC;
- }
- /* Initialize stack for high-water check */
- for(i=0;i<stksize;i++)
- pp->stack[i] = STACKPAT;
-
- /* Do machine-dependent initialization of stack */
- psetup(pp,iarg,parg1,parg2,pc);
-
- pp->freeargs = freeargs;
- pp->iarg = iarg;
- pp->parg1 = parg1;
- pp->parg2 = parg2;
-
- /* Inherit creator's input and output sockets */
- usesock(Curproc->input);
- pp->input = Curproc->input;
- usesock(Curproc->output);
- pp->output = Curproc->output;
-
- /* Add to ready process table */
- pp->state = READY;
- addproc(pp);
- return pp;
- }
-
- /* Free resources allocated to specified process. If a process wants to kill
- * itself, the reaper is called to do the dirty work. This avoids some
- * messy situations that would otherwise occur, like freeing your own stack.
- */
- void
- killproc(pp)
- register struct proc *pp;
- {
- char **argv;
-
- if(pp == NULLPROC)
- return;
- /* Don't check the stack here! Will cause infinite recursion if
- * called from a stack error
- */
-
- if(pp == Curproc)
- killself(); /* Doesn't return */
-
- /* Close any open sockets */
- freesock(pp);
-
- close_s(pp->input);
- close_s(pp->output);
-
- /* Stop alarm clock in case it's running */
- stop_timer(&pp->alarm);
-
- /* Alert everyone waiting for this proc to die */
- psignal(pp,0);
-
- /* Remove from appropriate table */
- delproc(pp);
-
- #ifdef PROCLOG
- fprintf(proclog,"id %lx name %s stack %u/%u\n",ptol(pp),
- pp->name,stkutil(pp),pp->stksize);
- fclose(proclog);
- proclog = fopen("proclog",APPEND_TEXT);
- proctrace = fopen("proctrace",APPEND_TEXT);
- #endif
- /* Free allocated memory resources */
- if(pp->freeargs){
- argv = pp->parg1;
- while(pp->iarg-- != 0)
- free(*argv++);
- free(pp->parg1);
- }
- free(pp->name);
- free(pp->stack);
- free(pp->outbuf);
- free((char *)pp);
- }
- /* Terminate current process by sending a request to the killer process.
- * Automatically called when a process function returns. Does not return.
- */
- void
- killself()
- {
- register struct mbuf *bp;
-
- if(Curproc != NULLPROC){
- bp = pushdown(NULLBUF,sizeof(Curproc));
- memcpy(bp->data,(char *)&Curproc,sizeof(Curproc));
- enqueue(&Killq,bp);
- }
- /* "Wait for me; I will be merciful and quick." */
- for(;;)
- pwait(NULL);
- }
- /* Process used by processes that want to kill themselves */
- void
- killer(i,v1,v2)
- int i;
- void *v1;
- void *v2;
- {
- struct proc *pp;
- struct mbuf *bp;
-
- for(;;){
- while(Killq == NULLBUF)
- pwait(&Killq);
- bp = dequeue(&Killq);
- pullup(&bp,(char *)&pp,sizeof(pp));
- free_p(bp);
- if(pp != Curproc) /* We're immortal */
- killproc(pp);
- }
- }
-
- #ifdef SUSPEND_PROC
- /* Inhibit a process from running */
- void
- suspend(pp)
- struct proc *pp;
- {
- if(pp == NULLPROC)
- return;
- if(pp != Curproc)
- delproc(pp); /* Running process isn't on any list */
- pp->state |= SUSPEND;
- if(pp != Curproc)
- addproc(pp); /* pwait will do it for us */
- else
- pwait(NULL);
- }
- /* Restart suspended process */
- void
- resume(pp)
- struct proc *pp;
- {
- if(pp == NULLPROC)
- return;
- delproc(pp); /* Can't be Curproc! */
- pp->state &= ~SUSPEND;
- addproc(pp);
- }
- #endif /* SUSPEND_PROC */
-
- /* Wakeup waiting process, regardless of event it's waiting for. The process
- * will see a return value of "val" from its pwait() call.
- */
- void
- alert(pp,val)
- struct proc *pp;
- int val;
- {
- if(pp == NULLPROC)
- return;
- #ifdef notdef
- if((pp->state & WAITING) == 0)
- return;
- #endif
- #ifdef PROCTRACE
- printf("alert(%lx,%u) [%s]\n",ptol(pp),val,pp->name);
- fflush(stdout);
- #endif
- if(pp != Curproc)
- delproc(pp);
- pp->state &= ~WAITING;
- pp->retval = val;
- pp->event = 0;
- if(pp != Curproc)
- addproc(pp);
- }
-
- /* Post a wait on a specified event and give up the CPU until it happens. The
- * null event is special: it means "I don't want to block on an event, but let
- * somebody else run for a while". It can also mean that the present process
- * is terminating; in this case the wait never returns.
- *
- * Pwait() returns 0 if the event was signaled; otherwise it returns the
- * arg in an alert() call. Pwait must not be called from interrupt level.
- *
- * Note that pwait can run with interrupts enabled even though it examines
- * a few global variables that can be modified by psignal at interrupt time.
- * These *seem* safe.
- */
- int
- pwait(event)
- void *event;
- {
- register struct proc *oldproc;
- int tmp;
-
- if(Curproc != NULLPROC){ /* If process isn't terminating */
- if(Stkchk)
- chkstk();
-
- if(event == NULL){
- /* Special case; just give up the processor.
- *
- * Optimization: if nothing else is ready, just return.
- */
- if(Rdytab == NULLPROC){
- return 0;
- }
- } else {
- /* Post a wait for the specified event */
- Curproc->event = event;
- Curproc->state = WAITING;
- }
- addproc(Curproc);
- }
- /* Look for a ready process and run it. If there are none,
- * loop or halt until an interrupt makes something ready.
- */
- while(Rdytab == NULLPROC){
- /* Give system back to upper-level multitasker, if any.
- * Note that this function enables interrupts internally
- * to prevent deadlock, but it restores our state
- * before returning.
- */
- kbint(); /***/
- giveup();
- }
- /* Remove first entry from ready list */
- oldproc = Curproc;
- Curproc = Rdytab;
- delproc(Curproc);
-
- /* Now do the context switch.
- * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
- *
- * If the old process has gone away, simply load the new process's
- * environment. Otherwise, save the current process's state. Then if
- * this is still the old process, load the new environment. Since the
- * new task will "think" it's returning from the setjmp() with a return
- * value of 1, the comparison with 0 will bypass the longjmp(), which
- * would otherwise cause an infinite loop.
- */
- #ifdef PROCTRACE
- if(strcmp(oldproc->name,Curproc->name) != 0){
- printf("-> %s(%d)\n",Curproc->name,!!Curproc->i_state);
- fflush(stdout);
- }
- #endif
- /* Note use of comma operator to save old interrupt state only if
- * oldproc is non-null
- */
- if(oldproc == NULLPROC
- || (oldproc->i_state = istate(), setjmp(oldproc->env) == 0)){
- /* We're still running in the old task; load new task context.
- * The interrupt state is restored here in case longjmp
- * doesn't do it (e.g., systems other than Turbo-C).
- */
- restore(Curproc->i_state);
- longjmp(Curproc->env,1);
- }
- /* At this point, we're running in the newly dispatched task */
- tmp = Curproc->retval;
- Curproc->retval = 0;
-
- /* Also restore the true interrupt state here, in case the longjmp
- * DOES restore the interrupt state saved at the time of the setjmp().
- * This is the case with Turbo-C's setjmp/longjmp.
- */
- restore(Curproc->i_state);
- return tmp;
- }
-
- /* Make ready the first 'n' processes waiting for a given event. The ready
- * processes will see a return value of 0 from pwait(). Note that they don't
- * actually get control until we explicitly give up the CPU ourselves through
- * a pwait(). Psignal may be called from interrupt level. It returns the
- * number of processes that were woken up.
- */
- int
- psignal(event,n)
- void *event; /* Event to signal */
- int n; /* Max number of processes to wake up */
- {
- register struct proc *pp;
- struct proc *pnext;
- int i_state;
- unsigned int hashval;
- int cnt = 0;
-
- if(Stkchk)
- chkstk();
-
- if(event == NULL)
- return 0; /* Null events are invalid */
-
- /* n = 0 means "signal everybody waiting for this event" */
- if(n == 0)
- n = 65535;
-
- hashval = phash(event);
- i_state = dirps();
- for(pp = Waittab[hashval];n != 0 && pp != NULLPROC;pp = pnext){
- pnext = pp->next;
- if(pp->event == event){
- #ifdef PROCTRACE
- if(i_state){
- printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
- ptol(pp),pp->name);
- fflush(stdout);
- }
- #endif
- delproc(pp);
- pp->state &= ~WAITING;
- pp->retval = 0;
- pp->event = NULL;
- addproc(pp);
- n--;
- cnt++;
- }
- }
- #ifdef SUSPEND_PROC
- for(pp = Susptab;n != 0 && pp != NULLPROC;pp = pnext){
- pnext = pp->next;
- if(pp->event == event){
- #ifdef PROCTRACE
- if(i_state){
- printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
- ptol(pp),pp->name);
- fflush(stdout);
- }
- #endif /* PROCTRACE */
- delproc(pp);
- pp->state &= ~WAITING;
- pp->event = 0;
- pp->retval = 0;
- addproc(pp);
- n--;
- cnt++;
- }
- }
- #endif /* SUSPEND_PROC */
- restore(i_state);
- return cnt;
- }
-
- /* Rename a process */
- void
- chname(pp,newname)
- struct proc *pp;
- char *newname;
- {
- free(pp->name);
- pp->name = strdup(newname);
- }
- /* Remove a process entry from the appropriate table */
- static void
- delproc(entry)
- register struct proc *entry; /* Pointer to entry */
- {
- int i_state;
-
- if(entry == NULLPROC)
- return;
-
- i_state = dirps();
- if(entry->next != NULLPROC)
- entry->next->prev = entry->prev;
- if(entry->prev != NULLPROC){
- entry->prev->next = entry->next;
- } else {
- switch(entry->state){
- case READY:
- Rdytab = entry->next;
- break;
- case WAITING:
- Waittab[phash(entry->event)] = entry->next;
- break;
- #ifdef SUSPEND_PROC
- case SUSPEND:
- case SUSPEND|WAITING:
- Susptab = entry->next;
- break;
- #endif
- }
- }
- restore(i_state);
- }
- /* Append proc entry to end of appropriate list */
- static void
- addproc(entry)
- register struct proc *entry; /* Pointer to entry */
- {
- register struct proc *pp;
- struct proc **head;
- int i_state;
-
- if(entry == NULLPROC)
- return;
-
- switch(entry->state){
- case READY:
- head = &Rdytab;
- break;
- case WAITING:
- head = &Waittab[phash(entry->event)];
- break;
- #ifdef SUSPEND_PROC
- case SUSPEND:
- case SUSPEND|WAITING:
- head = &Susptab;
- break;
- #endif
- }
- entry->next = NULLPROC;
- i_state = dirps();
- if(*head == NULLPROC){
- /* Empty list, stick at beginning */
- entry->prev = NULLPROC;
- *head = entry;
- } else {
- /* Find last entry on list */
- for(pp = *head;pp->next != NULLPROC;pp = pp->next)
- ;
- pp->next = entry;
- entry->prev = pp;
- }
- restore(i_state);
- }
-