Category : Files from Magazines
Archive   : OCT91DDJ.ZIP
Filename : 386BSD.101
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<
/* 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<
#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<
whichqs |= (1<
/* Mark this process as unlinked */
p->p_rlink = (struct proc *) 0;
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/