/* Little Smalltalk process manager dennis a. vadner and michael t. benhase, 11/84 modified by timothy a. budd 4/85 */ /* The source code for the Little Smalltalk System may be freely copied provided that the source of all files is acknowledged and that this condition is copied with each file. The Little Smalltalk System is distributed without responsibility for the performance of the program and without any guarantee of maintenance. All questions concerning Little Smalltalk should be addressed to: Professor Tim Budd Department of Computer Science The University of Arizona Tucson, Arizona 85721 USA */ # include "object.h" # include #undef SIGS # ifdef SIGS # include # endif # ifdef SETJUMP # include # endif # include "drive.h" # include "interp.h" # include "process.h" extern int test_driver(); /* routine to test for user keystrokes*/ static process *currentProcess; /* current process */ static process *fr_process = 0; /* process memory free list */ int atomcnt = 0; /* atomic action flag */ process *runningProcess; /* currently running process, may be different from currentProcess during process termination */ # define PROCINITMAX 6 static process prcinit[PROCINITMAX]; /* initial process free list */ /* init_process - initialize the process module */ init_process () { process *p; int i; /* first make the initial process free list */ for (p = prcinit, i = 0; i < PROCINITMAX; i++, p++) { p->next = fr_process; fr_process = p; } /* make the process associated with the driver */ currentProcess = cr_process(o_drive); assign(currentProcess->next, currentProcess); assign(currentProcess->prev, currentProcess); currentProcess->p_state = ACTIVE; } /* cr_process - create a new process with the given interpreter */ process *cr_process (anInterpreter) interpreter *anInterpreter; { process *new; if (fr_process) { new = (process *) fr_process; fr_process = fr_process->next; } else new = structalloc(process); new->p_ref_count = 0; new->p_size = PROCSIZE; sassign(new->interp, anInterpreter); new->p_state = SUSPENDED; sassign(new->next, (process *) o_nil); sassign(new->prev, (process *) o_nil); return(new); } /* free_process - return an unused process to free list */ free_process (aProcess) process *aProcess; { obj_dec((object *) aProcess->interp); obj_dec((object *) aProcess->next); obj_dec((object *) aProcess->prev); aProcess->p_state = TERMINATED; aProcess->next = fr_process; fr_process = aProcess; } /* flush_processes - flush out any remaining process from queue */ flush_processes () { while (currentProcess != currentProcess->next) remove_process(currentProcess); /* prev link and next link should point to the same place now. In order to avoid having memory recovered while we are manipulating pointers, we increment reference count, then change pointers, then decrement reference counts */ obj_inc((object *) currentProcess); safeassign(currentProcess->prev, (process *) o_nil); safeassign(currentProcess->next, (process *) o_nil); obj_dec((object *) currentProcess); } /* link_to_process - change the interpreter for the current process */ link_to_process (anInterpreter) interpreter *anInterpreter; { object *temp; safeassign(runningProcess->interp, anInterpreter); } /* remove_process - remove a process from process queue */ static remove_process (aProcess) process *aProcess; { if (aProcess == aProcess->next) cant_happen(15); /* removing last active process */ /* currentProcess must always point to a process that is on the process queue, make sure this remains true */ if (aProcess == currentProcess) currentProcess = currentProcess->prev; /* In order to avoid having memory recovered while we are changing pointers, we increment the reference counts on both processes, change pointers, then decrement reference counts */ obj_inc((object *) currentProcess); obj_inc((object *) aProcess); safeassign(aProcess->next->prev, aProcess->prev); safeassign(aProcess->prev->next, aProcess->next); obj_dec((object *) currentProcess); obj_dec((object *) aProcess); } /* schedule_process - add a new process to the process queue */ static schedule_process (aProcess) process *aProcess; { safeassign(aProcess->next, currentProcess); safeassign(aProcess->prev, currentProcess->prev); safeassign(aProcess->prev->next, aProcess); safeassign(currentProcess->prev, aProcess); } /* set_state - set the state on a process, which may involve inserting or removing it from the process queue */ int set_state (aProcess, state) process *aProcess; int state; { switch (state) { case BLOCKED: case SUSPENDED: case TERMINATED: if (aProcess->p_state == ACTIVE) remove_process(aProcess); aProcess->p_state |= state; break; case READY: case UNBLOCKED: if ((aProcess->p_state ^ state) == ~ACTIVE) schedule_process(aProcess); aProcess->p_state &= state; break; case CUR_STATE: break; default: cant_happen(17); } return(aProcess->p_state); } # ifdef SETJUMP static jmp_buf intenv; # endif /* brkfun - what to do on a break key */ brkfun() { static int warn = 1; # ifndef SETJUMP exit(1); # endif if (warn) { fprintf(stderr,"warning: recovery from interrupt may cause\n"); fprintf(stderr,"reference counts to be incorrect, and\n"); fprintf(stderr,"some memory to be inaccessible\n"); warn = 0; } # ifdef SETJUMP longjmp(intenv, 1); # endif } /* start_execution - main execution loop */ start_execution () { interpreter *presentInterpreter; atomcnt = 0; # ifdef SIGS /* trap user interrupt signals and recover */ signal(SIGINT, brkfun); # endif # ifdef SETJUMP if (setjmp(intenv)) { atomcnt = 0; link_to_process(o_drive); } # endif while (1) { /* unless it is an atomic action get the next process */ if (! atomcnt) runningProcess = currentProcess = currentProcess->next; if (! is_driver(runningProcess->interp)) { sassign(presentInterpreter, runningProcess->interp); resume(presentInterpreter); obj_dec((object *) presentInterpreter); } else if (! test_driver((currentProcess == currentProcess->next) || (atomcnt > 0))) break; } }