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