home *** CD-ROM | disk | FTP | other *** search
- _PORTING UNIX TO THE 386: MULTIPROGRAMMING AND MULTITASKING_
- by William Frederick Jolitz and Lynne Greer Jolitz
-
- [LISTING ONE]
-
- /* code fragment from i386/trap.c (in trap() and syscall()) */
- ...
- if (want_resched) {
- /*
- * Enqueue our current running process first, so
- * that we may eventually run again. Block clock
- * interrupts that may interfere with priority
- * (e.g. we'd rather it not be recalculated part
- * way thru setrun).
- */
- (void) splclock();
- setrq(p);
- (void) splnone();
- p->p_stats->p_ru.ru_nivcsw++;
- swtch();
- while (i = CURSIG(p))
- psig(i);
- }
- ...
-
-
-
-
- [LISTING TWO]
-
- /*-
- * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
- */
-
- /*
- * General sleep call.
- * Suspends current process until a wakeup is made on chan.
- * The process will then be made runnable with priority pri.
- * Sleeps at most timo/hz seconds (0 means no timeout).
- * If pri includes PCATCH flag, signals are checked
- * before and after sleeping, else signals are not checked.
- * Returns 0 if awakened, EWOULDBLOCK if the timeout expires.
- * If PCATCH is set and a signal needs to be delivered,
- * ERESTART is returned if the current system call should be restarted
- * if possible, and EINTR is returned if the system call should
- * be interrupted by the signal (return EINTR).
- */
- tsleep(chan, pri, wmesg, timo)
- caddr_t chan;
- int pri;
- char *wmesg;
- int timo;
- {
- register struct proc *p = curproc;
- register struct slpque *qp;
- register s;
- int sig, catch = pri & PCATCH;
- extern int cold;
- int endtsleep();
-
- s = splhigh();
- if (cold || panicstr) {
- /*
- * After a panic, or during autoconfiguration,
- * just give interrupts a chance, then just return;
- * don't run any other procs or panic below,
- * in case this is the idle process and already asleep.
- */
- splx(safepri);
- splx(s);
- return (0);
- }
-
- #ifdef DIAGNOSTIC
- if (chan == 0 || p->p_stat != SRUN || p->p_rlink)
- panic("tsleep");
- #endif
-
- p->p_wchan = chan;
- p->p_wmesg = wmesg;
- p->p_slptime = 0;
- p->p_pri = pri & PRIMASK;
-
- /* Insert onto the tail of a sleep queue list. */
- qp = &slpque[HASH(chan)];
- if (qp->sq_head == 0)
- qp->sq_head = p;
- else
- *qp->sq_tailp = p;
- *(qp->sq_tailp = &p->p_link) = 0;
-
- /*
- * If time limit to sleep, schedule a timeout
- */
- if (timo)
- timeout(endtsleep, (caddr_t)p, timo);
-
- /* We put ourselves on the sleep queue and start our timeout
- * before calling CURSIG, as we could stop there, and a wakeup
- * or a SIGCONT (or both) could occur while we were stopped.
- * A SIGCONT would cause us to be marked as SSLEEP
- * without resuming us, thus we must be ready for sleep
- * when CURSIG is called. If the wakeup happens while we're
- * stopped, p->p_wchan will be 0 upon return from CURSIG.
- */
- if (catch) {
- p->p_flag |= SSINTR;
- if (sig = CURSIG(p)) {
- if (p->p_wchan)
- unsleep(p);
- p->p_stat = SRUN;
- goto resume;
- }
- if (p->p_wchan == 0) {
- catch = 0;
- goto resume;
- }
- }
-
- /* Set process sleeping, go find another process to run */
- p->p_stat = SSLEEP;
- p->p_stats->p_ru.ru_nvcsw++;
- swtch();
-
- resume:
- splx(s);
- p->p_flag &= ~SSINTR;
-
- /* cleanup timeout case */
- if (p->p_flag & STIMO) {
- p->p_flag &= ~STIMO;
- if (catch == 0 || sig == 0)
- return (EWOULDBLOCK);
- } else if (timo)
- untimeout(endtsleep, (caddr_t)p);
-
- /* if signal was caught, return appropriately */
- if (catch && (sig != 0 || (sig = CURSIG(p)))) {
- if (p->p_sigacts->ps_sigintr & sigmask(sig))
- return (EINTR);
- return (ERESTART);
- }
- return (0);
- }
-
-
-
-
-
- [LISTING THREE]
-
- /*-
- * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
- */
-
- /* Wakeup on "chan"; set all processes
- * sleeping on chan to run state.
- */
- wakeup(chan)
- register caddr_t chan;
- {
- register struct slpque *qp;
- register struct proc *p, **q;
- int s;
-
- s = splhigh();
- qp = &slpque[HASH(chan)];
-
- restart:
- for (q = &qp->sq_head; p = *q; ) {
- #ifdef DIAGNOSTIC
- if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
- panic("wakeup");
- #endif
- if (p->p_wchan == chan) {
- p->p_wchan = 0;
- *q = p->p_link;
- if (qp->sq_tailp == &p->p_link)
- qp->sq_tailp = q;
- if (p->p_stat == SSLEEP) {
- /* OPTIMIZED INLINE EXPANSION OF setrun(p) */
- if (p->p_slptime > 1)
- updatepri(p);
- p->p_slptime = 0;
- p->p_stat = SRUN;
- if (p->p_flag & SLOAD)
- setrq(p);
- /*
- * Since curpri is a usrpri,
- * p->p_pri is always better than curpri.
- */
- if ((p->p_flag&SLOAD) == 0)
- wakeup((caddr_t)&proc0);
- else
- need_resched();
- /* END INLINE EXPANSION */
- goto restart;
- }
- } else
- q = &p->p_link;
- }
- splx(s);
- }
-
-
-
- [LISTING FOUR]
-
- /* Copyright (c) 1989, 1990, 1991 William Jolitz. All rights reserved.
- * Written by William Jolitz 6/89
- *
- * Redistribution and use in source and binary forms are freely permitted
- * provided that the above copyright notice and attribution and date of work
- * and this paragraph are duplicated in all such forms.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
- /* Swtch() */
- ENTRY(swtch)
-
- incl _cnt+V_SWTCH
-
- /* switch to new process. first, save context as needed */
- movl _curproc, %ecx
- movl P_ADDR(%ecx), %ecx
-
- /* unload processor registers, we need to use them */
- movl (%esp),%eax
- movl %eax, PCB_EIP(%ecx)
- movl %ebx, PCB_EBX(%ecx)
- movl %esp, PCB_ESP(%ecx)
- movl %ebp, PCB_EBP(%ecx)
- movl %esi, PCB_ESI(%ecx)
- movl %edi, PCB_EDI(%ecx)
-
- /* save system related details */
- movl $0,_CMAP2 /* blast temporary map PTE */
- movw _cpl, %ax
- movw %ax, PCB_IML(%ecx) /* save ipl */
-
- /* save is done, now choose a new process or idle */
- rescanfromidle:
- movl _whichqs,%edi
- 2:
- bsfl %edi,%eax /* found a full queue? */
- jz idle /* if nothing, idle waiting for some */
-
- /* we have a queue with something in it */
- btrl %eax,%edi /* clear queue full status */
- jnb 2b /* if it was clear, look for another */
- movl %eax,%ebx /* save which one we are using */
-
- /* obtain the run queue header */
- shll $3,%eax
- addl $_qs,%eax
- movl %eax,%esi
-
- #ifdef DIAGNOSTIC
- /* queue was promised to have a process in it */
- cmpl P_LINK(%eax),%eax /* linked to self? (e.g. not on list) */
- fje panicswtch /* not possible */
- #endif
-
- /* unlink from front of process q */
- movl P_LINK(%eax),%ecx
- movl P_LINK(%ecx),%edx
- movl %edx,P_LINK(%eax)
- movl P_RLINK(%ecx),%eax
- movl %eax,P_RLINK(%edx)
-
- /* is the queue truely empty? */
- cmpl P_LINK(%ecx),%esi
- je 3f
- btsl %ebx,%edi /* nope, set to indicate full */
- 3:
- movl %edi,_whichqs /* update queue status */
-
- /* notify system we've rescheduled */
- movl $0,%eax
- movl %eax,_want_resched
-
- #ifdef DIAGNOSTIC
- /* process was insured to be runnable, not sleeping */
- cmpl %eax,P_WCHAN(%ecx)
- jne panicswtch
- cmpb $ SRUN,P_STAT(%ecx)
- jne panicswtch
- #endif
-
- /* isolate process from run queues */
- movl %eax,P_RLINK(%ecx)
-
- /* record details of newproc in our global variables */
- movl %ecx,_curproc
- movl P_ADDR(%ecx),%edx
- movl %edx,_curpcb
- movl PCB_CR3(%edx),%ebx
-
- /* switch address space */
- movl %ebx,%cr3
-
- /* restore context */
- movl PCB_EBX(%edx), %ebx
- movl PCB_ESP(%edx), %esp
- movl PCB_EBP(%edx), %ebp
- movl PCB_ESI(%edx), %esi
- movl PCB_EDI(%edx), %edi
- movl PCB_EIP(%edx), %eax
- movl %eax, (%esp)
-
- #ifdef NPX
- /* npx will interrupt next instruction, delay npx switch till then */
- #define CR0_TS 0x08
- movl %cr0,%eax
- orb $CR0_TS,%al /* disable it */
- movl %eax,%cr0
- #endif
-
- /* set priority level we were at last time */
- pushl PCB_IML(%edx)
- call _splx
- popl %eax
-
- movl %edx,%eax /* return (1); (actually, non-zero) */
- ret
-
- /* When no processes are on the runq, Swtch branches to idle
- * to wait for something to come ready.
- */
- .globl Idle
- Idle:
- idle:
- call _spl0
- cmpl $0,_whichqs
- jne rescanfromidle
- hlt /* wait for interrupt */
- jmp idle
-
-
-
-
-
-
- [LISTING FIVE]
-
- /* Copyright (c) 1989, 1990 William Jolitz. All rights reserved.
- * Written by William Jolitz 7/91
- * Redistribution and use in source and binary forms are freely permitted
- * provided that the above copyright notice and attribution and date of work
- * and this paragraph are duplicated in all such forms.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
- /*
- * Enqueue a process on a run queue. Process will be on a run queue
- * until run for a time slice (swtch()), or removed by remrq().
- * Should only be called with a running process, and with the
- * processor protecting against rescheduling.
- */
- setrq(p) struct proc *p; {
- register rqidx;
- struct prochd *ph;
- struct proc *or;
-
- /* Rescale 256 priority levels to fit into 32 queue headers */
- rqidx = p->p_pri / 4;
-
- #ifdef DIAGNOSTIC
- /* If this process is already linked on run queue, we're in trouble. */
- if (p->p_rlink != 0)
- panic("setrq: already linked");
- #endif
-
- /* Link this process on the appropriate queue tail */
- ph = qs + rqidx;
- p->p_link = (struct proc *)ph;
- or = p->p_rlink = ph->ph_rlink;
- ph->ph_rlink = or->p_link = p;
-
- /* Indicate that this queue has at least one process in it */
- whichqs |= (1<<rqidx);
- }
-
- /* Dequeue a process from the run queue its stuck on. Must be called
- * with rescheduling clock blocked.
- */
- remrq(p) struct proc *p; {
- register rqidx;
- struct prochd *ph;
-
- /* Rescale 256 priority levels to fit into 32 queue headers */
- rqidx = p->p_pri / 4;
-
- #ifdef DIAGNOSTIC
- /* If a run queue is empty, something is definitely wrong */
- if (whichqs & (1<<rqidx) == 0)
- panic("remrq");
- #endif
-
- /* Unlink process off doublely-linked run queue */
- p->p_link->p_rlink = p->p_rlink;
- p->p_rlink->p_link = p->p_link;
-
- /* If something is still present on the queue,
- * set the corresponding bit. Otherwise clear it.
- */
- ph = qs + rqidx;
- if (ph->ph_link == ph)
- whichqs &= ~(1<<rqidx);
- else
- whichqs |= (1<<rqidx);
-
- /* Mark this process as unlinked */
- p->p_rlink = (struct proc *) 0;
- }
-