Added SYSV ipcs.

Obtained from: NetBSD and FreeBSD-1.1.5
This commit is contained in:
Doug Rabson 1994-09-13 14:47:38 +00:00
parent a78a18e9b9
commit 3d903220e4
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=2729
18 changed files with 3135 additions and 10 deletions

View File

@ -68,6 +68,11 @@ kern/subr_xxx.c standard
kern/sys_generic.c standard
kern/sys_process.c standard
kern/sys_socket.c standard
kern/sysv_ipc.c optional sysvshm
kern/sysv_ipc.c optional sysvmsg
kern/sysv_ipc.c optional sysvsem
kern/sysv_msg.c optional sysvmsg
kern/sysv_sem.c optional sysvsem
kern/sysv_shm.c optional sysvshm
kern/tty.c standard
kern/tty_compat.c standard

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)param.c 8.2 (Berkeley) 1/21/94
* $Id$
* $Id: param.c,v 1.3 1994/08/02 07:38:30 davidg Exp $
*/
#include <sys/param.h>
@ -56,6 +56,12 @@
#include <machine/vmparam.h>
#include <sys/shm.h>
#endif
#ifdef SYSVSEM
#include "sys/sem.h"
#endif
#ifdef SYSVMSG
#include "sys/msg.h"
#endif
/*
* System parameter formulae.
@ -105,6 +111,43 @@ struct shminfo shminfo = {
};
#endif
/*
* Values in support of System V compatible semaphores.
*/
#ifdef SYSVSEM
struct seminfo seminfo = {
SEMMAP, /* # of entries in semaphore map */
SEMMNI, /* # of semaphore identifiers */
SEMMNS, /* # of semaphores in system */
SEMMNU, /* # of undo structures in system */
SEMMSL, /* max # of semaphores per id */
SEMOPM, /* max # of operations per semop call */
SEMUME, /* max # of undo entries per process */
SEMUSZ, /* size in bytes of undo structure */
SEMVMX, /* semaphore maximum value */
SEMAEM /* adjust on exit max value */
};
#endif
/*
* Values in support of System V compatible messages.
*/
#ifdef SYSVMSG
struct msginfo msginfo = {
MSGMAX, /* max chars in a message */
MSGMNI, /* # of message queue identifiers */
MSGMNB, /* max chars in a queue */
MSGTQL, /* max messages in system */
MSGSSZ, /* size of a message segment */
/* (must be small power of 2 greater than 4) */
MSGSEG /* number of message segments */
};
#endif
/*
* These are initialized at bootstrap time
* to values dependent on memory size

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)init_main.c 8.9 (Berkeley) 1/21/94
* $Id: init_main.c,v 1.8 1994/09/01 05:12:37 davidg Exp $
* $Id: init_main.c,v 1.9 1994/09/01 11:20:11 davidg Exp $
*/
#include <sys/param.h>
@ -239,6 +239,21 @@ main(framep)
/* Initialize clists. */
clist_init();
#ifdef SYSVSHM
/* Initialize System V style shared memory. */
shminit();
#endif
#ifdef SYSVSEM
/* Initialize System V style semaphores. */
seminit();
#endif
#ifdef SYSVMSG
/* Initialize System V style message queues. */
msginit();
#endif
/*
* Attach pseudo-devices.
*/

View File

