1 /* kern_synch.c 4.19 82/09/04 */ 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 int pri; 34 { 35 register struct proc *rp, **hp; 36 register s; 37 38 rp = u.u_procp; 39 s = spl6(); 40 if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 41 panic("sleep"); 42 rp->p_wchan = chan; 43 rp->p_slptime = 0; 44 rp->p_pri = pri; 45 hp = &slpque[HASH(chan)]; 46 rp->p_link = *hp; 47 *hp = rp; 48 if (pri > PZERO) { 49 if (ISSIG(rp)) { 50 if (rp->p_wchan) 51 unsleep(rp); 52 rp->p_stat = SRUN; 53 (void) spl0(); 54 goto psig; 55 } 56 if (rp->p_wchan == 0) 57 goto out; 58 rp->p_stat = SSLEEP; 59 (void) spl0(); 60 u.u_ru.ru_nvcsw++; 61 swtch(); 62 if (ISSIG(rp)) 63 goto psig; 64 } else { 65 rp->p_stat = SSLEEP; 66 (void) spl0(); 67 u.u_ru.ru_nvcsw++; 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, execute non-local goto through 77 * u.u_qsav, aborting the system call in progress (see trap.c) 78 * (or finishing a tsleep, see below) 79 */ 80 psig: 81 longjmp(u.u_qsav); 82 /*NOTREACHED*/ 83 } 84 85 /* 86 * Sleep on chan at pri for at most a specified amount of time. 87 * Return (TS_OK,TS_TIME,TS_SIG) on (normal,timeout,signal) condition. 88 */ 89 tsleep(chan, pri, tvp) 90 caddr_t chan; 91 int pri; 92 struct timeval *tvp; 93 { 94 register struct proc *p = u.u_procp; 95 int s, rval; 96 97 s = spl7(); 98 if (timercmp(tvp, &p->p_realtimer.itimer_value, >)) { 99 /* alarm will occur first! */ 100 sleep(chan, pri); 101 rval = TS_OK; /* almost NOTREACHED modulo fuzz */ 102 } else { 103 label_t lqsav; 104 105 bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t)); 106 p->p_seltimer = *tvp; 107 if (setjmp(u.u_qsav)) 108 rval = TS_SIG; 109 else { 110 sleep(chan, pri); 111 rval = TS_OK; 112 } 113 timerclear(&p->p_seltimer); 114 bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t)); 115 } 116 splx(s); 117 return (rval); 118 } 119 120 /* 121 * Remove a process from its wait queue 122 */ 123 unsleep(p) 124 register struct proc *p; 125 { 126 register struct proc **hp; 127 register s; 128 129 s = spl6(); 130 if (p->p_wchan) { 131 hp = &slpque[HASH(p->p_wchan)]; 132 while (*hp != p) 133 hp = &(*hp)->p_link; 134 *hp = p->p_link; 135 p->p_wchan = 0; 136 } 137 splx(s); 138 } 139 140 /* 141 * Wake up all processes sleeping on chan. 142 */ 143 wakeup(chan) 144 register caddr_t chan; 145 { 146 register struct proc *p, **q, **h; 147 int s; 148 149 s = spl6(); 150 h = &slpque[HASH(chan)]; 151 restart: 152 for (q = h; p = *q; ) { 153 if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 154 panic("wakeup"); 155 if (p->p_wchan==chan) { 156 p->p_wchan = 0; 157 *q = p->p_link; 158 p->p_slptime = 0; 159 if (p->p_stat == SSLEEP) { 160 /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 161 p->p_stat = SRUN; 162 if (p->p_flag & SLOAD) 163 setrq(p); 164 if (p->p_pri < curpri) { 165 runrun++; 166 aston(); 167 } 168 if ((p->p_flag&SLOAD) == 0) { 169 if (runout != 0) { 170 runout = 0; 171 wakeup((caddr_t)&runout); 172 } 173 wantin++; 174 } 175 /* END INLINE EXPANSION */ 176 goto restart; 177 } 178 } else 179 q = &p->p_link; 180 } 181 splx(s); 182 } 183 184 /* 185 * Initialize the (doubly-linked) run queues 186 * to be empty. 187 */ 188 rqinit() 189 { 190 register int i; 191 192 for (i = 0; i < NQS; i++) 193 qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 194 } 195 196 /* 197 * Set the process running; 198 * arrange for it to be swapped in if necessary. 199 */ 200 setrun(p) 201 register struct proc *p; 202 { 203 register int s; 204 205 s = spl6(); 206 switch (p->p_stat) { 207 208 case 0: 209 case SWAIT: 210 case SRUN: 211 case SZOMB: 212 default: 213 panic("setrun"); 214 215 case SSTOP: 216 case SSLEEP: 217 unsleep(p); /* e.g. when sending signals */ 218 break; 219 220 case SIDL: 221 break; 222 } 223 p->p_stat = SRUN; 224 if (p->p_flag & SLOAD) 225 setrq(p); 226 splx(s); 227 if (p->p_pri < curpri) { 228 runrun++; 229 aston(); 230 } 231 if ((p->p_flag&SLOAD) == 0) { 232 if (runout != 0) { 233 runout = 0; 234 wakeup((caddr_t)&runout); 235 } 236 wantin++; 237 } 238 } 239 240 /* 241 * Set user priority. 242 * The rescheduling flag (runrun) 243 * is set if the priority is better 244 * than the currently running process. 245 */ 246 setpri(pp) 247 register struct proc *pp; 248 { 249 register int p; 250 251 p = (pp->p_cpu & 0377)/4; 252 p += PUSER + 2*(pp->p_nice - NZERO); 253 if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 254 p += 2*4; /* effectively, nice(4) */ 255 if (p > 127) 256 p = 127; 257 if (p < curpri) { 258 runrun++; 259 aston(); 260 } 261 pp->p_usrpri = p; 262 return (p); 263 } 264 265 /* 266 * Create a new process-- the internal version of 267 * sys fork. 268 * It returns 1 in the new process, 0 in the old. 269 */ 270 newproc(isvfork) 271 int isvfork; 272 { 273 register struct proc *p; 274 register struct proc *rpp, *rip; 275 register int n; 276 register struct file *fp; 277 278 p = NULL; 279 /* 280 * First, just locate a slot for a process 281 * and copy the useful info from this process into it. 282 * The panic "cannot happen" because fork has already 283 * checked for the existence of a slot. 284 */ 285 retry: 286 mpid++; 287 if (mpid >= 30000) { 288 mpid = 0; 289 goto retry; 290 } 291 for (rpp = proc; rpp < procNPROC; rpp++) { 292 if (rpp->p_stat == NULL && p==NULL) 293 p = rpp; 294 if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 295 goto retry; 296 } 297 if ((rpp = p) == NULL) 298 panic("no procs"); 299 300 /* 301 * Make a proc table entry for the new process. 302 */ 303 rip = u.u_procp; 304 #ifdef QUOTA 305 (rpp->p_quota = rip->p_quota)->q_cnt++; 306 #endif 307 rpp->p_stat = SIDL; 308 timerclear(&rpp->p_realtimer.itimer_value); 309 rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG)); 310 if (isvfork) { 311 rpp->p_flag |= SVFORK; 312 rpp->p_ndx = rip->p_ndx; 313 } else 314 rpp->p_ndx = rpp - proc; 315 rpp->p_uid = rip->p_uid; 316 rpp->p_pgrp = rip->p_pgrp; 317 rpp->p_nice = rip->p_nice; 318 rpp->p_textp = isvfork ? 0 : rip->p_textp; 319 rpp->p_pid = mpid; 320 rpp->p_ppid = rip->p_pid; 321 rpp->p_pptr = rip; 322 rpp->p_osptr = rip->p_cptr; 323 if (rip->p_cptr) 324 rip->p_cptr->p_ysptr = rpp; 325 rpp->p_ysptr = NULL; 326 rpp->p_cptr = NULL; 327 rip->p_cptr = rpp; 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_maxrss = rip->p_maxrss; 348 rpp->p_wchan = 0; 349 rpp->p_slptime = 0; 350 rpp->p_pctcpu = 0; 351 rpp->p_cpticks = 0; 352 n = PIDHASH(rpp->p_pid); 353 p->p_idhash = pidhash[n]; 354 pidhash[n] = rpp - proc; 355 multprog++; 356 357 /* 358 * Increase reference counts on shared objects. 359 */ 360 for (n = 0; n < NOFILE; n++) { 361 fp = u.u_ofile[n]; 362 if (fp == NULL) 363 continue; 364 fp->f_count++; 365 if (u.u_pofile[n]&RDLOCK) 366 fp->f_inode->i_rdlockc++; 367 if (u.u_pofile[n]&WRLOCK) 368 fp->f_inode->i_wrlockc++; 369 } 370 u.u_cdir->i_count++; 371 if (u.u_rdir) 372 u.u_rdir->i_count++; 373 374 /* 375 * Partially simulate the environment 376 * of the new process so that when it is actually 377 * created (by copying) it will look right. 378 * This begins the section where we must prevent the parent 379 * from being swapped. 380 */ 381 rip->p_flag |= SKEEP; 382 if (procdup(rpp, isvfork)) 383 return (1); 384 385 /* 386 * Make child runnable and add to run queue. 387 */ 388 (void) spl6(); 389 rpp->p_stat = SRUN; 390 setrq(rpp); 391 (void) spl0(); 392 393 /* 394 * Cause child to take a non-local goto as soon as it runs. 395 * On older systems this was done with SSWAP bit in proc 396 * table; on VAX we use u.u_pcb.pcb_sswap so don't need 397 * to do rpp->p_flag |= SSWAP. Actually do nothing here. 398 */ 399 /* rpp->p_flag |= SSWAP; */ 400 401 /* 402 * Now can be swapped. 403 */ 404 rip->p_flag &= ~SKEEP; 405 406 /* 407 * If vfork make chain from parent process to child 408 * (where virtal memory is temporarily). Wait for 409 * child to finish, steal virtual memory back, 410 * and wakeup child to let it die. 411 */ 412 if (isvfork) { 413 u.u_procp->p_xlink = rpp; 414 u.u_procp->p_flag |= SNOVM; 415 while (rpp->p_flag & SVFORK) 416 sleep((caddr_t)rpp, PZERO - 1); 417 if ((rpp->p_flag & SLOAD) == 0) 418 panic("newproc vfork"); 419 uaccess(rpp, Vfmap, &vfutl); 420 u.u_procp->p_xlink = 0; 421 vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 422 u.u_procp->p_flag &= ~SNOVM; 423 rpp->p_ndx = rpp - proc; 424 rpp->p_flag |= SVFDONE; 425 wakeup((caddr_t)rpp); 426 } 427 428 /* 429 * 0 return means parent. 430 */ 431 return (0); 432 } 433