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