xref: /freebsd/sys/kern/sysv_shm.c (revision 8e6b01171e30297084bb0b4457c4183c2746aacc)
1 /*	$Id: sysv_shm.c,v 1.9 1995/09/09 18:10:09 davidg Exp $ */
2 /*	$NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $	*/
3 
4 /*
5  * Copyright (c) 1994 Adam Glass and Charles Hannum.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Adam Glass and Charles
18  *	Hannum.
19  * 4. The names of the authors may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/sysproto.h>
37 #include <sys/kernel.h>
38 #include <sys/shm.h>
39 #include <sys/proc.h>
40 #include <sys/malloc.h>
41 #include <sys/mman.h>
42 #include <sys/stat.h>
43 #include <sys/sysent.h>
44 
45 #include <vm/vm.h>
46 #include <vm/vm_map.h>
47 #include <vm/vm_kern.h>
48 
49 struct shmat_args;
50 extern int shmat __P((struct proc *p, struct shmat_args *uap, int *retval));
51 struct shmctl_args;
52 extern int shmctl __P((struct proc *p, struct shmctl_args *uap, int *retval));
53 struct shmdt_args;
54 extern int shmdt __P((struct proc *p, struct shmdt_args *uap, int *retval));
55 struct shmget_args;
56 extern int shmget __P((struct proc *p, struct shmget_args *uap, int *retval));
57 
58 static void shminit __P((void *));
59 SYSINIT(sysv_shm, SI_SUB_SYSV_SHM, SI_ORDER_FIRST, shminit, NULL)
60 
61 struct oshmctl_args;
62 int oshmctl __P((struct proc *p, struct oshmctl_args *uap, int *retval));
63 static int shmget_allocate_segment __P((struct proc *p, struct shmget_args *uap, int mode, int *retval));
64 static int shmget_existing __P((struct proc *p, struct shmget_args *uap, int mode, int segnum, int *retval));
65 
66 /* XXX casting to (sy_call_t *) is bogus, as usual. */
67 sy_call_t *shmcalls[] = {
68 	(sy_call_t *)shmat, (sy_call_t *)oshmctl,
69 	(sy_call_t *)shmdt, (sy_call_t *)shmget,
70 	(sy_call_t *)shmctl
71 };
72 
73 #define	SHMSEG_FREE     	0x0200
74 #define	SHMSEG_REMOVED  	0x0400
75 #define	SHMSEG_ALLOCATED	0x0800
76 #define	SHMSEG_WANTED		0x1000
77 
78 vm_map_t sysvshm_map;
79 int shm_last_free, shm_nused, shm_committed;
80 struct shmid_ds	*shmsegs;
81 
82 struct shm_handle {
83 	vm_offset_t kva;
84 };
85 
86 struct shmmap_state {
87 	vm_offset_t va;
88 	int shmid;
89 };
90 
91 static void shm_deallocate_segment __P((struct shmid_ds *));
92 static int shm_find_segment_by_key __P((key_t));
93 static struct shmid_ds *shm_find_segment_by_shmid __P((int));
94 static int shm_delete_mapping __P((struct proc *, struct shmmap_state *));
95 
96 static int
97 shm_find_segment_by_key(key)
98 	key_t key;
99 {
100 	int i;
101 
102 	for (i = 0; i < shminfo.shmmni; i++)
103 		if ((shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) &&
104 		    shmsegs[i].shm_perm.key == key)
105 			return i;
106 	return -1;
107 }
108 
109 static struct shmid_ds *
110 shm_find_segment_by_shmid(shmid)
111 	int shmid;
112 {
113 	int segnum;
114 	struct shmid_ds *shmseg;
115 
116 	segnum = IPCID_TO_IX(shmid);
117 	if (segnum < 0 || segnum >= shminfo.shmmni)
118 		return NULL;
119 	shmseg = &shmsegs[segnum];
120 	if ((shmseg->shm_perm.mode & (SHMSEG_ALLOCATED | SHMSEG_REMOVED))
121 	    != SHMSEG_ALLOCATED ||
122 	    shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid))
123 		return NULL;
124 	return shmseg;
125 }
126 
127 static void
128 shm_deallocate_segment(shmseg)
129 	struct shmid_ds *shmseg;
130 {
131 	struct shm_handle *shm_handle;
132 	size_t size;
133 
134 	shm_handle = shmseg->shm_internal;
135 	size = (shmseg->shm_segsz + CLOFSET) & ~CLOFSET;
136 	(void) vm_map_remove(sysvshm_map, shm_handle->kva, shm_handle->kva + size);
137 	free((caddr_t)shm_handle, M_SHM);
138 	shmseg->shm_internal = NULL;
139 	shm_committed -= btoc(size);
140 	shm_nused--;
141 	shmseg->shm_perm.mode = SHMSEG_FREE;
142 }
143 
144 static int
145 shm_delete_mapping(p, shmmap_s)
146 	struct proc *p;
147 	struct shmmap_state *shmmap_s;
148 {
149 	struct shmid_ds *shmseg;
150 	int segnum, result;
151 	size_t size;
152 
153 	segnum = IPCID_TO_IX(shmmap_s->shmid);
154 	shmseg = &shmsegs[segnum];
155 	size = (shmseg->shm_segsz + CLOFSET) & ~CLOFSET;
156 	result = vm_map_remove(&p->p_vmspace->vm_map, shmmap_s->va, shmmap_s->va + size);
157 	if (result != KERN_SUCCESS)
158 		return EINVAL;
159 	shmmap_s->shmid = -1;
160 	shmseg->shm_dtime = time.tv_sec;
161 	if ((--shmseg->shm_nattch <= 0) &&
162 	    (shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
163 		shm_deallocate_segment(shmseg);
164 		shm_last_free = segnum;
165 	}
166 	return 0;
167 }
168 
169 struct shmdt_args {
170 	void *shmaddr;
171 };
172 int
173 shmdt(p, uap, retval)
174 	struct proc *p;
175 	struct shmdt_args *uap;
176 	int *retval;
177 {
178 	struct shmmap_state *shmmap_s;
179 	int i;
180 
181 	shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
182 	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
183 		if (shmmap_s->shmid != -1 &&
184 		    shmmap_s->va == (vm_offset_t)uap->shmaddr)
185 			break;
186 	if (i == shminfo.shmseg)
187 		return EINVAL;
188 	return shm_delete_mapping(p, shmmap_s);
189 }
190 
191 struct shmat_args {
192 	int shmid;
193 	void *shmaddr;
194 	int shmflg;
195 };
196 int
197 shmat(p, uap, retval)
198 	struct proc *p;
199 	struct shmat_args *uap;
200 	int *retval;
201 {
202 	int error, i, flags;
203 	struct ucred *cred = p->p_ucred;
204 	struct shmid_ds *shmseg;
205 	struct shmmap_state *shmmap_s = NULL;
206 	vm_offset_t attach_va;
207 	vm_prot_t prot;
208 	vm_size_t size;
209 
210 	shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
211 	if (shmmap_s == NULL) {
212 		size = shminfo.shmseg * sizeof(struct shmmap_state);
213 		shmmap_s = malloc(size, M_SHM, M_WAITOK);
214 		for (i = 0; i < shminfo.shmseg; i++)
215 			shmmap_s[i].shmid = -1;
216 		p->p_vmspace->vm_shm = (caddr_t)shmmap_s;
217 	}
218 	shmseg = shm_find_segment_by_shmid(uap->shmid);
219 	if (shmseg == NULL)
220 		return EINVAL;
221 	error = ipcperm(cred, &shmseg->shm_perm,
222 	    (uap->shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
223 	if (error)
224 		return error;
225 	for (i = 0; i < shminfo.shmseg; i++) {
226 		if (shmmap_s->shmid == -1)
227 			break;
228 		shmmap_s++;
229 	}
230 	if (i >= shminfo.shmseg)
231 		return EMFILE;
232 	size = (shmseg->shm_segsz + CLOFSET) & ~CLOFSET;
233 	prot = VM_PROT_READ;
234 	if ((uap->shmflg & SHM_RDONLY) == 0)
235 		prot |= VM_PROT_WRITE;
236 	flags = MAP_ANON | MAP_SHARED;
237 	if (uap->shmaddr) {
238 		flags |= MAP_FIXED;
239 		if (uap->shmflg & SHM_RND)
240 			attach_va = (vm_offset_t)uap->shmaddr & ~(SHMLBA-1);
241 		else if (((vm_offset_t)uap->shmaddr & (SHMLBA-1)) == 0)
242 			attach_va = (vm_offset_t)uap->shmaddr;
243 		else
244 			return EINVAL;
245 	} else {
246 		/* This is just a hint to vm_mmap() about where to put it. */
247 		attach_va = round_page(p->p_vmspace->vm_daddr + MAXDSIZ);
248 	}
249 	error = vm_mmap(&p->p_vmspace->vm_map, &attach_va, size, prot,
250 	    VM_PROT_DEFAULT, flags, (caddr_t) uap->shmid, 0);
251 	if (error)
252 		return error;
253 	shmmap_s->va = attach_va;
254 	shmmap_s->shmid = uap->shmid;
255 	shmseg->shm_lpid = p->p_pid;
256 	shmseg->shm_atime = time.tv_sec;
257 	shmseg->shm_nattch++;
258 	*retval = attach_va;
259 	return 0;
260 }
261 
262 struct oshmid_ds {
263 	struct	ipc_perm shm_perm;	/* operation perms */
264 	int	shm_segsz;		/* size of segment (bytes) */
265 	ushort	shm_cpid;		/* pid, creator */
266 	ushort	shm_lpid;		/* pid, last operation */
267 	short	shm_nattch;		/* no. of current attaches */
268 	time_t	shm_atime;		/* last attach time */
269 	time_t	shm_dtime;		/* last detach time */
270 	time_t	shm_ctime;		/* last change time */
271 	void	*shm_handle;		/* internal handle for shm segment */
272 };
273 
274 struct oshmctl_args {
275 	int shmid;
276 	int cmd;
277 	struct oshmid_ds *ubuf;
278 };
279 
280 int
281 oshmctl(p, uap, retval)
282 	struct proc *p;
283 	struct oshmctl_args *uap;
284 	int *retval;
285 {
286 #ifdef COMPAT_43
287 	int error;
288 	struct ucred *cred = p->p_ucred;
289 	struct shmid_ds *shmseg;
290 	struct oshmid_ds outbuf;
291 
292 	shmseg = shm_find_segment_by_shmid(uap->shmid);
293 	if (shmseg == NULL)
294 		return EINVAL;
295 	switch (uap->cmd) {
296 	case IPC_STAT:
297 		error = ipcperm(cred, &shmseg->shm_perm, IPC_R);
298 		if (error)
299 			return error;
300 		outbuf.shm_perm = shmseg->shm_perm;
301 		outbuf.shm_segsz = shmseg->shm_segsz;
302 		outbuf.shm_cpid = shmseg->shm_cpid;
303 		outbuf.shm_lpid = shmseg->shm_lpid;
304 		outbuf.shm_nattch = shmseg->shm_nattch;
305 		outbuf.shm_atime = shmseg->shm_atime;
306 		outbuf.shm_dtime = shmseg->shm_dtime;
307 		outbuf.shm_ctime = shmseg->shm_ctime;
308 		outbuf.shm_handle = shmseg->shm_internal;
309 		error = copyout((caddr_t)&outbuf, uap->ubuf, sizeof(outbuf));
310 		if (error)
311 			return error;
312 		break;
313 	default:
314 		/* XXX casting to (sy_call_t *) is bogus, as usual. */
315 		return ((sy_call_t *)shmctl)(p, uap, retval);
316 	}
317 	return 0;
318 #else
319 	return EINVAL;
320 #endif
321 }
322 
323 struct shmctl_args {
324 	int shmid;
325 	int cmd;
326 	struct shmid_ds *ubuf;
327 };
328 int
329 shmctl(p, uap, retval)
330 	struct proc *p;
331 	struct shmctl_args *uap;
332 	int *retval;
333 {
334 	int error;
335 	struct ucred *cred = p->p_ucred;
336 	struct shmid_ds inbuf;
337 	struct shmid_ds *shmseg;
338 
339 	shmseg = shm_find_segment_by_shmid(uap->shmid);
340 	if (shmseg == NULL)
341 		return EINVAL;
342 	switch (uap->cmd) {
343 	case IPC_STAT:
344 		error = ipcperm(cred, &shmseg->shm_perm, IPC_R);
345 		if (error)
346 			return error;
347 		error = copyout((caddr_t)shmseg, uap->ubuf, sizeof(inbuf));
348 		if (error)
349 			return error;
350 		break;
351 	case IPC_SET:
352 		error = ipcperm(cred, &shmseg->shm_perm, IPC_M);
353 		if (error)
354 			return error;
355 		error = copyin(uap->ubuf, (caddr_t)&inbuf, sizeof(inbuf));
356 		if (error)
357 			return error;
358 		shmseg->shm_perm.uid = inbuf.shm_perm.uid;
359 		shmseg->shm_perm.gid = inbuf.shm_perm.gid;
360 		shmseg->shm_perm.mode =
361 		    (shmseg->shm_perm.mode & ~ACCESSPERMS) |
362 		    (inbuf.shm_perm.mode & ACCESSPERMS);
363 		shmseg->shm_ctime = time.tv_sec;
364 		break;
365 	case IPC_RMID:
366 		error = ipcperm(cred, &shmseg->shm_perm, IPC_M);
367 		if (error)
368 			return error;
369 		shmseg->shm_perm.key = IPC_PRIVATE;
370 		shmseg->shm_perm.mode |= SHMSEG_REMOVED;
371 		if (shmseg->shm_nattch <= 0) {
372 			shm_deallocate_segment(shmseg);
373 			shm_last_free = IPCID_TO_IX(uap->shmid);
374 		}
375 		break;
376 #if 0
377 	case SHM_LOCK:
378 	case SHM_UNLOCK:
379 #endif
380 	default:
381 		return EINVAL;
382 	}
383 	return 0;
384 }
385 
386 struct shmget_args {
387 	key_t key;
388 	size_t size;
389 	int shmflg;
390 };
391 static int
392 shmget_existing(p, uap, mode, segnum, retval)
393 	struct proc *p;
394 	struct shmget_args *uap;
395 	int mode;
396 	int segnum;
397 	int *retval;
398 {
399 	struct shmid_ds *shmseg;
400 	struct ucred *cred = p->p_ucred;
401 	int error;
402 
403 	shmseg = &shmsegs[segnum];
404 	if (shmseg->shm_perm.mode & SHMSEG_REMOVED) {
405 		/*
406 		 * This segment is in the process of being allocated.  Wait
407 		 * until it's done, and look the key up again (in case the
408 		 * allocation failed or it was freed).
409 		 */
410 		shmseg->shm_perm.mode |= SHMSEG_WANTED;
411 		error = tsleep((caddr_t)shmseg, PLOCK | PCATCH, "shmget", 0);
412 		if (error)
413 			return error;
414 		return EAGAIN;
415 	}
416 	error = ipcperm(cred, &shmseg->shm_perm, mode);
417 	if (error)
418 		return error;
419 	if (uap->size && uap->size > shmseg->shm_segsz)
420 		return EINVAL;
421 	if (uap->shmflg & (IPC_CREAT | IPC_EXCL) == (IPC_CREAT | IPC_EXCL))
422 		return EEXIST;
423 	*retval = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
424 	return 0;
425 }
426 
427 static int
428 shmget_allocate_segment(p, uap, mode, retval)
429 	struct proc *p;
430 	struct shmget_args *uap;
431 	int mode;
432 	int *retval;
433 {
434 	int i, segnum, result, shmid, size;
435 	struct ucred *cred = p->p_ucred;
436 	struct shmid_ds *shmseg;
437 	struct shm_handle *shm_handle;
438 
439 	if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
440 		return EINVAL;
441 	if (shm_nused >= shminfo.shmmni) /* any shmids left? */
442 		return ENOSPC;
443 	size = (uap->size + CLOFSET) & ~CLOFSET;
444 	if (shm_committed + btoc(size) > shminfo.shmall)
445 		return ENOMEM;
446 	if (shm_last_free < 0) {
447 		for (i = 0; i < shminfo.shmmni; i++)
448 			if (shmsegs[i].shm_perm.mode & SHMSEG_FREE)
449 				break;
450 		if (i == shminfo.shmmni)
451 			panic("shmseg free count inconsistent");
452 		segnum = i;
453 	} else  {
454 		segnum = shm_last_free;
455 		shm_last_free = -1;
456 	}
457 	shmseg = &shmsegs[segnum];
458 	/*
459 	 * In case we sleep in malloc(), mark the segment present but deleted
460 	 * so that noone else tries to create the same key.
461 	 */
462 	shmseg->shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED;
463 	shmseg->shm_perm.key = uap->key;
464 	shmseg->shm_perm.seq = (shmseg->shm_perm.seq + 1) & 0x7fff;
465 	shm_handle = (struct shm_handle *)
466 	    malloc(sizeof(struct shm_handle), M_SHM, M_WAITOK);
467 	shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
468 	result = vm_mmap(sysvshm_map, &shm_handle->kva, size, VM_PROT_ALL,
469 	    VM_PROT_DEFAULT, MAP_ANON, (caddr_t) shmid, 0);
470 	if (result != KERN_SUCCESS) {
471 		shmseg->shm_perm.mode = SHMSEG_FREE;
472 		shm_last_free = segnum;
473 		free((caddr_t)shm_handle, M_SHM);
474 		/* Just in case. */
475 		wakeup((caddr_t)shmseg);
476 		return ENOMEM;
477 	}
478 	shmseg->shm_internal = shm_handle;
479 	shmseg->shm_perm.cuid = shmseg->shm_perm.uid = cred->cr_uid;
480 	shmseg->shm_perm.cgid = shmseg->shm_perm.gid = cred->cr_gid;
481 	shmseg->shm_perm.mode = (shmseg->shm_perm.mode & SHMSEG_WANTED) |
482 	    (mode & ACCESSPERMS) | SHMSEG_ALLOCATED;
483 	shmseg->shm_segsz = uap->size;
484 	shmseg->shm_cpid = p->p_pid;
485 	shmseg->shm_lpid = shmseg->shm_nattch = 0;
486 	shmseg->shm_atime = shmseg->shm_dtime = 0;
487 	shmseg->shm_ctime = time.tv_sec;
488 	shm_committed += btoc(size);
489 	shm_nused++;
490 	if (shmseg->shm_perm.mode & SHMSEG_WANTED) {
491 		/*
492 		 * Somebody else wanted this key while we were asleep.  Wake
493 		 * them up now.
494 		 */
495 		shmseg->shm_perm.mode &= ~SHMSEG_WANTED;
496 		wakeup((caddr_t)shmseg);
497 	}
498 	*retval = shmid;
499 	return 0;
500 }
501 
502 int
503 shmget(p, uap, retval)
504 	struct proc *p;
505 	struct shmget_args *uap;
506 	int *retval;
507 {
508 	int segnum, mode, error;
509 
510 	mode = uap->shmflg & ACCESSPERMS;
511 	if (uap->key != IPC_PRIVATE) {
512 	again:
513 		segnum = shm_find_segment_by_key(uap->key);
514 		if (segnum >= 0) {
515 			error = shmget_existing(p, uap, mode, segnum, retval);
516 			if (error == EAGAIN)
517 				goto again;
518 			return error;
519 		}
520 		if ((uap->shmflg & IPC_CREAT) == 0)
521 			return ENOENT;
522 	}
523 	return shmget_allocate_segment(p, uap, mode, retval);
524 }
525 
526 int
527 shmsys(p, uap, retval)
528 	struct proc *p;
529 	/* XXX actually varargs. */
530 	struct shmsys_args /* {
531 		u_int	which;
532 		int	a2;
533 		int	a3;
534 		int	a4;
535 	} */ *uap;
536 	int *retval;
537 {
538 
539 	if (uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0]))
540 		return EINVAL;
541 	return ((*shmcalls[uap->which])(p, &uap->a2, retval));
542 }
543 
544 void
545 shmfork(p1, p2, isvfork)
546 	struct proc *p1, *p2;
547 	int isvfork;
548 {
549 	struct shmmap_state *shmmap_s;
550 	size_t size;
551 	int i;
552 
553 	size = shminfo.shmseg * sizeof(struct shmmap_state);
554 	shmmap_s = malloc(size, M_SHM, M_WAITOK);
555 	bcopy((caddr_t)p1->p_vmspace->vm_shm, (caddr_t)shmmap_s, size);
556 	p2->p_vmspace->vm_shm = (caddr_t)shmmap_s;
557 	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
558 		if (shmmap_s->shmid != -1)
559 			shmsegs[IPCID_TO_IX(shmmap_s->shmid)].shm_nattch++;
560 }
561 
562 void
563 shmexit(p)
564 	struct proc *p;
565 {
566 	struct shmmap_state *shmmap_s;
567 	int i;
568 
569 	shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
570 	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
571 		if (shmmap_s->shmid != -1)
572 			shm_delete_mapping(p, shmmap_s);
573 	free((caddr_t)p->p_vmspace->vm_shm, M_SHM);
574 	p->p_vmspace->vm_shm = NULL;
575 }
576 
577 void
578 shminit(dummy)
579 	void *dummy;
580 {
581 	int i;
582 	vm_offset_t garbage1, garbage2;
583 
584 	/* actually this *should* be pageable.  SHM_{LOCK,UNLOCK} */
585 	sysvshm_map = kmem_suballoc(kernel_map, &garbage1, &garbage2,
586 				    shminfo.shmall * NBPG, TRUE);
587 	for (i = 0; i < shminfo.shmmni; i++) {
588 		shmsegs[i].shm_perm.mode = SHMSEG_FREE;
589 		shmsegs[i].shm_perm.seq = 0;
590 	}
591 	shm_last_free = 0;
592 	shm_nused = 0;
593 	shm_committed = 0;
594 }
595