1 /* kern_synch.c 4.18 82/08/10 */ 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 #include "../h/quota.h" 15 16 #define SQSIZE 0100 /* Must be power of 2 */ 17 #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 18 struct proc *slpque[SQSIZE]; 19 20 /* 21 * Give up the processor till a wakeup occurs 22 * on chan, at which time the process 23 * enters the scheduling queue at priority pri. 24 * The most important effect of pri is that when 25 * pri<=PZERO a signal cannot disturb the sleep; 26 * if pri>PZERO signals will be processed. 27 * Callers of this routine must be prepared for 28 * premature return, and check that the reason for 29 * sleeping has gone away. 30 */ 31 sleep(chan, pri) 32 caddr_t chan; 33 { 34 register struct proc *rp, **hp; 35 register s; 36 37 rp = u.u_procp; 38 s = spl6(); 39 if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 40 panic("sleep"); 41 rp->p_wchan = chan; 42 rp->p_slptime = 0; 43 rp->p_pri = pri; 44 hp = &slpque[HASH(chan)]; 45 rp->p_link = *hp; 46 *hp = rp; 47 if (pri > PZERO) { 48 if (ISSIG(rp)) { 49 if (rp->p_wchan) 50 unsleep(rp); 51 rp->p_stat = SRUN; 52 (void) spl0(); 53 goto psig; 54 } 55 if (rp->p_wchan == 0) 56 goto out; 57 rp->p_stat = SSLEEP; 58 (void) spl0(); 59 swtch(); 60 if (ISSIG(rp)) 61 goto psig; 62 } else { 63 rp->p_stat = SSLEEP; 64 (void) spl0(); 65 swtch(); 66 } 67 out: 68 splx(s); 69 return; 70 71 /* 72 * If priority was low (>PZERO) and 73 * there has been a signal, execute non-local goto through 74 * u.u_qsav, aborting the system call in progress (see trap.c) 75 * (or finishing a tsleep, see below) 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 * SHOULD HAVE OPTION TO SLEEP TO ABSOLUTE TIME OR AN 91 * INCREMENT IN MILLISECONDS! 92 */ 93 tsleep(chan, pri, seconds) 94 caddr_t chan; 95 int pri, seconds; 96 { 97 label_t lqsav; 98 register struct proc *pp; 99 register sec, n, rval, sov; 100 101 pp = u.u_procp; 102 n = spl7(); 103 sec = 0; 104 rval = 0; 105 sov = 0; 106 if (pp->p_clktim && pp->p_clktim<seconds) 107 if (pri > PZERO) 108 seconds = 0; 109 else 110 sov++; 111 if (seconds) { 112 pp->p_flag |= STIMO; 113 sec = pp->p_clktim-seconds; 114 pp->p_clktim = seconds; 115 } 116 bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t)); 117 if (setjmp(u.u_qsav)) 118 rval = TS_SIG; 119 else { 120 sleep(chan, pri); 121 if ((pp->p_flag&STIMO)==0 && seconds) 122 rval = TS_TIME; 123 else 124 rval = TS_OK; 125 } 126 pp->p_flag &= ~STIMO; 127 bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t)); 128 if (sec > 0) 129 pp->p_clktim += sec; 130 else if (sov) { 131 if ((pp->p_clktim += sec) <= 0) { 132 pp->p_clktim = 0; 133 psignal(pp, SIGALRM); 134 } 135 } else 136 pp->p_clktim = 0; 137 splx(n); 138 return (rval); 139 } 140 141 /* 142 * Remove a process from its wait queue 143 */ 144 unsleep(p) 145 register struct proc *p; 146 { 147 register struct proc **hp; 148 register s; 149 150 s = spl6(); 151 if (p->p_wchan) { 152 hp = &slpque[HASH(p->p_wchan)]; 153 while (*hp != p) 154 hp = &(*hp)->p_link; 155 *hp = p->p_link; 156 p->p_wchan = 0; 157 } 158 splx(s); 159 } 160 161 /* 162 * Wake up all processes sleeping on chan. 163 */ 164 wakeup(chan) 165 register caddr_t chan; 166 { 167 register struct proc *p, **q, **h; 168 int s; 169 170 s = spl6(); 171 h = &slpque[HASH(chan)]; 172 restart: 173 for (q = h; p = *q; ) { 174 if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 175 panic("wakeup"); 176 if (p->p_wchan==chan) { 177 p->p_wchan = 0; 178 *q = p->p_link; 179 p->p_slptime = 0; 180 if (p->p_stat == SSLEEP) { 181 /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 182 p->p_stat = SRUN; 183 if (p->p_flag & SLOAD) 184 setrq(p); 185 if (p->p_pri < curpri) { 186 runrun++; 187 aston(); 188 } 189 if ((p->p_flag&SLOAD) == 0) { 190 if (runout != 0) { 191 runout = 0; 192 wakeup((caddr_t)&runout); 193 } 194 wantin++; 195 } 196 /* END INLINE EXPANSION */ 197 goto restart; 198 } 199 } else 200 q = &p->p_link; 201 } 202 splx(s); 203 } 204 205 /* 206 * Initialize the (doubly-linked) run queues 207 * to be empty. 208 */ 209 rqinit() 210 { 211 register int i; 212 213 for (i = 0; i < NQS; i++) 214 qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 215 } 216 217 /* 218 * Set the process running; 219 * arrange for it to be swapped in if necessary. 220 */ 221 setrun(p) 222 register struct proc *p; 223 { 224 register int s; 225 226 s = spl6(); 227 switch (p->p_stat) { 228 229 case 0: 230 case SWAIT: 231 case SRUN: 232 case SZOMB: 233 default: 234 panic("setrun"); 235 236 case SSTOP: 237 case SSLEEP: 238 unsleep(p); /* e.g. when sending signals */ 239 break; 240 241 case SIDL: 242 break; 243 } 244 p->p_stat = SRUN; 245 if (p->p_flag & SLOAD) 246 setrq(p); 247 splx(s); 248 if (p->p_pri < curpri) { 249 runrun++; 250 aston(); 251 } 252 if ((p->p_flag&SLOAD) == 0) { 253 if (runout != 0) { 254 runout = 0; 255 wakeup((caddr_t)&runout); 256 } 257 wantin++; 258 } 259 } 260 261 /* 262 * Set user priority. 263 * The rescheduling flag (runrun) 264 * is set if the priority is better 265 * than the currently running process. 266 */ 267 setpri(pp) 268 register struct proc *pp; 269 { 270 register int p; 271 272 p = (pp->p_cpu & 0377)/4; 273 p += PUSER + 2*(pp->p_nice - NZERO); 274 if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 275 p += 2*4; /* effectively, nice(4) */ 276 if (p > 127) 277 p = 127; 278 if (p < curpri) { 279 runrun++; 280 aston(); 281 } 282 pp->p_usrpri = p; 283 return (p); 284 } 285 286 /* 287 * Create a new process-- the internal version of 288 * sys fork. 289 * It returns 1 in the new process, 0 in the old. 290 */ 291 newproc(isvfork) 292 int isvfork; 293 { 294 register struct proc *p; 295 register struct proc *rpp, *rip; 296 register int n; 297 register struct file *fp; 298 299 p = NULL; 300 /* 301 * First, just locate a slot for a process 302 * and copy the useful info from this process into it. 303 * The panic "cannot happen" because fork has already 304 * checked for the existence of a slot. 305 */ 306 retry: 307 mpid++; 308 if (mpid >= 30000) { 309 mpid = 0; 310 goto retry; 311 } 312 for (rpp = proc; rpp < procNPROC; rpp++) { 313 if (rpp->p_stat == NULL && p==NULL) 314 p = rpp; 315 if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 316 goto retry; 317 } 318 if ((rpp = p) == NULL) 319 panic("no procs"); 320 321 /* 322 * Make a proc table entry for the new process. 323 */ 324 rip = u.u_procp; 325 #ifdef QUOTA 326 (rpp->p_quota = rip->p_quota)->q_cnt++; 327 #endif 328 rpp->p_stat = SIDL; 329 rpp->p_clktim = 0; 330 rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG)); 331 if (isvfork) { 332 rpp->p_flag |= SVFORK; 333 rpp->p_ndx = rip->p_ndx; 334 } else 335 rpp->p_ndx = rpp - proc; 336 rpp->p_uid = rip->p_uid; 337 rpp->p_pgrp = rip->p_pgrp; 338 rpp->p_nice = rip->p_nice; 339 rpp->p_textp = isvfork ? 0 : rip->p_textp; 340 rpp->p_pid = mpid; 341 rpp->p_ppid = rip->p_pid; 342 rpp->p_pptr = rip; 343 rpp->p_osptr = rip->p_cptr; 344 if (rip->p_cptr) 345 rip->p_cptr->p_ysptr = rpp; 346 rpp->p_ysptr = NULL; 347 rpp->p_cptr = NULL; 348 rip->p_cptr = rpp; 349 rpp->p_time = 0; 350 rpp->p_cpu = 0; 351 rpp->p_siga0 = rip->p_siga0; 352 rpp->p_siga1 = rip->p_siga1; 353 /* take along any pending signals, like stops? */ 354 if (isvfork) { 355 rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 356 rpp->p_szpt = clrnd(ctopt(UPAGES)); 357 forkstat.cntvfork++; 358 forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 359 } else { 360 rpp->p_tsize = rip->p_tsize; 361 rpp->p_dsize = rip->p_dsize; 362 rpp->p_ssize = rip->p_ssize; 363 rpp->p_szpt = rip->p_szpt; 364 forkstat.cntfork++; 365 forkstat.sizfork += rip->p_dsize + rip->p_ssize; 366 } 367 rpp->p_rssize = 0; 368 rpp->p_maxrss = rip->p_maxrss; 369 rpp->p_wchan = 0; 370 rpp->p_slptime = 0; 371 rpp->p_pctcpu = 0; 372 rpp->p_cpticks = 0; 373 n = PIDHASH(rpp->p_pid); 374 p->p_idhash = pidhash[n]; 375 pidhash[n] = rpp - proc; 376 multprog++; 377 378 /* 379 * Increase reference counts on shared objects. 380 */ 381 for (n = 0; n < NOFILE; n++) { 382 fp = u.u_ofile[n]; 383 if (fp == NULL) 384 continue; 385 fp->f_count++; 386 if (u.u_pofile[n]&RDLOCK) 387 fp->f_inode->i_rdlockc++; 388 if (u.u_pofile[n]&WRLOCK) 389 fp->f_inode->i_wrlockc++; 390 } 391 u.u_cdir->i_count++; 392 if (u.u_rdir) 393 u.u_rdir->i_count++; 394 395 /* 396 * Partially simulate the environment 397 * of the new process so that when it is actually 398 * created (by copying) it will look right. 399 * This begins the section where we must prevent the parent 400 * from being swapped. 401 */ 402 rip->p_flag |= SKEEP; 403 if (procdup(rpp, isvfork)) 404 return (1); 405 406 /* 407 * Make child runnable and add to run queue. 408 */ 409 (void) spl6(); 410 rpp->p_stat = SRUN; 411 setrq(rpp); 412 (void) spl0(); 413 414 /* 415 * Cause child to take a non-local goto as soon as it runs. 416 * On older systems this was done with SSWAP bit in proc 417 * table; on VAX we use u.u_pcb.pcb_sswap so don't need 418 * to do rpp->p_flag |= SSWAP. Actually do nothing here. 419 */ 420 /* rpp->p_flag |= SSWAP; */ 421 422 /* 423 * Now can be swapped. 424 */ 425 rip->p_flag &= ~SKEEP; 426 427 /* 428 * If vfork make chain from parent process to child 429 * (where virtal memory is temporarily). Wait for 430 * child to finish, steal virtual memory back, 431 * and wakeup child to let it die. 432 */ 433 if (isvfork) { 434 u.u_procp->p_xlink = rpp; 435 u.u_procp->p_flag |= SNOVM; 436 while (rpp->p_flag & SVFORK) 437 sleep((caddr_t)rpp, PZERO - 1); 438 if ((rpp->p_flag & SLOAD) == 0) 439 panic("newproc vfork"); 440 uaccess(rpp, Vfmap, &vfutl); 441 u.u_procp->p_xlink = 0; 442 vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 443 u.u_procp->p_flag &= ~SNOVM; 444 rpp->p_ndx = rpp - proc; 445 rpp->p_flag |= SVFDONE; 446 wakeup((caddr_t)rpp); 447 } 448 449 /* 450 * 0 return means parent. 451 */ 452 return (0); 453 } 454