xref: /csrg-svn/sys/vm/vm_glue.c (revision 48493)
1 /*
2  * Copyright (c) 1991 Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * The Mach Operating System project at Carnegie-Mellon University.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)vm_glue.c	7.3 (Berkeley) 04/21/91
11  *
12  *
13  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
14  * All rights reserved.
15  *
16  * Permission to use, copy, modify and distribute this software and
17  * its documentation is hereby granted, provided that both the copyright
18  * notice and this permission notice appear in all copies of the
19  * software, derivative works or modified versions, and any portions
20  * thereof, and that both notices appear in supporting documentation.
21  *
22  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
23  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
24  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
25  *
26  * Carnegie Mellon requests users of this software to return to
27  *
28  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
29  *  School of Computer Science
30  *  Carnegie Mellon University
31  *  Pittsburgh PA 15213-3890
32  *
33  * any improvements or extensions that they make and grant Carnegie the
34  * rights to redistribute these changes.
35  */
36 
37 #include "param.h"
38 #include "systm.h"
39 #include "proc.h"
40 #include "resourcevar.h"
41 #include "buf.h"
42 #include "user.h"
43 
44 #include "vm.h"
45 #include "vm_page.h"
46 #include "vm_kern.h"
47 
48 int	avefree = 0;		/* XXX */
49 unsigned maxdmap = MAXDSIZ;	/* XXX */
50 
51 kernacc(addr, len, rw)
52 	caddr_t addr;
53 	int len, rw;
54 {
55 	boolean_t rv;
56 	vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
57 
58 	rv = vm_map_check_protection(kernel_map, trunc_page(addr),
59 				     round_page(addr+len-1), prot);
60 	return(rv == TRUE);
61 }
62 
63 useracc(addr, len, rw)
64 	caddr_t addr;
65 	int len, rw;
66 {
67 	boolean_t rv;
68 	vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
69 
70 	rv = vm_map_check_protection(&curproc->p_vmspace->vm_map,
71 	    trunc_page(addr), round_page(addr+len-1), prot);
72 	return(rv == TRUE);
73 }
74 
75 #ifdef KGDB
76 /*
77  * Change protections on kernel pages from addr to addr+size
78  * (presumably so debugger can plant a breakpoint).
79  * All addresses are assumed to reside in the Sysmap,
80  */
81 chgkprot(addr, len, rw)
82 	register caddr_t addr;
83 	int len, rw;
84 {
85 	vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
86 
87 	vm_map_protect(kernel_map, trunc_page(addr),
88 		       round_page(addr+len-1), prot, FALSE);
89 }
90 #endif
91 
92 vslock(addr, len)
93 	caddr_t	addr;
94 	u_int	len;
95 {
96 	vm_map_pageable(&curproc->p_vmspace->vm_map, trunc_page(addr),
97 			round_page(addr+len-1), FALSE);
98 }
99 
100 vsunlock(addr, len, dirtied)
101 	caddr_t	addr;
102 	u_int	len;
103 	int dirtied;
104 {
105 #ifdef	lint
106 	dirtied++;
107 #endif	lint
108 	vm_map_pageable(&curproc->p_vmspace->vm_map, trunc_page(addr),
109 			round_page(addr+len-1), TRUE);
110 }
111 
112 vm_fork(p1, p2, isvfork)
113 	register struct proc *p1, *p2;
114 	int isvfork;
115 {
116 	register struct user *up;
117 	vm_offset_t addr;
118 	vm_size_t size;
119 
120 	p2->p_vmspace = vmspace_fork(p1->p_vmspace);
121 
122 #ifdef SYSVSHM
123 	if (p1->p_vmspace->vm_shm)
124 		shmfork(p1, p2, isvfork);
125 #endif
126 
127 	/*
128 	 * Allocate a wired-down (for now) u-area for the process
129 	 */
130 	size = round_page(ctob(UPAGES));
131 	addr = kmem_alloc_pageable(kernel_map, size);
132 	vm_map_pageable(kernel_map, addr, addr + size, FALSE);
133 	p2->p_addr = (caddr_t)addr;
134 	up = (struct user *)addr;
135 
136 	/*
137 	 * Update the current u-area and copy it to the new one
138 	 * THIS SHOULD BE DONE DIFFERENTLY, probably with a single
139 	 * machine-dependent call that copies and updates the pcb+stack,
140 	 * replacing the resume and savectx.
141 	 */
142 	resume(pcbb(p1));
143 	bcopy(p1->p_addr, p2->p_addr, size);
144 	/*
145 	 * p_stats and p_sigacts currently point at fields
146 	 * in the user struct but not at &u, instead at p_addr.
147 	 */
148 	p2->p_stats = &((struct user *)p2->p_addr)->u_stats;
149 	p2->p_sigacts = &((struct user *)p2->p_addr)->u_sigacts;
150 
151 	/*
152 	 * Clear vm statistics of new process.
153 	 */
154 	bzero((caddr_t)&up->u_stats.p_ru, sizeof (struct rusage));
155 	bzero((caddr_t)&up->u_stats.p_cru, sizeof (struct rusage));
156 
157 	PMAP_ACTIVATE(&p2->p_vmspace->vm_pmap, (struct pcb *)p2->p_addr, 0);
158 
159 	/*
160 	 * Arrange for a non-local goto when the new process
161 	 * is started, to resume here, returning nonzero from setjmp.
162 	 */
163 	up->u_pcb.pcb_sswap = (int *)&u.u_ssave;
164 	if (savectx(&up->u_ssave)) {
165 		/*
166 		 * Return 1 in child.
167 		 */
168 		return (1);
169 	}
170 	return (0);
171 }
172 
173 /*
174  * Set default limits for VM system.
175  * Called for proc 0, and then inherited by all others.
176  */
177 vm_init_limits(p)
178 	register struct proc *p;
179 {
180 
181 	/*
182 	 * Set up the initial limits on process VM.
183 	 * Set the maximum resident set size to be all
184 	 * of (reasonably) available memory.  This causes
185 	 * any single, large process to start random page
186 	 * replacement once it fills memory.
187 	 */
188         p->p_rlimit[RLIMIT_STACK].rlim_cur = DFLSSIZ;
189         p->p_rlimit[RLIMIT_STACK].rlim_max = MAXSSIZ;
190         p->p_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
191         p->p_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
192 	p->p_rlimit[RLIMIT_RSS].rlim_cur = p->p_rlimit[RLIMIT_RSS].rlim_max =
193 		ptoa(vm_page_free_count);
194 }
195 
196 #include "../vm/vm_pageout.h"
197 
198 #ifdef DEBUG
199 int	enableswap = 1;
200 int	swapdebug = 0;
201 #define	SDB_FOLLOW	1
202 #define SDB_SWAPIN	2
203 #define SDB_SWAPOUT	4
204 #endif
205 
206 /*
207  * Brutally simple:
208  *	1. Attempt to swapin every swaped-out, runnable process in
209  *	   order of priority.
210  *	2. If not enough memory, wake the pageout daemon and let it
211  *	   clear some space.
212  */
213 sched()
214 {
215 	register struct proc *p;
216 	register int pri;
217 	struct proc *pp;
218 	int ppri;
219 	vm_offset_t addr;
220 	vm_size_t size;
221 
222 loop:
223 #ifdef DEBUG
224 	if (!enableswap) {
225 		pp = NULL;
226 		goto noswap;
227 	}
228 #endif
229 	pp = NULL;
230 	ppri = INT_MIN;
231 	for (p = allproc; p != NULL; p = p->p_nxt)
232 		if (p->p_stat == SRUN && (p->p_flag & SLOAD) == 0) {
233 			pri = p->p_time + p->p_slptime - p->p_nice * 8;
234 			if (pri > ppri) {
235 				pp = p;
236 				ppri = pri;
237 			}
238 		}
239 #ifdef DEBUG
240 	if (swapdebug & SDB_FOLLOW)
241 		printf("sched: running, procp %x pri %d\n", pp, ppri);
242 noswap:
243 #endif
244 	/*
245 	 * Nothing to do, back to sleep
246 	 */
247 	if ((p = pp) == NULL) {
248 		sleep((caddr_t)&proc0, PVM);
249 		goto loop;
250 	}
251 
252 	/*
253 	 * We would like to bring someone in.
254 	 * This part is really bogus cuz we could deadlock on memory
255 	 * despite our feeble check.
256 	 */
257 	size = round_page(ctob(UPAGES));
258 	addr = (vm_offset_t) p->p_addr;
259 	if (vm_page_free_count > atop(size)) {
260 #ifdef DEBUG
261 		if (swapdebug & SDB_SWAPIN)
262 			printf("swapin: pid %d(%s)@%x, pri %d free %d\n",
263 			       p->p_pid, p->p_comm, p->p_addr,
264 			       ppri, vm_page_free_count);
265 #endif
266 		vm_map_pageable(kernel_map, addr, addr+size, FALSE);
267 		(void) splclock();
268 		if (p->p_stat == SRUN)
269 			setrq(p);
270 		p->p_flag |= SLOAD;
271 		(void) spl0();
272 		p->p_time = 0;
273 		goto loop;
274 	}
275 	/*
276 	 * Not enough memory, jab the pageout daemon and wait til the
277 	 * coast is clear.
278 	 */
279 #ifdef DEBUG
280 	if (swapdebug & SDB_FOLLOW)
281 		printf("sched: no room for pid %d(%s), free %d\n",
282 		       p->p_pid, p->p_comm, vm_page_free_count);
283 #endif
284 	(void) splhigh();
285 	VM_WAIT;
286 	(void) spl0();
287 #ifdef DEBUG
288 	if (swapdebug & SDB_FOLLOW)
289 		printf("sched: room again, free %d\n", vm_page_free_count);
290 #endif
291 	goto loop;
292 }
293 
294 #define	swappable(p) \
295 	(((p)->p_flag & (SSYS|SLOAD|SKEEP|SWEXIT|SPHYSIO)) == SLOAD)
296 
297 /*
298  * Swapout is driven by the pageout daemon.  Very simple, we find eligible
299  * procs and unwire their u-areas.  We try to always "swap" at least one
300  * process in case we need the room for a swapin.
301  * If any procs have been sleeping/stopped for at least maxslp seconds,
302  * they are swapped.  Else, we swap the longest-sleeping or stopped process,
303  * if any, otherwise the longest-resident process.
304  */
305 swapout_threads()
306 {
307 	register struct proc *p;
308 	struct proc *outp, *outp2;
309 	int outpri, outpri2;
310 	int didswap = 0;
311 	extern int maxslp;
312 
313 #ifdef DEBUG
314 	if (!enableswap)
315 		return;
316 #endif
317 	outp = outp2 = NULL;
318 	outpri = outpri2 = 0;
319 	for (p = allproc; p != NULL; p = p->p_nxt) {
320 		if (!swappable(p))
321 			continue;
322 		switch (p->p_stat) {
323 		case SRUN:
324 			if (p->p_time > outpri2) {
325 				outp2 = p;
326 				outpri2 = p->p_time;
327 			}
328 			continue;
329 
330 		case SSLEEP:
331 		case SSTOP:
332 			if (p->p_slptime > maxslp) {
333 				swapout(p);
334 				didswap++;
335 			} else if (p->p_slptime > outpri) {
336 				outp = p;
337 				outpri = p->p_slptime;
338 			}
339 			continue;
340 		}
341 	}
342 	/*
343 	 * If we didn't get rid of any real duds, toss out the next most
344 	 * likely sleeping/stopped or running candidate.  We only do this
345 	 * if we are real low on memory since we don't gain much by doing
346 	 * it (UPAGES pages).
347 	 */
348 	if (didswap == 0 &&
349 	    vm_page_free_count <= atop(round_page(ctob(UPAGES)))) {
350 		if ((p = outp) == 0)
351 			p = outp2;
352 #ifdef DEBUG
353 		if (swapdebug & SDB_SWAPOUT)
354 			printf("swapout_threads: no duds, try procp %x\n", p);
355 #endif
356 		if (p)
357 			swapout(p);
358 	}
359 }
360 
361 swapout(p)
362 	register struct proc *p;
363 {
364 	vm_offset_t addr;
365 	vm_size_t size;
366 
367 #ifdef DEBUG
368 	if (swapdebug & SDB_SWAPOUT)
369 		printf("swapout: pid %d(%s)@%x, stat %x pri %d free %d\n",
370 		       p->p_pid, p->p_comm, p->p_addr, p->p_stat,
371 		       p->p_slptime, vm_page_free_count);
372 #endif
373 	size = round_page(ctob(UPAGES));
374 	addr = (vm_offset_t) p->p_addr;
375 	vm_map_pageable(kernel_map, addr, addr+size, TRUE);
376 	pmap_collect(vm_map_pmap(&p->p_vmspace->vm_map));
377 	(void) splhigh();
378 	p->p_flag &= ~SLOAD;
379 	if (p->p_stat == SRUN)
380 		remrq(p);
381 	(void) spl0();
382 	p->p_time = 0;
383 }
384 
385 /*
386  * The rest of these routines fake thread handling
387  */
388 
389 void
390 assert_wait(event, ruptible)
391 	int event;
392 	boolean_t ruptible;
393 {
394 #ifdef lint
395 	ruptible++;
396 #endif
397 	curproc->p_thread = event;
398 }
399 
400 void
401 thread_block()
402 {
403 	int s = splhigh();
404 
405 	if (curproc->p_thread)
406 		sleep((caddr_t)curproc->p_thread, PVM);
407 	splx(s);
408 }
409 
410 thread_sleep(event, lock, ruptible)
411 	int event;
412 	simple_lock_t lock;
413 	boolean_t ruptible;
414 {
415 #ifdef lint
416 	ruptible++;
417 #endif
418 	int s = splhigh();
419 
420 	curproc->p_thread = event;
421 	simple_unlock(lock);
422 	if (curproc->p_thread)
423 		sleep((caddr_t)event, PVM);
424 	splx(s);
425 }
426 
427 thread_wakeup(event)
428 	int event;
429 {
430 	int s = splhigh();
431 
432 	wakeup((caddr_t)event);
433 	splx(s);
434 }
435 
436 /*
437  * DEBUG stuff
438  */
439 
440 int indent = 0;
441 
442 /*ARGSUSED2*/
443 iprintf(a, b, c, d, e, f, g, h)
444 	char *a;
445 {
446 	register int i;
447 
448 	for (i = indent; i > 0; ) {
449 		if (i >= 8) {
450 			putchar('\t', 1, (caddr_t)0);
451 			i -= 8;
452 		} else {
453 			putchar(' ', 1, (caddr_t)0);
454 			i--;
455 		}
456 	}
457 	printf(a, b, c, d, e, f, g, h);
458 }
459