/* kern_synch.c 4.16 82/01/24 */
#define SQSIZE 0100 /* Must be power of 2 */
#define HASH(x) (( (int) x >> 5) & (SQSIZE-1))
struct proc
*slpque
[SQSIZE
];
* Give up the processor till a wakeup occurs
* on chan, at which time the process
* enters the scheduling queue at priority pri.
* The most important effect of pri is that when
* pri<=PZERO a signal cannot disturb the sleep;
* if pri>PZERO signals will be processed.
* Callers of this routine must be prepared for
* premature return, and check that the reason for
* sleeping has gone away.
register struct proc
*rp
, **hp
;
if (chan
==0 || rp
->p_stat
!= SRUN
|| rp
->p_rlink
)
hp
= &slpque
[HASH(chan
)];
* If priority was low (>PZERO) and
* there has been a signal, execute non-local goto through
* u.u_qsav, aborting the system call in progress (see trap.c)
* (or finishing a tsleep, see below)
* Return in no more than the indicated number of seconds.
* (If seconds==0, no timeout implied)
* Return TS_OK if chan was awakened normally
* TS_TIME if timeout occurred
* TS_SIG if asynchronous signal occurred
* SHOULD HAVE OPTION TO SLEEP TO ABSOLUTE TIME OR AN
* INCREMENT IN MILLISECONDS!
tsleep(chan
, pri
, seconds
)
register struct proc
*pp
;
if (pp
->p_clktim
&& pp
->p_clktim
<seconds
)
sec
= pp
->p_clktim
-seconds
;
bcopy((caddr_t
)u
.u_qsav
, (caddr_t
)lqsav
, sizeof (label_t
));
if ((pp
->p_flag
&STIMO
)==0 && seconds
)
bcopy((caddr_t
)lqsav
, (caddr_t
)u
.u_qsav
, sizeof (label_t
));
* Remove a process from its wait queue
register struct proc
**hp
;
hp
= &slpque
[HASH(p
->p_wchan
)];
* Wake up all processes sleeping on chan.
register struct proc
*p
, **q
, **h
;
if (p
->p_rlink
|| p
->p_stat
!= SSLEEP
&& p
->p_stat
!= SSTOP
)
if (p
->p_stat
== SSLEEP
) {
/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
if ((p
->p_flag
&SLOAD
) == 0) {
wakeup((caddr_t
)&runout
);
/* END INLINE EXPANSION */
* Initialize the (doubly-linked) run queues
for (i
= 0; i
< NQS
; i
++)
qs
[i
].ph_link
= qs
[i
].ph_rlink
= (struct proc
*)&qs
[i
];
* Set the process running;
* arrange for it to be swapped in if necessary.
unsleep(p
); /* e.g. when sending signals */
if ((p
->p_flag
&SLOAD
) == 0) {
wakeup((caddr_t
)&runout
);
* The rescheduling flag (runrun)
* is set if the priority is better
* than the currently running process.
register struct proc
*pp
;
p
= (pp
->p_cpu
& 0377)/4;
p
+= PUSER
+ 2*(pp
->p_nice
- NZERO
);
if (pp
->p_rssize
> pp
->p_maxrss
&& freemem
< desfree
)
p
+= 2*4; /* effectively, nice(4) */
* Create a new process-- the internal version of
* It returns 1 in the new process, 0 in the old.
register struct proc
*rpp
, *rip
;
* First, just locate a slot for a process
* and copy the useful info from this process into it.
* The panic "cannot happen" because fork has already
* checked for the existence of a slot.
for (rpp
= proc
; rpp
< procNPROC
; rpp
++) {
if (rpp
->p_stat
== NULL
&& p
==NULL
)
if (rpp
->p_pid
==mpid
|| rpp
->p_pgrp
==mpid
)
* Make a proc table entry for the new process.
rpp
->p_flag
= SLOAD
| (rip
->p_flag
& (SPAGI
|SNUSIG
));
rpp
->p_pgrp
= rip
->p_pgrp
;
rpp
->p_nice
= rip
->p_nice
;
rpp
->p_textp
= isvfork
? 0 : rip
->p_textp
;
rpp
->p_ppid
= rip
->p_pid
;
rpp
->p_siga0
= rip
->p_siga0
;
rpp
->p_siga1
= rip
->p_siga1
;
/* take along any pending signals, like stops? */
rpp
->p_tsize
= rpp
->p_dsize
= rpp
->p_ssize
= 0;
rpp
->p_szpt
= clrnd(ctopt(UPAGES
));
forkstat
.sizvfork
+= rip
->p_dsize
+ rip
->p_ssize
;
rpp
->p_tsize
= rip
->p_tsize
;
rpp
->p_dsize
= rip
->p_dsize
;
rpp
->p_ssize
= rip
->p_ssize
;
rpp
->p_szpt
= rip
->p_szpt
;
forkstat
.sizfork
+= rip
->p_dsize
+ rip
->p_ssize
;
rpp
->p_maxrss
= rip
->p_maxrss
;
p
->p_idhash
= pidhash
[n
];
* Increase reference counts on shared objects.
if (u
.u_ofile
[n
] != NULL
)
* Partially simulate the environment
* of the new process so that when it is actually
* created (by copying) it will look right.
* This begins the section where we must prevent the parent
if (procdup(rpp
, isvfork
))
* Make child runnable and add to run queue.
* Cause child to take a non-local goto as soon as it runs.
* On older systems this was done with SSWAP bit in proc
* table; on VAX we use u.u_pcb.pcb_sswap so don't need
* to do rpp->p_flag |= SSWAP. Actually do nothing here.
/* rpp->p_flag |= SSWAP; */
* If vfork make chain from parent process to child
* (where virtal memory is temporarily). Wait for
* child to finish, steal virtual memory back,
* and wakeup child to let it die.
u
.u_procp
->p_xlink
= rpp
;
u
.u_procp
->p_flag
|= SNOVM
;
while (rpp
->p_flag
& SVFORK
)
sleep((caddr_t
)rpp
, PZERO
- 1);
if ((rpp
->p_flag
& SLOAD
) == 0)
uaccess(rpp
, Vfmap
, &vfutl
);
vpassvm(rpp
, u
.u_procp
, &vfutl
, &u
, Vfmap
);
u
.u_procp
->p_flag
&= ~SNOVM
;