@ -2,7 +2,7 @@
* System call switch table.
*
* DO NOT EDIT-- this file is automatically generated.
* created from $Id: syscalls.master,v 1.6 1994/09/01 05:12:42 davidg Exp $
* created from $Id: syscalls.master,v 1.7 1994/09/13 00:48:19 wollman Exp $
*/
#include <sys/param.h>
@ -142,6 +142,14 @@ int setdomainname();
int uname();
int sysarch();
int rtprio();
#ifdef SYSVSEM
int semsys();
#else
#endif
#ifdef SYSVMSG
int msgsys();
#else
#endif
#ifdef SYSVSHM
int shmsys();
#else
@ -237,6 +245,12 @@ int ogetdirentries();
#ifdef NFS
#else
#endif
#ifdef SYSVSEM
#else
#endif
#ifdef SYSVMSG
#else
#endif
#ifdef SYSVSHM
#else
#endif
@ -441,8 +455,16 @@ struct sysent sysent[] = {
{ 2, rtprio }, /* 166 = rtprio */
{ 0, nosys }, /* 167 = nosys */
{ 0, nosys }, /* 168 = nosys */
#ifdef SYSVSEM
{ 5, semsys }, /* 169 = semsys */
#else
{ 0, nosys }, /* 169 = nosys */
#endif
#ifdef SYSVMSG
{ 6, msgsys }, /* 170 = msgsys */
#else
{ 0, nosys }, /* 170 = nosys */
#endif
#ifdef SYSVSHM
{ 4, shmsys }, /* 171 = shmsys */
#else

View File

@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: kern_exec.c,v 1.4 1994/08/18 22:34:59 wollman Exp $
* $Id: kern_exec.c,v 1.5 1994/08/24 10:53:53 davidg Exp $
*/
#include <sys/param.h>
@ -338,6 +338,8 @@ exec_new_vmspace(iparams)
iparams->vmspace_destroyed = 1;
/* Blow away entire process VM */
if (vmspace->vm_shm)
shmexit(iparams->proc);
vm_deallocate(&vmspace->vm_map, 0, USRSTACK);
/* Allocate a new stack */

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)param.c 8.2 (Berkeley) 1/21/94
* $Id$
* $Id: param.c,v 1.3 1994/08/02 07:38:30 davidg Exp $
*/
#include <sys/param.h>
@ -56,6 +56,12 @@
#include <machine/vmparam.h>
#include <sys/shm.h>
#endif
#ifdef SYSVSEM
#include "sys/sem.h"
#endif
#ifdef SYSVMSG
#include "sys/msg.h"
#endif
/*
* System parameter formulae.
@ -105,6 +111,43 @@ struct shminfo shminfo = {
};
#endif
/*
* Values in support of System V compatible semaphores.
*/
#ifdef SYSVSEM
struct seminfo seminfo = {
SEMMAP, /* # of entries in semaphore map */
SEMMNI, /* # of semaphore identifiers */
SEMMNS, /* # of semaphores in system */
SEMMNU, /* # of undo structures in system */
SEMMSL, /* max # of semaphores per id */
SEMOPM, /* max # of operations per semop call */
SEMUME, /* max # of undo entries per process */
SEMUSZ, /* size in bytes of undo structure */
SEMVMX, /* semaphore maximum value */
SEMAEM /* adjust on exit max value */
};
#endif
/*
* Values in support of System V compatible messages.
*/
#ifdef SYSVMSG
struct msginfo msginfo = {
MSGMAX, /* max chars in a message */
MSGMNI, /* # of message queue identifiers */
MSGMNB, /* max chars in a queue */
MSGTQL, /* max messages in system */
MSGSSZ, /* size of a message segment */
/* (must be small power of 2 greater than 4) */
MSGSEG /* number of message segments */
};
#endif
/*
* These are initialized at bootstrap time
* to values dependent on memory size

View File

@ -2,7 +2,7 @@
* System call names.
*
* DO NOT EDIT-- this file is automatically generated.
* created from $Id: syscalls.master,v 1.6 1994/09/01 05:12:42 davidg Exp $
* created from $Id: syscalls.master,v 1.7 1994/09/13 00:48:19 wollman Exp $
*/
char *syscallnames[] = {
@ -195,8 +195,16 @@ char *syscallnames[] = {
"rtprio", /* 166 = rtprio */
"#167", /* 167 = nosys */
"#168", /* 168 = nosys */
#ifdef SYSVSEM
"semsys", /* 169 = semsys */
#else
"#169", /* 169 = nosys */
#endif
#ifdef SYSVMSG
"msgsys", /* 170 = msgsys */
#else
"#170", /* 170 = nosys */
#endif
#ifdef SYSVSHM
"shmsys", /* 171 = shmsys */
#else

View File

@ -1,4 +1,4 @@
$Id: syscalls.master,v 1.6 1994/09/01 05:12:42 davidg Exp $
$Id: syscalls.master,v 1.7 1994/09/13 00:48:19 wollman Exp $
; from: @(#)syscalls.master 8.2 (Berkeley) 1/13/94
;
; System call name/number master file.
@ -222,8 +222,16 @@
166 STD 2 BSD rtprio
167 UNIMPL 0 NOHIDE nosys
168 UNIMPL 0 NOHIDE nosys
#ifdef SYSVSEM
169 STD 5 BSD semsys
#else
169 UNIMPL 0 NOHIDE nosys
#endif
#ifdef SYSVMSG
170 STD 6 BSD msgsys
#else
170 UNIMPL 0 NOHIDE nosys
#endif
#ifdef SYSVSHM
171 STD 4 BSD shmsys
#else

69
sys/kern/sysv_ipc.c Normal file
View File

@ -0,0 +1,69 @@
/* $Id$ */
/* $NetBSD: sysv_ipc.c,v 1.7 1994/06/29 06:33:11 cgd Exp $ */
/*
* Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Herb Peyerl.
* 4. The name of Herb Peyerl may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/ipc.h>
#include <sys/systm.h>
/*
* Check for ipc permission
*/
int
ipcperm(cred, perm, mode)
struct ucred *cred;
struct ipc_perm *perm;
int mode;
{
if (cred->cr_uid == 0)
return (0);
/* Check for user match. */
if (cred->cr_uid != perm->cuid && cred->cr_uid != perm->uid) {
if (mode & IPC_M)
return (EPERM);
/* Check for group match. */
mode >>= 3;
if (!groupmember(perm->gid, cred) &&
!groupmember(perm->cgid, cred))
/* Check for `other' match. */
mode >>= 3;
}
if (mode & IPC_M)
return (0);
return ((mode & perm->mode) == mode ? 0 : EACCES);
}

1006
sys/kern/sysv_msg.c Normal file

File diff suppressed because it is too large Load Diff

939
sys/kern/sysv_sem.c Normal file
View File

@ -0,0 +1,939 @@
/* $Id$ */
/*
* Implementation of SVID semaphores
*
* Author: Daniel Boulet
*
* This software is provided ``AS IS'' without any warranties of any kind.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/sem.h>
#include <sys/malloc.h>
static int semctl(), semget(), semop(), semconfig();
int (*semcalls[])() = { semctl, semget, semop, semconfig };
int semtot = 0;
static struct proc *semlock_holder = NULL;
int
seminit()
{
register int i;
vm_offset_t whocares1, whocares2;
if (sema == NULL)
panic("sema is NULL");
if (semu == NULL)
panic("semu is NULL");
for (i = 0; i < seminfo.semmni; i++) {
sema[i].sem_base = 0;
sema[i].sem_perm.mode = 0;
}
for (i = 0; i < seminfo.semmnu; i++) {
register struct sem_undo *suptr = SEMU(i);
suptr->un_proc = NULL;
}
semu_list = NULL;
}
/*
* Entry point for all SEM calls
*/
struct semsys_args {
u_int which;
};
int
semsys(p, uap, retval)
struct proc *p;
struct semsys_args *uap;
int *retval;
{
while (semlock_holder != NULL && semlock_holder != p)
sleep((caddr_t)&semlock_holder, (PZERO - 4));
if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
return (EINVAL);
return ((*semcalls[uap->which])(p, &uap[1], retval));
}
/*
* Lock or unlock the entire semaphore facility.
*
* This will probably eventually evolve into a general purpose semaphore
* facility status enquiry mechanism (I don't like the "read /dev/kmem"
* approach currently taken by ipcs and the amount of info that we want
* to be able to extract for ipcs is probably beyond what the capability
* of the getkerninfo facility.
*
* At the time that the current version of semconfig was written, ipcs is
* the only user of the semconfig facility. It uses it to ensure that the
* semaphore facility data structures remain static while it fishes around
* in /dev/kmem.
*/
struct semconfig_args {
semconfig_ctl_t flag;
};
int
semconfig(p, uap, retval)
struct proc *p;
struct semconfig_args *uap;
int *retval;
{
int eval = 0;
switch (uap->flag) {
case SEM_CONFIG_FREEZE:
semlock_holder = p;
break;
case SEM_CONFIG_THAW:
semlock_holder = NULL;
wakeup((caddr_t)&semlock_holder);
break;
default:
printf("semconfig: unknown flag parameter value (%d) - ignored\n",
uap->flag);
eval = EINVAL;
break;
}
*retval = 0;
return(eval);
}
/*
* Allocate a new sem_undo structure for a process
* (returns ptr to structure or NULL if no more room)
*/
struct sem_undo *
semu_alloc(p)
struct proc *p;
{
register int i;
register struct sem_undo *suptr;
register struct sem_undo **supptr;
int attempt;
/*
* Try twice to allocate something.
* (we'll purge any empty structures after the first pass so
* two passes are always enough)
*/
for (attempt = 0; attempt < 2; attempt++) {
/*
* Look for a free structure.
* Fill it in and return it if we find one.
*/
for (i = 0; i < seminfo.semmnu; i++) {
suptr = SEMU(i);
if (suptr->un_proc == NULL) {
suptr->un_next = semu_list;
semu_list = suptr;
suptr->un_cnt = 0;
suptr->un_proc = p;
return(suptr);
}
}
/*
* We didn't find a free one, if this is the first attempt
* then try to free some structures.
*/
if (attempt == 0) {
/* All the structures are in use - try to free some */
int did_something = 0;
supptr = &semu_list;
while ((suptr = *supptr) != NULL) {
if (suptr->un_cnt == 0) {
suptr->un_proc = NULL;
*supptr = suptr->un_next;
did_something = 1;
} else
supptr = &(suptr->un_next);
}
/* If we didn't free anything then just give-up */
if (!did_something)
return(NULL);
} else {
/*
* The second pass failed even though we freed
* something after the first pass!
* This is IMPOSSIBLE!
*/
panic("semu_alloc - second attempt failed");
}
}
}
/*
* Adjust a particular entry for a particular proc
*/
int
semundo_adjust(p, supptr, semid, semnum, adjval)
register struct proc *p;
struct sem_undo **supptr;
int semid, semnum;
int adjval;
{
register struct sem_undo *suptr;
register struct undo *sunptr;
int i;
/* Look for and remember the sem_undo if the caller doesn't provide
it */
suptr = *supptr;
if (suptr == NULL) {
for (suptr = semu_list; suptr != NULL;
suptr = suptr->un_next) {
if (suptr->un_proc == p) {
*supptr = suptr;
break;
}
}
if (suptr == NULL) {
if (adjval == 0)
return(0);
suptr = semu_alloc(p);
if (suptr == NULL)
return(ENOSPC);
*supptr = suptr;
}
}
/*
* Look for the requested entry and adjust it (delete if adjval becomes
* 0).
*/
sunptr = &suptr->un_ent[0];
for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
if (sunptr->un_id != semid || sunptr->un_num != semnum)
continue;
if (adjval == 0)
sunptr->un_adjval = 0;
else
sunptr->un_adjval += adjval;
if (sunptr->un_adjval == 0) {
suptr->un_cnt--;
if (i < suptr->un_cnt)
suptr->un_ent[i] =
suptr->un_ent[suptr->un_cnt];
}
return(0);
}
/* Didn't find the right entry - create it */
if (adjval == 0)
return(0);
if (suptr->un_cnt != SEMUME) {
sunptr = &suptr->un_ent[suptr->un_cnt];
suptr->un_cnt++;
sunptr->un_adjval = adjval;
sunptr->un_id = semid; sunptr->un_num = semnum;
} else
return(EINVAL);
return(0);
}
void
semundo_clear(semid, semnum)
int semid, semnum;
{
register struct sem_undo *suptr;
for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) {
register struct undo *sunptr = &suptr->un_ent[0];
register int i = 0;
while (i < suptr->un_cnt) {
if (sunptr->un_id == semid) {
if (semnum == -1 || sunptr->un_num == semnum) {
suptr->un_cnt--;
if (i < suptr->un_cnt) {
suptr->un_ent[i] =
suptr->un_ent[suptr->un_cnt];
continue;
}
}
if (semnum != -1)
break;
}
i++, sunptr++;
}
}
}
struct semctl_args {
int semid;
int semnum;
int cmd;
union semun *arg;
};
int
semctl(p, uap, retval)
struct proc *p;
register struct semctl_args *uap;
int *retval;
{
int semid = uap->semid;
int semnum = uap->semnum;
int cmd = uap->cmd;
union semun *arg = uap->arg;
union semun real_arg;
struct ucred *cred = p->p_ucred;
int i, rval, eval;
struct semid_ds sbuf;
register struct semid_ds *semaptr;
#ifdef SEM_DEBUG
printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg);
#endif
semid = IPCID_TO_IX(semid);
if (semid < 0 || semid >= seminfo.semmsl)
return(EINVAL);
semaptr = &sema[semid];
if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
return(EINVAL);
eval = 0;
rval = 0;
switch (cmd) {
case IPC_RMID:
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M)))
return(eval);
semaptr->sem_perm.cuid = cred->cr_uid;
semaptr->sem_perm.uid = cred->cr_uid;
semtot -= semaptr->sem_nsems;
for (i = semaptr->sem_base - sem; i < semtot; i++)
sem[i] = sem[i + semaptr->sem_nsems];
for (i = 0; i < seminfo.semmni; i++) {
if ((sema[i].sem_perm.mode & SEM_ALLOC) &&
sema[i].sem_base > semaptr->sem_base)
sema[i].sem_base -= semaptr->sem_nsems;
}
semaptr->sem_perm.mode = 0;
semundo_clear(semid, -1);
wakeup((caddr_t)semaptr);
break;
case IPC_SET:
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M)))
return(eval);
if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
return(eval);
if ((eval = copyin(real_arg.buf, (caddr_t)&sbuf,
sizeof(sbuf))) != 0)
return(eval);
semaptr->sem_perm.uid = sbuf.sem_perm.uid;
semaptr->sem_perm.gid = sbuf.sem_perm.gid;
semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
(sbuf.sem_perm.mode & 0777);
semaptr->sem_ctime = time.tv_sec;
break;
case IPC_STAT:
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
return(eval);
if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
return(eval);
eval = copyout((caddr_t)semaptr, real_arg.buf,
sizeof(struct semid_ds));
break;
case GETNCNT:
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
return(eval);
if (semnum < 0 || semnum >= semaptr->sem_nsems)
return(EINVAL);
rval = semaptr->sem_base[semnum].semncnt;
break;
case GETPID:
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
return(eval);
if (semnum < 0 || semnum >= semaptr->sem_nsems)
return(EINVAL);
rval = semaptr->sem_base[semnum].sempid;
break;
case GETVAL:
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
return(eval);
if (semnum < 0 || semnum >= semaptr->sem_nsems)
return(EINVAL);
rval = semaptr->sem_base[semnum].semval;
break;
case GETALL:
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
return(eval);
if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
return(eval);
for (i = 0; i < semaptr->sem_nsems; i++) {
eval = copyout((caddr_t)&semaptr->sem_base[i].semval,
&real_arg.array[i], sizeof(real_arg.array[0]));
if (eval != 0)
break;
}
break;
case GETZCNT:
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
return(eval);
if (semnum < 0 || semnum >= semaptr->sem_nsems)
return(EINVAL);
rval = semaptr->sem_base[semnum].semzcnt;
break;
case SETVAL:
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
return(eval);
if (semnum < 0 || semnum >= semaptr->sem_nsems)
return(EINVAL);
if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
return(eval);
semaptr->sem_base[semnum].semval = real_arg.val;
semundo_clear(semid, semnum);
wakeup((caddr_t)semaptr);
break;
case SETALL:
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
return(eval);
if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
return(eval);
for (i = 0; i < semaptr->sem_nsems; i++) {
eval = copyin(&real_arg.array[i],
(caddr_t)&semaptr->sem_base[i].semval,
sizeof(real_arg.array[0]));
if (eval != 0)
break;
}
semundo_clear(semid, -1);
wakeup((caddr_t)semaptr);
break;
default:
return(EINVAL);
}
if (eval == 0)
*retval = rval;
return(eval);
}
struct semget_args {
key_t key;
int nsems;
int semflg;
};
int
semget(p, uap, retval)
struct proc *p;
register struct semget_args *uap;
int *retval;
{
int semid, eval;
int key = uap->key;
int nsems = uap->nsems;
int semflg = uap->semflg;
struct ucred *cred = p->p_ucred;
#ifdef SEM_DEBUG
printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg);
#endif
if (key != IPC_PRIVATE) {
for (semid = 0; semid < seminfo.semmni; semid++) {
if ((sema[semid].sem_perm.mode & SEM_ALLOC) &&
sema[semid].sem_perm.key == key)
break;
}
if (semid < seminfo.semmni) {
#ifdef SEM_DEBUG
printf("found public key\n");
#endif
if ((eval = ipcperm(cred, &sema[semid].sem_perm,
semflg & 0700)))
return(eval);
if (nsems > 0 && sema[semid].sem_nsems < nsems) {
#ifdef SEM_DEBUG
printf("too small\n");
#endif
return(EINVAL);
}
if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
#ifdef SEM_DEBUG
printf("not exclusive\n");
#endif
return(EEXIST);
}
goto found;
}
}
#ifdef SEM_DEBUG
printf("need to allocate the semid_ds\n");
#endif
if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
if (nsems <= 0 || nsems > seminfo.semmsl) {
#ifdef SEM_DEBUG
printf("nsems out of range (0<%d<=%d)\n", nsems,
seminfo.semmsl);
#endif
return(EINVAL);
}
if (nsems > seminfo.semmns - semtot) {
#ifdef SEM_DEBUG
printf("not enough semaphores left (need %d, got %d)\n",
nsems, seminfo.semmns - semtot);
#endif
return(ENOSPC);
}
for (semid = 0; semid < seminfo.semmni; semid++) {
if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
break;
}
if (semid == seminfo.semmni) {
#ifdef SEM_DEBUG
printf("no more semid_ds's available\n");
#endif
return(ENOSPC);
}
#ifdef SEM_DEBUG
printf("semid %d is available\n", semid);
#endif
sema[semid].sem_perm.key = key;
sema[semid].sem_perm.cuid = cred->cr_uid;
sema[semid].sem_perm.uid = cred->cr_uid;
sema[semid].sem_perm.cgid = cred->cr_gid;
sema[semid].sem_perm.gid = cred->cr_gid;
sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
sema[semid].sem_perm.seq =
(sema[semid].sem_perm.seq + 1) & 0x7fff;
sema[semid].sem_nsems = nsems;
sema[semid].sem_otime = 0;
sema[semid].sem_ctime = time.tv_sec;
sema[semid].sem_base = &sem[semtot];
semtot += nsems;
bzero(sema[semid].sem_base,
sizeof(sema[semid].sem_base[0])*nsems);
#ifdef SEM_DEBUG
printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base,
&sem[semtot]);
#endif
} else {
#ifdef SEM_DEBUG
printf("didn't find it and wasn't asked to create it\n");
#endif
return(ENOENT);
}
found:
*retval = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm);
return(0);
}
struct semop_args {
int semid;
struct sembuf *sops;
int nsops;
};
int
semop(p, uap, retval)
struct proc *p;
register struct semop_args *uap;
int *retval;
{
int semid = uap->semid;
int nsops = uap->nsops;
struct sembuf sops[MAX_SOPS];
register struct semid_ds *semaptr;
register struct sembuf *sopptr;
register struct sem *semptr;
struct sem_undo *suptr = NULL;
struct ucred *cred = p->p_ucred;
int i, j, eval;
int all_ok, do_wakeup, do_undos;
#ifdef SEM_DEBUG
printf("call to semop(%d, 0x%x, %d)\n", semid, sops, nsops);
#endif
semid = IPCID_TO_IX(semid); /* Convert back to zero origin */
if (semid < 0 || semid >= seminfo.semmsl)
return(EINVAL);
semaptr = &sema[semid];
if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
return(EINVAL);
if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
return(EINVAL);
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) {
#ifdef SEM_DEBUG
printf("eval = %d from ipaccess\n", eval);
#endif
return(eval);
}
if (nsops > MAX_SOPS) {
#ifdef SEM_DEBUG
printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops);
#endif
return(E2BIG);
}
if ((eval = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0) {
#ifdef SEM_DEBUG
printf("eval = %d from copyin(%08x, %08x, %d)\n", eval,
uap->sops, &sops, nsops * sizeof(sops[0]));
#endif
return(eval);
}
/*
* Loop trying to satisfy the vector of requests.
* If we reach a point where we must wait, any requests already
* performed are rolled back and we go to sleep until some other
* process wakes us up. At this point, we start all over again.
*
* This ensures that from the perspective of other tasks, a set
* of requests is atomic (never partially satisfied).
*/
do_undos = 0;
for (;;) {
do_wakeup = 0;
for (i = 0; i < nsops; i++) {
sopptr = &sops[i];
if (sopptr->sem_num >= semaptr->sem_nsems)
return(EFBIG);
semptr = &semaptr->sem_base[sopptr->sem_num];
#ifdef SEM_DEBUG
printf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
semaptr, semaptr->sem_base, semptr,
sopptr->sem_num, semptr->semval, sopptr->sem_op,
(sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait");
#endif
if (sopptr->sem_op < 0) {
if (semptr->semval + sopptr->sem_op < 0) {
#ifdef SEM_DEBUG
printf("semop: can't do it now\n");
#endif
break;
} else {
semptr->semval += sopptr->sem_op;
if (semptr->semval == 0 &&
semptr->semzcnt > 0)
do_wakeup = 1;
}
if (sopptr->sem_flg & SEM_UNDO)
do_undos = 1;
} else if (sopptr->sem_op == 0) {
if (semptr->semval > 0) {
#ifdef SEM_DEBUG
printf("semop: not zero now\n");
#endif
break;
}
} else {
if (semptr->semncnt > 0)
do_wakeup = 1;
semptr->semval += sopptr->sem_op;
if (sopptr->sem_flg & SEM_UNDO)
do_undos = 1;
}
}
/*
* Did we get through the entire vector?
*/
if (i >= nsops)
goto done;
/*
* No ... rollback anything that we've already done
*/
#ifdef SEM_DEBUG
printf("semop: rollback 0 through %d\n", i-1);
#endif
for (j = 0; j < i; j++)
semaptr->sem_base[sops[j].sem_num].semval -=
sops[j].sem_op;
/*
* If the request that we couldn't satisfy has the
* NOWAIT flag set then return with EAGAIN.
*/
if (sopptr->sem_flg & IPC_NOWAIT)
return(EAGAIN);
if (sopptr->sem_op == 0)
semptr->semzcnt++;
else
semptr->semncnt++;
#ifdef SEM_DEBUG
printf("semop: good night!\n");
#endif
eval = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH,
"semwait", 0);
#ifdef SEM_DEBUG
printf("semop: good morning (eval=%d)!\n", eval);
#endif
suptr = NULL; /* sem_undo may have been reallocated */
if (eval != 0)
return(EINTR);
#ifdef SEM_DEBUG
printf("semop: good morning!\n");
#endif
/*
* Make sure that the semaphore still exists
*/
if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
/* The man page says to return EIDRM. */
/* Unfortunately, BSD doesn't define that code! */
#ifdef EIDRM
return(EIDRM);
#else
return(EINVAL);
#endif
}
/*
* The semaphore is still alive. Readjust the count of
* waiting processes.
*/
if (sopptr->sem_op == 0)
semptr->semzcnt--;
else
semptr->semncnt--;
}
done:
/*
* Process any SEM_UNDO requests.
*/
if (do_undos) {
for (i = 0; i < nsops; i++) {
/*
* We only need to deal with SEM_UNDO's for non-zero
* op's.
*/
int adjval;
if ((sops[i].sem_flg & SEM_UNDO) == 0)
continue;
adjval = sops[i].sem_op;
if (adjval == 0)
continue;
eval = semundo_adjust(p, &suptr, semid,
sops[i].sem_num, -adjval);
if (eval == 0)
continue;
/*
* Oh-Oh! We ran out of either sem_undo's or undo's.
* Rollback the adjustments to this point and then
* rollback the semaphore ups and down so we can return
* with an error with all structures restored. We
* rollback the undo's in the exact reverse order that
* we applied them. This guarantees that we won't run
* out of space as we roll things back out.
*/
for (j = i - 1; j >= 0; j--) {
if ((sops[j].sem_flg & SEM_UNDO) == 0)
continue;
adjval = sops[j].sem_op;
if (adjval == 0)
continue;
if (semundo_adjust(p, &suptr, semid,
sops[j].sem_num, adjval) != 0)
panic("semop - can't undo undos");
}
for (j = 0; j < nsops; j++)
semaptr->sem_base[sops[j].sem_num].semval -=
sops[j].sem_op;
#ifdef SEM_DEBUG
printf("eval = %d from semundo_adjust\n", eval);
#endif
return(eval);
} /* loop through the sops */
} /* if (do_undos) */
/* We're definitely done - set the sempid's */
for (i = 0; i < nsops; i++) {
sopptr = &sops[i];
semptr = &semaptr->sem_base[sopptr->sem_num];
semptr->sempid = p->p_pid;
}
/* Do a wakeup if any semaphore was up'd. */
if (do_wakeup) {
#ifdef SEM_DEBUG
printf("semop: doing wakeup\n");
#ifdef SEM_WAKEUP
sem_wakeup((caddr_t)semaptr);
#else
wakeup((caddr_t)semaptr);
#endif
printf("semop: back from wakeup\n");
#else
wakeup((caddr_t)semaptr);
#endif
}
#ifdef SEM_DEBUG
printf("semop: done\n");
#endif
*retval = 0;
return(0);
}
/*
* Go through the undo structures for this process and apply the adjustments to
* semaphores.
*/
semexit(p)
struct proc *p;
{
register struct sem_undo *suptr;
register struct sem_undo **supptr;
int did_something;
/*
* If somebody else is holding the global semaphore facility lock
* then sleep until it is released.
*/
while (semlock_holder != NULL && semlock_holder != p) {
#ifdef SEM_DEBUG
printf("semaphore facility locked - sleeping ...\n");
#endif
sleep((caddr_t)&semlock_holder, (PZERO - 4));
}
did_something = 0;
/*
* Go through the chain of undo vectors looking for one
* associated with this process.
*/
for (supptr = &semu_list; (suptr = *supptr) != NULL;
supptr = &suptr->un_next) {
if (suptr->un_proc == p)
break;
}
if (suptr == NULL)
goto unlock;
#ifdef SEM_DEBUG
printf("proc @%08x has undo structure with %d entries\n", p,
suptr->un_cnt);
#endif
/*
* If there are any active undo elements then process them.
*/
if (suptr->un_cnt > 0) {
int ix;
for (ix = 0; ix < suptr->un_cnt; ix++) {
int semid = suptr->un_ent[ix].un_id;
int semnum = suptr->un_ent[ix].un_num;
int adjval = suptr->un_ent[ix].un_adjval;
struct semid_ds *semaptr;
semaptr = &sema[semid];
if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
panic("semexit - semid not allocated");
if (semnum >= semaptr->sem_nsems)
panic("semexit - semnum out of range");
#ifdef SEM_DEBUG
printf("semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",
suptr->un_proc, suptr->un_ent[ix].un_id,
suptr->un_ent[ix].un_num,
suptr->un_ent[ix].un_adjval,
semaptr->sem_base[semnum].semval);
#endif
if (adjval < 0) {
if (semaptr->sem_base[semnum].semval < -adjval)
semaptr->sem_base[semnum].semval = 0;
else
semaptr->sem_base[semnum].semval +=
adjval;
} else
semaptr->sem_base[semnum].semval += adjval;
#ifdef SEM_WAKEUP
sem_wakeup((caddr_t)semaptr);
#else
wakeup((caddr_t)semaptr);
#endif
#ifdef SEM_DEBUG
printf("semexit: back from wakeup\n");
#endif
}
}
/*
* Deallocate the undo vector.
*/
#ifdef SEM_DEBUG
printf("removing vector\n");
#endif
suptr->un_proc = NULL;
*supptr = suptr->un_next;
unlock:
/*
* If the exiting process is holding the global semaphore facility
* lock then release it.
*/
if (semlock_holder == p) {
semlock_holder = NULL;
wakeup((caddr_t)&semlock_holder);
}
}

