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