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