Files
Arquivotheca.Solaris-2.5/uts/common/os/msg.c
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

833 lines
20 KiB
C
Executable File

/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#pragma ident "@(#)msg.c 1.32 95/08/08 SMI" /* from S5R4 1.15 */
/*
* Inter-Process Communication Message Facility.
*/
#include <sys/types.h>
#include <sys/t_lock.h>
#include <sys/param.h>
#include <sys/cred.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/time.h>
#include <sys/map.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/systm.h>
#include <sys/sysmacros.h>
#include <sys/cpuvar.h>
#include <sys/kmem.h>
#include <sys/ddi.h>
#include <sys/errno.h>
#include <sys/cmn_err.h>
#include <sys/debug.h>
/*
* ATTENTION: All ye who enter here
* As an optimization, all global data items are declared in space.c
* When this module get unloaded, the data stays around. The data
* is only allocated on first load.
*
* XXX Unloading disabled - there's more to leaving state
* lying around in the system than not freeing global data.
*/
/*
* The following variables msginfo_* are there so that the
* elements of the data structure msginfo can be tuned
* (if necessary) using the /etc/system file syntax for
* tuning of integer data types.
*/
int msginfo_msgmap = 100; /* # of entries in msg map */
int msginfo_msgmax = 2048; /* max message size */
int msginfo_msgmnb = 4096; /* max # bytes on queue */
int msginfo_msgmni = 50; /* # of message queue identifiers */
int msginfo_msgssz = 8; /* msg segment size (s/b word size multiple) */
int msginfo_msgtql = 40; /* # of system message headers */
ushort msginfo_msgseg = 1024; /* # of msg segments (MUST BE < 32768) */
static kmutex_t msg_lock; /* protects msg mechanism data structures */
static kcondvar_t msgfp_cv;
/* define macro to round up to nearest int boundary "from machdep.c" */
#define INTRND(X) roundup((X), sizeof (int))
#include <sys/modctl.h>
#include <sys/syscall.h>
struct msgsysa;
static int msgsys(struct msgsysa *uap, rval_t *rvp);
static struct sysent ipcmsg_sysent = {
6,
SE_NOUNLOAD,
msgsys
};
/*
* Module linkage information for the kernel.
*/
static struct modlsys modlsys = {
&mod_syscallops, "System V message facility", &ipcmsg_sysent
};
static struct modlinkage modlinkage = {
MODREV_1, (void *)&modlsys, NULL
};
char _depends_on[] = "misc/ipc"; /* ipcaccess, ipcget */
int
_init(void)
{
int retval;
register int i; /* loop control */
register struct msg *mp; /* ptr to msg being linked */
u_longlong_t mavail;
/*
* msginfo_* are inited in param.c to default values
* These values can be tuned if need be using the
* integer tuning capabilities in the /etc/system file.
*/
msginfo.msgmap = msginfo_msgmap;
msginfo.msgmax = msginfo_msgmax;
msginfo.msgmnb = msginfo_msgmnb;
msginfo.msgmni = msginfo_msgmni;
msginfo.msgssz = msginfo_msgssz;
msginfo.msgtql = msginfo_msgtql;
msginfo.msgseg = msginfo_msgseg;
/*
* Don't use more than 25% of the available kernel memory
*/
mavail = kmem_maxavail() / 4;
if ((INTRND((u_longlong_t)msginfo.msgseg * (u_longlong_t)msginfo.msgssz)
* sizeof (char) +
(u_longlong_t)msginfo.msgmap * sizeof (struct map) +
(u_longlong_t)msginfo.msgmni * sizeof (struct msqid_ds) +
INTRND((u_longlong_t)msginfo.msgmni * sizeof (struct msglock)) +
(u_longlong_t)msginfo.msgtql * sizeof (struct msg)) > mavail) {
cmn_err(CE_WARN,
"msgsys: can't load module, too much memory requested");
return (ENOMEM);
}
mutex_init(&msg_lock, "Sys V msg queue", MUTEX_DEFAULT, NULL);
cv_init(&msgfp_cv, "msgfp cv", CV_DEFAULT, NULL);
ASSERT(msg == NULL);
ASSERT(msgmap == NULL);
ASSERT(msgh == NULL);
ASSERT(msgque == NULL);
ASSERT(msglock == NULL);
msg = kmem_zalloc(INTRND(msginfo.msgseg * msginfo.msgssz)
* sizeof (char), KM_SLEEP);
msgmap = kmem_zalloc(msginfo.msgmap * sizeof (struct map), KM_SLEEP);
msgh = kmem_zalloc(msginfo.msgtql * sizeof (struct msg), KM_SLEEP);
msgque = kmem_zalloc(msginfo.msgmni * sizeof (struct msqid_ds),
KM_SLEEP);
msglock = kmem_zalloc(INTRND(msginfo.msgmni * sizeof (struct msglock)),
KM_SLEEP);
mapinit(msgmap, (long)msginfo.msgseg, (ulong)1, "msgmap",
msginfo.msgmap);
for (i = 0, mp = msgfp = msgh; ++i < msginfo.msgtql; mp++)
mp->msg_next = mp + 1;
if ((retval = mod_install(&modlinkage)) == 0)
return (0);
kmem_free(msg, INTRND(msginfo.msgseg * msginfo.msgssz) * sizeof (char));
kmem_free(msgmap, msginfo.msgmap * sizeof (struct map));
kmem_free(msgh, msginfo.msgtql * sizeof (struct msg));
kmem_free(msgque, msginfo.msgmni * sizeof (struct msqid_ds));
kmem_free(msglock, INTRND(msginfo.msgmni * sizeof (struct msglock)));
msg = NULL;
msgmap = NULL;
msgh = NULL;
msgque = NULL;
msglock = NULL;
cv_destroy(&msgfp_cv);
mutex_destroy(&msg_lock);
return (retval);
}
/*
* See comments in shm.c.
*/
int
_fini(void)
{
return (EBUSY);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
/* HACK :: msgbuf structure renamed to avoid kernel compilation conflicts */
#define msgbuf ipcmsgbuf
/* Convert bytes to msg segments. */
#define btoq(X) (((long)(X) + msginfo.msgssz - 1) / msginfo.msgssz)
/*
* Argument vectors for the various flavors of msgsys().
*/
#define MSGGET 0
#define MSGCTL 1
#define MSGRCV 2
#define MSGSND 3
struct msgsysa {
int opcode;
};
struct msgctla {
int opcode;
int msgid;
int cmd;
struct msqid_ds *buf;
};
struct msggeta {
int opcode;
key_t key;
int msgflg;
};
struct msgrcva {
int opcode;
int msqid;
struct msgbuf *msgp;
int msgsz;
long msgtyp;
int msgflg;
};
struct msgsnda {
int opcode;
int msqid;
struct msgbuf *msgp;
int msgsz;
int msgflg;
};
/*
* msgfree - Free up space and message header, relink pointers on q,
* and wakeup anyone waiting for resources.
*/
static void
msgfree(
register struct msqid_ds *qp, /* ptr to q of mesg being freed */
register struct msg *pmp, /* ptr to mp's predecessor */
register struct msg *mp) /* ptr to msg being freed */
{
ASSERT(MUTEX_HELD(&msg_lock));
/* Unlink message from the q. */
if (pmp == NULL)
qp->msg_first = mp->msg_next;
else
pmp->msg_next = mp->msg_next;
if (mp->msg_next == NULL)
qp->msg_last = pmp;
qp->msg_qnum--;
if (qp->msg_perm.mode & MSG_WWAIT) {
qp->msg_perm.mode &= ~MSG_WWAIT;
cv_broadcast(&qp->msg_cv);
}
/* Free up message text. */
if (mp->msg_ts) {
rmfree(msgmap, btoq(mp->msg_ts), (ulong)(mp->msg_spot + 1));
}
/* Free up header */
mp->msg_next = msgfp;
if (msgfp == NULL)
cv_broadcast(&msgfp_cv);
msgfp = mp;
}
/*
* msgconv - Convert a user supplied message queue id into a ptr to a
* msqid_ds structure.
*/
static int
msgconv(register int id, struct msqid_ds **qpp)
{
register struct msqid_ds *qp; /* ptr to associated q slot */
register struct msglock *lockp; /* ptr to lock. */
ASSERT(MUTEX_HELD(&msg_lock));
if (id < 0)
return (EINVAL);
qp = &msgque[id % msginfo.msgmni];
lockp = MSGLOCK(qp);
while (lockp->msglock_lock) {
if (!cv_wait_sig(&lockp->msglock_cv, &msg_lock))
return (EINTR);
}
lockp->msglock_lock = 1;
if ((qp->msg_perm.mode & IPC_ALLOC) == 0 ||
(id / msginfo.msgmni) != qp->msg_perm.seq) {
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
return (EINVAL);
}
*qpp = qp;
return (0);
}
/*
* msgctl - Msgctl system call.
*/
static int
msgctl(register struct msgctla *uap, rval_t *rvp)
{
struct o_msqid_ds ods; /* SVR3 queue work area */
struct msqid_ds ds; /* SVR4 queue work area */
struct msqid_ds *qp; /* ptr to associated q */
register struct msglock *lockp;
register int error;
register struct cred *cr;
ASSERT(MUTEX_HELD(&msg_lock));
if (error = msgconv(uap->msgid, &qp)) {
/* get msqid_ds for this msgid */
return (error);
}
lockp = MSGLOCK(qp);
cr = CRED();
rvp->r_val1 = 0;
switch (uap->cmd) {
case IPC_O_RMID:
case IPC_RMID:
/*
* IPC_RMID is for use with expanded msqid_ds struct -
* msqid_ds not currently used with this command
*/
if (cr->cr_uid != qp->msg_perm.uid &&
cr->cr_uid != qp->msg_perm.cuid &&
!suser(cr)) {
error = EPERM;
break;
}
while (qp->msg_first)
msgfree(qp, (struct msg *)NULL, qp->msg_first);
qp->msg_cbytes = 0;
if (uap->msgid + msginfo.msgmni < 0)
qp->msg_perm.seq = 0;
else
qp->msg_perm.seq++;
if (qp->msg_perm.mode & MSG_RWAIT)
cv_broadcast(&qp->msg_qnum_cv);
if (qp->msg_perm.mode & MSG_WWAIT)
cv_broadcast(&qp->msg_cv);
qp->msg_perm.mode = 0;
break;
case IPC_O_SET:
if (cr->cr_uid != qp->msg_perm.uid &&
cr->cr_uid != qp->msg_perm.cuid &&
!suser(cr)) {
error = EPERM;
break;
}
if (copyin((caddr_t)uap->buf, (caddr_t)&ods, sizeof (ods))) {
error = EFAULT;
break;
}
if (ods.msg_qbytes > qp->msg_qbytes && !suser(cr)) {
error = EPERM;
break;
}
if (ods.msg_perm.uid > MAXUID || ods.msg_perm.gid > MAXUID) {
error = EINVAL;
break;
}
qp->msg_perm.uid = ods.msg_perm.uid;
qp->msg_perm.gid = ods.msg_perm.gid;
qp->msg_perm.mode =
(qp->msg_perm.mode & ~0777) | (ods.msg_perm.mode & 0777);
qp->msg_qbytes = ods.msg_qbytes;
qp->msg_ctime = hrestime.tv_sec;
break;
case IPC_SET:
if (cr->cr_uid != qp->msg_perm.uid &&
cr->cr_uid != qp->msg_perm.cuid &&
!suser(cr)) {
error = EPERM;
break;
}
if (copyin((caddr_t)uap->buf, (caddr_t)&ds, sizeof (ds))) {
error = EFAULT;
break;
}
if (ds.msg_qbytes > qp->msg_qbytes && !suser(cr)) {
error = EPERM;
break;
}
if (ds.msg_perm.uid < (uid_t)0 || ds.msg_perm.uid > MAXUID ||
ds.msg_perm.gid < (gid_t)0 || ds.msg_perm.gid > MAXUID) {
error = EINVAL;
break;
}
qp->msg_perm.uid = ds.msg_perm.uid;
qp->msg_perm.gid = ds.msg_perm.gid;
qp->msg_perm.mode =
(qp->msg_perm.mode & ~0777) | (ds.msg_perm.mode & 0777);
qp->msg_qbytes = ds.msg_qbytes;
qp->msg_ctime = hrestime.tv_sec;
break;
case IPC_O_STAT:
if (error = ipcaccess(&qp->msg_perm, MSG_R, cr))
break;
/*
* copy expanded msqid_ds struct to SVR3 msqid_ds structure -
* support for non-eft applications.
* Check whether SVR4 values are too large to store into an SVR3
* msqid_ds structure.
*/
if ((unsigned)qp->msg_perm.uid > USHRT_MAX ||
(unsigned)qp->msg_perm.gid > USHRT_MAX ||
(unsigned)qp->msg_perm.cuid > USHRT_MAX ||
(unsigned)qp->msg_perm.cgid > USHRT_MAX ||
(unsigned)qp->msg_perm.seq > USHRT_MAX ||
(unsigned)qp->msg_cbytes > USHRT_MAX ||
(unsigned)qp->msg_qnum > USHRT_MAX ||
(unsigned)qp->msg_qbytes > USHRT_MAX ||
(unsigned)qp->msg_lspid > SHRT_MAX ||
(unsigned)qp->msg_lrpid > SHRT_MAX) {
error = EOVERFLOW;
break;
}
ods.msg_perm.uid = (o_uid_t)qp->msg_perm.uid;
ods.msg_perm.gid = (o_gid_t)qp->msg_perm.gid;
ods.msg_perm.cuid = (o_uid_t)qp->msg_perm.cuid;
ods.msg_perm.cgid = (o_gid_t)qp->msg_perm.cgid;
ods.msg_perm.mode = (o_mode_t)qp->msg_perm.mode;
ods.msg_perm.seq = (ushort)qp->msg_perm.seq;
ods.msg_perm.key = qp->msg_perm.key;
ods.msg_first = NULL; /* kernel addr */
ods.msg_last = NULL;
ods.msg_cbytes = (ushort)qp->msg_cbytes;
ods.msg_qnum = (ushort)qp->msg_qnum;
ods.msg_qbytes = (ushort)qp->msg_qbytes;
ods.msg_lspid = (o_pid_t)qp->msg_lspid;
ods.msg_lrpid = (o_pid_t)qp->msg_lrpid;
ods.msg_stime = qp->msg_stime;
ods.msg_rtime = qp->msg_rtime;
ods.msg_ctime = qp->msg_ctime;
if (copyout((caddr_t)&ods, (caddr_t)uap->buf, sizeof (ods))) {
error = EFAULT;
break;
}
break;
case IPC_STAT:
if (error = ipcaccess(&qp->msg_perm, MSG_R, cr))
break;
if (copyout((caddr_t)qp, (caddr_t)uap->buf, sizeof (*qp))) {
error = EFAULT;
break;
}
break;
default:
error = EINVAL;
break;
}
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
return (error);
}
/*
* msgget - Msgget system call.
*/
static int
msgget(register struct msggeta *uap, rval_t *rvp)
{
struct msqid_ds *qp; /* ptr to associated q */
int s; /* ipcget status return */
register int error;
ASSERT(MUTEX_HELD(&msg_lock));
if (error = ipcget(uap->key, uap->msgflg, (struct ipc_perm *)msgque,
msginfo.msgmni, sizeof (*qp), &s, (struct ipc_perm **)&qp))
return (error);
if (s) {
/* This is a new queue. Finish initialization. */
qp->msg_first = qp->msg_last = NULL;
qp->msg_qnum = 0;
qp->msg_qbytes = msginfo.msgmnb;
qp->msg_lspid = qp->msg_lrpid = 0;
qp->msg_stime = qp->msg_rtime = 0;
qp->msg_ctime = hrestime.tv_sec;
/* initialize reserve area */
{
int i;
for (i = 0; i < 4; i++)
qp->msg_perm.pad[i] = 0;
qp->msg_pad1 = 0;
qp->msg_pad2 = 0;
qp->msg_pad3 = 0;
for (i = 0; i < 3; i++)
qp->msg_pad4[i] = 0;
}
}
rvp->r_val1 = qp->msg_perm.seq * msginfo.msgmni + (qp - msgque);
return (0);
}
/*
* msgrcv - Msgrcv system call.
*/
static int
msgrcv(register struct msgrcva *uap, rval_t *rvp)
{
register struct msg *mp; /* ptr to msg on q */
register struct msg *pmp; /* ptr to mp's predecessor */
register struct msg *smp; /* ptr to best msg on q */
register struct msg *spmp; /* ptr to smp's predecessor */
struct msqid_ds *qp; /* ptr to associated q */
register struct msglock *lockp;
struct msqid_ds *qp1;
int sz; /* transfer byte count */
int error;
ASSERT(MUTEX_HELD(&msg_lock));
CPU_STAT_ADD(CPU, cpu_sysinfo.msg, 1); /* bump msg send/rcv count */
if (error = msgconv(uap->msqid, &qp))
return (error);
lockp = MSGLOCK(qp);
if (error = ipcaccess(&qp->msg_perm, MSG_R, CRED()))
goto msgrcv_out;
if (uap->msgsz < 0) {
error = EINVAL;
goto msgrcv_out;
}
smp = spmp = NULL;
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
findmsg:
if (msgconv(uap->msqid, &qp1) != 0)
return (EIDRM);
if (qp1 != qp) {
lockp = MSGLOCK(qp1);
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
return (EIDRM);
}
pmp = NULL;
mp = qp->msg_first;
if (uap->msgtyp == 0)
smp = mp;
else
for (; mp; pmp = mp, mp = mp->msg_next) {
if (uap->msgtyp > 0) {
if (uap->msgtyp != mp->msg_type)
continue;
smp = mp;
spmp = pmp;
break;
}
if (mp->msg_type <= -uap->msgtyp) {
if (smp && smp->msg_type <= mp->msg_type)
continue;
smp = mp;
spmp = pmp;
}
}
if (smp) {
if ((unsigned)uap->msgsz < smp->msg_ts)
if (!(uap->msgflg & MSG_NOERROR)) {
error = E2BIG;
goto msgrcv_out;
} else
sz = uap->msgsz;
else
sz = smp->msg_ts;
if (copyout((caddr_t)&smp->msg_type, (caddr_t)uap->msgp,
sizeof (smp->msg_type))) {
error = EFAULT;
goto msgrcv_out;
}
if (sz &&
copyout((caddr_t)(msg + msginfo.msgssz * smp->msg_spot),
(caddr_t)uap->msgp + sizeof (smp->msg_type), sz)) {
error = EFAULT;
goto msgrcv_out;
}
rvp->r_val1 = sz;
qp->msg_cbytes -= smp->msg_ts;
qp->msg_lrpid = ttoproc(curthread)->p_pid;
qp->msg_rtime = hrestime.tv_sec;
msgfree(qp, spmp, smp);
goto msgrcv_out;
}
if (uap->msgflg & IPC_NOWAIT) {
error = ENOMSG;
goto msgrcv_out;
}
qp->msg_perm.mode |= MSG_RWAIT;
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
if (!cv_wait_sig(&qp->msg_qnum_cv, &msg_lock))
return (EINTR);
goto findmsg;
msgrcv_out:
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
return (error);
}
/*
* msgsnd - Msgsnd system call.
*/
static int
msgsnd(register struct msgsnda *uap, rval_t *rvp)
{
struct msqid_ds *qp; /* ptr to associated q */
register struct msg *mp; /* ptr to allocated msg hdr */
register int cnt; /* byte count */
register ulong spot; /* msg pool allocation spot */
register struct msglock *lockp;
struct msqid_ds *qp1;
long type; /* msg type */
int error;
ASSERT(MUTEX_HELD(&msg_lock));
CPU_STAT_ADD(CPU, cpu_sysinfo.msg, 1); /* bump msg send/rcv count */
if (error = msgconv(uap->msqid, &qp))
return (error);
lockp = MSGLOCK(qp);
if (error = ipcaccess(&qp->msg_perm, MSG_W, CRED()))
goto msgsnd_out;
if ((cnt = uap->msgsz) < 0 || cnt > msginfo.msgmax) {
error = EINVAL;
goto msgsnd_out;
}
if (copyin((caddr_t)uap->msgp, (caddr_t)&type, sizeof (type))) {
error = EFAULT;
goto msgsnd_out;
}
if (type < 1) {
error = EINVAL;
goto msgsnd_out;
}
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
getres:
/* Be sure that q has not been removed. */
if (msgconv(uap->msqid, &qp1) != 0)
return (EIDRM);
if (qp1 != qp) {
lockp = MSGLOCK(qp1);
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
return (EIDRM);
}
/* Allocate space on q, message header, & buffer space. */
if (cnt + qp->msg_cbytes > (uint)qp->msg_qbytes) {
if (uap->msgflg & IPC_NOWAIT) {
error = EAGAIN;
goto msgsnd_out;
}
qp->msg_perm.mode |= MSG_WWAIT;
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
if (!cv_wait_sig(&qp->msg_cv, &msg_lock)) {
if (error = msgconv(uap->msqid, &qp1)) {
return (error);
}
error = EINTR;
if (qp1 != qp) {
lockp = MSGLOCK(qp1);
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
return (error);
}
qp->msg_perm.mode &= ~MSG_WWAIT;
cv_broadcast(&qp->msg_cv);
goto msgsnd_out;
}
goto getres;
}
if (msgfp == NULL) {
if (uap->msgflg & IPC_NOWAIT) {
error = EAGAIN;
goto msgsnd_out;
}
lockp->msglock_lock = 0;
if (!cv_wait_sig(&msgfp_cv, &msg_lock)) {
if (error = msgconv(uap->msqid, &qp1))
return (error);
error = EINTR;
if (qp1 != qp) {
lockp = MSGLOCK(qp1);
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
return (error);
}
goto msgsnd_out;
}
goto getres;
}
mp = msgfp;
msgfp = mp->msg_next;
mutex_enter(&maplock(msgmap));
if (cnt && (spot = rmalloc_locked(msgmap, btoq(cnt))) == NULL) {
if (uap->msgflg & IPC_NOWAIT) {
error = EAGAIN;
mutex_exit(&maplock(msgmap));
goto msgsnd_out1;
}
mapwant(msgmap)++;
mp->msg_next = msgfp;
if (msgfp == NULL)
cv_broadcast(&msgfp_cv);
msgfp = mp;
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
mutex_exit(&msg_lock);
if (!cv_wait_sig(&map_cv(msgmap), &maplock(msgmap))) {
mutex_exit(&maplock(msgmap));
mutex_enter(&msg_lock);
if (error = msgconv(uap->msqid, &qp1))
return (error);
error = EINTR;
if (qp1 != qp) {
lockp = MSGLOCK(qp1);
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
return (error);
}
goto msgsnd_out;
} else {
mutex_exit(&maplock(msgmap));
mutex_enter(&msg_lock);
}
goto getres;
} else
mutex_exit(&maplock(msgmap));
/* Everything is available, copy in text and put msg on q. */
if (cnt && copyin((caddr_t)uap->msgp + sizeof (type),
(caddr_t)(msg + msginfo.msgssz * --spot), cnt)) {
error = EFAULT;
rmfree(msgmap, btoq(cnt), spot + 1);
goto msgsnd_out1;
}
qp->msg_qnum++;
qp->msg_cbytes += cnt;
qp->msg_lspid = curproc->p_pid;
qp->msg_stime = hrestime.tv_sec;
mp->msg_next = NULL;
mp->msg_type = type;
mp->msg_ts = (ushort)cnt;
mp->msg_spot = (short)(cnt ? spot : -1);
if (qp->msg_last == NULL)
qp->msg_first = qp->msg_last = mp;
else {
qp->msg_last->msg_next = mp;
qp->msg_last = mp;
}
if (qp->msg_perm.mode & MSG_RWAIT) {
qp->msg_perm.mode &= ~MSG_RWAIT;
cv_broadcast(&qp->msg_qnum_cv);
}
rvp->r_val1 = 0;
goto msgsnd_out;
msgsnd_out1:
mp->msg_next = msgfp;
if (msgfp == NULL)
cv_broadcast(&msgfp_cv);
msgfp = mp;
msgsnd_out:
lockp->msglock_lock = 0;
cv_broadcast(&lockp->msglock_cv);
return (error);
}
/*
* msgsys - System entry point for msgctl, msgget, msgrcv, and msgsnd
* system calls.
*/
static int
msgsys(register struct msgsysa *uap, rval_t *rvp)
{
register int error;
mutex_enter(&msg_lock);
switch (uap->opcode) {
case MSGGET:
error = msgget((struct msggeta *)uap, rvp);
break;
case MSGCTL:
error = msgctl((struct msgctla *)uap, rvp);
break;
case MSGRCV:
error = msgrcv((struct msgrcva *)uap, rvp);
break;
case MSGSND:
error = msgsnd((struct msgsnda *)uap, rvp);
break;
default:
error = EINVAL;
break;
}
mutex_exit(&msg_lock);
return (error);
}