sysv_shm.c revision 42957
1219974Smav/* $Id: sysv_shm.c,v 1.39 1998/10/13 08:24:40 dg Exp $ */ 2219974Smav/* $NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $ */ 3219974Smav 4219974Smav/* 5219974Smav * Copyright (c) 1994 Adam Glass and Charles Hannum. All rights reserved. 6219974Smav * 7219974Smav * Redistribution and use in source and binary forms, with or without 8219974Smav * modification, are permitted provided that the following conditions 9219974Smav * are met: 10219974Smav * 1. Redistributions of source code must retain the above copyright 11219974Smav * notice, this list of conditions and the following disclaimer. 12219974Smav * 2. Redistributions in binary form must reproduce the above copyright 13219974Smav * notice, this list of conditions and the following disclaimer in the 14219974Smav * documentation and/or other materials provided with the distribution. 15219974Smav * 3. All advertising materials mentioning features or use of this software 16219974Smav * must display the following acknowledgement: 17219974Smav * This product includes software developed by Adam Glass and Charles 18219974Smav * Hannum. 19219974Smav * 4. The names of the authors may not be used to endorse or promote products 20219974Smav * derived from this software without specific prior written permission. 21219974Smav * 22219974Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 23219974Smav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24219974Smav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25219974Smav * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26219974Smav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27219974Smav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28219974Smav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29219974Smav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30219974Smav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31219974Smav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32219974Smav */ 33219974Smav 34219974Smav#include "opt_compat.h" 35219974Smav#include "opt_rlimit.h" 36219974Smav 37219974Smav#include <sys/param.h> 38219974Smav#include <sys/systm.h> 39219974Smav#include <sys/sysproto.h> 40219974Smav#include <sys/kernel.h> 41219974Smav#include <sys/shm.h> 42219974Smav#include <sys/proc.h> 43219974Smav#include <sys/malloc.h> 44219974Smav#include <sys/mman.h> 45219974Smav#include <sys/stat.h> 46219974Smav#include <sys/sysent.h> 47219974Smav 48219974Smav#include <vm/vm.h> 49219974Smav#include <vm/vm_param.h> 50219974Smav#include <vm/vm_prot.h> 51219974Smav#include <sys/lock.h> 52219974Smav#include <vm/pmap.h> 53219974Smav#include <vm/vm_object.h> 54219974Smav#include <vm/vm_map.h> 55219974Smav#include <vm/vm_page.h> 56219974Smav#include <vm/vm_pager.h> 57219974Smav#include <vm/vm_inherit.h> 58219974Smav 59219974Smav#ifndef _SYS_SYSPROTO_H_ 60219974Smavstruct shmat_args; 61219974Smavextern int shmat __P((struct proc *p, struct shmat_args *uap)); 62219974Smavstruct shmctl_args; 63219974Smavextern int shmctl __P((struct proc *p, struct shmctl_args *uap)); 64219974Smavstruct shmdt_args; 65219974Smavextern int shmdt __P((struct proc *p, struct shmdt_args *uap)); 66219974Smavstruct shmget_args; 67219974Smavextern int shmget __P((struct proc *p, struct shmget_args *uap)); 68219974Smav#endif 69219974Smav 70219974Smavstatic MALLOC_DEFINE(M_SHM, "shm", "SVID compatible shared memory segments"); 71219974Smav 72219974Smavstatic void shminit __P((void *)); 73219974SmavSYSINIT(sysv_shm, SI_SUB_SYSV_SHM, SI_ORDER_FIRST, shminit, NULL) 74219974Smav 75219974Smavstruct oshmctl_args; 76219974Smavstatic int oshmctl __P((struct proc *p, struct oshmctl_args *uap)); 77219974Smavstatic int shmget_allocate_segment __P((struct proc *p, struct shmget_args *uap, int mode)); 78219974Smavstatic int shmget_existing __P((struct proc *p, struct shmget_args *uap, int mode, int segnum)); 79219974Smav 80219974Smav/* XXX casting to (sy_call_t *) is bogus, as usual. */ 81219974Smavstatic sy_call_t *shmcalls[] = { 82219974Smav (sy_call_t *)shmat, (sy_call_t *)oshmctl, 83219974Smav (sy_call_t *)shmdt, (sy_call_t *)shmget, 84219974Smav (sy_call_t *)shmctl 85219974Smav}; 86219974Smav 87219974Smav#define SHMSEG_FREE 0x0200 88219974Smav#define SHMSEG_REMOVED 0x0400 89219974Smav#define SHMSEG_ALLOCATED 0x0800 90219974Smav#define SHMSEG_WANTED 0x1000 91219974Smav 92219974Smavstatic int shm_last_free, shm_nused, shm_committed; 93219974Smavstruct shmid_ds *shmsegs; 94219974Smav 95219974Smavstruct shm_handle { 96219974Smav /* vm_offset_t kva; */ 97219974Smav vm_object_t shm_object; 98219974Smav}; 99219974Smav 100219974Smavstruct shmmap_state { 101219974Smav vm_offset_t va; 102219974Smav int shmid; 103219974Smav}; 104219974Smav 105219974Smavstatic void shm_deallocate_segment __P((struct shmid_ds *)); 106219974Smavstatic int shm_find_segment_by_key __P((key_t)); 107219974Smavstatic struct shmid_ds *shm_find_segment_by_shmid __P((int)); 108219974Smavstatic int shm_delete_mapping __P((struct proc *, struct shmmap_state *)); 109219974Smav 110219974Smavstatic int 111219974Smavshm_find_segment_by_key(key) 112219974Smav key_t key; 113219974Smav{ 114219974Smav int i; 115219974Smav 116219974Smav for (i = 0; i < shminfo.shmmni; i++) 117219974Smav if ((shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) && 118219974Smav shmsegs[i].shm_perm.key == key) 119219974Smav return i; 120219974Smav return -1; 121219974Smav} 122219974Smav 123219974Smavstatic struct shmid_ds * 124219974Smavshm_find_segment_by_shmid(shmid) 125219974Smav int shmid; 126219974Smav{ 127219974Smav int segnum; 128219974Smav struct shmid_ds *shmseg; 129219974Smav 130219974Smav segnum = IPCID_TO_IX(shmid); 131219974Smav if (segnum < 0 || segnum >= shminfo.shmmni) 132219974Smav return NULL; 133219974Smav shmseg = &shmsegs[segnum]; 134219974Smav if ((shmseg->shm_perm.mode & (SHMSEG_ALLOCATED | SHMSEG_REMOVED)) 135219974Smav != SHMSEG_ALLOCATED || 136219974Smav shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid)) 137219974Smav return NULL; 138219974Smav return shmseg; 139219974Smav} 140219974Smav 141219974Smavstatic void 142219974Smavshm_deallocate_segment(shmseg) 143219974Smav struct shmid_ds *shmseg; 144219974Smav{ 145219974Smav struct shm_handle *shm_handle; 146219974Smav size_t size; 147219974Smav 148219974Smav shm_handle = shmseg->shm_internal; 149219974Smav vm_object_deallocate(shm_handle->shm_object); 150219974Smav free((caddr_t)shm_handle, M_SHM); 151219974Smav shmseg->shm_internal = NULL; 152219974Smav size = round_page(shmseg->shm_segsz); 153219974Smav shm_committed -= btoc(size); 154219974Smav shm_nused--; 155219974Smav shmseg->shm_perm.mode = SHMSEG_FREE; 156219974Smav} 157219974Smav 158219974Smavstatic int 159219974Smavshm_delete_mapping(p, shmmap_s) 160219974Smav struct proc *p; 161219974Smav struct shmmap_state *shmmap_s; 162219974Smav{ 163219974Smav struct shmid_ds *shmseg; 164219974Smav int segnum, result; 165219974Smav size_t size; 166219974Smav 167219974Smav segnum = IPCID_TO_IX(shmmap_s->shmid); 168219974Smav shmseg = &shmsegs[segnum]; 169219974Smav size = round_page(shmseg->shm_segsz); 170219974Smav result = vm_map_remove(&p->p_vmspace->vm_map, shmmap_s->va, shmmap_s->va + size); 171219974Smav if (result != KERN_SUCCESS) 172219974Smav return EINVAL; 173219974Smav shmmap_s->shmid = -1; 174219974Smav shmseg->shm_dtime = time_second; 175219974Smav if ((--shmseg->shm_nattch <= 0) && 176219974Smav (shmseg->shm_perm.mode & SHMSEG_REMOVED)) { 177219974Smav shm_deallocate_segment(shmseg); 178219974Smav shm_last_free = segnum; 179219974Smav } 180219974Smav return 0; 181219974Smav} 182219974Smav 183219974Smav#ifndef _SYS_SYSPROTO_H_ 184219974Smavstruct shmdt_args { 185219974Smav void *shmaddr; 186219974Smav}; 187219974Smav#endif 188219974Smav 189219974Smavint 190219974Smavshmdt(p, uap) 191219974Smav struct proc *p; 192219974Smav struct shmdt_args *uap; 193219974Smav{ 194219974Smav struct shmmap_state *shmmap_s; 195219974Smav int i; 196219974Smav 197219974Smav shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm; 198219974Smav if (shmmap_s == NULL) 199219974Smav return EINVAL; 200219974Smav for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) 201219974Smav if (shmmap_s->shmid != -1 && 202219974Smav shmmap_s->va == (vm_offset_t)uap->shmaddr) 203219974Smav break; 204219974Smav if (i == shminfo.shmseg) 205219974Smav return EINVAL; 206219974Smav return shm_delete_mapping(p, shmmap_s); 207219974Smav} 208219974Smav 209219974Smav#ifndef _SYS_SYSPROTO_H_ 210219974Smavstruct shmat_args { 211219974Smav int shmid; 212219974Smav void *shmaddr; 213219974Smav int shmflg; 214219974Smav}; 215219974Smav#endif 216219974Smav 217219974Smavint 218219974Smavshmat(p, uap) 219219974Smav struct proc *p; 220219974Smav struct shmat_args *uap; 221219974Smav{ 222219974Smav int error, i, flags; 223219974Smav struct ucred *cred = p->p_ucred; 224219974Smav struct shmid_ds *shmseg; 225219974Smav struct shmmap_state *shmmap_s = NULL; 226219974Smav struct shm_handle *shm_handle; 227219974Smav vm_offset_t attach_va; 228219974Smav vm_prot_t prot; 229219974Smav vm_size_t size; 230219974Smav int rv; 231219974Smav 232219974Smav shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm; 233219974Smav if (shmmap_s == NULL) { 234219974Smav size = shminfo.shmseg * sizeof(struct shmmap_state); 235219974Smav shmmap_s = malloc(size, M_SHM, M_WAITOK); 236219974Smav for (i = 0; i < shminfo.shmseg; i++) 237219974Smav shmmap_s[i].shmid = -1; 238219974Smav p->p_vmspace->vm_shm = (caddr_t)shmmap_s; 239219974Smav } 240219974Smav shmseg = shm_find_segment_by_shmid(uap->shmid); 241219974Smav if (shmseg == NULL) 242219974Smav return EINVAL; 243219974Smav error = ipcperm(cred, &shmseg->shm_perm, 244219974Smav (uap->shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W); 245219974Smav if (error) 246219974Smav return error; 247219974Smav for (i = 0; i < shminfo.shmseg; i++) { 248219974Smav if (shmmap_s->shmid == -1) 249219974Smav break; 250219974Smav shmmap_s++; 251219974Smav } 252219974Smav if (i >= shminfo.shmseg) 253219974Smav return EMFILE; 254219974Smav size = round_page(shmseg->shm_segsz); 255219974Smav prot = VM_PROT_READ; 256219974Smav if ((uap->shmflg & SHM_RDONLY) == 0) 257219974Smav prot |= VM_PROT_WRITE; 258219974Smav flags = MAP_ANON | MAP_SHARED; 259219974Smav if (uap->shmaddr) { 260219974Smav flags |= MAP_FIXED; 261219974Smav if (uap->shmflg & SHM_RND) 262219974Smav attach_va = (vm_offset_t)uap->shmaddr & ~(SHMLBA-1); 263219974Smav else if (((vm_offset_t)uap->shmaddr & (SHMLBA-1)) == 0) 264219974Smav attach_va = (vm_offset_t)uap->shmaddr; 265219974Smav else 266219974Smav return EINVAL; 267219974Smav } else { 268219974Smav /* This is just a hint to vm_map_find() about where to put it. */ 269219974Smav attach_va = round_page((vm_offset_t)p->p_vmspace->vm_taddr + MAXTSIZ + MAXDSIZ); 270219974Smav } 271219974Smav 272219974Smav shm_handle = shmseg->shm_internal; 273219974Smav vm_object_reference(shm_handle->shm_object); 274219974Smav rv = vm_map_find(&p->p_vmspace->vm_map, shm_handle->shm_object, 275219974Smav 0, &attach_va, size, (flags & MAP_FIXED)?0:1, prot, prot, 0); 276219974Smav if (rv != KERN_SUCCESS) { 277219974Smav return ENOMEM; 278219974Smav } 279219974Smav vm_map_inherit(&p->p_vmspace->vm_map, 280219974Smav attach_va, attach_va + size, VM_INHERIT_SHARE); 281219974Smav 282219974Smav shmmap_s->va = attach_va; 283219974Smav shmmap_s->shmid = uap->shmid; 284219974Smav shmseg->shm_lpid = p->p_pid; 285219974Smav shmseg->shm_atime = time_second; 286219974Smav shmseg->shm_nattch++; 287219974Smav p->p_retval[0] = attach_va; 288219974Smav return 0; 289219974Smav} 290219974Smav 291219974Smavstruct oshmid_ds { 292219974Smav struct ipc_perm shm_perm; /* operation perms */ 293219974Smav int shm_segsz; /* size of segment (bytes) */ 294219974Smav ushort shm_cpid; /* pid, creator */ 295219974Smav ushort shm_lpid; /* pid, last operation */ 296219974Smav short shm_nattch; /* no. of current attaches */ 297219974Smav time_t shm_atime; /* last attach time */ 298219974Smav time_t shm_dtime; /* last detach time */ 299219974Smav time_t shm_ctime; /* last change time */ 300219974Smav void *shm_handle; /* internal handle for shm segment */ 301219974Smav}; 302219974Smav 303219974Smavstruct oshmctl_args { 304219974Smav int shmid; 305219974Smav int cmd; 306219974Smav struct oshmid_ds *ubuf; 307219974Smav}; 308219974Smav 309219974Smavstatic int 310219974Smavoshmctl(p, uap) 311219974Smav struct proc *p; 312219974Smav struct oshmctl_args *uap; 313219974Smav{ 314219974Smav#ifdef COMPAT_43 315219974Smav int error; 316219974Smav struct ucred *cred = p->p_ucred; 317219974Smav struct shmid_ds *shmseg; 318219974Smav struct oshmid_ds outbuf; 319219974Smav 320219974Smav shmseg = shm_find_segment_by_shmid(uap->shmid); 321219974Smav if (shmseg == NULL) 322219974Smav return EINVAL; 323219974Smav switch (uap->cmd) { 324219974Smav case IPC_STAT: 325219974Smav error = ipcperm(cred, &shmseg->shm_perm, IPC_R); 326219974Smav if (error) 327219974Smav return error; 328219974Smav outbuf.shm_perm = shmseg->shm_perm; 329219974Smav outbuf.shm_segsz = shmseg->shm_segsz; 330219974Smav outbuf.shm_cpid = shmseg->shm_cpid; 331219974Smav outbuf.shm_lpid = shmseg->shm_lpid; 332219974Smav outbuf.shm_nattch = shmseg->shm_nattch; 333219974Smav outbuf.shm_atime = shmseg->shm_atime; 334219974Smav outbuf.shm_dtime = shmseg->shm_dtime; 335219974Smav outbuf.shm_ctime = shmseg->shm_ctime; 336219974Smav outbuf.shm_handle = shmseg->shm_internal; 337219974Smav error = copyout((caddr_t)&outbuf, uap->ubuf, sizeof(outbuf)); 338219974Smav if (error) 339219974Smav return error; 340219974Smav break; 341219974Smav default: 342219974Smav /* XXX casting to (sy_call_t *) is bogus, as usual. */ 343219974Smav return ((sy_call_t *)shmctl)(p, uap); 344 } 345 return 0; 346#else 347 return EINVAL; 348#endif 349} 350 351#ifndef _SYS_SYSPROTO_H_ 352struct shmctl_args { 353 int shmid; 354 int cmd; 355 struct shmid_ds *buf; 356}; 357#endif 358 359int 360shmctl(p, uap) 361 struct proc *p; 362 struct shmctl_args *uap; 363{ 364 int error; 365 struct ucred *cred = p->p_ucred; 366 struct shmid_ds inbuf; 367 struct shmid_ds *shmseg; 368 369 shmseg = shm_find_segment_by_shmid(uap->shmid); 370 if (shmseg == NULL) 371 return EINVAL; 372 switch (uap->cmd) { 373 case IPC_STAT: 374 error = ipcperm(cred, &shmseg->shm_perm, IPC_R); 375 if (error) 376 return error; 377 error = copyout((caddr_t)shmseg, uap->buf, sizeof(inbuf)); 378 if (error) 379 return error; 380 break; 381 case IPC_SET: 382 error = ipcperm(cred, &shmseg->shm_perm, IPC_M); 383 if (error) 384 return error; 385 error = copyin(uap->buf, (caddr_t)&inbuf, sizeof(inbuf)); 386 if (error) 387 return error; 388 shmseg->shm_perm.uid = inbuf.shm_perm.uid; 389 shmseg->shm_perm.gid = inbuf.shm_perm.gid; 390 shmseg->shm_perm.mode = 391 (shmseg->shm_perm.mode & ~ACCESSPERMS) | 392 (inbuf.shm_perm.mode & ACCESSPERMS); 393 shmseg->shm_ctime = time_second; 394 break; 395 case IPC_RMID: 396 error = ipcperm(cred, &shmseg->shm_perm, IPC_M); 397 if (error) 398 return error; 399 shmseg->shm_perm.key = IPC_PRIVATE; 400 shmseg->shm_perm.mode |= SHMSEG_REMOVED; 401 if (shmseg->shm_nattch <= 0) { 402 shm_deallocate_segment(shmseg); 403 shm_last_free = IPCID_TO_IX(uap->shmid); 404 } 405 break; 406#if 0 407 case SHM_LOCK: 408 case SHM_UNLOCK: 409#endif 410 default: 411 return EINVAL; 412 } 413 return 0; 414} 415 416#ifndef _SYS_SYSPROTO_H_ 417struct shmget_args { 418 key_t key; 419 size_t size; 420 int shmflg; 421}; 422#endif 423 424static int 425shmget_existing(p, uap, mode, segnum) 426 struct proc *p; 427 struct shmget_args *uap; 428 int mode; 429 int segnum; 430{ 431 struct shmid_ds *shmseg; 432 struct ucred *cred = p->p_ucred; 433 int error; 434 435 shmseg = &shmsegs[segnum]; 436 if (shmseg->shm_perm.mode & SHMSEG_REMOVED) { 437 /* 438 * This segment is in the process of being allocated. Wait 439 * until it's done, and look the key up again (in case the 440 * allocation failed or it was freed). 441 */ 442 shmseg->shm_perm.mode |= SHMSEG_WANTED; 443 error = tsleep((caddr_t)shmseg, PLOCK | PCATCH, "shmget", 0); 444 if (error) 445 return error; 446 return EAGAIN; 447 } 448 error = ipcperm(cred, &shmseg->shm_perm, mode); 449 if (error) 450 return error; 451 if (uap->size && uap->size > shmseg->shm_segsz) 452 return EINVAL; 453 if ((uap->shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL)) 454 return EEXIST; 455 p->p_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm); 456 return 0; 457} 458 459static int 460shmget_allocate_segment(p, uap, mode) 461 struct proc *p; 462 struct shmget_args *uap; 463 int mode; 464{ 465 int i, segnum, shmid, size; 466 struct ucred *cred = p->p_ucred; 467 struct shmid_ds *shmseg; 468 struct shm_handle *shm_handle; 469 470 if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax) 471 return EINVAL; 472 if (shm_nused >= shminfo.shmmni) /* any shmids left? */ 473 return ENOSPC; 474 size = round_page(uap->size); 475 if (shm_committed + btoc(size) > shminfo.shmall) 476 return ENOMEM; 477 if (shm_last_free < 0) { 478 for (i = 0; i < shminfo.shmmni; i++) 479 if (shmsegs[i].shm_perm.mode & SHMSEG_FREE) 480 break; 481 if (i == shminfo.shmmni) 482 panic("shmseg free count inconsistent"); 483 segnum = i; 484 } else { 485 segnum = shm_last_free; 486 shm_last_free = -1; 487 } 488 shmseg = &shmsegs[segnum]; 489 /* 490 * In case we sleep in malloc(), mark the segment present but deleted 491 * so that noone else tries to create the same key. 492 */ 493 shmseg->shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED; 494 shmseg->shm_perm.key = uap->key; 495 shmseg->shm_perm.seq = (shmseg->shm_perm.seq + 1) & 0x7fff; 496 shm_handle = (struct shm_handle *) 497 malloc(sizeof(struct shm_handle), M_SHM, M_WAITOK); 498 shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm); 499 500 /* 501 * We make sure that we have allocated a pager before we need 502 * to. 503 */ 504 shm_handle->shm_object = 505 vm_pager_allocate(OBJT_SWAP, 0, size, VM_PROT_DEFAULT, 0); 506 vm_object_clear_flag(shm_handle->shm_object, OBJ_ONEMAPPING); 507 vm_object_set_flag(shm_handle->shm_object, OBJ_NOSPLIT); 508 509 shmseg->shm_internal = shm_handle; 510 shmseg->shm_perm.cuid = shmseg->shm_perm.uid = cred->cr_uid; 511 shmseg->shm_perm.cgid = shmseg->shm_perm.gid = cred->cr_gid; 512 shmseg->shm_perm.mode = (shmseg->shm_perm.mode & SHMSEG_WANTED) | 513 (mode & ACCESSPERMS) | SHMSEG_ALLOCATED; 514 shmseg->shm_segsz = uap->size; 515 shmseg->shm_cpid = p->p_pid; 516 shmseg->shm_lpid = shmseg->shm_nattch = 0; 517 shmseg->shm_atime = shmseg->shm_dtime = 0; 518 shmseg->shm_ctime = time_second; 519 shm_committed += btoc(size); 520 shm_nused++; 521 if (shmseg->shm_perm.mode & SHMSEG_WANTED) { 522 /* 523 * Somebody else wanted this key while we were asleep. Wake 524 * them up now. 525 */ 526 shmseg->shm_perm.mode &= ~SHMSEG_WANTED; 527 wakeup((caddr_t)shmseg); 528 } 529 p->p_retval[0] = shmid; 530 return 0; 531} 532 533int 534shmget(p, uap) 535 struct proc *p; 536 struct shmget_args *uap; 537{ 538 int segnum, mode, error; 539 540 mode = uap->shmflg & ACCESSPERMS; 541 if (uap->key != IPC_PRIVATE) { 542 again: 543 segnum = shm_find_segment_by_key(uap->key); 544 if (segnum >= 0) { 545 error = shmget_existing(p, uap, mode, segnum); 546 if (error == EAGAIN) 547 goto again; 548 return error; 549 } 550 if ((uap->shmflg & IPC_CREAT) == 0) 551 return ENOENT; 552 } 553 return shmget_allocate_segment(p, uap, mode); 554} 555 556int 557shmsys(p, uap) 558 struct proc *p; 559 /* XXX actually varargs. */ 560 struct shmsys_args /* { 561 u_int which; 562 int a2; 563 int a3; 564 int a4; 565 } */ *uap; 566{ 567 568 if (uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0])) 569 return EINVAL; 570 return ((*shmcalls[uap->which])(p, &uap->a2)); 571} 572 573void 574shmfork(p1, p2) 575 struct proc *p1, *p2; 576{ 577 struct shmmap_state *shmmap_s; 578 size_t size; 579 int i; 580 581 size = shminfo.shmseg * sizeof(struct shmmap_state); 582 shmmap_s = malloc(size, M_SHM, M_WAITOK); 583 bcopy((caddr_t)p1->p_vmspace->vm_shm, (caddr_t)shmmap_s, size); 584 p2->p_vmspace->vm_shm = (caddr_t)shmmap_s; 585 for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) 586 if (shmmap_s->shmid != -1) 587 shmsegs[IPCID_TO_IX(shmmap_s->shmid)].shm_nattch++; 588} 589 590void 591shmexit(p) 592 struct proc *p; 593{ 594 struct shmmap_state *shmmap_s; 595 int i; 596 597 shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm; 598 for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) 599 if (shmmap_s->shmid != -1) 600 shm_delete_mapping(p, shmmap_s); 601 free((caddr_t)p->p_vmspace->vm_shm, M_SHM); 602 p->p_vmspace->vm_shm = NULL; 603} 604 605void 606shminit(dummy) 607 void *dummy; 608{ 609 int i; 610 for (i = 0; i < shminfo.shmmni; i++) { 611 shmsegs[i].shm_perm.mode = SHMSEG_FREE; 612 shmsegs[i].shm_perm.seq = 0; 613 } 614 shm_last_free = 0; 615 shm_nused = 0; 616 shm_committed = 0; 617} 618