1 /* kern_synch.c 3.4 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 sec = 0; 98 rval = 0; 99 n = spl7(); 100 if (pp->p_clktim && pp->p_clktim<seconds) 101 seconds = 0; 102 if (seconds) { 103 pp->p_flag |= STIMO; 104 if ((sec = pp->p_clktim-seconds) < 0) 105 sec = 0; 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 pp->p_clktim += sec; 121 splx(n); 122 return(rval); 123 } 124 125 /* 126 * Wake up all processes sleeping on chan. 127 */ 128 wakeup(chan) 129 register caddr_t chan; 130 { 131 register struct proc *p, *q; 132 register i; 133 int s; 134 135 s = spl6(); 136 i = HASH(chan); 137 restart: 138 p = slpque[i]; 139 q = NULL; 140 while(p != NULL) { 141 if (p->p_rlink || p->p_stat != SSLEEP) 142 panic("wakeup"); 143 if (p->p_wchan==chan && p->p_stat!=SZOMB) { 144 if (q == NULL) 145 slpque[i] = p->p_link; 146 else 147 q->p_link = p->p_link; 148 p->p_wchan = 0; 149 p->p_slptime = 0; 150 /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 151 p->p_stat = SRUN; 152 if (p->p_flag & SLOAD) { 153 #ifndef FASTVAX 154 p->p_link = runq; 155 runq = p->p_link; 156 #else 157 setrq(p); 158 #endif 159 } 160 if(p->p_pri < curpri) 161 runrun++; 162 if(runout != 0 && (p->p_flag&SLOAD) == 0) { 163 runout = 0; 164 wakeup((caddr_t)&runout); 165 } 166 /* END INLINE EXPANSION */ 167 goto restart; 168 } 169 q = p; 170 p = p->p_link; 171 } 172 splx(s); 173 } 174 175 #ifdef FASTVAX 176 /* 177 * Initialize the (doubly-linked) run queues 178 * to be empty. 179 */ 180 rqinit() 181 { 182 register int i; 183 184 for (i = 0; i < NQS; i++) 185 qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 186 } 187 #endif 188 189 /* 190 * Set the process running; 191 * arrange for it to be swapped in if necessary. 192 */ 193 setrun(p) 194 register struct proc *p; 195 { 196 register caddr_t w; 197 register s; 198 199 s = spl6(); 200 switch (p->p_stat) { 201 202 case 0: 203 case SWAIT: 204 case SRUN: 205 case SZOMB: 206 default: 207 panic("setrun"); 208 209 case SSLEEP: 210 if (w = p->p_wchan) { 211 wakeup(w); 212 splx(s); 213 return; 214 } 215 break; 216 217 case SIDL: 218 case SSTOP: 219 break; 220 } 221 p->p_stat = SRUN; 222 if (p->p_flag & SLOAD) 223 setrq(p); 224 splx(s); 225 if(p->p_pri < curpri) 226 runrun++; 227 if(runout != 0 && (p->p_flag&SLOAD) == 0) { 228 runout = 0; 229 wakeup((caddr_t)&runout); 230 } 231 } 232 233 /* 234 * Set user priority. 235 * The rescheduling flag (runrun) 236 * is set if the priority is better 237 * than the currently running process. 238 */ 239 setpri(pp) 240 register struct proc *pp; 241 { 242 register p; 243 244 p = (pp->p_cpu & 0377)/16; 245 p += PUSER + pp->p_nice - NZERO; 246 if(p > 127) 247 p = 127; 248 if(p < curpri) 249 runrun++; 250 pp->p_usrpri = p; 251 return(p); 252 } 253 254 /* 255 * Create a new process-- the internal version of 256 * sys fork. 257 * It returns 1 in the new process, 0 in the old. 258 */ 259 newproc(isvfork) 260 { 261 register struct proc *p; 262 register struct proc *rpp, *rip; 263 register int n; 264 265 p = NULL; 266 /* 267 * First, just locate a slot for a process 268 * and copy the useful info from this process into it. 269 * The panic "cannot happen" because fork has already 270 * checked for the existence of a slot. 271 */ 272 retry: 273 mpid++; 274 if(mpid >= 30000) { 275 mpid = 0; 276 goto retry; 277 } 278 for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) { 279 if(rpp->p_stat == NULL && p==NULL) 280 p = rpp; 281 if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 282 goto retry; 283 } 284 if ((rpp = p)==NULL) 285 panic("no procs"); 286 287 /* 288 * make proc entry for new proc 289 */ 290 291 rip = u.u_procp; 292 rpp->p_stat = SIDL; 293 rpp->p_clktim = 0; 294 rpp->p_flag = SLOAD | (rip->p_flag & SPAGI); 295 if (isvfork) { 296 rpp->p_flag |= SVFORK; 297 rpp->p_ndx = rip->p_ndx; 298 } else 299 rpp->p_ndx = rpp - proc; 300 rpp->p_uid = rip->p_uid; 301 rpp->p_pgrp = rip->p_pgrp; 302 rpp->p_nice = rip->p_nice; 303 rpp->p_textp = isvfork ? 0 : rip->p_textp; 304 rpp->p_pid = mpid; 305 rpp->p_ppid = rip->p_pid; 306 rpp->p_time = 0; 307 rpp->p_cpu = 0; 308 if (isvfork) { 309 rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 310 rpp->p_szpt = clrnd(ctopt(UPAGES)); 311 forkstat.cntvfork++; 312 forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 313 } else { 314 rpp->p_tsize = rip->p_tsize; 315 rpp->p_dsize = rip->p_dsize; 316 rpp->p_ssize = rip->p_ssize; 317 rpp->p_szpt = rip->p_szpt; 318 forkstat.cntfork++; 319 forkstat.sizfork += rip->p_dsize + rip->p_ssize; 320 } 321 rpp->p_rssize = 0; 322 rpp->p_wchan = 0; 323 rpp->p_slptime = 0; 324 rpp->p_aveflt = rip->p_aveflt; 325 rate.v_pgin += rip->p_aveflt; 326 rpp->p_faults = 0; 327 n = PIDHASH(rpp->p_pid); 328 p->p_idhash = pidhash[n]; 329 pidhash[n] = rpp - proc; 330 331 /* 332 * make duplicate entries 333 * where needed 334 */ 335 336 multprog++; 337 338 for(n=0; n<NOFILE; n++) 339 if(u.u_ofile[n] != NULL) { 340 u.u_ofile[n]->f_count++; 341 if(!isvfork && u.u_vrpages[n]) 342 u.u_ofile[n]->f_inode->i_vfdcnt++; 343 } 344 345 u.u_cdir->i_count++; 346 if (u.u_rdir) 347 u.u_rdir->i_count++; 348 /* 349 * Partially simulate the environment 350 * of the new process so that when it is actually 351 * created (by copying) it will look right. 352 */ 353 354 rip->p_flag |= SKEEP; /* prevent parent from being swapped */ 355 356 if (procdup(rpp, isvfork)) 357 return (1); 358 359 spl6(); 360 rpp->p_stat = SRUN; 361 setrq(rpp); 362 spl0(); 363 /* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */ 364 /* rpp->p_flag |= SSWAP; */ 365 rip->p_flag &= ~SKEEP; 366 if (isvfork) { 367 u.u_procp->p_xlink = rpp; 368 u.u_procp->p_flag |= SNOVM; 369 while (rpp->p_flag & SVFORK) 370 sleep((caddr_t)rpp, PZERO - 1); 371 if ((rpp->p_flag & SLOAD) == 0) 372 panic("newproc vfork"); 373 uaccess(rpp, Vfmap, &vfutl); 374 u.u_procp->p_xlink = 0; 375 vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 376 for (n = 0; n < NOFILE; n++) 377 if (vfutl.u_vrpages[n]) { 378 if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0) 379 if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0) 380 panic("newproc i_vfdcnt"); 381 vfutl.u_vrpages[n] = 0; 382 } 383 u.u_procp->p_flag &= ~SNOVM; 384 rpp->p_ndx = rpp - proc; 385 rpp->p_flag |= SVFDONE; 386 wakeup((caddr_t)rpp); 387 } 388 return (0); 389 } 390