home *** CD-ROM | disk | FTP | other *** search
- /*
- Copyright 1990,1991,1992 Eric R. Smith.
- Copyright 1992,1993 Atari Corporation.
- All rights reserved.
- */
-
- /* routines for handling processes */
-
- #include "mint.h"
- #include "xbra.h"
-
- static void do_wakeup_things P_((void));
-
- extern short proc_clock;
-
- /* global process variables */
- PROC *proclist; /* list of all active processes */
- PROC *curproc; /* current process */
- PROC *rootproc; /* pid 0 -- MiNT itself */
- PROC *sys_q[NUM_QUEUES];
-
- short time_slice = 2; /* default; actual value comes from mint.cnf */
-
- #if 0
- #define TIME_SLICE 2 /* number of 20ms ticks before process is
- pre-empted */
- #else
- #define TIME_SLICE time_slice
- #endif
-
- /* macro for calculating number of missed time slices, based on a
- * process' priority
- */
- #define SLICES(pri) (((pri) >= 0) ? 0 : -(pri))
-
- extern FILESYS bios_filesys;
-
- /*
- * get a new process struct
- */
-
- PROC *
- new_proc()
- {
- PROC *p;
- void *pt;
-
- pt = kmalloc(page_table_size + 16);
- if (!pt) return 0;
-
- p = (PROC *)kmalloc(SIZEOF(PROC));
- if (!p) {
- kfree(pt);
- return 0;
- }
- /* page tables must be on 16 byte boundaries, so we
- * round off by 16 for that; however, we will want to
- * kfree that memory at some point, so we squirrel
- * away the original address for later use
- */
- p->page_table = ROUND16(pt);
- p->pt_mem = pt;
- return p;
- }
-
- /*
- * dispose of an old proc
- */
-
- void
- dispose_proc(p)
- PROC *p;
- {
- TRACELOW(("dispose_proc"));
- kfree(p->pt_mem);
- kfree(p);
- }
-
- /*
- * create a new process that is (practically) a duplicate of the
- * current one
- */
-
- PROC *
- fork_proc()
- {
- PROC *p;
- int i;
- FILEPTR *f;
- long_desc *pthold;
- void *ptmemhold;
-
- if ((p = new_proc()) == 0) {
- nomem:
- DEBUG(("fork_proc: insufficient memory"));
- mint_errno = ENSMEM; return 0;
- }
-
- /* child shares most things with parent, but hold on to page table ptr */
- pthold = p->page_table;
- ptmemhold = p->pt_mem;
- *p = *curproc;
- p->page_table = pthold;
- p->pt_mem = ptmemhold;
-
- /* these things are not inherited */
- p->ppid = curproc->pid;
- p->pid = newpid();
- p->sigpending = 0;
- p->nsigs = 0;
- p->sysstack = (long)(p->stack + STKSIZE - 12);
- p->ctxt[CURRENT].ssp = p->sysstack;
- p->ctxt[SYSCALL].ssp = (long)(p->stack + ISTKSIZE);
- p->alarmtim = 0;
- p->curpri = p->pri;
- p->slices = SLICES(p->pri);
- p->starttime = timestamp;
- p->startdate = datestamp;
-
- ((long *)p->sysstack)[1] = FRAME_MAGIC;
- ((long *)p->sysstack)[2] = 0;
- ((long *)p->sysstack)[3] = 0;
-
- p->usrtime = p->systime = p->chldstime = p->chldutime = 0;
-
- /* allocate space for memory regions: do it here so that we can fail
- * before we duplicate anything else. The memory regions are
- * actually copied later
- */
- p->mem = (MEMREGION **) kmalloc(p->num_reg * SIZEOF(MEMREGION *));
- if (!p->mem) {
- dispose_proc(p);
- goto nomem;
- }
- p->addr = (virtaddr *)kmalloc(p->num_reg * SIZEOF(virtaddr));
- if (!p->addr) {
- kfree(p->mem);
- dispose_proc(p);
- goto nomem;
- }
-
- /* copy open handles */
- for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
- if ((f = p->handle[i]) != 0) {
- if (f->flags & O_NOINHERIT)
- /* oops, we didn't really want to copy this handle */
- p->handle[i] = 0;
- else
- f->links++;
- }
- }
-
- /* copy root and current directories */
- for (i = 0; i < NUM_DRIVES; i++) {
- dup_cookie(&p->root[i], &curproc->root[i]);
- dup_cookie(&p->curdir[i], &curproc->curdir[i]);
- }
-
- /* jr: copy ploadinfo */
- strcpy (p->cmdlin, curproc->cmdlin);
- strcpy (p->fname, curproc->fname);
-
- /* clear directory search info */
- zero((char *)p->srchdta, NUM_SEARCH * SIZEOF(DTABUF *));
- zero((char *)p->srchdir, SIZEOF(p->srchdir));
- p->searches = 0;
-
- /* copy memory */
- for (i = 0; i < curproc->num_reg; i++) {
- p->mem[i] = curproc->mem[i];
- if (p->mem[i] != 0)
- p->mem[i]->links++;
- p->addr[i] = curproc->addr[i];
- }
-
- /* now that memory ownership is copied, fill in page table */
- init_page_table(p);
-
- /* child isn't traced */
- p->ptracer = 0;
- p->ptraceflags = 0;
-
- p->starttime = Tgettime();
- p->startdate = Tgetdate();
-
- p->q_next = 0;
- p->wait_q = 0;
- p->gl_next = proclist;
- proclist = p; /* hook into the process list */
- return p;
- }
-
- /*
- * initialize the process table
- */
-
- void
- init_proc()
- {
- int i;
- FILESYS *fs;
- fcookie dir;
- long_desc *pthold;
- void *ptmemhold;
-
- rootproc = curproc = new_proc();
- assert(curproc);
-
- pthold = curproc->page_table;
- ptmemhold = curproc->pt_mem;
- zero((char *)curproc, (long)sizeof(PROC));
- curproc->page_table = pthold;
- curproc->pt_mem = ptmemhold;
-
- curproc->ppid = -1; /* no parent */
- curproc->domain = DOM_TOS; /* TOS domain */
- curproc->sysstack = (long) (curproc->stack+STKSIZE-12);
- curproc->magic = CTXT_MAGIC;
- curproc->memflags = F_PROT_S; /* default prot mode: super-only */
- ((long *)curproc->sysstack)[1] = FRAME_MAGIC;
- ((long *)curproc->sysstack)[2] = 0;
- ((long *)curproc->sysstack)[3] = 0;
-
- /* NOTE: in main.c this could be changed, later */
- curproc->base = _base;
-
- strcpy(curproc->name, "MiNT");
-
- /* get some memory */
- curproc->mem = (MEMREGION **)kmalloc(NUM_REGIONS*SIZEOF(MEMREGION *));
- curproc->addr = (virtaddr *)kmalloc(NUM_REGIONS*SIZEOF(virtaddr));
- assert(curproc->mem && curproc->addr);
-
- /* make sure it's filled with zeros */
- zero((char *)curproc->addr, NUM_REGIONS * SIZEOF(virtaddr));
- zero((char *)curproc->mem, NUM_REGIONS * SIZEOF(MEMREGION *));
- curproc->num_reg = NUM_REGIONS;
-
- /* get root and current directories for all drives */
- for (i = 0; i < NUM_DRIVES; i++) {
- if ((fs = drives[i]) != 0 && (*fs->root)(i, &dir) == E_OK) {
- dup_cookie(&curproc->curdir[i], &dir);
- curproc->root[i] = dir;
- } else {
- curproc->root[i].fs = curproc->curdir[i].fs = 0;
- curproc->root[i].dev = curproc->curdir[i].dev = i;
- }
- }
-
- init_page_table(curproc);
-
- /* Set the correct drive. The current directory we
- * set later, after all file systems have been loaded.
- */
-
- curproc->curdrv = Dgetdrv();
- proclist = curproc;
-
- curproc->umask = 0;
-
- /*
- * some more protection against job control; unless these signals are
- * re-activated by a shell that knows about job control, they'll have
- * no effect
- */
- curproc->sighandle[SIGTTIN] = curproc->sighandle[SIGTTOU] =
- curproc->sighandle[SIGTSTP] = SIG_IGN;
-
- /* set up some more per-process variables */
- curproc->starttime = Tgettime();
- curproc->startdate = Tgetdate();
- if (has_bconmap)
- curproc->bconmap = curbconmap;
- else
- curproc->bconmap = 1;
-
- curproc->logbase = (void *)Logbase();
- curproc->criticerr = *((long ARGS_ON_STACK (**) P_((long)))0x404L);
- }
-
- /*
- * reset all process priorities to their base level
- * called once per second, so that cpu hogs can get _some_ time
- * slices :-).
- */
-
- void
- reset_priorities()
- {
- PROC *p;
-
- for (p = proclist; p; p = p->gl_next) {
- p->curpri = p->pri;
- p->slices = SLICES(p->curpri);
- }
- }
-
- /*
- * more priority code stuff:
- * run_next(p, slices): schedule process "p" to run next, with "slices"
- * initial time slices; "p" does not actually start running until
- * the next context switch
- * fresh_slices(slices): give the current process "slices" more slices in
- * which to run
- */
-
- void
- run_next(p, slices)
- PROC *p;
- int slices; /* BUG: currently ignored */
- {
- UNUSED(slices);
-
- p->slices = 0;
- p->curpri = MAX_NICE;
- p->wait_q = READY_Q;
- p->q_next = sys_q[READY_Q];
- sys_q[READY_Q] = p;
- }
-
- void
- fresh_slices(slices)
- int slices;
- {
- curproc->slices = 0;
- curproc->curpri = MAX_NICE+1;
- proc_clock = slices;
- }
-
- /*
- * add a process to a wait (or ready) queue.
- *
- * processes go onto a queue in first in-first out order
- */
-
- void
- add_q(que, proc)
- int que;
- PROC *proc;
- {
- PROC *q, **lastq;
-
- /* "proc" should not already be on a list */
- assert(proc->wait_q == 0);
- assert(proc->q_next == 0);
-
- lastq = &sys_q[que];
- q = *lastq;
- while(q) {
- lastq = &q->q_next;
- q = *lastq;
- }
- *lastq = proc;
- proc->wait_q = que;
- if (que != READY_Q) {
- proc->curpri = proc->pri; /* reward the process */
- proc->slices = SLICES(proc->curpri);
- }
- }
-
- /*
- * remove a process from a queue
- */
-
- void
- rm_q(que, proc)
- int que;
- PROC *proc;
- {
- PROC *q;
- PROC *old = 0;
-
- assert(proc->wait_q == que);
-
- q = sys_q[que];
- while (q && q != proc) {
- old = q;
- q = q->q_next;
- }
- if (q == 0)
- FATAL("rm_q: unable to remove process from queue");
-
- if (old)
- old->q_next = proc->q_next;
- else
- sys_q[que] = proc->q_next;
-
- proc->wait_q = 0;
- proc->q_next = 0;
- }
-
- /*
- * preempt(): called by the vbl routine and/or the trap handlers when
- * they detect that a process has exceeded its time slice and hasn't
- * yielded gracefully. For now, it just does sleep(READY_Q); later,
- * we might want to keep track of statistics or something.
- */
-
- void ARGS_ON_STACK
- preempt()
- {
- extern short bconbsiz; /* in bios.c */
-
- if (bconbsiz)
- (void)bflush();
- else {
- /* punish the pre-empted process */
- if (curproc->curpri >= MIN_NICE)
- curproc->curpri -= 1;
- }
- sleep(READY_Q, curproc->wait_cond);
- }
-
- /*
- * sleep(que, cond): put the current process on the given queue, then switch
- * contexts. Before a new process runs, give it a fresh time slice. "cond"
- * is the condition for which the process is waiting, and is placed in
- * curproc->wait_cond
- */
-
- static void
- do_wakeup_things()
- {
- /*
- * check for stack underflow, just in case
- */
- auto int foo;
- PROC *p;
-
- p = curproc;
-
- if ( p->pid != 0 &&
- ((long)&foo) < (long)p->stack + ISTKSIZE + 512 ) {
- ALERT("stack underflow");
- handle_sig(SIGBUS);
- }
-
- /* see if process' time limit has been exceeded */
-
- if (p->maxcpu) {
- if (p->maxcpu <= p->systime + p->usrtime) {
- DEBUG(("cpu limit exceeded"));
- raise(SIGXCPU);
- }
- }
-
- /*
- * check for alarms and similar time out stuff (see timeout.c)
- */
-
- checkalarms();
- if (p->sigpending)
- check_sigs(); /* check for signals */
-
- proc_clock = TIME_SLICE; /* get a fresh time slice */
- p->slices = SLICES(p->curpri);
- }
-
- /*
- * sleep: returns 1 if no signals have happened since our last sleep, 0
- * if some have
- */
-
- int ARGS_ON_STACK
- sleep(que, cond)
- int que;
- long cond;
- {
- PROC *p;
- short sr;
- ulong onsigs = curproc->nsigs;
- extern short kintr; /* in bios.c */
- #ifndef MULTITOS
- #ifdef FASTTEXT
- extern int hardscroll; /* in fasttext.c */
- #endif
- #endif
-
- /*
- * if there have been keyboard interrupts since our last sleep, check for
- * special keys like CTRL-ALT-Fx
- */
-
- if (kintr) {
- (void)checkkeys();
- kintr = 0;
- }
-
- if (que == READY_Q && !sys_q[READY_Q]) {
- /* we're just going to wake up again right away! */
- do_wakeup_things();
- return (onsigs != curproc->nsigs);
- }
-
- sr = spl7();
-
- add_q(que, curproc);
- curproc->wait_cond = cond;
-
- if (!sys_q[READY_Q]) {
- /* hmm, no-one is ready to run. might be a deadlock, might not.
- * first, try waking up any napping processes; if that doesn't work,
- * run the root process, just so we have someone to charge time
- * to.
- */
- wake(SELECT_Q, (long)nap);
- if (!sys_q[READY_Q]) {
- p = rootproc; /* pid 0 */
- rm_q(p->wait_q, p);
- add_q(READY_Q, p);
- }
- }
-
- /*
- * Walk through the ready list, to find what process should run next.
- * Lower priority processes don't get to run every time through this
- * loop; if "p->slices" is positive, it's the number of times that they
- * will have to miss a turn before getting to run again
- */
-
- /*
- * Loop structure:
- * while (we haven't picked anybody) {
- * for (each process) {
- * if (sleeping off a penalty) {
- * decrement penalty counter
- * }
- * else {
- * pick this one and break out of both loops
- * }
- * }
- * }
- */
- p = 0;
-
- while (!p) {
- for (p = sys_q[READY_Q]; p; p = p->q_next) {
- if (p->slices > 0)
- p->slices--;
- else
- break;
- }
- }
-
- /* p is our victim */
-
- rm_q(READY_Q, p);
-
- spl(sr);
-
- if (save_context(&(curproc->ctxt[CURRENT]))) {
- /*
- * restore per-process variables here
- */
- #ifndef MULTITOS
- #ifdef FASTTEXT
- if (!hardscroll)
- #endif
- *((void **)0x44eL) = curproc->logbase;
- #endif
- do_wakeup_things();
- return (onsigs != curproc->nsigs);
- }
- /*
- * save per-process variables here
- */
- #ifndef MULTITOS
- #ifdef FASTTEXT
- if (!hardscroll)
- #endif
- curproc->logbase = *((void **)0x44eL);
- #endif
- curproc->ctxt[CURRENT].regs[0] = 1;
- curproc = p;
- proc_clock = TIME_SLICE; /* fresh time */
- if ((p->ctxt[CURRENT].sr & 0x2000) == 0) { /* user mode? */
- leave_kernel();
- }
- assert(p->magic == CTXT_MAGIC);
- change_context(&(p->ctxt[CURRENT]));
- /* not reached */
- return 0;
- }
-
- /*
- * wake(que, cond): wake up all processes on the given queue that are waiting
- * for the indicated condition
- */
-
- void ARGS_ON_STACK
- wake(que, cond)
- int que;
- long cond;
- {
- PROC *p;
-
- if (que == READY_Q) {
- ALERT("wake: why wake up ready processes??");
- return;
- }
- top:
- for(p = sys_q[que]; p; p = p->q_next) {
- if (p->wait_cond == cond) {
- short s = spl7();
- rm_q(que, p);
- add_q(READY_Q, p);
- spl(s);
- goto top;
- }
- }
- }
-
- /*
- * wakeselect(p): wake process p from a select() system call
- * may be called by an interrupt handler or whatever
- */
-
- void ARGS_ON_STACK
- wakeselect(param)
- long param;
- {
- PROC *p = (PROC *)param;
- short s;
-
- s = spl7(); /* block interrupts */
- if(p->wait_cond == (long)wakeselect) {
- p->wait_cond = 0;
- }
- if (p->wait_q == SELECT_Q) {
- rm_q(SELECT_Q, p);
- add_q(READY_Q, p);
- }
- spl(s);
- }
-
- /*
- * dump out information about processes
- */
-
- /*
- * kludge alert! In order to get the right pid printed by FORCE, we use
- * curproc as the loop variable.
- *
- * I have changed this function so it is more useful to a user, less to
- * somebody debugging MiNT. I haven't had any stack problems in MiNT
- * at all, so I consider all that stack info wasted space. -- AKP
- */
-
- #ifdef DEBUG_INFO
- static const char *qstring[] = {
- "run", "ready", "wait", "iowait", "zombie", "tsr", "stop", "select"
- };
-
- /* UNSAFE macro for qname, evaluates x 1, 2, or 3 times */
- #define qname(x) ((x >= 0 && x < NUM_QUEUES) ? qstring[x] : "unkn")
- #endif
-
- void
- DUMPPROC()
- {
- #ifdef DEBUG_INFO
- PROC *p = curproc;
-
- for (curproc = proclist; curproc; curproc = curproc->gl_next) {
- FORCE("state %s PC: %lx BP: %lx",
- qname(curproc->wait_q),
- curproc->ctxt[SYSCALL].pc,
- curproc->base);
- }
- curproc = p; /* restore the real curproc */
- #endif
- }
-