xref: /original-bsd/sys/vm/vm_glue.c (revision ba762ddc)
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.4 (Berkeley) 05/02/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+len
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 /*
113  * Implement fork's actions on an address space.
114  * Here we arrange for the address space to be copied or referenced,
115  * allocate a user struct (pcb and kernel stack), then call the
116  * machine-dependent layer to fill those in and make the new process
117  * ready to run.
118  * NOTE: the kernel stack may be at a different location in the child
119  * process, and thus addresses of automatic variables may be invalid
120  * after cpu_fork returns in the child process.  We do nothing here
121  * after cpu_fork returns.
122  */
123 vm_fork(p1, p2, isvfork)
124 	register struct proc *p1, *p2;
125 	int isvfork;
126 {
127 	register struct user *up;
128 	vm_offset_t addr;
129 
130 	p2->p_vmspace = vmspace_fork(p1->p_vmspace);
131 
132 #ifdef SYSVSHM
133 	if (p1->p_vmspace->vm_shm)
134 		shmfork(p1, p2, isvfork);
135 #endif
136 
137 	/*
138 	 * Allocate a wired-down (for now) pcb and kernel stack for the process
139 	 */
140 	addr = kmem_alloc_pageable(kernel_map, ctob(UPAGES));
141 	vm_map_pageable(kernel_map, addr, addr + ctob(UPAGES), FALSE);
142 	up = (struct user *)addr;
143 	p2->p_addr = up;
144 
145 	/*
146 	 * p_stats and p_sigacts currently point at fields
147 	 * in the user struct but not at &u, instead at p_addr.
148 	 * Copy p_sigacts and parts of p_stats; zero the rest
149 	 * of p_stats (statistics).
150 	 */
151 	p2->p_stats = &up->u_stats;
152 	p2->p_sigacts = &up->u_sigacts;
153 	up->u_sigacts = *p1->p_sigacts;
154 	bzero(&up->u_stats.pstat_startzero,
155 	    (unsigned) ((caddr_t)&up->u_stats.pstat_endzero -
156 	    (caddr_t)&up->u_stats.pstat_startzero));
157 	bcopy(&p1->p_stats->pstat_startcopy, &up->u_stats.pstat_startcopy,
158 	    ((caddr_t)&up->u_stats.pstat_endcopy -
159 	     (caddr_t)&up->u_stats.pstat_startcopy));
160 
161 	/*
162 	 * cpu_fork will copy and update the kernel stack and pcb,
163 	 * and make the child ready to run.  It marks the child
164 	 * so that it can return differently than the parent.
165 	 * It returns twice, once in the parent process and
166 	 * once in the child.
167 	 */
168 	return (cpu_fork(p1, p2));
169 }
170 
171 /*
172  * Set default limits for VM system.
173  * Called for proc 0, and then inherited by all others.
174  */
175 vm_init_limits(p)
176 	register struct proc *p;
177 {
178 
179 	/*
180 	 * Set up the initial limits on process VM.
181 	 * Set the maximum resident set size to be all
182 	 * of (reasonably) available memory.  This causes
183 	 * any single, large process to start random page
184 	 * replacement once it fills memory.
185 	 */
186         p->p_rlimit[RLIMIT_STACK].rlim_cur = DFLSSIZ;
187         p->p_rlimit[RLIMIT_STACK].rlim_max = MAXSSIZ;
188         p->p_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
189         p->p_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
190 	p->p_rlimit[RLIMIT_RSS].rlim_cur = p->p_rlimit[RLIMIT_RSS].rlim_max =
191 		ptoa(vm_page_free_count);
192 }
193 
194 #include "../vm/vm_pageout.h"
195 
196 #ifdef DEBUG
197 int	enableswap = 1;
198 int	swapdebug = 0;
199 #define	SDB_FOLLOW	1
200 #define SDB_SWAPIN	2
201 #define SDB_SWAPOUT	4
202 #endif
203 
204 /*
205  * Brutally simple:
206  *	1. Attempt to swapin every swaped-out, runnable process in
207  *	   order of priority.
208  *	2. If not enough memory, wake the pageout daemon and let it
209  *	   clear some space.
210  */
211 sched()
212 {
213 	register struct proc *p;
214 	register int pri;
215 	struct proc *pp;
216 	int ppri;
217 	vm_offset_t addr;
218 	vm_size_t size;
219 
220 loop:
221 #ifdef DEBUG
222 	if (!enableswap) {
223 		pp = NULL;
224 		goto noswap;
225 	}
226 #endif
227 	pp = NULL;
228 	ppri = INT_MIN;
229 	for (p = allproc; p != NULL; p = p->p_nxt)
230 		if (p->p_stat == SRUN && (p->p_flag & SLOAD) == 0) {
231 			pri = p->p_time + p->p_slptime - p->p_nice * 8;
232 			if (pri > ppri) {
233 				pp = p;
234 				ppri = pri;
235 			}
236 		}
237 #ifdef DEBUG
238 	if (swapdebug & SDB_FOLLOW)
239 		printf("sched: running, procp %x pri %d\n", pp, ppri);
240 noswap:
241 #endif
242 	/*
243 	 * Nothing to do, back to sleep
244 	 */
245 	if ((p = pp) == NULL) {
246 		sleep((caddr_t)&proc0, PVM);
247 		goto loop;
248 	}
249 
250 	/*
251 	 * We would like to bring someone in.
252 	 * This part is really bogus cuz we could deadlock on memory
253 	 * despite our feeble check.
254 	 */
255 	size = round_page(ctob(UPAGES));
256 	addr = (vm_offset_t) p->p_addr;
257 	if (vm_page_free_count > atop(size)) {
258 #ifdef DEBUG
259 		if (swapdebug & SDB_SWAPIN)
260 			printf("swapin: pid %d(%s)@%x, pri %d free %d\n",
261 			       p->p_pid, p->p_comm, p->p_addr,
262 			       ppri, vm_page_free_count);
263 #endif
264 		vm_map_pageable(kernel_map, addr, addr+size, FALSE);
265 		(void) splclock();
266 		if (p->p_stat == SRUN)
267 			setrq(p);
268 		p->p_flag |= SLOAD;
269 		(void) spl0();
270 		p->p_time = 0;
271 		goto loop;
272 	}
273 	/*
274 	 * Not enough memory, jab the pageout daemon and wait til the
275 	 * coast is clear.
276 	 */
277 #ifdef DEBUG
278 	if (swapdebug & SDB_FOLLOW)
279 		printf("sched: no room for pid %d(%s), free %d\n",
280 		       p->p_pid, p->p_comm, vm_page_free_count);
281 #endif
282 	(void) splhigh();
283 	VM_WAIT;
284 	(void) spl0();
285 #ifdef DEBUG
286 	if (swapdebug & SDB_FOLLOW)
287 		printf("sched: room again, free %d\n", vm_page_free_count);
288 #endif
289 	goto loop;
290 }
291 
292 #define	swappable(p) \
293 	(((p)->p_flag & (SSYS|SLOAD|SKEEP|SWEXIT|SPHYSIO)) == SLOAD)
294 
295 /*
296  * Swapout is driven by the pageout daemon.  Very simple, we find eligible
297  * procs and unwire their u-areas.  We try to always "swap" at least one
298  * process in case we need the room for a swapin.
299  * If any procs have been sleeping/stopped for at least maxslp seconds,
300  * they are swapped.  Else, we swap the longest-sleeping or stopped process,
301  * if any, otherwise the longest-resident process.
302  */
303 swapout_threads()
304 {
305 	register struct proc *p;
306 	struct proc *outp, *outp2;
307 	int outpri, outpri2;
308 	int didswap = 0;
309 	extern int maxslp;
310 
311 #ifdef DEBUG
312 	if (!enableswap)
313 		return;
314 #endif
315 	outp = outp2 = NULL;
316 	outpri = outpri2 = 0;
317 	for (p = allproc; p != NULL; p = p->p_nxt) {
318 		if (!swappable(p))
319 			continue;
320 		switch (p->p_stat) {
321 		case SRUN:
322 			if (p->p_time > outpri2) {
323 				outp2 = p;
324 				outpri2 = p->p_time;
325 			}
326 			continue;
327 
328 		case SSLEEP:
329 		case SSTOP:
330 			if (p->p_slptime > maxslp) {
331 				swapout(p);
332 				didswap++;
333 			} else if (p->p_slptime > outpri) {
334 				outp = p;
335 				outpri = p->p_slptime;
336 			}
337 			continue;
338 		}
339 	}
340 	/*
341 	 * If we didn't get rid of any real duds, toss out the next most
342 	 * likely sleeping/stopped or running candidate.  We only do this
343 	 * if we are real low on memory since we don't gain much by doing
344 	 * it (UPAGES pages).
345 	 */
346 	if (didswap == 0 &&
347 	    vm_page_free_count <= atop(round_page(ctob(UPAGES)))) {
348 		if ((p = outp) == 0)
349 			p = outp2;
350 #ifdef DEBUG
351 		if (swapdebug & SDB_SWAPOUT)
352 			printf("swapout_threads: no duds, try procp %x\n", p);
353 #endif
354 		if (p)
355 			swapout(p);
356 	}
357 }
358 
359 swapout(p)
360 	register struct proc *p;
361 {
362 	vm_offset_t addr;
363 	vm_size_t size;
364 
365 #ifdef DEBUG
366 	if (swapdebug & SDB_SWAPOUT)
367 		printf("swapout: pid %d(%s)@%x, stat %x pri %d free %d\n",
368 		       p->p_pid, p->p_comm, p->p_addr, p->p_stat,
369 		       p->p_slptime, vm_page_free_count);
370 #endif
371 	size = round_page(ctob(UPAGES));
372 	addr = (vm_offset_t) p->p_addr;
373 	vm_map_pageable(kernel_map, addr, addr+size, TRUE);
374 	pmap_collect(vm_map_pmap(&p->p_vmspace->vm_map));
375 	(void) splhigh();
376 	p->p_flag &= ~SLOAD;
377 	if (p->p_stat == SRUN)
378 		remrq(p);
379 	(void) spl0();
380 	p->p_time = 0;
381 }
382 
383 /*
384  * The rest of these routines fake thread handling
385  */
386 
387 void
388 assert_wait(event, ruptible)
389 	int event;
390 	boolean_t ruptible;
391 {
392 #ifdef lint
393 	ruptible++;
394 #endif
395 	curproc->p_thread = event;
396 }
397 
398 void
399 thread_block()
400 {
401 	int s = splhigh();
402 
403 	if (curproc->p_thread)
404 		sleep((caddr_t)curproc->p_thread, PVM);
405 	splx(s);
406 }
407 
408 thread_sleep(event, lock, ruptible)
409 	int event;
410 	simple_lock_t lock;
411 	boolean_t ruptible;
412 {
413 #ifdef lint
414 	ruptible++;
415 #endif
416 	int s = splhigh();
417 
418 	curproc->p_thread = event;
419 	simple_unlock(lock);
420 	if (curproc->p_thread)
421 		sleep((caddr_t)event, PVM);
422 	splx(s);
423 }
424 
425 thread_wakeup(event)
426 	int event;
427 {
428 	int s = splhigh();
429 
430 	wakeup((caddr_t)event);
431 	splx(s);
432 }
433 
434 /*
435  * DEBUG stuff
436  */
437 
438 int indent = 0;
439 
440 /*ARGSUSED2*/
441 iprintf(a, b, c, d, e, f, g, h)
442 	char *a;
443 {
444 	register int i;
445 
446 	for (i = indent; i > 0; ) {
447 		if (i >= 8) {
448 			putchar('\t', 1, (caddr_t)0);
449 			i -= 8;
450 		} else {
451 			putchar(' ', 1, (caddr_t)0);
452 			i--;
453 		}
454 	}
455 	printf(a, b, c, d, e, f, g, h);
456 }
457