summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordfr <dfr@FreeBSD.org>1994-09-13 14:47:38 +0000
committerdfr <dfr@FreeBSD.org>1994-09-13 14:47:38 +0000
commit580fe46632ff236a0f268c29705d04d44ad2f89a (patch)
tree0b43a166c9d31a9a5c55d5efd7085507563a3825
parenta7c9d6c8b52a067267445732a70349e616440364 (diff)
downloadFreeBSD-src-580fe46632ff236a0f268c29705d04d44ad2f89a.zip
FreeBSD-src-580fe46632ff236a0f268c29705d04d44ad2f89a.tar.gz
Added SYSV ipcs.
Obtained from: NetBSD and FreeBSD-1.1.5
-rw-r--r--sys/conf/files5
-rw-r--r--sys/conf/param.c45
-rw-r--r--sys/kern/init_main.c17
-rw-r--r--sys/kern/init_sysent.c24
-rw-r--r--sys/kern/kern_exec.c4
-rw-r--r--sys/kern/subr_param.c45
-rw-r--r--sys/kern/syscalls.c10
-rw-r--r--sys/kern/syscalls.master10
-rw-r--r--sys/kern/sysv_ipc.c69
-rw-r--r--sys/kern/sysv_msg.c1006
-rw-r--r--sys/kern/sysv_sem.c939
-rw-r--r--sys/kern/sysv_shm.c517
-rw-r--r--sys/sys/ipc.h10
-rw-r--r--sys/sys/msg.h161
-rw-r--r--sys/sys/sem.h179
-rw-r--r--sys/sys/shm.h90
-rw-r--r--sys/sys/syscall-hide.h10
-rw-r--r--sys/sys/syscall.h4
18 files changed, 3135 insertions, 10 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 216785e..bc9d1ae 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -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
diff --git a/sys/conf/param.c b/sys/conf/param.c
index 2fdecf0..f714cab 100644
--- a/sys/conf/param.c
+++ b/sys/conf/param.c
@@ -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.
@@ -106,6 +112,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
*/
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 2a870ed..146c0e3 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -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.
*/
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
index c50ea7c..a7f7988 100644
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -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
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 157c347..5b79149 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -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 */
diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c
index 2fdecf0..f714cab 100644
--- a/sys/kern/subr_param.c
+++ b/sys/kern/subr_param.c
@@ -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.
@@ -106,6 +112,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
*/
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
index 8ecac7c..9050b01 100644
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -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
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 8c67063..c00bcd1 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -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
diff --git a/sys/kern/sysv_ipc.c b/sys/kern/sysv_ipc.c
new file mode 100644
index 0000000..f0e907b
--- /dev/null
+++ b/sys/kern/sysv_ipc.c
@@ -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);
+}
diff --git a/sys/kern/sysv_msg.c b/sys/kern/sysv_msg.c
new file mode 100644
index 0000000..0d68840
--- /dev/null
+++ b/sys/kern/sysv_msg.c
@@ -0,0 +1,1006 @@
+/* $Id$ */
+
+/*
+ * Implementation of SVID messages
+ *
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/msg.h>
+#include <sys/malloc.h>
+
+#define MSG_DEBUG
+#undef MSG_DEBUG_OK
+
+static int msgctl(), msgget(), msgsnd(), msgrcv();
+
+int (*msgcalls[])() = { msgctl, msgget, msgsnd, msgrcv };
+
+int nfree_msgmaps; /* # of free map entries */
+short free_msgmaps; /* head of linked list of free map entries */
+struct msg *free_msghdrs; /* list of free msg headers */
+
+int
+msginit()
+{
+ register int i;
+ vm_offset_t whocares1, whocares2;
+
+ /*
+ * msginfo.msgssz should be a power of two for efficiency reasons.
+ * It is also pretty silly if msginfo.msgssz is less than 8
+ * or greater than about 256 so ...
+ */
+
+ i = 8;
+ while (i < 1024 && i != msginfo.msgssz)
+ i <<= 1;
+ if (i != msginfo.msgssz) {
+ printf("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
+ msginfo.msgssz);
+ panic("msginfo.msgssz not a small power of 2");
+ }
+
+ if (msginfo.msgseg > 32767) {
+ printf("msginfo.msgseg=%d\n", msginfo.msgseg);
+ panic("msginfo.msgseg > 32767");
+ }
+
+ if (msgmaps == NULL)
+ panic("msgmaps is NULL");
+
+ for (i = 0; i < msginfo.msgseg; i++) {
+ if (i > 0)
+ msgmaps[i-1].next = i;
+ msgmaps[i].next = -1; /* implies entry is available */
+ }
+ free_msgmaps = 0;
+ nfree_msgmaps = msginfo.msgseg;
+
+ if (msghdrs == NULL)
+ panic("msghdrs is NULL");
+
+ for (i = 0; i < msginfo.msgtql; i++) {
+ msghdrs[i].msg_type = 0;
+ if (i > 0)
+ msghdrs[i-1].msg_next = &msghdrs[i];
+ msghdrs[i].msg_next = NULL;
+ }
+ free_msghdrs = &msghdrs[0];
+
+ if (msqids == NULL)
+ panic("msqids is NULL");
+
+ for (i = 0; i < msginfo.msgmni; i++) {
+ msqids[i].msg_qbytes = 0; /* implies entry is available */
+ msqids[i].msg_perm.seq = 0; /* reset to a known value */
+ }
+}
+
+/*
+ * Entry point for all MSG calls
+ */
+
+struct msgsys_args {
+ u_int which;
+};
+
+int
+msgsys(p, uap, retval)
+ struct caller *p;
+ struct msgsys_args *uap;
+ int *retval;
+{
+
+ if (uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0]))
+ return (EINVAL);
+ return ((*msgcalls[uap->which])(p, &uap[1], retval));
+}
+
+static void
+msg_freehdr(msghdr)
+ struct msg *msghdr;
+{
+ while (msghdr->msg_ts > 0) {
+ short next;
+ if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
+ panic("msghdr->msg_spot out of range");
+ next = msgmaps[msghdr->msg_spot].next;
+ msgmaps[msghdr->msg_spot].next = free_msgmaps;
+ free_msgmaps = msghdr->msg_spot;
+ nfree_msgmaps++;
+ msghdr->msg_spot = next;
+ if (msghdr->msg_ts >= msginfo.msgssz)
+ msghdr->msg_ts -= msginfo.msgssz;
+ else
+ msghdr->msg_ts = 0;
+ }
+ if (msghdr->msg_spot != -1)
+ panic("msghdr->msg_spot != -1");
+ msghdr->msg_next = free_msghdrs;
+ free_msghdrs = msghdr;
+}
+
+struct msgctl_args {
+ int msqid;
+ int cmd;
+ struct msqid_ds *user_msqptr;
+};
+
+int
+msgctl(p, uap, retval)
+ struct proc *p;
+ register struct msgctl_args *uap;
+ int *retval;
+{
+ int msqid = uap->msqid;
+ int cmd = uap->cmd;
+ struct msqid_ds *user_msqptr = uap->user_msqptr;
+ struct ucred *cred = p->p_ucred;
+ int i, rval, eval;
+ struct msqid_ds msqbuf;
+ register struct msqid_ds *msqptr;
+
+#ifdef MSG_DEBUG_OK
+ printf("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, user_msqptr);
+#endif
+
+ msqid = IPCID_TO_IX(msqid);
+
+ if (msqid < 0 || msqid >= msginfo.msgmni) {
+#ifdef MSG_DEBUG_OK
+ printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
+ msginfo.msgmni);
+#endif
+ return(EINVAL);
+ }
+
+ msqptr = &msqids[msqid];
+
+ if (msqptr->msg_qbytes == 0) {
+#ifdef MSG_DEBUG_OK
+ printf("no such msqid\n");
+#endif
+ return(EINVAL);
+ }
+ if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
+#ifdef MSG_DEBUG_OK
+ printf("wrong sequence number\n");
+#endif
+ return(EINVAL);
+ }
+
+ eval = 0;
+ rval = 0;
+
+ switch (cmd) {
+
+ case IPC_RMID:
+ {
+ struct msg *msghdr;
+ if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_M)))
+ return(eval);
+ /* Free the message headers */
+ msghdr = msqptr->msg_first;
+ while (msghdr != NULL) {
+ struct msg *msghdr_tmp;
+
+ /* Free the segments of each message */
+ msqptr->msg_cbytes -= msghdr->msg_ts;
+ msqptr->msg_qnum--;
+ msghdr_tmp = msghdr;
+ msghdr = msghdr->msg_next;
+ msg_freehdr(msghdr_tmp);
+ }
+
+ if (msqptr->msg_cbytes != 0)
+ panic("msg_cbytes is screwed up");
+ if (msqptr->msg_qnum != 0)
+ panic("msg_qnum is screwed up");
+
+ msqptr->msg_qbytes = 0; /* Mark it as free */
+
+ wakeup((caddr_t)msqptr);
+ }
+
+ break;
+
+ case IPC_SET:
+ if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_M)))
+ return(eval);
+ if ((eval = copyin(user_msqptr, &msqbuf, sizeof(msqbuf))) != 0)
+ return(eval);
+ if (msqbuf.msg_qbytes > msqptr->msg_qbytes && cred->cr_uid != 0)
+ return(EPERM);
+ if (msqbuf.msg_qbytes > msginfo.msgmnb) {
+#ifdef MSG_DEBUG_OK
+ printf("can't increase msg_qbytes beyond %d (truncating)\n",
+ msginfo.msgmnb);
+#endif
+ msqbuf.msg_qbytes = msginfo.msgmnb; /* silently restrict qbytes to system limit */
+ }
+ if (msqbuf.msg_qbytes == 0) {
+#ifdef MSG_DEBUG_OK
+ printf("can't reduce msg_qbytes to 0\n");
+#endif
+ return(EINVAL); /* non-standard errno! */
+ }
+ msqptr->msg_perm.uid = msqbuf.msg_perm.uid; /* change the owner */
+ msqptr->msg_perm.gid = msqbuf.msg_perm.gid; /* change the owner */
+ msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
+ (msqbuf.msg_perm.mode & 0777);
+ msqptr->msg_qbytes = msqbuf.msg_qbytes;
+ msqptr->msg_ctime = time.tv_sec;
+ break;
+
+ case IPC_STAT:
+ if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
+#ifdef MSG_DEBUG_OK
+ printf("requester doesn't have read access\n");
+#endif
+ return(eval);
+ }
+ eval = copyout((caddr_t)msqptr, user_msqptr,
+ sizeof(struct msqid_ds));
+ break;
+
+ default:
+#ifdef MSG_DEBUG_OK
+ printf("invalid command %d\n", cmd);
+#endif
+ return(EINVAL);
+ }
+
+ if (eval == 0)
+ *retval = rval;
+ return(eval);
+}
+
+struct msgget_args {
+ key_t key;
+ int msgflg;
+};
+
+int
+msgget(p, uap, retval)
+ struct proc *p;
+ register struct msgget_args *uap;
+ int *retval;
+{
+ int msqid, eval;
+ int key = uap->key;
+ int msgflg = uap->msgflg;
+ struct ucred *cred = p->p_ucred;
+ register struct msqid_ds *msqptr;
+
+#ifdef MSG_DEBUG_OK
+ printf("msgget(0x%x, 0%o)\n", key, msgflg);
+#endif
+
+ if (key != IPC_PRIVATE) {
+ for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
+ msqptr = &msqids[msqid];
+ if (msqptr->msg_qbytes != 0 &&
+ msqptr->msg_perm.key == key)
+ break;
+ }
+ if (msqid < msginfo.msgmni) {
+#ifdef MSG_DEBUG_OK
+ printf("found public key\n");
+#endif
+ if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
+#ifdef MSG_DEBUG_OK
+ printf("not exclusive\n");
+#endif
+ return(EEXIST);
+ }
+ if ((eval = ipcperm(cred, &msqptr->msg_perm, msgflg & 0700 ))) {
+#ifdef MSG_DEBUG_OK
+ printf("requester doesn't have 0%o access\n",
+ msgflg & 0700);
+#endif
+ return(eval);
+ }
+ goto found;
+ }
+ }
+
+#ifdef MSG_DEBUG_OK
+ printf("need to allocate the msqid_ds\n");
+#endif
+ if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
+ for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
+ /*
+ * Look for an unallocated and unlocked msqid_ds.
+ * msqid_ds's can be locked by msgsnd or msgrcv while
+ * they are copying the message in/out. We can't
+ * re-use the entry until they release it.
+ */
+ msqptr = &msqids[msqid];
+ if (msqptr->msg_qbytes == 0 &&
+ (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
+ break;
+ }
+ if (msqid == msginfo.msgmni) {
+#ifdef MSG_DEBUG_OK
+ printf("no more msqid_ds's available\n");
+#endif
+ return(ENOSPC);
+ }
+#ifdef MSG_DEBUG_OK
+ printf("msqid %d is available\n", msqid);
+#endif
+ msqptr->msg_perm.key = key;
+ msqptr->msg_perm.cuid = cred->cr_uid;
+ msqptr->msg_perm.uid = cred->cr_uid;
+ msqptr->msg_perm.cgid = cred->cr_gid;
+ msqptr->msg_perm.gid = cred->cr_gid;
+ msqptr->msg_perm.mode = (msgflg & 0777);
+ /* Make sure that the returned msqid is unique */
+ msqptr->msg_perm.seq++;
+ msqptr->msg_first = NULL;
+ msqptr->msg_last = NULL;
+ msqptr->msg_cbytes = 0;
+ msqptr->msg_qnum = 0;
+ msqptr->msg_qbytes = msginfo.msgmnb;
+ msqptr->msg_lspid = 0;
+ msqptr->msg_lrpid = 0;
+ msqptr->msg_stime = 0;
+ msqptr->msg_rtime = 0;
+ msqptr->msg_ctime = time.tv_sec;
+ } else {
+#ifdef MSG_DEBUG_OK
+ printf("didn't find it and wasn't asked to create it\n");
+#endif
+ return(ENOENT);
+ }
+
+found:
+ /* Construct the unique msqid */
+ *retval = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
+ return(0);
+}
+
+struct msgsnd_args {
+ int msqid;
+ void *user_msgp;
+ size_t msgsz;
+ int msgflg;
+};
+
+int
+msgsnd(p, uap, retval)
+ struct proc *p;
+ register struct msgsnd_args *uap;
+ int *retval;
+{
+ int msqid = uap->msqid;
+ void *user_msgp = uap->user_msgp;
+ size_t msgsz = uap->msgsz;
+ int msgflg = uap->msgflg;
+ int segs_needed, eval;
+ struct ucred *cred = p->p_ucred;
+ register struct msqid_ds *msqptr;
+ register struct msg *msghdr;
+ short next;
+
+#ifdef MSG_DEBUG_OK
+ printf("call to msgsnd(%d, 0x%x, %d, %d)\n", msqid, user_msgp, msgsz,
+ msgflg);
+#endif
+
+ msqid = IPCID_TO_IX(msqid);
+
+ if (msqid < 0 || msqid >= msginfo.msgmni) {
+#ifdef MSG_DEBUG_OK
+ printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
+ msginfo.msgmni);
+#endif
+ return(EINVAL);
+ }
+
+ msqptr = &msqids[msqid];
+ if (msqptr->msg_qbytes == 0) {
+#ifdef MSG_DEBUG_OK
+ printf("no such message queue id\n");
+#endif
+ return(EINVAL);
+ }
+ if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
+#ifdef MSG_DEBUG_OK
+ printf("wrong sequence number\n");
+#endif
+ return(EINVAL);
+ }
+
+ if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_W))) {
+#ifdef MSG_DEBUG_OK
+ printf("requester doesn't have write access\n");
+#endif
+ return(eval);
+ }
+
+ segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
+#ifdef MSG_DEBUG_OK
+ printf("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz,
+ segs_needed);
+#endif
+ for (;;) {
+ int need_more_resources = 0;
+
+ /*
+ * check msgsz
+ * (inside this loop in case msg_qbytes changes while we sleep)
+ */
+
+ if (msgsz < 0 || msgsz > msqptr->msg_qbytes) {
+#ifdef MSG_DEBUG_OK
+ printf("msgsz > msqptr->msg_qbytes\n");
+#endif
+ return(EINVAL);
+ }
+
+ if (msqptr->msg_perm.mode & MSG_LOCKED) {
+#ifdef MSG_DEBUG_OK
+ printf("msqid is locked\n");
+#endif
+ need_more_resources = 1;
+ }
+ if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) {
+#ifdef MSG_DEBUG_OK
+ printf("msgsz + msg_cbytes > msg_qbytes\n");
+#endif
+ need_more_resources = 1;
+ }
+ if (segs_needed > nfree_msgmaps) {
+#ifdef MSG_DEBUG_OK
+ printf("segs_needed > nfree_msgmaps\n");
+#endif
+ need_more_resources = 1;
+ }
+ if (free_msghdrs == NULL) {
+#ifdef MSG_DEBUG_OK
+ printf("no more msghdrs\n");
+#endif
+ need_more_resources = 1;
+ }
+
+ if (need_more_resources) {
+ int we_own_it;
+
+ if ((msgflg & IPC_NOWAIT) != 0) {
+#ifdef MSG_DEBUG_OK
+ printf("need more resources but caller doesn't want to wait\n");
+#endif
+ return(EAGAIN);
+ }
+
+ if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
+#ifdef MSG_DEBUG_OK
+ printf("we don't own the msqid_ds\n");
+#endif
+ we_own_it = 0;
+ } else {
+ /* Force later arrivals to wait for our
+ request */
+#ifdef MSG_DEBUG_OK
+ printf("we own the msqid_ds\n");
+#endif
+ msqptr->msg_perm.mode |= MSG_LOCKED;
+ we_own_it = 1;
+ }
+#ifdef MSG_DEBUG_OK
+ printf("goodnight\n");
+#endif
+ eval = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH,
+ "msgwait", 0);
+#ifdef MSG_DEBUG_OK
+ printf("good morning, eval=%d\n", eval);
+#endif
+ if (we_own_it)
+ msqptr->msg_perm.mode &= ~MSG_LOCKED;
+ if (eval != 0) {
+#ifdef MSG_DEBUG_OK
+ printf("msgsnd: interrupted system call\n");
+#endif
+ return(EINTR);
+ }
+
+ /*
+ * Make sure that the msq queue still exists
+ */
+
+ if (msqptr->msg_qbytes == 0) {
+#ifdef MSG_DEBUG_OK
+ printf("msqid deleted\n");
+#endif
+ /* The SVID says to return EIDRM. */
+#ifdef EIDRM
+ return(EIDRM);
+#else
+ /* Unfortunately, BSD doesn't define that code
+ yet! */
+ return(EINVAL);
+#endif
+ }
+
+ } else {
+#ifdef MSG_DEBUG_OK
+ printf("got all the resources that we need\n");
+#endif
+ break;
+ }
+ }
+
+ /*
+ * We have the resources that we need.
+ * Make sure!
+ */
+
+ if (msqptr->msg_perm.mode & MSG_LOCKED)
+ panic("msg_perm.mode & MSG_LOCKED");
+ if (segs_needed > nfree_msgmaps)
+ panic("segs_needed > nfree_msgmaps");
+ if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes)
+ panic("msgsz + msg_cbytes > msg_qbytes");
+ if (free_msghdrs == NULL)
+ panic("no more msghdrs");
+
+ /*
+ * Re-lock the msqid_ds in case we page-fault when copying in the
+ * message
+ */
+
+ if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0)
+ panic("msqid_ds is already locked");
+ msqptr->msg_perm.mode |= MSG_LOCKED;
+
+ /*
+ * Allocate a message header
+ */
+
+ msghdr = free_msghdrs;
+ free_msghdrs = msghdr->msg_next;
+ msghdr->msg_spot = -1;
+ msghdr->msg_ts = msgsz;
+
+ /*
+ * Allocate space for the message
+ */
+
+ while (segs_needed > 0) {
+ if (nfree_msgmaps <= 0)
+ panic("not enough msgmaps");
+ if (free_msgmaps == -1)
+ panic("nil free_msgmaps");
+ next = free_msgmaps;
+ if (next <= -1)
+ panic("next too low #1");
+ if (next >= msginfo.msgseg)
+ panic("next out of range #1");
+#ifdef MSG_DEBUG_OK
+ printf("allocating segment %d to message\n", next);
+#endif
+ free_msgmaps = msgmaps[next].next;
+ nfree_msgmaps--;
+ msgmaps[next].next = msghdr->msg_spot;
+ msghdr->msg_spot = next;
+ segs_needed--;
+ }
+
+ /*
+ * Copy in the message type
+ */
+
+ if ((eval = copyin(user_msgp, &msghdr->msg_type,
+ sizeof(msghdr->msg_type))) != 0) {
+#ifdef MSG_DEBUG_OK
+ printf("error %d copying the message type\n", eval);
+#endif
+ msg_freehdr(msghdr);
+ msqptr->msg_perm.mode &= ~MSG_LOCKED;
+ wakeup((caddr_t)msqptr);
+ return(eval);
+ }
+ user_msgp += sizeof(msghdr->msg_type);
+
+ /*
+ * Validate the message type
+ */
+
+ if (msghdr->msg_type < 1) {
+ msg_freehdr(msghdr);
+ msqptr->msg_perm.mode &= ~MSG_LOCKED;
+ wakeup((caddr_t)msqptr);
+#ifdef MSG_DEBUG_OK
+ printf("mtype (%d) < 1\n", msghdr->msg_type);
+#endif
+ return(EINVAL);
+ }
+
+ /*
+ * Copy in the message body
+ */
+
+ next = msghdr->msg_spot;
+ while (msgsz > 0) {
+ size_t tlen;
+ if (msgsz > msginfo.msgssz)
+ tlen = msginfo.msgssz;
+ else
+ tlen = msgsz;
+ if (next <= -1)
+ panic("next too low #2");
+ if (next >= msginfo.msgseg)
+ panic("next out of range #2");
+ if ((eval = copyin(user_msgp, &msgpool[next * msginfo.msgssz],
+ tlen)) != 0) {
+#ifdef MSG_DEBUG_OK
+ printf("error %d copying in message segment\n", eval);
+#endif
+ msg_freehdr(msghdr);
+ msqptr->msg_perm.mode &= ~MSG_LOCKED;
+ wakeup((caddr_t)msqptr);
+ return(eval);
+ }
+ msgsz -= tlen;
+ user_msgp += tlen;
+ next = msgmaps[next].next;
+ }
+ if (next != -1)
+ panic("didn't use all the msg segments");
+
+ /*
+ * We've got the message. Unlock the msqid_ds.
+ */
+
+ msqptr->msg_perm.mode &= ~MSG_LOCKED;
+
+ /*
+ * Make sure that the msqid_ds is still allocated.
+ */
+
+ if (msqptr->msg_qbytes == 0) {
+ msg_freehdr(msghdr);
+ wakeup((caddr_t)msqptr);
+ /* The SVID says to return EIDRM. */
+#ifdef EIDRM
+ return(EIDRM);
+#else
+ /* Unfortunately, BSD doesn't define that code yet! */
+ return(EINVAL);
+#endif
+ }
+
+ /*
+ * Put the message into the queue
+ */
+
+ if (msqptr->msg_first == NULL) {
+ msqptr->msg_first = msghdr;
+ msqptr->msg_last = msghdr;
+ } else {
+ msqptr->msg_last->msg_next = msghdr;
+ msqptr->msg_last = msghdr;
+ }
+ msqptr->msg_last->msg_next = NULL;
+
+ msqptr->msg_cbytes += msghdr->msg_ts;
+ msqptr->msg_qnum++;
+ msqptr->msg_lspid = p->p_pid;
+ msqptr->msg_stime = time.tv_sec;
+
+ wakeup((caddr_t)msqptr);
+ *retval = 0;
+ return(0);
+}
+
+struct msgrcv_args {
+ int msqid;
+ void *msgp;
+ size_t msgsz;
+ long msgtyp;
+ int msgflg;
+};
+
+int
+msgrcv(p, uap, retval)
+ struct proc *p;
+ register struct msgrcv_args *uap;
+ int *retval;
+{
+ int msqid = uap->msqid;
+ void *user_msgp = uap->msgp;
+ size_t msgsz = uap->msgsz;
+ long msgtyp = uap->msgtyp;
+ int msgflg = uap->msgflg;
+ size_t len;
+ struct ucred *cred = p->p_ucred;
+ register struct msqid_ds *msqptr;
+ register struct msg *msghdr;
+ int eval;
+ short next;
+
+#ifdef MSG_DEBUG_OK
+ printf("call to msgrcv(%d, 0x%x, %d, %ld, %d)\n", msqid, user_msgp,
+ msgsz, msgtyp, msgflg);
+#endif
+
+ msqid = IPCID_TO_IX(msqid);
+
+ if (msqid < 0 || msqid >= msginfo.msgmni) {
+#ifdef MSG_DEBUG_OK
+ printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
+ msginfo.msgmni);
+#endif
+ return(EINVAL);
+ }
+
+ msqptr = &msqids[msqid];
+ if (msqptr->msg_qbytes == 0) {
+#ifdef MSG_DEBUG_OK
+ printf("no such message queue id\n");
+#endif
+ return(EINVAL);
+ }
+ if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
+#ifdef MSG_DEBUG_OK
+ printf("wrong sequence number\n");
+#endif
+ return(EINVAL);
+ }
+
+ if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
+#ifdef MSG_DEBUG_OK
+ printf("requester doesn't have read access\n");
+#endif
+ return(eval);
+ }
+
+ if (msgsz < 0) {
+#ifdef MSG_DEBUG_OK
+ printf("msgsz < 0\n");
+#endif
+ return(EINVAL);
+ }
+
+ msghdr = NULL;
+ while (msghdr == NULL) {
+ if (msgtyp == 0) {
+ msghdr = msqptr->msg_first;
+ if (msghdr != NULL) {
+ if (msgsz < msghdr->msg_ts &&
+ (msgflg & MSG_NOERROR) == 0) {
+#ifdef MSG_DEBUG_OK
+ printf("first message on the queue is too big (want %d, got %d)\n",
+ msgsz, msghdr->msg_ts);
+#endif
+ return(E2BIG);
+ }
+ if (msqptr->msg_first == msqptr->msg_last) {
+ msqptr->msg_first = NULL;
+ msqptr->msg_last = NULL;
+ } else {
+ msqptr->msg_first = msghdr->msg_next;
+ if (msqptr->msg_first == NULL)
+ panic("msg_first/last screwed up #1");
+ }
+ }
+ } else {
+ struct msg *previous;
+ struct msg **prev;
+
+ previous = NULL;
+ prev = &(msqptr->msg_first);
+ while ((msghdr = *prev) != NULL) {
+ /*
+ * Is this message's type an exact match or is
+ * this message's type less than or equal to
+ * the absolute value of a negative msgtyp?
+ * Note that the second half of this test can
+ * NEVER be true if msgtyp is positive since
+ * msg_type is always positive!
+ */
+
+ if (msgtyp == msghdr->msg_type ||
+ msghdr->msg_type <= -msgtyp) {
+#ifdef MSG_DEBUG_OK
+ printf("found message type %d, requested %d\n",
+ msghdr->msg_type, msgtyp);
+#endif
+ if (msgsz < msghdr->msg_ts &&
+ (msgflg & MSG_NOERROR) == 0) {
+#ifdef MSG_DEBUG_OK
+ printf("requested message on the queue is too big (want %d, got %d)\n",
+ msgsz, msghdr->msg_ts);
+#endif
+ return(E2BIG);
+ }
+ *prev = msghdr->msg_next;
+ if (msghdr == msqptr->msg_last) {
+ if (previous == NULL) {
+ if (prev !=
+ &msqptr->msg_first)
+ panic("msg_first/last screwed up #2");
+ msqptr->msg_first =
+ NULL;
+ msqptr->msg_last =
+ NULL;
+ } else {
+ if (prev ==
+ &msqptr->msg_first)
+ panic("msg_first/last screwed up #3");
+ msqptr->msg_last =
+ previous;
+ }
+ }
+ break;
+ }
+ previous = msghdr;
+ prev = &(msghdr->msg_next);
+ }
+ }
+
+ /*
+ * We've either extracted the msghdr for the appropriate
+ * message or there isn't one.
+ * If there is one then bail out of this loop.
+ */
+
+ if (msghdr != NULL)
+ break;
+
+ /*
+ * Hmph! No message found. Does the user want to wait?
+ */
+
+ if ((msgflg & IPC_NOWAIT) != 0) {
+#ifdef MSG_DEBUG_OK
+ printf("no appropriate message found (msgtyp=%d)\n",
+ msgtyp);
+#endif
+ /* The SVID says to return ENOMSG. */
+#ifdef ENOMSG
+ return(ENOMSG);
+#else
+ /* Unfortunately, BSD doesn't define that code yet! */
+ return(EAGAIN);
+#endif
+ }
+
+ /*
+ * Wait for something to happen
+ */
+
+#ifdef MSG_DEBUG_OK
+ printf("msgrcv: goodnight\n");
+#endif
+ eval = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH, "msgwait",
+ 0);
+#ifdef MSG_DEBUG_OK
+ printf("msgrcv: good morning (eval=%d)\n", eval);
+#endif
+
+ if (eval != 0) {
+#ifdef MSG_DEBUG_OK
+ printf("msgsnd: interrupted system call\n");
+#endif
+ return(EINTR);
+ }
+
+ /*
+ * Make sure that the msq queue still exists
+ */
+
+ if (msqptr->msg_qbytes == 0 ||
+ msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
+#ifdef MSG_DEBUG_OK
+ printf("msqid deleted\n");
+#endif
+ /* The SVID says to return EIDRM. */
+#ifdef EIDRM
+ return(EIDRM);
+#else
+ /* Unfortunately, BSD doesn't define that code yet! */
+ return(EINVAL);
+#endif
+ }
+ }
+
+ /*
+ * Return the message to the user.
+ *
+ * First, do the bookkeeping (before we risk being interrupted).
+ */
+
+ msqptr->msg_cbytes -= msghdr->msg_ts;
+ msqptr->msg_qnum--;
+ msqptr->msg_lrpid = p->p_pid;
+ msqptr->msg_rtime = time.tv_sec;
+
+ /*
+ * Make msgsz the actual amount that we'll be returning.
+ * Note that this effectively truncates the message if it is too long
+ * (since msgsz is never increased).
+ */
+
+#ifdef MSG_DEBUG_OK
+ printf("found a message, msgsz=%d, msg_ts=%d\n", msgsz,
+ msghdr->msg_ts);
+#endif
+ if (msgsz > msghdr->msg_ts)
+ msgsz = msghdr->msg_ts;
+
+ /*
+ * Return the type to the user.
+ */
+
+ eval = copyout((caddr_t)&(msghdr->msg_type), user_msgp,
+ sizeof(msghdr->msg_type));
+ if (eval != 0) {
+#ifdef MSG_DEBUG_OK
+ printf("error (%d) copying out message type\n", eval);
+#endif
+ msg_freehdr(msghdr);
+ wakeup((caddr_t)msqptr);
+ return(eval);
+ }
+ user_msgp += sizeof(msghdr->msg_type);
+
+ /*
+ * Return the segments to the user
+ */
+
+ next = msghdr->msg_spot;
+ for (len = 0; len < msgsz; len += msginfo.msgssz) {
+ size_t tlen;
+
+ if (msgsz > msginfo.msgssz)
+ tlen = msginfo.msgssz;
+ else
+ tlen = msgsz;
+ if (next <= -1)
+ panic("next too low #3");
+ if (next >= msginfo.msgseg)
+ panic("next out of range #3");
+ eval = copyout((caddr_t)&msgpool[next * msginfo.msgssz],
+ user_msgp, tlen);
+ if (eval != 0) {
+#ifdef MSG_DEBUG_OK
+ printf("error (%d) copying out message segment\n",
+ eval);
+#endif
+ msg_freehdr(msghdr);
+ wakeup((caddr_t)msqptr);
+ return(eval);
+ }
+ user_msgp += tlen;
+ next = msgmaps[next].next;
+ }
+
+ /*
+ * Done, return the actual number of bytes copied out.
+ */
+
+ msg_freehdr(msghdr);
+ wakeup((caddr_t)msqptr);
+ *retval = msgsz;
+ return(0);
+}
diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c
new file mode 100644
index 0000000..fb0ff5f
--- /dev/null
+++ b/sys/kern/sysv_sem.c
@@ -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);
+ }
+}
diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c
new file mode 100644
index 0000000..e7de878
--- /dev/null
+++ b/sys/kern/sysv_shm.c
@@ -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;
+}
diff --git a/sys/sys/ipc.h b/sys/sys/ipc.h
index 7cd33da..1af00e1 100644
--- a/sys/sys/ipc.h
+++ b/sys/sys/ipc.h
@@ -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_ */
diff --git a/sys/sys/msg.h b/sys/sys/msg.h
new file mode 100644
index 0000000..5332af1
--- /dev/null
+++ b/sys/sys/msg.h
@@ -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_ */
diff --git a/sys/sys/sem.h b/sys/sys/sem.h
new file mode 100644
index 0000000..6b982c4
--- /dev/null
+++ b/sys/sys/sem.h
@@ -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_ */
diff --git a/sys/sys/shm.h b/sys/sys/shm.h
new file mode 100644
index 0000000..28e638e
--- /dev/null
+++ b/sys/sys/shm.h
@@ -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_ */
diff --git a/sys/sys/syscall-hide.h b/sys/sys/syscall-hide.h
index fd91f49..92aea01 100644
--- a/sys/sys/syscall-hide.h
+++ b/sys/sys/syscall-hide.h
@@ -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
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
index ca8ed07..7b43d43 100644
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -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
OpenPOWER on IntegriCloud