517
sys/kern/sysv_shm.c Normal file
View File

@ -0,0 +1,517 @@
/* $Id$ */
/* $NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $ */
/*
* Copyright (c) 1994 Adam Glass and Charles Hannum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Adam Glass and Charles
* Hannum.
* 4. The names of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/shm.h>
#include <sys/proc.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/systm.h>
#include <sys/stat.h>
#include <vm/vm.h>
#include <vm/vm_map.h>
#include <vm/vm_map.h>
#include <vm/vm_kern.h>
/*
* Provides the following externally accessible functions:
*
* shminit(void); initialization
* shmexit(struct proc *) cleanup
* shmfork(struct proc *, struct proc *, int) fork handling
* shmsys(arg1, arg2, arg3, arg4); shm{at,ctl,dt,get}(arg2, arg3, arg4)
*
* Structures:
* shmsegs (an array of 'struct shmid_ds')
* per proc array of 'struct shmmap_state'
*/
int shmat(), shmctl(), shmdt(), shmget();
int (*shmcalls[])() = { shmat, shmctl, shmdt, shmget };
#define SHMSEG_FREE 0x0200
#define SHMSEG_REMOVED 0x0400
#define SHMSEG_ALLOCATED 0x0800
#define SHMSEG_WANTED 0x1000
vm_map_t sysvshm_map;
int shm_last_free, shm_nused, shm_committed;
struct shm_handle {
vm_offset_t kva;
};
struct shmmap_state {
vm_offset_t va;
int shmid;
};
static void shm_deallocate_segment __P((struct shmid_ds *));
static int shm_find_segment_by_key __P((key_t));
static struct shmid_ds *shm_find_segment_by_shmid __P((int));
static int shm_delete_mapping __P((struct proc *, struct shmmap_state *));
static int
shm_find_segment_by_key(key)
key_t key;
{
int i;
for (i = 0; i < shminfo.shmmni; i++)
if ((shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) &&
shmsegs[i].shm_perm.key == key)
return i;
return -1;
}
static struct shmid_ds *
shm_find_segment_by_shmid(shmid)
int shmid;
{
int segnum;
struct shmid_ds *shmseg;
segnum = IPCID_TO_IX(shmid);
if (segnum < 0 || segnum >= shminfo.shmmni)
return NULL;
shmseg = &shmsegs[segnum];
if ((shmseg->shm_perm.mode & (SHMSEG_ALLOCATED | SHMSEG_REMOVED))
!= SHMSEG_ALLOCATED ||
shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid))
return NULL;
return shmseg;
}
static void
shm_deallocate_segment(shmseg)
struct shmid_ds *shmseg;
{
struct shm_handle *shm_handle;
size_t size;
shm_handle = shmseg->shm_internal;
size = (shmseg->shm_segsz + CLOFSET) & ~CLOFSET;
vm_deallocate(sysvshm_map, shm_handle->kva, size);
free((caddr_t)shm_handle, M_SHM);
shmseg->shm_internal = NULL;
shm_committed -= btoc(size);
shm_nused--;
shmseg->shm_perm.mode = SHMSEG_FREE;
}
static int
shm_delete_mapping(p, shmmap_s)
struct proc *p;
struct shmmap_state *shmmap_s;
{
struct shmid_ds *shmseg;
int segnum, result;
size_t size;
segnum = IPCID_TO_IX(shmmap_s->shmid);
shmseg = &shmsegs[segnum];
size = (shmseg->shm_segsz + CLOFSET) & ~CLOFSET;
result = vm_deallocate(&p->p_vmspace->vm_map, shmmap_s->va, size);
if (result != KERN_SUCCESS)
return EINVAL;
shmmap_s->shmid = -1;
shmseg->shm_dtime = time.tv_sec;
if ((--shmseg->shm_nattch <= 0) &&
(shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
shm_deallocate_segment(shmseg);
shm_last_free = segnum;
}
return 0;
}
struct shmdt_args {
void *shmaddr;
};
int
shmdt(p, uap, retval)
struct proc *p;
struct shmdt_args *uap;
int *retval;
{
struct shmmap_state *shmmap_s;
int i;
shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
if (shmmap_s->shmid != -1 &&
shmmap_s->va == (vm_offset_t)uap->shmaddr)
break;
if (i == shminfo.shmseg)
return EINVAL;
return shm_delete_mapping(p, shmmap_s);
}
struct shmat_args {
int shmid;
void *shmaddr;
int shmflg;
};
int
shmat(p, uap, retval)
struct proc *p;
struct shmat_args *uap;
int *retval;
{
int error, i, flags;
struct ucred *cred = p->p_ucred;
struct shmid_ds *shmseg;
struct shmmap_state *shmmap_s = NULL;
vm_offset_t attach_va;
vm_prot_t prot;
vm_size_t size;
shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
if (shmmap_s == NULL) {
size = shminfo.shmseg * sizeof(struct shmmap_state);
shmmap_s = malloc(size, M_SHM, M_WAITOK);
for (i = 0; i < shminfo.shmseg; i++)
shmmap_s[i].shmid = -1;
p->p_vmspace->vm_shm = (caddr_t)shmmap_s;
}
shmseg = shm_find_segment_by_shmid(uap->shmid);
if (shmseg == NULL)
return EINVAL;
if (error = ipcperm(cred, &shmseg->shm_perm,
(uap->shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W))
return error;
for (i = 0; i < shminfo.shmseg; i++) {
if (shmmap_s->shmid == -1)
break;
shmmap_s++;
}
if (i >= shminfo.shmseg)
return EMFILE;
size = (shmseg->shm_segsz + CLOFSET) & ~CLOFSET;
prot = VM_PROT_READ;
if ((uap->shmflg & SHM_RDONLY) == 0)
prot |= VM_PROT_WRITE;
flags = MAP_ANON | MAP_SHARED;
if (uap->shmaddr) {
flags |= MAP_FIXED;
if (uap->shmflg & SHM_RND)
attach_va = (vm_offset_t)uap->shmaddr & ~(SHMLBA-1);
else if (((vm_offset_t)uap->shmaddr & (SHMLBA-1)) == 0)
attach_va = (vm_offset_t)uap->shmaddr;
else
return EINVAL;
} else {
/* This is just a hint to vm_mmap() about where to put it. */
attach_va = round_page(p->p_vmspace->vm_daddr + MAXDSIZ);
}
error = vm_mmap(&p->p_vmspace->vm_map, &attach_va, size, prot,
VM_PROT_DEFAULT, flags, (caddr_t) uap->shmid, 0);
if (error)
return error;
shmmap_s->va = attach_va;
shmmap_s->shmid = uap->shmid;
shmseg->shm_lpid = p->p_pid;
shmseg->shm_atime = time.tv_sec;
shmseg->shm_nattch++;
*retval = attach_va;
return 0;
}
struct shmctl_args {
int shmid;
int cmd;
struct shmat_ds *ubuf;
};
int
shmctl(p, uap, retval)
struct proc *p;
struct shmctl_args *uap;
int *retval;
{
int error, segnum;
struct ucred *cred = p->p_ucred;
struct shmid_ds inbuf;
struct shmid_ds *shmseg;
shmseg = shm_find_segment_by_shmid(uap->shmid);
if (shmseg == NULL)
return EINVAL;
switch (uap->cmd) {
case IPC_STAT:
if (error = ipcperm(cred, &shmseg->shm_perm, IPC_R))
return error;
if (error = copyout((caddr_t)shmseg, uap->ubuf, sizeof(inbuf)))
return error;
break;
case IPC_SET:
if (error = ipcperm(cred, &shmseg->shm_perm, IPC_M))
return error;
if (error = copyin(uap->ubuf, (caddr_t)&inbuf, sizeof(inbuf)))
return error;
shmseg->shm_perm.uid = inbuf.shm_perm.uid;
shmseg->shm_perm.gid = inbuf.shm_perm.gid;
shmseg->shm_perm.mode =
(shmseg->shm_perm.mode & ~ACCESSPERMS) |
(inbuf.shm_perm.mode & ACCESSPERMS);
shmseg->shm_ctime = time.tv_sec;
break;
case IPC_RMID:
if (error = ipcperm(cred, &shmseg->shm_perm, IPC_M))
return error;
shmseg->shm_perm.key = IPC_PRIVATE;
shmseg->shm_perm.mode |= SHMSEG_REMOVED;
if (shmseg->shm_nattch <= 0) {
shm_deallocate_segment(shmseg);
shm_last_free = IPCID_TO_IX(uap->shmid);
}
break;
#if 0
case SHM_LOCK:
case SHM_UNLOCK:
#endif
default:
return EINVAL;
}
return 0;
}
struct shmget_args {
key_t key;
size_t size;
int shmflg;
};
static int
shmget_existing(p, uap, mode, segnum, retval)
struct proc *p;
struct shmget_args *uap;
int mode;
int segnum;
int *retval;
{
struct shmid_ds *shmseg;
struct ucred *cred = p->p_ucred;
int error;
shmseg = &shmsegs[segnum];
if (shmseg->shm_perm.mode & SHMSEG_REMOVED) {
/*
* This segment is in the process of being allocated. Wait
* until it's done, and look the key up again (in case the
* allocation failed or it was freed).
*/
shmseg->shm_perm.mode |= SHMSEG_WANTED;
if (error =
tsleep((caddr_t)shmseg, PLOCK | PCATCH, "shmget", 0))
return error;
return EAGAIN;
}
if (error = ipcperm(cred, &shmseg->shm_perm, mode))
return error;
if (uap->size && uap->size > shmseg->shm_segsz)
return EINVAL;
if (uap->shmflg & (IPC_CREAT | IPC_EXCL) == (IPC_CREAT | IPC_EXCL))
return EEXIST;
*retval = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
return 0;
}
static int
shmget_allocate_segment(p, uap, mode, retval)
struct proc *p;
struct shmget_args *uap;
int mode;
int *retval;
{
int i, segnum, result, shmid, size;
struct ucred *cred = p->p_ucred;
struct shmid_ds *shmseg;
struct shm_handle *shm_handle;
if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
return EINVAL;
if (shm_nused >= shminfo.shmmni) /* any shmids left? */
return ENOSPC;
size = (uap->size + CLOFSET) & ~CLOFSET;
if (shm_committed + btoc(size) > shminfo.shmall)
return ENOMEM;
if (shm_last_free < 0) {
for (i = 0; i < shminfo.shmmni; i++)
if (shmsegs[i].shm_perm.mode & SHMSEG_FREE)
break;
if (i == shminfo.shmmni)
panic("shmseg free count inconsistent");
segnum = i;
} else {
segnum = shm_last_free;
shm_last_free = -1;
}
shmseg = &shmsegs[segnum];
/*
* In case we sleep in malloc(), mark the segment present but deleted
* so that noone else tries to create the same key.
*/
shmseg->shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED;
shmseg->shm_perm.key = uap->key;
shmseg->shm_perm.seq = (shmseg->shm_perm.seq + 1) & 0x7fff;
shm_handle = (struct shm_handle *)
malloc(sizeof(struct shm_handle), M_SHM, M_WAITOK);
shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
result = vm_mmap(sysvshm_map, &shm_handle->kva, size, VM_PROT_ALL,
VM_PROT_DEFAULT, MAP_ANON, (caddr_t) shmid, 0);
if (result != KERN_SUCCESS) {
shmseg->shm_perm.mode = SHMSEG_FREE;
shm_last_free = segnum;
free((caddr_t)shm_handle, M_SHM);
/* Just in case. */
wakeup((caddr_t)shmseg);
return ENOMEM;
}
shmseg->shm_internal = shm_handle;
shmseg->shm_perm.cuid = shmseg->shm_perm.uid = cred->cr_uid;
shmseg->shm_perm.cgid = shmseg->shm_perm.gid = cred->cr_gid;
shmseg->shm_perm.mode = (shmseg->shm_perm.mode & SHMSEG_WANTED) |
(mode & ACCESSPERMS) | SHMSEG_ALLOCATED;
shmseg->shm_segsz = uap->size;
shmseg->shm_cpid = p->p_pid;
shmseg->shm_lpid = shmseg->shm_nattch = 0;
shmseg->shm_atime = shmseg->shm_dtime = 0;
shmseg->shm_ctime = time.tv_sec;
shm_committed += btoc(size);
shm_nused++;
if (shmseg->shm_perm.mode & SHMSEG_WANTED) {
/*
* Somebody else wanted this key while we were asleep. Wake
* them up now.
*/
shmseg->shm_perm.mode &= ~SHMSEG_WANTED;
wakeup((caddr_t)shmseg);
}
*retval = shmid;
return 0;
}
int
shmget(p, uap, retval)
struct proc *p;
struct shmget_args *uap;
int *retval;
{
int segnum, mode, error;
struct shmid_ds *shmseg;
mode = uap->shmflg & ACCESSPERMS;
if (uap->key != IPC_PRIVATE) {
again:
segnum = shm_find_segment_by_key(uap->key);
if (segnum >= 0) {
error = shmget_existing(p, uap, mode, segnum, retval);
if (error == EAGAIN)
goto again;
return error;
}
if ((uap->shmflg & IPC_CREAT) == 0)
return ENOENT;
}
return shmget_allocate_segment(p, uap, mode, retval);
}
struct shmsys_args {
u_int which;
};
int
shmsys(p, uap, retval)
struct proc *p;
struct shmsys_args *uap;
int *retval;
{
if (uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0]))
return EINVAL;
return ((*shmcalls[uap->which])(p, &uap[1], retval));
}
void
shmfork(p1, p2, isvfork)
struct proc *p1, *p2;
int isvfork;
{
struct shmmap_state *shmmap_s;
size_t size;
int i;
size = shminfo.shmseg * sizeof(struct shmmap_state);
shmmap_s = malloc(size, M_SHM, M_WAITOK);
bcopy((caddr_t)p1->p_vmspace->vm_shm, (caddr_t)shmmap_s, size);
p2->p_vmspace->vm_shm = (caddr_t)shmmap_s;
for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
if (shmmap_s->shmid != -1)
shmsegs[IPCID_TO_IX(shmmap_s->shmid)].shm_nattch++;
}
void
shmexit(p)
struct proc *p;
{
struct shmmap_state *shmmap_s;
struct shmid_ds *shmseg;
int i;
shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
if (shmmap_s->shmid != -1)
shm_delete_mapping(p, shmmap_s);
free((caddr_t)p->p_vmspace->vm_shm, M_SHM);
p->p_vmspace->vm_shm = NULL;
}
void
shminit()
{
int i;
vm_offset_t garbage1, garbage2;
/* actually this *should* be pageable. SHM_{LOCK,UNLOCK} */
sysvshm_map = kmem_suballoc(kernel_map, &garbage1, &garbage2,
shminfo.shmall * NBPG, TRUE);
for (i = 0; i < shminfo.shmmni; i++) {
shmsegs[i].shm_perm.mode = SHMSEG_FREE;
shmsegs[i].shm_perm.seq = 0;
}
shm_last_free = 0;
shm_nused = 0;
shm_committed = 0;
}

