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