1 /* kern_synch.c 4.5 02/15/81 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/dir.h" 6 #include "../h/user.h" 7 #include "../h/proc.h" 8 #include "../h/file.h" 9 #include "../h/inode.h" 10 #include "../h/vm.h" 11 #include "../h/pte.h" 12 #include "../h/inline.h" 13 #include "../h/mtpr.h" 14 15 #define SQSIZE 0100 /* Must be power of 2 */ 16 #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 17 struct proc *slpque[SQSIZE]; 18 19 /* 20 * Give up the processor till a wakeup occurs 21 * on chan, at which time the process 22 * enters the scheduling queue at priority pri. 23 * The most important effect of pri is that when 24 * pri<=PZERO a signal cannot disturb the sleep; 25 * if pri>PZERO signals will be processed. 26 * Callers of this routine must be prepared for 27 * premature return, and check that the reason for 28 * sleeping has gone away. 29 */ 30 sleep(chan, pri) 31 caddr_t chan; 32 { 33 register struct proc *rp, **hp; 34 register s; 35 36 rp = u.u_procp; 37 s = spl6(); 38 if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 39 panic("sleep"); 40 rp->p_wchan = chan; 41 rp->p_slptime = 0; 42 rp->p_pri = pri; 43 hp = &slpque[HASH(chan)]; 44 rp->p_link = *hp; 45 *hp = rp; 46 if(pri > PZERO) { 47 if(ISSIG(rp)) { 48 if (rp->p_wchan) 49 unsleep(rp); 50 rp->p_stat = SRUN; 51 (void) spl0(); 52 goto psig; 53 } 54 if (rp->p_wchan == 0) 55 goto out; 56 rp->p_stat = SSLEEP; 57 (void) spl0(); 58 if(runin != 0) { 59 runin = 0; 60 wakeup((caddr_t)&runin); 61 } 62 swtch(); 63 if(ISSIG(rp)) 64 goto psig; 65 } else { 66 rp->p_stat = SSLEEP; 67 (void) spl0(); 68 swtch(); 69 } 70 out: 71 splx(s); 72 return; 73 74 /* 75 * If priority was low (>PZERO) and 76 * there has been a signal, 77 * execute non-local goto to 78 * the qsav location. 79 * (see trap1/trap.c) 80 */ 81 psig: 82 longjmp(u.u_qsav); 83 /*NOTREACHED*/ 84 } 85 86 /* 87 * Sleep on chan at pri. 88 * Return in no more than the indicated number of seconds. 89 * (If seconds==0, no timeout implied) 90 * Return TS_OK if chan was awakened normally 91 * TS_TIME if timeout occurred 92 * TS_SIG if asynchronous signal occurred 93 */ 94 tsleep(chan, pri, seconds) 95 caddr_t chan; 96 { 97 label_t lqsav; 98 register struct proc *pp; 99 register sec, n, rval; 100 101 pp = u.u_procp; 102 n = spl7(); 103 sec = 0; 104 rval = 0; 105 if (pp->p_clktim && pp->p_clktim<seconds) 106 seconds = 0; 107 if (seconds) { 108 pp->p_flag |= STIMO; 109 sec = pp->p_clktim-seconds; 110 pp->p_clktim = seconds; 111 } 112 bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t)); 113 if (setjmp(u.u_qsav)) 114 rval = TS_SIG; 115 else { 116 sleep(chan, pri); 117 if ((pp->p_flag&STIMO)==0 && seconds) 118 rval = TS_TIME; 119 else 120 rval = TS_OK; 121 } 122 pp->p_flag &= ~STIMO; 123 bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t)); 124 if (sec > 0) 125 pp->p_clktim += sec; 126 else 127 pp->p_clktim = 0; 128 splx(n); 129 return(rval); 130 } 131 132 /* 133 * Remove a process from its wait queue 134 */ 135 unsleep(p) 136 register struct proc *p; 137 { 138 register struct proc **hp; 139 register s; 140 141 s = spl6(); 142 if (p->p_wchan) { 143 hp = &slpque[HASH(p->p_wchan)]; 144 while (*hp != p) 145 hp = &(*hp)->p_link; 146 *hp = p->p_link; 147 p->p_wchan = 0; 148 } 149 splx(s); 150 } 151 152 /* 153 * Wake up all processes sleeping on chan. 154 */ 155 wakeup(chan) 156 register caddr_t chan; 157 { 158 register struct proc *p, **q, **h; 159 int s; 160 161 s = spl6(); 162 h = &slpque[HASH(chan)]; 163 restart: 164 for (q = h; p = *q; ) { 165 if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 166 panic("wakeup"); 167 if (p->p_wchan==chan) { 168 p->p_wchan = 0; 169 *q = p->p_link; 170 p->p_slptime = 0; 171 if (p->p_stat == SSLEEP) { 172 /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 173 p->p_stat = SRUN; 174 if (p->p_flag & SLOAD) { 175 #ifndef FASTVAX 176 p->p_link = runq; 177 runq = p->p_link; 178 #else 179 setrq(p); 180 #endif 181 } 182 if(p->p_pri < curpri) { 183 runrun++; 184 aston(); 185 } 186 if(runout != 0 && (p->p_flag&SLOAD) == 0) { 187 runout = 0; 188 wakeup((caddr_t)&runout); 189 } 190 /* END INLINE EXPANSION */ 191 goto restart; 192 } 193 } else 194 q = &p->p_link; 195 } 196 splx(s); 197 } 198 199 #ifdef FASTVAX 200 /* 201 * Initialize the (doubly-linked) run queues 202 * to be empty. 203 */ 204 rqinit() 205 { 206 register int i; 207 208 for (i = 0; i < NQS; i++) 209 qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 210 } 211 #endif 212 213 /* 214 * Set the process running; 215 * arrange for it to be swapped in if necessary. 216 */ 217 setrun(p) 218 register struct proc *p; 219 { 220 register s; 221 222 s = spl6(); 223 switch (p->p_stat) { 224 225 case 0: 226 case SWAIT: 227 case SRUN: 228 case SZOMB: 229 default: 230 panic("setrun"); 231 232 case SSTOP: 233 case SSLEEP: 234 unsleep(p); /* e.g. when sending signals */ 235 break; 236 237 case SIDL: 238 break; 239 } 240 p->p_stat = SRUN; 241 if (p->p_flag & SLOAD) 242 setrq(p); 243 splx(s); 244 if(p->p_pri < curpri) { 245 runrun++; 246 aston(); 247 } 248 if(runout != 0 && (p->p_flag&SLOAD) == 0) { 249 runout = 0; 250 wakeup((caddr_t)&runout); 251 } 252 } 253 254 /* 255 * Set user priority. 256 * The rescheduling flag (runrun) 257 * is set if the priority is better 258 * than the currently running process. 259 */ 260 setpri(pp) 261 register struct proc *pp; 262 { 263 register p; 264 265 p = (pp->p_cpu & 0377)/16; 266 p += PUSER + 2*(pp->p_nice - NZERO); 267 if(p > 127) 268 p = 127; 269 if(p < curpri) 270 runrun++; 271 pp->p_usrpri = p; 272 return(p); 273 } 274 275 /* 276 * Create a new process-- the internal version of 277 * sys fork. 278 * It returns 1 in the new process, 0 in the old. 279 */ 280 newproc(isvfork) 281 { 282 register struct proc *p; 283 register struct proc *rpp, *rip; 284 register int n; 285 286 p = NULL; 287 /* 288 * First, just locate a slot for a process 289 * and copy the useful info from this process into it. 290 * The panic "cannot happen" because fork has already 291 * checked for the existence of a slot. 292 */ 293 retry: 294 mpid++; 295 if(mpid >= 30000) { 296 mpid = 0; 297 goto retry; 298 } 299 for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) { 300 if(rpp->p_stat == NULL && p==NULL) 301 p = rpp; 302 if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 303 goto retry; 304 } 305 if ((rpp = p)==NULL) 306 panic("no procs"); 307 308 /* 309 * make proc entry for new proc 310 */ 311 312 rip = u.u_procp; 313 rpp->p_stat = SIDL; 314 rpp->p_clktim = 0; 315 rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SDETACH|SNUSIG)); 316 if (isvfork) { 317 rpp->p_flag |= SVFORK; 318 rpp->p_ndx = rip->p_ndx; 319 } else 320 rpp->p_ndx = rpp - proc; 321 rpp->p_uid = rip->p_uid; 322 rpp->p_pgrp = rip->p_pgrp; 323 rpp->p_nice = rip->p_nice; 324 rpp->p_textp = isvfork ? 0 : rip->p_textp; 325 rpp->p_pid = mpid; 326 rpp->p_ppid = rip->p_pid; 327 rpp->p_pptr = rip; 328 rpp->p_time = 0; 329 rpp->p_cpu = 0; 330 rpp->p_siga0 = rip->p_siga0; 331 rpp->p_siga1 = rip->p_siga1; 332 /* take along any pending signals, like stops? */ 333 if (isvfork) { 334 rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 335 rpp->p_szpt = clrnd(ctopt(UPAGES)); 336 forkstat.cntvfork++; 337 forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 338 } else { 339 rpp->p_tsize = rip->p_tsize; 340 rpp->p_dsize = rip->p_dsize; 341 rpp->p_ssize = rip->p_ssize; 342 rpp->p_szpt = rip->p_szpt; 343 forkstat.cntfork++; 344 forkstat.sizfork += rip->p_dsize + rip->p_ssize; 345 } 346 rpp->p_rssize = 0; 347 rpp->p_wchan = 0; 348 rpp->p_slptime = 0; 349 rpp->p_pctcpu = 0; 350 rpp->p_cpticks = 0; 351 n = PIDHASH(rpp->p_pid); 352 p->p_idhash = pidhash[n]; 353 pidhash[n] = rpp - proc; 354 355 /* 356 * make duplicate entries 357 * where needed 358 */ 359 360 multprog++; 361 362 for(n=0; n<NOFILE; n++) 363 if(u.u_ofile[n] != NULL) { 364 #ifdef UCBIPC 365 if (u.u_pofile[n] & ISPORT) 366 u.u_oport[n]->pt_count++; 367 else { 368 #endif 369 u.u_ofile[n]->f_count++; 370 if(!isvfork && u.u_vrpages[n]) 371 u.u_ofile[n]->f_inode->i_vfdcnt++; 372 #ifdef UCBIPC 373 } 374 #endif UCBIPC 375 } 376 377 u.u_cdir->i_count++; 378 if (u.u_rdir) 379 u.u_rdir->i_count++; 380 /* 381 * Partially simulate the environment 382 * of the new process so that when it is actually 383 * created (by copying) it will look right. 384 */ 385 386 rip->p_flag |= SKEEP; /* prevent parent from being swapped */ 387 388 if (procdup(rpp, isvfork)) 389 return (1); 390 391 (void) spl6(); 392 rpp->p_stat = SRUN; 393 setrq(rpp); 394 (void) spl0(); 395 /* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */ 396 /* rpp->p_flag |= SSWAP; */ 397 rip->p_flag &= ~SKEEP; 398 if (isvfork) { 399 u.u_procp->p_xlink = rpp; 400 u.u_procp->p_flag |= SNOVM; 401 while (rpp->p_flag & SVFORK) 402 sleep((caddr_t)rpp, PZERO - 1); 403 if ((rpp->p_flag & SLOAD) == 0) 404 panic("newproc vfork"); 405 uaccess(rpp, Vfmap, &vfutl); 406 u.u_procp->p_xlink = 0; 407 vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 408 for (n = 0; n < NOFILE; n++) 409 if (vfutl.u_vrpages[n]) { 410 if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0) 411 if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0) 412 panic("newproc i_vfdcnt"); 413 vfutl.u_vrpages[n] = 0; 414 } 415 u.u_procp->p_flag &= ~SNOVM; 416 rpp->p_ndx = rpp - proc; 417 rpp->p_flag |= SVFDONE; 418 wakeup((caddr_t)rpp); 419 } 420 return (0); 421 } 422