View File

@ -41,7 +41,7 @@
* SUCH DAMAGE.
*
* @(#)ipc.h 8.3 (Berkeley) 1/21/94
* $Id$
* $Id: ipc.h,v 1.2 1994/08/02 07:53:06 davidg Exp $
*/
/*
@ -65,6 +65,7 @@ struct ipc_perm {
/* common mode bits */
#define IPC_R 00400 /* read permission */
#define IPC_W 00200 /* write/alter permission */
#define IPC_M 10000 /* permission to change control info */
/* SVID required constants (same values as system 5) */
#define IPC_CREAT 01000 /* create entry if key does not exist */
@ -77,4 +78,11 @@ struct ipc_perm {
#define IPC_SET 1 /* set options */
#define IPC_STAT 2 /* get options */
#ifdef KERNEL
/* Macros to convert between ipc ids and array indices or sequence ids */
#define IPCID_TO_IX(id) ((id) & 0xffff)
#define IPCID_TO_SEQ(id) (((id) >> 16) & 0xffff)
#define IXSEQ_TO_IPCID(ix,perm) (((perm.seq) << 16) | (ix & 0xffff))
#endif /* KERNEL */
#endif /* !_SYS_IPC_H_ */

161
sys/sys/msg.h Normal file
View File

@ -0,0 +1,161 @@
/* $Id$ */
/* $NetBSD: msg.h,v 1.4 1994/06/29 06:44:43 cgd Exp $ */
/*
* SVID compatible msg.h file
*
* Author: Daniel Boulet
*
* Copyright 1993 Daniel Boulet and RTMX Inc.
*
* This system call was implemented by Daniel Boulet under contract from RTMX.
*
* Redistribution and use in source forms, with and without modification,
* are permitted provided that this entire comment appears intact.
*
* Redistribution in binary form may occur without any restrictions.
* Obviously, it would be nice if you gave credit where credit is due
* but requiring it would be too onerous.
*
* This software is provided ``AS IS'' without any warranties of any kind.
*/
#ifndef _SYS_MSG_H_
#define _SYS_MSG_H_
#include <sys/ipc.h>
/*
* The MSG_NOERROR identifier value, the msqid_ds struct and the msg struct
* are as defined by the SV API Intel 386 Processor Supplement.
*/
#define MSG_NOERROR 010000 /* don't complain about too long msgs */
struct msqid_ds {
struct ipc_perm msg_perm; /* msg queue permission bits */
struct msg *msg_first; /* first message in the queue */
struct msg *msg_last; /* last message in the queue */
u_long msg_cbytes; /* number of bytes in use on the queue */
u_long msg_qnum; /* number of msgs in the queue */
u_long msg_qbytes; /* max # of bytes on the queue */
pid_t msg_lspid; /* pid of last msgsnd() */
pid_t msg_lrpid; /* pid of last msgrcv() */
time_t msg_stime; /* time of last msgsnd() */
long msg_pad1;
time_t msg_rtime; /* time of last msgrcv() */
long msg_pad2;
time_t msg_ctime; /* time of last msgctl() */
long msg_pad3;
long msg_pad4[4];
};
struct msg {
struct msg *msg_next; /* next msg in the chain */
long msg_type; /* type of this message */
/* >0 -> type of this message */
/* 0 -> free header */
u_short msg_ts; /* size of this message */
short msg_spot; /* location of start of msg in buffer */
};
/*
* Structure describing a message. The SVID doesn't suggest any
* particular name for this structure. There is a reference in the
* msgop man page that reads "The structure mymsg is an example of what
* this user defined buffer might look like, and includes the following
* members:". This sentence is followed by two lines equivalent
* to the mtype and mtext field declarations below. It isn't clear
* if "mymsg" refers to the naem of the structure type or the name of an
* instance of the structure...
*/
struct mymsg {
long mtype; /* message type (+ve integer) */
char mtext[1]; /* message body */
};
/*
* Based on the configuration parameters described in an SVR2 (yes, two)
* config(1m) man page.
*
* Each message is broken up and stored in segments that are msgssz bytes
* long. For efficiency reasons, this should be a power of two. Also,
* it doesn't make sense if it is less than 8 or greater than about 256.
* Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
* two between 8 and 1024 inclusive (and panic's if it isn't).
*/
struct msginfo {
int msgmax, /* max chars in a message */
msgmni, /* max message queue identifiers */
msgmnb, /* max chars in a queue */
msgtql, /* max messages in system */
msgssz, /* size of a message segment (see notes above) */
msgseg; /* number of message segments */
};
struct msginfo msginfo;
#ifdef KERNEL
#ifndef MSGSSZ
#define MSGSSZ 8 /* Each segment must be 2^N long */
#endif
#ifndef MSGSEG
#define MSGSEG 2048 /* must be less than 32767 */
#endif
#undef MSGMAX /* ALWAYS compute MGSMAX! */
#define MSGMAX (MSGSSZ*MSGSEG)
#ifndef MSGMNB
#define MSGMNB 2048 /* max # of bytes in a queue */
#endif
#ifndef MSGMNI
#define MSGMNI 40
#endif
#ifndef MSGTQL
#define MSGTQL 40
#endif
/*
* macros to convert between msqid_ds's and msqid's.
* (specific to this implementation)
*/
#define MSQID(ix,ds) ((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000))
#define MSQID_IX(id) ((id) & 0xffff)
#define MSQID_SEQ(id) (((id) >> 16) & 0xffff)
#endif
/*
* The rest of this file is specific to this particular implementation.
*/
#ifdef KERNEL
/*
* Stuff allocated in machdep.h
*/
struct msgmap {
short next; /* next segment in buffer */
/* -1 -> available */
/* 0..(MSGSEG-1) -> index of next segment */
};
char *msgpool; /* MSGMAX byte long msg buffer pool */
struct msgmap *msgmaps; /* MSGSEG msgmap structures */
struct msg *msghdrs; /* MSGTQL msg headers */
struct msqid_ds *msqids; /* MSGMNI msqid_ds struct's */
#define MSG_LOCKED 01000 /* Is this msqid_ds locked? */
#endif
#ifndef KERNEL
#include <sys/cdefs.h>
__BEGIN_DECLS
int msgsys __P((int, ...));
int msgctl __P((int, int, struct msqid_ds *));
int msgget __P((key_t, int));
int msgsnd __P((int, void *, size_t, int));
int msgrcv __P((int, void*, size_t, long, int));
__END_DECLS
#endif /* !KERNEL */
#endif /* !_SYS_MSG_H_ */

179
sys/sys/sem.h Normal file
View File

@ -0,0 +1,179 @@
/* $Id$ */
/* $NetBSD: sem.h,v 1.5 1994/06/29 06:45:15 cgd Exp $ */
/*
* SVID compatible sem.h file
*
* Author: Daniel Boulet
*/
#ifndef _SYS_SEM_H_
#define _SYS_SEM_H_
#include <sys/ipc.h>
struct sem {
u_short semval; /* semaphore value */
pid_t sempid; /* pid of last operation */
u_short semncnt; /* # awaiting semval > cval */
u_short semzcnt; /* # awaiting semval = 0 */
};
struct semid_ds {
struct ipc_perm sem_perm; /* operation permission struct */
struct sem *sem_base; /* pointer to first semaphore in set */
u_short sem_nsems; /* number of sems in set */
time_t sem_otime; /* last operation time */
long sem_pad1; /* SVABI/386 says I need this here */
time_t sem_ctime; /* last change time */
/* Times measured in secs since */
/* 00:00:00 GMT, Jan. 1, 1970 */
long sem_pad2; /* SVABI/386 says I need this here */
long sem_pad3[4]; /* SVABI/386 says I need this here */
};
/*
* semop's sops parameter structure
*/
struct sembuf {
u_short sem_num; /* semaphore # */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
};
#define SEM_UNDO 010000
#define MAX_SOPS 5 /* maximum # of sembuf's per semop call */
/*
* semctl's arg parameter structure
*/
union semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
u_short *array; /* array for GETALL & SETALL */
};
/*
* commands for semctl
*/
#define GETNCNT 3 /* Return the value of semncnt {READ} */
#define GETPID 4 /* Return the value of sempid {READ} */
#define GETVAL 5 /* Return the value of semval {READ} */
#define GETALL 6 /* Return semvals into arg.array {READ} */
#define GETZCNT 7 /* Return the value of semzcnt {READ} */
#define SETVAL 8 /* Set the value of semval to arg.val {ALTER} */
#define SETALL 9 /* Set semvals from arg.array {ALTER} */
#ifdef KERNEL
/*
* Kernel implementation stuff
*/
#define SEMVMX 32767 /* semaphore maximum value */
#define SEMAEM 16384 /* adjust on exit max value */
/*
* Permissions
*/
#define SEM_A 0200 /* alter permission */
#define SEM_R 0400 /* read permission */
/*
* Undo structure (one per process)
*/
struct sem_undo {
struct sem_undo *un_next; /* ptr to next active undo structure */
struct proc *un_proc; /* owner of this structure */
short un_cnt; /* # of active entries */
struct undo {
short un_adjval; /* adjust on exit values */
short un_num; /* semaphore # */
int un_id; /* semid */
} un_ent[1]; /* undo entries */
};
/*
* semaphore info struct
*/
struct seminfo {
int semmap, /* # of entries in semaphore map */
semmni, /* # of semaphore identifiers */
semmns, /* # of semaphores in system */
semmnu, /* # of undo structures in system */
semmsl, /* max # of semaphores per id */
semopm, /* max # of operations per semop call */
semume, /* max # of undo entries per process */
semusz, /* size in bytes of undo structure */
semvmx, /* semaphore maximum value */
semaem; /* adjust on exit max value */
};
struct seminfo seminfo;
/* internal "mode" bits */
#define SEM_ALLOC 01000 /* semaphore is allocated */
#define SEM_DEST 02000 /* semaphore will be destroyed on last detach */
/*
* Configuration parameters
*/
#ifndef SEMMNI
#define SEMMNI 10 /* # of semaphore identifiers */
#endif
#ifndef SEMMNS
#define SEMMNS 60 /* # of semaphores in system */
#endif
#ifndef SEMUME
#define SEMUME 10 /* max # of undo entries per process */
#endif
#ifndef SEMMNU
#define SEMMNU 30 /* # of undo structures in system */
#endif
/* shouldn't need tuning */
#ifndef SEMMAP
#define SEMMAP 30 /* # of entries in semaphore map */
#endif
#ifndef SEMMSL
#define SEMMSL SEMMNS /* max # of semaphores per id */
#endif
#ifndef SEMOPM
#define SEMOPM 100 /* max # of operations per semop call */
#endif
/* actual size of an undo structure */
#define SEMUSZ (sizeof(struct sem_undo)+sizeof(struct undo)*SEMUME)
/*
* Structures allocated in machdep.c
*/
struct semid_ds *sema; /* semaphore id pool */
struct sem *sem; /* semaphore pool */
struct map *semmap; /* semaphore allocation map */
struct sem_undo *semu_list; /* list of active undo structures */
int *semu; /* undo structure pool */
/*
* Macro to find a particular sem_undo vector
*/
#define SEMU(ix) ((struct sem_undo *)(((long)semu)+ix * SEMUSZ))
/*
* Parameters to the semconfig system call
*/
typedef enum {
SEM_CONFIG_FREEZE, /* Freeze the semaphore facility. */
SEM_CONFIG_THAW /* Thaw the semaphore facility. */
} semconfig_ctl_t;
#endif /* KERNEL */
#ifndef KERNEL
#include <sys/cdefs.h>
__BEGIN_DECLS
int semsys __P((int, ...));
int semctl __P((int, int, int, union semun));
int semget __P((key_t, int, int));
int semop __P((int, struct sembuf *,unsigned));
__END_DECLS
#endif /* !KERNEL */
#endif /* !_SEM_H_ */

90
sys/sys/shm.h Normal file
View File

@ -0,0 +1,90 @@
/* $Id$ */
/* $NetBSD: shm.h,v 1.15 1994/06/29 06:45:17 cgd Exp $ */
/*
* Copyright (c) 1994 Adam Glass
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Adam Glass.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* As defined+described in "X/Open System Interfaces and Headers"
* Issue 4, p. XXX
*/
#ifndef _SYS_SHM_H_
#define _SYS_SHM_H_
#include <sys/ipc.h>
#define SHM_RDONLY 010000 /* Attach read-only (else read-write) */
#define SHM_RND 020000 /* Round attach address to SHMLBA */
#define SHMLBA CLBYTES /* Segment low boundry address multiple */
struct shmid_ds {
struct ipc_perm shm_perm; /* operation permission structure */
int shm_segsz; /* size of segment in bytes */
pid_t shm_lpid; /* process ID of last shared memory op */
pid_t shm_cpid; /* process ID of creator */
short shm_nattch; /* number of current attaches */
time_t shm_atime; /* time of last shmat() */
time_t shm_dtime; /* time of last shmdt() */
time_t shm_ctime; /* time of last change by shmctl() */
void *shm_internal; /* sysv stupidity */
};
#ifdef KERNEL
/*
* System 5 style catch-all structure for shared memory constants that
* might be of interest to user programs. Do we really want/need this?
*/
struct shminfo {
int shmmax, /* max shared memory segment size (bytes) */
shmmin, /* min shared memory segment size (bytes) */
shmmni, /* max number of shared memory identifiers */
shmseg, /* max shared memory segments per process */
shmall; /* max amount of shared memory (pages) */
};
struct shminfo shminfo;
struct shmid_ds *shmsegs;
#else /* !KERNEL */
#include <sys/cdefs.h>
__BEGIN_DECLS
int shmsys __P((int, ...));
void *shmat __P((int, void *, int));
int shmget __P((key_t, int, int));
int shmctl __P((int, int, struct shmid_ds *));
int shmdt __P((void *));
__END_DECLS
#endif /* !KERNEL */
#endif /* !_SYS_SHM_H_ */

View File

@ -2,7 +2,7 @@
* System call hiders.
*
* DO NOT EDIT-- this file is automatically generated.
* created from $Id: syscalls.master,v 1.6 1994/09/01 05:12:42 davidg Exp $
* created from $Id: syscalls.master,v 1.7 1994/09/13 00:48:19 wollman Exp $
*/
HIDE_POSIX(fork)
@ -175,6 +175,14 @@ HIDE_BSD(setdomainname)
HIDE_BSD(uname)
HIDE_BSD(sysarch)
HIDE_BSD(rtprio)
#ifdef SYSVSEM
HIDE_BSD(semsys)
#else
#endif
#ifdef SYSVMSG
HIDE_BSD(msgsys)
#else
#endif
#ifdef SYSVSHM
HIDE_BSD(shmsys)
#else

View File

@ -2,7 +2,7 @@
* System call numbers.
*
* DO NOT EDIT-- this file is automatically generated.
* created from $Id: syscalls.master,v 1.6 1994/09/01 05:12:42 davidg Exp $
* created from $Id: syscalls.master,v 1.7 1994/09/13 00:48:19 wollman Exp $
*/
#define SYS_syscall 0
@ -165,6 +165,8 @@
#define SYS_uname 164
#define SYS_sysarch 165
#define SYS_rtprio 166
#define SYS_semsys 169
#define SYS_msgsys 170
#define SYS_shmsys 171
#define SYS_ntp_gettime 175
#define SYS_ntp_adjtime 176