182657471SMarkus Pfeiffer /* $FreeBSD: src/sys/kern/sysv_msg.c,v 1.23.2.5 2002/12/31 08:54:53 maxim Exp $ */
282657471SMarkus Pfeiffer
382657471SMarkus Pfeiffer /*
482657471SMarkus Pfeiffer * Implementation of SVID messages
582657471SMarkus Pfeiffer *
682657471SMarkus Pfeiffer * Author: Daniel Boulet
782657471SMarkus Pfeiffer *
882657471SMarkus Pfeiffer * Copyright 1993 Daniel Boulet and RTMX Inc.
982657471SMarkus Pfeiffer * Copyright (c) 2013 Larisa Grigore <larisagrigore@gmail.com>
1082657471SMarkus Pfeiffer *
1182657471SMarkus Pfeiffer * This system call was implemented by Daniel Boulet under contract from RTMX.
1282657471SMarkus Pfeiffer *
1382657471SMarkus Pfeiffer * Redistribution and use in source forms, with and without modification,
1482657471SMarkus Pfeiffer * are permitted provided that this entire comment appears intact.
1582657471SMarkus Pfeiffer *
1682657471SMarkus Pfeiffer * Redistribution in binary form may occur without any restrictions.
1782657471SMarkus Pfeiffer * Obviously, it would be nice if you gave credit where credit is due
1882657471SMarkus Pfeiffer * but requiring it would be too onerous.
1982657471SMarkus Pfeiffer *
2082657471SMarkus Pfeiffer * This software is provided ``AS IS'' without any warranties of any kind.
2182657471SMarkus Pfeiffer */
2282657471SMarkus Pfeiffer
2382657471SMarkus Pfeiffer #include "namespace.h"
2482657471SMarkus Pfeiffer #include <stdio.h>
2582657471SMarkus Pfeiffer #include <stdlib.h>
2682657471SMarkus Pfeiffer #include <errno.h>
2782657471SMarkus Pfeiffer #include <err.h>
2882657471SMarkus Pfeiffer #include <pthread.h>
2982657471SMarkus Pfeiffer #include <string.h>
3082657471SMarkus Pfeiffer #include <stdarg.h>
3182657471SMarkus Pfeiffer #include <sys/param.h>
3282657471SMarkus Pfeiffer #include <sys/queue.h>
3382657471SMarkus Pfeiffer #include <sys/mman.h>
3482657471SMarkus Pfeiffer #include "un-namespace.h"
3582657471SMarkus Pfeiffer
3682657471SMarkus Pfeiffer #include "sysvipc_lock.h"
3782657471SMarkus Pfeiffer #include "sysvipc_ipc.h"
3882657471SMarkus Pfeiffer #include "sysvipc_hash.h"
3982657471SMarkus Pfeiffer #include "sysvipc_msg.h"
4082657471SMarkus Pfeiffer #include "sysvipc_shm.h"
4182657471SMarkus Pfeiffer
4282657471SMarkus Pfeiffer #define SYSV_MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x)
4382657471SMarkus Pfeiffer #define SYSV_MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x)
4482657471SMarkus Pfeiffer #define SYSV_MUTEX_DESTROY(x) if (__isthreaded) _pthread_mutex_destroy(x)
4582657471SMarkus Pfeiffer
4682657471SMarkus Pfeiffer extern struct hashtable *shmaddrs;
4782657471SMarkus Pfeiffer extern struct hashtable *shmres;
4882657471SMarkus Pfeiffer extern pthread_mutex_t lock_resources;
4982657471SMarkus Pfeiffer
5082657471SMarkus Pfeiffer struct msginfo msginfo = {
5182657471SMarkus Pfeiffer MSGMAX, /* max chars in a message */
5282657471SMarkus Pfeiffer MSGMNI, /* # of message queue identifiers */
5382657471SMarkus Pfeiffer MSGMNB, /* max chars in a queue */
5482657471SMarkus Pfeiffer MSGTQL, /* max messages in system */
5582657471SMarkus Pfeiffer MSGSSZ, /* size of a message segment (must be small power of 2 greater than 4) */
5682657471SMarkus Pfeiffer MSGSEG /* number of message segments */
5782657471SMarkus Pfeiffer };
5882657471SMarkus Pfeiffer
5982657471SMarkus Pfeiffer static int
put_shmdata(int id)60*ff86f401SSascha Wildner put_shmdata(int id)
61*ff86f401SSascha Wildner {
6282657471SMarkus Pfeiffer struct shm_data *data;
6382657471SMarkus Pfeiffer int ret = -1;
6482657471SMarkus Pfeiffer
6582657471SMarkus Pfeiffer SYSV_MUTEX_LOCK(&lock_resources);
6682657471SMarkus Pfeiffer data = _hash_lookup(shmres, id);
6782657471SMarkus Pfeiffer if (!data) {
6882657471SMarkus Pfeiffer sysv_print_err("something wrong put_shmdata\n");
6982657471SMarkus Pfeiffer goto done; /* It should not reach here. */
7082657471SMarkus Pfeiffer }
7182657471SMarkus Pfeiffer
7282657471SMarkus Pfeiffer data->used--;
7382657471SMarkus Pfeiffer if (data->used == 0 && data->removed) {
7482657471SMarkus Pfeiffer sysv_print("really remove the sem\n");
7582657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_resources);
7682657471SMarkus Pfeiffer /* OBS: Even if the shmctl fails (the thread doesn't
7782657471SMarkus Pfeiffer * have IPC_M permissions), all structures associated
7882657471SMarkus Pfeiffer * with it will be removed in the current process.*/
7982657471SMarkus Pfeiffer shmdt(data->internal);
8082657471SMarkus Pfeiffer if (data->removed == SEG_ALREADY_REMOVED)
8182657471SMarkus Pfeiffer return 1; /* The queue was removed
8282657471SMarkus Pfeiffer by another process so there is nothing else
8382657471SMarkus Pfeiffer we must do. */
8482657471SMarkus Pfeiffer /* Else inform the daemon that the segment is removed. */
8582657471SMarkus Pfeiffer return (sysvipc_shmctl(id, IPC_RMID, NULL));
8682657471SMarkus Pfeiffer }
8782657471SMarkus Pfeiffer
8882657471SMarkus Pfeiffer ret = 0;
8982657471SMarkus Pfeiffer done:
9082657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_resources);
9182657471SMarkus Pfeiffer return (ret);
9282657471SMarkus Pfeiffer }
9382657471SMarkus Pfeiffer
9482657471SMarkus Pfeiffer static struct msqid_pool*
get_msqpptr(int msqid,int to_remove,int shm_access)95*ff86f401SSascha Wildner get_msqpptr(int msqid, int to_remove, int shm_access)
96*ff86f401SSascha Wildner {
9782657471SMarkus Pfeiffer struct msqid_pool *msqpptr;
9882657471SMarkus Pfeiffer
9982657471SMarkus Pfeiffer struct shm_data *shmdata =
10082657471SMarkus Pfeiffer get_shmdata(msqid, to_remove, shm_access);
10182657471SMarkus Pfeiffer if (!shmdata) {
10282657471SMarkus Pfeiffer /* Error is set in get_shmdata. */
10382657471SMarkus Pfeiffer return NULL;
10482657471SMarkus Pfeiffer }
10582657471SMarkus Pfeiffer
10682657471SMarkus Pfeiffer msqpptr = (struct msqid_pool *)shmdata->internal;
10782657471SMarkus Pfeiffer if (!msqpptr) {
10882657471SMarkus Pfeiffer put_shmdata(msqid);
10982657471SMarkus Pfeiffer errno = EINVAL;
11082657471SMarkus Pfeiffer return NULL;
11182657471SMarkus Pfeiffer }
11282657471SMarkus Pfeiffer
11382657471SMarkus Pfeiffer return msqpptr;
11482657471SMarkus Pfeiffer }
11582657471SMarkus Pfeiffer
11682657471SMarkus Pfeiffer static int
msqp_exist(int msqid,struct msqid_pool * msqpptr)117*ff86f401SSascha Wildner msqp_exist(int msqid, struct msqid_pool *msqpptr)
118*ff86f401SSascha Wildner {
11982657471SMarkus Pfeiffer /* Was it removed? */
12082657471SMarkus Pfeiffer if (msqpptr->gen == -1 ||
12182657471SMarkus Pfeiffer msqpptr->ds.msg_perm.seq != IPCID_TO_SEQ(msqid))
12282657471SMarkus Pfeiffer return 0;
12382657471SMarkus Pfeiffer
12482657471SMarkus Pfeiffer return 1;
12582657471SMarkus Pfeiffer }
12682657471SMarkus Pfeiffer
12782657471SMarkus Pfeiffer static int
try_rwlock_rdlock(int msqid,struct msqid_pool * msqpptr)128*ff86f401SSascha Wildner try_rwlock_rdlock(int msqid, struct msqid_pool *msqpptr)
129*ff86f401SSascha Wildner {
13082657471SMarkus Pfeiffer sysv_print("try get rd lock\n");
13182657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
13282657471SMarkus Pfeiffer sysv_rwlock_rdlock(&msqpptr->rwlock);
13382657471SMarkus Pfeiffer #else
13482657471SMarkus Pfeiffer sysv_mutex_lock(&msqpptr->mutex);
13582657471SMarkus Pfeiffer #endif
13682657471SMarkus Pfeiffer sysv_print("get rd lock\n");
13782657471SMarkus Pfeiffer if (!msqp_exist(msqid, msqpptr)) {
13882657471SMarkus Pfeiffer errno = EINVAL;
13982657471SMarkus Pfeiffer sysv_print("error rd lock\n");
14082657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
14182657471SMarkus Pfeiffer sysv_rwlock_unlock(&msqpptr->rwlock);
14282657471SMarkus Pfeiffer #else
14382657471SMarkus Pfeiffer sysv_mutex_unlock(&msqpptr->mutex);
14482657471SMarkus Pfeiffer #endif
14582657471SMarkus Pfeiffer return -1;
14682657471SMarkus Pfeiffer }
14782657471SMarkus Pfeiffer sysv_print("end rd lock\n");
14882657471SMarkus Pfeiffer return 0;
14982657471SMarkus Pfeiffer }
15082657471SMarkus Pfeiffer
15182657471SMarkus Pfeiffer static int
try_rwlock_wrlock(int msqid,struct msqid_pool * msqpptr)152*ff86f401SSascha Wildner try_rwlock_wrlock(int msqid, struct msqid_pool *msqpptr)
153*ff86f401SSascha Wildner {
15482657471SMarkus Pfeiffer sysv_print("try get wr lock\n");
15582657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
15682657471SMarkus Pfeiffer sysv_rwlock_wrlock(&msqpptr->rwlock);
15782657471SMarkus Pfeiffer #else
15882657471SMarkus Pfeiffer sysv_mutex_lock(&msqpptr->mutex);
15982657471SMarkus Pfeiffer #endif
16082657471SMarkus Pfeiffer sysv_print("get wr lock\n");
16182657471SMarkus Pfeiffer if (!msqp_exist(msqid, msqpptr)) {
16282657471SMarkus Pfeiffer sysv_print("error rw lock\n");
16382657471SMarkus Pfeiffer errno = EINVAL;
16482657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
16582657471SMarkus Pfeiffer sysv_rwlock_unlock(&msqpptr->rwlock);
16682657471SMarkus Pfeiffer #else
16782657471SMarkus Pfeiffer sysv_mutex_unlock(&msqpptr->mutex);
16882657471SMarkus Pfeiffer #endif
16982657471SMarkus Pfeiffer return -1;
17082657471SMarkus Pfeiffer }
17182657471SMarkus Pfeiffer sysv_print("end rw lock\n");
17282657471SMarkus Pfeiffer return 0;
17382657471SMarkus Pfeiffer }
17482657471SMarkus Pfeiffer
17582657471SMarkus Pfeiffer static int
rwlock_unlock(int msqid,struct msqid_pool * msqpptr)176*ff86f401SSascha Wildner rwlock_unlock(int msqid, struct msqid_pool *msqpptr)
177*ff86f401SSascha Wildner {
17882657471SMarkus Pfeiffer if (!msqp_exist(msqid, msqpptr)) {
17982657471SMarkus Pfeiffer errno = EINVAL;
18082657471SMarkus Pfeiffer return -1;
18182657471SMarkus Pfeiffer }
18282657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
18382657471SMarkus Pfeiffer sysv_rwlock_unlock(&msqpptr->rwlock);
18482657471SMarkus Pfeiffer #else
18582657471SMarkus Pfeiffer sysv_mutex_unlock(&msqpptr->mutex);
18682657471SMarkus Pfeiffer #endif
18782657471SMarkus Pfeiffer sysv_print("unlock rw lock\n");
18882657471SMarkus Pfeiffer return 0;
18982657471SMarkus Pfeiffer }
19082657471SMarkus Pfeiffer
19182657471SMarkus Pfeiffer static void
msg_freehdr(struct msqid_pool * msqpptr,struct msg * msghdr)19282657471SMarkus Pfeiffer msg_freehdr(struct msqid_pool *msqpptr, struct msg *msghdr)
19382657471SMarkus Pfeiffer {
19482657471SMarkus Pfeiffer while (msghdr->msg_ts > 0) {
19582657471SMarkus Pfeiffer short next;
19682657471SMarkus Pfeiffer if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg) {
19782657471SMarkus Pfeiffer sysv_print_err("msghdr->msg_spot out of range");
19882657471SMarkus Pfeiffer exit(-1);
19982657471SMarkus Pfeiffer }
20082657471SMarkus Pfeiffer next = msqpptr->msgmaps[msghdr->msg_spot].next;
20182657471SMarkus Pfeiffer msqpptr->msgmaps[msghdr->msg_spot].next =
20282657471SMarkus Pfeiffer msqpptr->free_msgmaps;
20382657471SMarkus Pfeiffer msqpptr->free_msgmaps = msghdr->msg_spot;
20482657471SMarkus Pfeiffer msqpptr->nfree_msgmaps++;
20582657471SMarkus Pfeiffer msghdr->msg_spot = next;
20682657471SMarkus Pfeiffer if (msghdr->msg_ts >= msginfo.msgssz)
20782657471SMarkus Pfeiffer msghdr->msg_ts -= msginfo.msgssz;
20882657471SMarkus Pfeiffer else
20982657471SMarkus Pfeiffer msghdr->msg_ts = 0;
21082657471SMarkus Pfeiffer }
21182657471SMarkus Pfeiffer if (msghdr->msg_spot != -1) {
21282657471SMarkus Pfeiffer sysv_print_err("msghdr->msg_spot != -1");
21382657471SMarkus Pfeiffer exit(-1);
21482657471SMarkus Pfeiffer }
21582657471SMarkus Pfeiffer msghdr->msg_next = msqpptr->free_msghdrs;
21682657471SMarkus Pfeiffer msqpptr->free_msghdrs = (msghdr - &msqpptr->msghdrs[0]) /
21782657471SMarkus Pfeiffer sizeof(struct msg);
21882657471SMarkus Pfeiffer }
21982657471SMarkus Pfeiffer
22082657471SMarkus Pfeiffer int
sysvipc_msgget(key_t key,int msgflg)221*ff86f401SSascha Wildner sysvipc_msgget(key_t key, int msgflg)
222*ff86f401SSascha Wildner {
22382657471SMarkus Pfeiffer int msqid;
22482657471SMarkus Pfeiffer void *shmaddr;
22582657471SMarkus Pfeiffer size_t size = sizeof(struct msqid_pool);
22682657471SMarkus Pfeiffer
22782657471SMarkus Pfeiffer msqid = _shmget(key, size, msgflg, MSGGET);
22882657471SMarkus Pfeiffer if (msqid == -1)
22982657471SMarkus Pfeiffer goto done;
23082657471SMarkus Pfeiffer
23182657471SMarkus Pfeiffer /* If the msg is in process of being removed there are two cases:
23282657471SMarkus Pfeiffer * - the daemon knows that and it will handle this situation.
23382657471SMarkus Pfeiffer * - one of the threads from this address space remove it and the daemon
23482657471SMarkus Pfeiffer * wasn't announced yet; in this scenario, the msg is marked
23582657471SMarkus Pfeiffer * using "removed" field of shm_data and future calls will return
23682657471SMarkus Pfeiffer * EIDRM error.
23782657471SMarkus Pfeiffer */
23882657471SMarkus Pfeiffer
23982657471SMarkus Pfeiffer #if 0
24082657471SMarkus Pfeiffer /* Set access type. */
24182657471SMarkus Pfeiffer shm_access = semflg & (IPC_W | IPC_R);
24282657471SMarkus Pfeiffer if(set_shmdata_access(semid, shm_access) != 0) {
24382657471SMarkus Pfeiffer /* errno already set. */
24482657471SMarkus Pfeiffer goto done;
24582657471SMarkus Pfeiffer }
24682657471SMarkus Pfeiffer #endif
24782657471SMarkus Pfeiffer
24882657471SMarkus Pfeiffer shmaddr = sysvipc_shmat(msqid, NULL, 0);
24982657471SMarkus Pfeiffer if (!shmaddr) {
25082657471SMarkus Pfeiffer msqid = -1;
25182657471SMarkus Pfeiffer sysvipc_shmctl(msqid, IPC_RMID, NULL);
25282657471SMarkus Pfeiffer goto done;
25382657471SMarkus Pfeiffer }
25482657471SMarkus Pfeiffer sysv_print("shmaddr = %lx\n", (unsigned long)shmaddr);
25582657471SMarkus Pfeiffer
25682657471SMarkus Pfeiffer done:
25782657471SMarkus Pfeiffer return msqid;
25882657471SMarkus Pfeiffer }
25982657471SMarkus Pfeiffer
26082657471SMarkus Pfeiffer int
sysvipc_msgctl(int msqid,int cmd,struct msqid_ds * buf)261*ff86f401SSascha Wildner sysvipc_msgctl(int msqid, int cmd, struct msqid_ds *buf)
262*ff86f401SSascha Wildner {
26382657471SMarkus Pfeiffer int error;
26482657471SMarkus Pfeiffer struct msqid_pool *msqpptr = NULL;
26582657471SMarkus Pfeiffer struct shmid_ds shmds;
26682657471SMarkus Pfeiffer int shm_access = 0;
26782657471SMarkus Pfeiffer
26882657471SMarkus Pfeiffer error = 0;
26982657471SMarkus Pfeiffer
27082657471SMarkus Pfeiffer switch (cmd) {
27182657471SMarkus Pfeiffer case IPC_SET: /* Originally was IPC_M but this is checked
27282657471SMarkus Pfeiffer by daemon. */
27382657471SMarkus Pfeiffer shm_access = IPC_W;
27482657471SMarkus Pfeiffer break;
27582657471SMarkus Pfeiffer case IPC_STAT:
27682657471SMarkus Pfeiffer shm_access = IPC_R;
27782657471SMarkus Pfeiffer break;
27882657471SMarkus Pfeiffer default:
27982657471SMarkus Pfeiffer break;
28082657471SMarkus Pfeiffer }
28182657471SMarkus Pfeiffer
28282657471SMarkus Pfeiffer msqpptr = get_msqpptr(msqid, cmd==IPC_RMID, shm_access);
28382657471SMarkus Pfeiffer if (!msqpptr) {
28482657471SMarkus Pfeiffer errno = EINVAL;
28582657471SMarkus Pfeiffer return -1;
28682657471SMarkus Pfeiffer }
28782657471SMarkus Pfeiffer
28882657471SMarkus Pfeiffer switch (cmd) {
28982657471SMarkus Pfeiffer case IPC_RMID:
29082657471SMarkus Pfeiffer /* Mark that the segment is removed. This is done in
29182657471SMarkus Pfeiffer * get_msqpptr call in order to announce other processes.
29282657471SMarkus Pfeiffer * It will be actually removed after put_shmdata call and
29382657471SMarkus Pfeiffer * not other thread from this address space use shm_data
29482657471SMarkus Pfeiffer * structure.
29582657471SMarkus Pfeiffer */
29682657471SMarkus Pfeiffer break;
29782657471SMarkus Pfeiffer case IPC_SET:
29882657471SMarkus Pfeiffer error = try_rwlock_rdlock(msqid, msqpptr);
29982657471SMarkus Pfeiffer if (error)
30082657471SMarkus Pfeiffer break;
30182657471SMarkus Pfeiffer if (buf->msg_qbytes == 0) {
30282657471SMarkus Pfeiffer sysv_print_err("can't reduce msg_qbytes to 0\n");
30382657471SMarkus Pfeiffer errno = EINVAL; /* non-standard errno! */
30482657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr);
30582657471SMarkus Pfeiffer break;
30682657471SMarkus Pfeiffer }
30782657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr);
30882657471SMarkus Pfeiffer
30982657471SMarkus Pfeiffer memset(&shmds, 0, sizeof(shmds)/sizeof(unsigned char));
31082657471SMarkus Pfeiffer memcpy(&shmds.shm_perm, &buf->msg_perm,
31182657471SMarkus Pfeiffer sizeof(struct ipc_perm));
31282657471SMarkus Pfeiffer error = sysvipc_shmctl(msqid, cmd, &shmds);
31382657471SMarkus Pfeiffer if (error)
31482657471SMarkus Pfeiffer break;
31582657471SMarkus Pfeiffer
31682657471SMarkus Pfeiffer /* There is no need to check if we have right to modify the
31782657471SMarkus Pfeiffer * size because we have right to change other fileds. */
31882657471SMarkus Pfeiffer
31982657471SMarkus Pfeiffer if (round_page(buf->msg_qbytes) !=
32082657471SMarkus Pfeiffer round_page(msqpptr->ds.msg_qbytes)) {
32182657471SMarkus Pfeiffer sysv_print("change msg size\n");
32282657471SMarkus Pfeiffer /* TODO same as in semundo_adjust only
32382657471SMarkus Pfeiffer * that there is no way to inform other
32482657471SMarkus Pfeiffer * processes about the change. */
32582657471SMarkus Pfeiffer }
32682657471SMarkus Pfeiffer
32782657471SMarkus Pfeiffer error = try_rwlock_wrlock(msqid, msqpptr);
32882657471SMarkus Pfeiffer if (error)
32982657471SMarkus Pfeiffer break;
33082657471SMarkus Pfeiffer msqpptr->ds.msg_qbytes = buf->msg_qbytes;
33182657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr);
33282657471SMarkus Pfeiffer /* OBS: didn't update ctime and mode as in kernel implementation
33382657471SMarkus Pfeiffer * it is done. Those fields are already updated for shmid_ds
33482657471SMarkus Pfeiffer * struct when calling shmctl
33582657471SMarkus Pfeiffer */
33682657471SMarkus Pfeiffer break;
33782657471SMarkus Pfeiffer
33882657471SMarkus Pfeiffer case IPC_STAT:
33982657471SMarkus Pfeiffer error = sysvipc_shmctl(msqid, cmd, &shmds);
34082657471SMarkus Pfeiffer if (error)
34182657471SMarkus Pfeiffer break;
34282657471SMarkus Pfeiffer
34382657471SMarkus Pfeiffer memcpy(&buf->msg_perm, &shmds.shm_perm,
34482657471SMarkus Pfeiffer sizeof(struct ipc_perm));
34582657471SMarkus Pfeiffer buf->msg_ctime = shmds.shm_ctime;
34682657471SMarkus Pfeiffer
34782657471SMarkus Pfeiffer /* Read fields that are not kept in shmds. */
34882657471SMarkus Pfeiffer error = try_rwlock_rdlock(msqid, msqpptr);
34982657471SMarkus Pfeiffer if (error)
35082657471SMarkus Pfeiffer break;
35182657471SMarkus Pfeiffer buf->msg_first = (struct msg *)(u_long)
35282657471SMarkus Pfeiffer msqpptr->ds.first.msg_first_index;
35382657471SMarkus Pfeiffer buf->msg_last = (struct msg *)(u_long)
35482657471SMarkus Pfeiffer msqpptr->ds.last.msg_last_index;
35582657471SMarkus Pfeiffer buf->msg_cbytes = msqpptr->ds.msg_cbytes;
35682657471SMarkus Pfeiffer buf->msg_qnum = msqpptr->ds.msg_qnum;
35782657471SMarkus Pfeiffer buf->msg_qbytes = msqpptr->ds.msg_qbytes;
35882657471SMarkus Pfeiffer buf->msg_lspid = msqpptr->ds.msg_lspid;
35982657471SMarkus Pfeiffer buf->msg_lrpid = msqpptr->ds.msg_lrpid;
36082657471SMarkus Pfeiffer buf->msg_stime = msqpptr->ds.msg_stime;
36182657471SMarkus Pfeiffer buf->msg_rtime = msqpptr->ds.msg_rtime;
36282657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr);
36382657471SMarkus Pfeiffer break;
36482657471SMarkus Pfeiffer default:
36582657471SMarkus Pfeiffer sysv_print_err("invalid command %d\n", cmd);
36682657471SMarkus Pfeiffer errno = EINVAL;
36782657471SMarkus Pfeiffer break;
36882657471SMarkus Pfeiffer }
36982657471SMarkus Pfeiffer
37082657471SMarkus Pfeiffer put_shmdata(msqid);
37182657471SMarkus Pfeiffer
37282657471SMarkus Pfeiffer return(error);
37382657471SMarkus Pfeiffer }
37482657471SMarkus Pfeiffer
37582657471SMarkus Pfeiffer int
sysvipc_msgsnd(int msqid,const void * msgp,size_t msgsz,int msgflg)376d217426cSSascha Wildner sysvipc_msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
37782657471SMarkus Pfeiffer {
37882657471SMarkus Pfeiffer int segs_needed, error;
37982657471SMarkus Pfeiffer struct msg *msghdr;
38082657471SMarkus Pfeiffer struct msqid_pool *msqpptr, *auxmsqpptr;
38182657471SMarkus Pfeiffer struct msqid_ds_internal *msqptr;
38282657471SMarkus Pfeiffer short next;
38382657471SMarkus Pfeiffer int val_to_sleep;
38482657471SMarkus Pfeiffer char *auxmsgp = (char *)msgp;
38582657471SMarkus Pfeiffer int _index;
38682657471SMarkus Pfeiffer
38782657471SMarkus Pfeiffer sysv_print("call to msgsnd(%d, %ld, %d)\n", msqid, msgsz, msgflg);
38882657471SMarkus Pfeiffer
38982657471SMarkus Pfeiffer /*if (!jail_sysvipc_allowed && td->td_ucred->cr_prison != NULL)
39082657471SMarkus Pfeiffer return (ENOSYS);
39182657471SMarkus Pfeiffer */
39282657471SMarkus Pfeiffer if (!msgp) {
39382657471SMarkus Pfeiffer errno = EINVAL;
39482657471SMarkus Pfeiffer return -1;
39582657471SMarkus Pfeiffer }
39682657471SMarkus Pfeiffer
39782657471SMarkus Pfeiffer msqpptr = get_msqpptr(msqid, 0, IPC_W);
39882657471SMarkus Pfeiffer if (!msqpptr) {
39982657471SMarkus Pfeiffer errno = EINVAL;
40082657471SMarkus Pfeiffer return -1;
40182657471SMarkus Pfeiffer }
40282657471SMarkus Pfeiffer error = -1;
40382657471SMarkus Pfeiffer
40482657471SMarkus Pfeiffer if (try_rwlock_wrlock(msqid, msqpptr) == -1) {
40582657471SMarkus Pfeiffer errno = EIDRM;
40682657471SMarkus Pfeiffer goto done;
40782657471SMarkus Pfeiffer }
40882657471SMarkus Pfeiffer
40982657471SMarkus Pfeiffer msqptr = &msqpptr->ds;
41082657471SMarkus Pfeiffer
41182657471SMarkus Pfeiffer segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
41282657471SMarkus Pfeiffer sysv_print("msgsz=%ld, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz,
41382657471SMarkus Pfeiffer segs_needed);
41482657471SMarkus Pfeiffer for (;;) {
41582657471SMarkus Pfeiffer int need_more_resources = 0;
41682657471SMarkus Pfeiffer
41782657471SMarkus Pfeiffer if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) {
41882657471SMarkus Pfeiffer sysv_print("msgsz + msg_cbytes > msg_qbytes\n");
41982657471SMarkus Pfeiffer need_more_resources = 1;
42082657471SMarkus Pfeiffer }
42182657471SMarkus Pfeiffer
42282657471SMarkus Pfeiffer if (segs_needed > msqpptr->nfree_msgmaps) {
42382657471SMarkus Pfeiffer sysv_print("segs_needed > nfree_msgmaps (= %d)\n",
42482657471SMarkus Pfeiffer msqpptr->nfree_msgmaps);
42582657471SMarkus Pfeiffer need_more_resources = 1;
42682657471SMarkus Pfeiffer }
42782657471SMarkus Pfeiffer
42882657471SMarkus Pfeiffer if (msqpptr->free_msghdrs == -1) {
42982657471SMarkus Pfeiffer sysv_print("no more msghdrs\n");
43082657471SMarkus Pfeiffer need_more_resources = 1;
43182657471SMarkus Pfeiffer }
43282657471SMarkus Pfeiffer
43382657471SMarkus Pfeiffer if (need_more_resources) {
43482657471SMarkus Pfeiffer if ((msgflg & IPC_NOWAIT) != 0) {
43582657471SMarkus Pfeiffer sysv_print_err("need more resources but caller doesn't want to wait\n");
43682657471SMarkus Pfeiffer errno = EAGAIN;
43782657471SMarkus Pfeiffer goto done;
43882657471SMarkus Pfeiffer }
43982657471SMarkus Pfeiffer
44082657471SMarkus Pfeiffer sysv_print("goodnight\n");
44182657471SMarkus Pfeiffer val_to_sleep = msqpptr->gen;
44282657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr);
44382657471SMarkus Pfeiffer put_shmdata(msqid);
44482657471SMarkus Pfeiffer
44582657471SMarkus Pfeiffer if (umtx_sleep((int *)&msqpptr->gen, val_to_sleep, SYSV_TIMEOUT) != 0) {
44682657471SMarkus Pfeiffer sysv_print_err("msgsnd: interrupted system call\n");
44782657471SMarkus Pfeiffer errno = EINTR;
44882657471SMarkus Pfeiffer goto done;
44982657471SMarkus Pfeiffer }
45082657471SMarkus Pfeiffer
45182657471SMarkus Pfeiffer /* Check if another thread didn't remove the msg queue. */
45282657471SMarkus Pfeiffer auxmsqpptr = get_msqpptr(msqid, 0, IPC_W);
45382657471SMarkus Pfeiffer if (!auxmsqpptr) {
45482657471SMarkus Pfeiffer errno = EIDRM;
45582657471SMarkus Pfeiffer return -1;
45682657471SMarkus Pfeiffer }
45782657471SMarkus Pfeiffer
45882657471SMarkus Pfeiffer if (auxmsqpptr != msqpptr) {
45982657471SMarkus Pfeiffer errno = EIDRM;
46082657471SMarkus Pfeiffer goto done;
46182657471SMarkus Pfeiffer }
46282657471SMarkus Pfeiffer
46382657471SMarkus Pfeiffer /* Check if another process didn't remove the queue. */
46482657471SMarkus Pfeiffer if (try_rwlock_wrlock(msqid, msqpptr) == -1) {
46582657471SMarkus Pfeiffer errno = EIDRM;
46682657471SMarkus Pfeiffer goto done;
46782657471SMarkus Pfeiffer }
46882657471SMarkus Pfeiffer
46982657471SMarkus Pfeiffer if (msqptr != &msqpptr->ds) {
47082657471SMarkus Pfeiffer sysv_print("msqptr != &msqpptr->ds");
47182657471SMarkus Pfeiffer exit(-1);
47282657471SMarkus Pfeiffer }
47382657471SMarkus Pfeiffer
47482657471SMarkus Pfeiffer } else {
47582657471SMarkus Pfeiffer sysv_print("got all the resources that we need\n");
47682657471SMarkus Pfeiffer break;
47782657471SMarkus Pfeiffer }
47882657471SMarkus Pfeiffer }
47982657471SMarkus Pfeiffer
48082657471SMarkus Pfeiffer /*
48182657471SMarkus Pfeiffer * We have the resources that we need.
48282657471SMarkus Pfeiffer * Make sure!
48382657471SMarkus Pfeiffer */
48482657471SMarkus Pfeiffer #if 0
48582657471SMarkus Pfeiffer if (segs_needed > nfree_msgmaps) {
48682657471SMarkus Pfeiffer sysv_print_err("segs_needed > nfree_msgmaps");
48782657471SMarkus Pfeiffer exit(-1);
48882657471SMarkus Pfeiffer }
48982657471SMarkus Pfeiffer #endif
49082657471SMarkus Pfeiffer if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) {
49182657471SMarkus Pfeiffer sysv_print_err("msgsz + msg_cbytes > msg_qbytes");
49282657471SMarkus Pfeiffer exit(-1);
49382657471SMarkus Pfeiffer }
49482657471SMarkus Pfeiffer
49582657471SMarkus Pfeiffer /*
49682657471SMarkus Pfeiffer * Allocate a message header
49782657471SMarkus Pfeiffer */
49882657471SMarkus Pfeiffer msghdr = &msqpptr->msghdrs[msqpptr->free_msghdrs];
49982657471SMarkus Pfeiffer msqpptr->free_msghdrs = msghdr->msg_next;
50082657471SMarkus Pfeiffer msghdr->msg_spot = -1;
50182657471SMarkus Pfeiffer msghdr->msg_ts = msgsz;
50282657471SMarkus Pfeiffer
50382657471SMarkus Pfeiffer /*
50482657471SMarkus Pfeiffer * Allocate space for the message
50582657471SMarkus Pfeiffer */
50682657471SMarkus Pfeiffer while (segs_needed > 0) {
50782657471SMarkus Pfeiffer next = msqpptr->free_msgmaps;
50882657471SMarkus Pfeiffer if (next < 0 || next > msginfo.msgseg) {
50982657471SMarkus Pfeiffer sysv_print_err("out of range free_msgmaps %d #1\n", next);
51082657471SMarkus Pfeiffer exit(-1);
51182657471SMarkus Pfeiffer }
51282657471SMarkus Pfeiffer
51382657471SMarkus Pfeiffer msqpptr->free_msgmaps = msqpptr->msgmaps[next].next;
51482657471SMarkus Pfeiffer msqpptr->nfree_msgmaps--;
51582657471SMarkus Pfeiffer msqpptr->msgmaps[next].next = msghdr->msg_spot;
51682657471SMarkus Pfeiffer msghdr->msg_spot = next;
51782657471SMarkus Pfeiffer segs_needed--;
51882657471SMarkus Pfeiffer }
51982657471SMarkus Pfeiffer
52082657471SMarkus Pfeiffer /*
52182657471SMarkus Pfeiffer * Copy in the message type
52282657471SMarkus Pfeiffer */
52382657471SMarkus Pfeiffer memcpy(&msghdr->msg_type, auxmsgp, sizeof(msghdr->msg_type));
52482657471SMarkus Pfeiffer auxmsgp = (char *)auxmsgp + sizeof(msghdr->msg_type);
52582657471SMarkus Pfeiffer
52682657471SMarkus Pfeiffer /*
52782657471SMarkus Pfeiffer * Validate the message type
52882657471SMarkus Pfeiffer */
52982657471SMarkus Pfeiffer sysv_print("msg_type = %ld\n", msghdr->msg_type);
53082657471SMarkus Pfeiffer
53182657471SMarkus Pfeiffer if (msghdr->msg_type < 1) {
53282657471SMarkus Pfeiffer msg_freehdr(msqpptr, msghdr);
53382657471SMarkus Pfeiffer umtx_wakeup((int *)&msqpptr->gen, 0);
53482657471SMarkus Pfeiffer sysv_print_err("mtype (%ld) < 1\n", msghdr->msg_type);
53582657471SMarkus Pfeiffer errno = EINVAL;
53682657471SMarkus Pfeiffer goto done;
53782657471SMarkus Pfeiffer }
53882657471SMarkus Pfeiffer
53982657471SMarkus Pfeiffer /*
54082657471SMarkus Pfeiffer * Copy in the message body
54182657471SMarkus Pfeiffer */
54282657471SMarkus Pfeiffer next = msghdr->msg_spot;
54382657471SMarkus Pfeiffer while (msgsz > 0) {
54482657471SMarkus Pfeiffer size_t tlen;
54582657471SMarkus Pfeiffer if (msgsz > (size_t)msginfo.msgssz)
54682657471SMarkus Pfeiffer tlen = msginfo.msgssz;
54782657471SMarkus Pfeiffer else
54882657471SMarkus Pfeiffer tlen = msgsz;
54982657471SMarkus Pfeiffer if (next < 0 || next > msginfo.msgseg) {
55082657471SMarkus Pfeiffer sysv_print_err("out of range free_msgmaps %d #2\n", next);
55182657471SMarkus Pfeiffer exit(-1);
55282657471SMarkus Pfeiffer }
55382657471SMarkus Pfeiffer
55482657471SMarkus Pfeiffer memcpy(&msqpptr->msgpool[next * msginfo.msgssz], auxmsgp, tlen);
55582657471SMarkus Pfeiffer msgsz -= tlen;
55682657471SMarkus Pfeiffer auxmsgp = (char *)auxmsgp + tlen;
55782657471SMarkus Pfeiffer next = msqpptr->msgmaps[next].next;
55882657471SMarkus Pfeiffer }
55982657471SMarkus Pfeiffer
56082657471SMarkus Pfeiffer /*
56182657471SMarkus Pfeiffer * Put the message into the queue
56282657471SMarkus Pfeiffer */
56382657471SMarkus Pfeiffer _index = (msghdr - &msqpptr->msghdrs[0]) /
56482657471SMarkus Pfeiffer sizeof(struct msg);
56582657471SMarkus Pfeiffer sysv_print("index_msghdr = %d\n", _index);
56682657471SMarkus Pfeiffer if (msqptr->first.msg_first_index == -1) {
56782657471SMarkus Pfeiffer msqptr->first.msg_first_index = _index;
56882657471SMarkus Pfeiffer msqptr->last.msg_last_index = _index;
56982657471SMarkus Pfeiffer } else {
57082657471SMarkus Pfeiffer msqpptr->msghdrs[msqptr->last.msg_last_index].msg_next = _index;
57182657471SMarkus Pfeiffer msqptr->last.msg_last_index = _index;
57282657471SMarkus Pfeiffer }
57382657471SMarkus Pfeiffer msqpptr->msghdrs[msqptr->last.msg_last_index].msg_next = -1;
57482657471SMarkus Pfeiffer
57582657471SMarkus Pfeiffer msqptr->msg_cbytes += msghdr->msg_ts;
57682657471SMarkus Pfeiffer msqptr->msg_qnum++;
57782657471SMarkus Pfeiffer msqptr->msg_lspid = getpid();
57882657471SMarkus Pfeiffer msqptr->msg_stime = time(NULL);
57982657471SMarkus Pfeiffer
58082657471SMarkus Pfeiffer umtx_wakeup((int *)&msqpptr->gen, 0);
58182657471SMarkus Pfeiffer error = 0;
58282657471SMarkus Pfeiffer
58382657471SMarkus Pfeiffer done:
58482657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr);
58582657471SMarkus Pfeiffer put_shmdata(msqid);
58682657471SMarkus Pfeiffer return(error);
58782657471SMarkus Pfeiffer }
58882657471SMarkus Pfeiffer
58982657471SMarkus Pfeiffer int
sysvipc_msgrcv(int msqid,void * msgp,size_t msgsz,long mtype,int msgflg)59082657471SMarkus Pfeiffer sysvipc_msgrcv(int msqid, void *msgp, size_t msgsz, long mtype, int msgflg)
59182657471SMarkus Pfeiffer {
59282657471SMarkus Pfeiffer size_t len;
59382657471SMarkus Pfeiffer struct msqid_pool *msqpptr, *auxmsqpptr;
59482657471SMarkus Pfeiffer struct msqid_ds_internal *msqptr;
59582657471SMarkus Pfeiffer struct msg *msghdr;
59682657471SMarkus Pfeiffer short msghdr_index;
59782657471SMarkus Pfeiffer int error;
59882657471SMarkus Pfeiffer short next;
59982657471SMarkus Pfeiffer int val_to_sleep;
60082657471SMarkus Pfeiffer char *auxmsgp = (char *)msgp;
60182657471SMarkus Pfeiffer
60282657471SMarkus Pfeiffer sysv_print("call to msgrcv(%d, %ld, %ld, %d)\n", msqid, msgsz, mtype, msgflg);
60382657471SMarkus Pfeiffer /*
60482657471SMarkus Pfeiffer if (!jail_sysvipc_allowed && td->td_ucred->cr_prison != NULL)
60582657471SMarkus Pfeiffer return (ENOSYS);
60682657471SMarkus Pfeiffer */
60782657471SMarkus Pfeiffer
60882657471SMarkus Pfeiffer if (!msgp) {
60982657471SMarkus Pfeiffer errno = EINVAL;
61082657471SMarkus Pfeiffer return -1;
61182657471SMarkus Pfeiffer }
61282657471SMarkus Pfeiffer
61382657471SMarkus Pfeiffer msqpptr = get_msqpptr(msqid, 0, IPC_R);
61482657471SMarkus Pfeiffer if (!msqpptr) {
61582657471SMarkus Pfeiffer errno = EINVAL;
61682657471SMarkus Pfeiffer return -1;
61782657471SMarkus Pfeiffer }
61882657471SMarkus Pfeiffer
61982657471SMarkus Pfeiffer error = -1;
62082657471SMarkus Pfeiffer
62182657471SMarkus Pfeiffer if (try_rwlock_wrlock(msqid, msqpptr) == -1) {
62282657471SMarkus Pfeiffer errno = EIDRM;
62382657471SMarkus Pfeiffer goto done;
62482657471SMarkus Pfeiffer }
62582657471SMarkus Pfeiffer
62682657471SMarkus Pfeiffer msqptr = &msqpptr->ds;
62782657471SMarkus Pfeiffer
62882657471SMarkus Pfeiffer msghdr_index = -1;
62982657471SMarkus Pfeiffer while (msghdr_index == -1) {
63082657471SMarkus Pfeiffer if (mtype == 0) {
63182657471SMarkus Pfeiffer msghdr_index = msqptr->first.msg_first_index;
63282657471SMarkus Pfeiffer msghdr = &msqpptr->msghdrs[msghdr_index];
63382657471SMarkus Pfeiffer if (msghdr_index != -1) {
63482657471SMarkus Pfeiffer if (msgsz < msghdr->msg_ts &&
63582657471SMarkus Pfeiffer (msgflg & MSG_NOERROR) == 0) {
63682657471SMarkus Pfeiffer sysv_print_err("first message on the queue is too big"
63740d436c0SSascha Wildner "(want %zu, got %d)\n",
63882657471SMarkus Pfeiffer msgsz, msghdr->msg_ts);
63982657471SMarkus Pfeiffer errno = E2BIG;
64082657471SMarkus Pfeiffer goto done;
64182657471SMarkus Pfeiffer }
64282657471SMarkus Pfeiffer if (msqptr->first.msg_first_index == msqptr->last.msg_last_index) {
64382657471SMarkus Pfeiffer msqptr->first.msg_first_index = -1;
64482657471SMarkus Pfeiffer msqptr->last.msg_last_index = -1;
64582657471SMarkus Pfeiffer } else {
64682657471SMarkus Pfeiffer msqptr->first.msg_first_index = msghdr->msg_next;
64782657471SMarkus Pfeiffer if (msqptr->first.msg_first_index == -1) {
64882657471SMarkus Pfeiffer sysv_print_err("first.msg_first_index/last screwed up #1");
64982657471SMarkus Pfeiffer exit(-1);
65082657471SMarkus Pfeiffer }
65182657471SMarkus Pfeiffer }
65282657471SMarkus Pfeiffer }
65382657471SMarkus Pfeiffer } else {
65482657471SMarkus Pfeiffer short previous;
65582657471SMarkus Pfeiffer short prev;
65682657471SMarkus Pfeiffer previous = -1;
65782657471SMarkus Pfeiffer prev = msqptr->first.msg_first_index;
65882657471SMarkus Pfeiffer while ((msghdr_index = prev) != -1) {
65982657471SMarkus Pfeiffer msghdr = &msqpptr->msghdrs[msghdr_index];
66082657471SMarkus Pfeiffer /*
66182657471SMarkus Pfeiffer * Is this message's type an exact match or is
66282657471SMarkus Pfeiffer * this message's type less than or equal to
66382657471SMarkus Pfeiffer * the absolute value of a negative mtype?
66482657471SMarkus Pfeiffer * Note that the second half of this test can
66582657471SMarkus Pfeiffer * NEVER be true if mtype is positive since
66682657471SMarkus Pfeiffer * msg_type is always positive!
66782657471SMarkus Pfeiffer */
66882657471SMarkus Pfeiffer if (mtype == msghdr->msg_type ||
66982657471SMarkus Pfeiffer msghdr->msg_type <= -mtype) {
67040d436c0SSascha Wildner sysv_print("found message type %ld, requested %ld\n",
67182657471SMarkus Pfeiffer msghdr->msg_type, mtype);
67282657471SMarkus Pfeiffer if (msgsz < msghdr->msg_ts &&
67382657471SMarkus Pfeiffer (msgflg & MSG_NOERROR) == 0) {
67482657471SMarkus Pfeiffer sysv_print_err("requested message on the queue"
67540d436c0SSascha Wildner " is too big (want %zu, got %d)\n",
67682657471SMarkus Pfeiffer msgsz, msghdr->msg_ts);
67782657471SMarkus Pfeiffer errno = E2BIG;
67882657471SMarkus Pfeiffer goto done;
67982657471SMarkus Pfeiffer }
68082657471SMarkus Pfeiffer prev = msghdr->msg_next;
68182657471SMarkus Pfeiffer if (msghdr_index == msqptr->last.msg_last_index) {
68282657471SMarkus Pfeiffer if (previous == -1) {
68382657471SMarkus Pfeiffer msqptr->first.msg_first_index = -1;
68482657471SMarkus Pfeiffer msqptr->last.msg_last_index = -1;
68582657471SMarkus Pfeiffer } else {
68682657471SMarkus Pfeiffer msqptr->last.msg_last_index = previous;
68782657471SMarkus Pfeiffer }
68882657471SMarkus Pfeiffer }
68982657471SMarkus Pfeiffer break;
69082657471SMarkus Pfeiffer }
69182657471SMarkus Pfeiffer previous = msghdr_index;
69282657471SMarkus Pfeiffer prev = msghdr->msg_next;
69382657471SMarkus Pfeiffer }
69482657471SMarkus Pfeiffer }
69582657471SMarkus Pfeiffer
69682657471SMarkus Pfeiffer /*
69782657471SMarkus Pfeiffer * We've either extracted the msghdr for the appropriate
69882657471SMarkus Pfeiffer * message or there isn't one.
69982657471SMarkus Pfeiffer * If there is one then bail out of this loop.
70082657471SMarkus Pfeiffer */
70182657471SMarkus Pfeiffer if (msghdr_index != -1)
70282657471SMarkus Pfeiffer break;
70382657471SMarkus Pfeiffer
70482657471SMarkus Pfeiffer /*
70582657471SMarkus Pfeiffer * No message found. Does the user want to wait?
70682657471SMarkus Pfeiffer */
70782657471SMarkus Pfeiffer if ((msgflg & IPC_NOWAIT) != 0) {
70840d436c0SSascha Wildner sysv_print_err("no appropriate message found (mtype=%ld)\n",
70982657471SMarkus Pfeiffer mtype);
71082657471SMarkus Pfeiffer errno = ENOMSG;
71182657471SMarkus Pfeiffer goto done;
71282657471SMarkus Pfeiffer }
71382657471SMarkus Pfeiffer
71482657471SMarkus Pfeiffer /*
71582657471SMarkus Pfeiffer * Wait for something to happen
71682657471SMarkus Pfeiffer */
71782657471SMarkus Pfeiffer sysv_print("goodnight\n");
71882657471SMarkus Pfeiffer val_to_sleep = msqpptr->gen;
71982657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr);
72082657471SMarkus Pfeiffer put_shmdata(msqid);
72182657471SMarkus Pfeiffer
72282657471SMarkus Pfeiffer /* We don't sleep more than SYSV_TIMEOUT because we could
72382657471SMarkus Pfeiffer * go to sleep after another process calls wakeup and remain
72482657471SMarkus Pfeiffer * blocked.
72582657471SMarkus Pfeiffer */
72682657471SMarkus Pfeiffer if (umtx_sleep((int *)&msqpptr->gen, val_to_sleep, SYSV_TIMEOUT) != 0) {
72782657471SMarkus Pfeiffer sysv_print_err("msgrcv: interrupted system call\n");
72882657471SMarkus Pfeiffer errno = EINTR;
72982657471SMarkus Pfeiffer goto done;
73082657471SMarkus Pfeiffer }
73182657471SMarkus Pfeiffer sysv_print("msgrcv: good morning (error=%d)\n", errno);
73282657471SMarkus Pfeiffer
73382657471SMarkus Pfeiffer /* Check if another thread didn't remove the msg queue. */
73482657471SMarkus Pfeiffer auxmsqpptr = get_msqpptr(msqid, 0, IPC_R);
73582657471SMarkus Pfeiffer if (!auxmsqpptr) {
73682657471SMarkus Pfeiffer errno = EIDRM;
73782657471SMarkus Pfeiffer return -1;
73882657471SMarkus Pfeiffer }
73982657471SMarkus Pfeiffer
74082657471SMarkus Pfeiffer if (auxmsqpptr != msqpptr) {
74182657471SMarkus Pfeiffer errno = EIDRM;
74282657471SMarkus Pfeiffer goto done;
74382657471SMarkus Pfeiffer }
74482657471SMarkus Pfeiffer
74582657471SMarkus Pfeiffer /* Check if another process didn't remove the msg queue. */
74682657471SMarkus Pfeiffer if (try_rwlock_wrlock(msqid, msqpptr) == -1) {
74782657471SMarkus Pfeiffer errno = EIDRM;
74882657471SMarkus Pfeiffer goto done;
74982657471SMarkus Pfeiffer }
75082657471SMarkus Pfeiffer
75182657471SMarkus Pfeiffer if (msqptr != &msqpptr->ds) {
75282657471SMarkus Pfeiffer sysv_print_err("msqptr != &msqpptr->ds");
75382657471SMarkus Pfeiffer exit(-1);
75482657471SMarkus Pfeiffer }
75582657471SMarkus Pfeiffer }
75682657471SMarkus Pfeiffer
75782657471SMarkus Pfeiffer /*
75882657471SMarkus Pfeiffer * Return the message to the user.
75982657471SMarkus Pfeiffer */
76082657471SMarkus Pfeiffer msqptr->msg_cbytes -= msghdr->msg_ts;
76182657471SMarkus Pfeiffer msqptr->msg_qnum--;
76282657471SMarkus Pfeiffer msqptr->msg_lrpid = getpid();
76382657471SMarkus Pfeiffer msqptr->msg_rtime = time(NULL);
76482657471SMarkus Pfeiffer
76582657471SMarkus Pfeiffer /*
76682657471SMarkus Pfeiffer * Make msgsz the actual amount that we'll be returning.
76782657471SMarkus Pfeiffer * Note that this effectively truncates the message if it is too long
76882657471SMarkus Pfeiffer * (since msgsz is never increased).
76982657471SMarkus Pfeiffer */
77040d436c0SSascha Wildner sysv_print("found a message, msgsz=%zu, msg_ts=%d\n", msgsz,
77182657471SMarkus Pfeiffer msghdr->msg_ts);
77282657471SMarkus Pfeiffer if (msgsz > msghdr->msg_ts)
77382657471SMarkus Pfeiffer msgsz = msghdr->msg_ts;
77482657471SMarkus Pfeiffer
77582657471SMarkus Pfeiffer /*
77682657471SMarkus Pfeiffer * Return the type to the user.
77782657471SMarkus Pfeiffer */
77882657471SMarkus Pfeiffer memcpy(auxmsgp, (caddr_t)&(msghdr->msg_type), sizeof(msghdr->msg_type));
77982657471SMarkus Pfeiffer auxmsgp = (char *)auxmsgp + sizeof(msghdr->msg_type);
78082657471SMarkus Pfeiffer
78182657471SMarkus Pfeiffer /*
78282657471SMarkus Pfeiffer * Return the segments to the user
78382657471SMarkus Pfeiffer */
78482657471SMarkus Pfeiffer next = msghdr->msg_spot;
78582657471SMarkus Pfeiffer for (len = 0; len < msgsz; len += msginfo.msgssz) {
78682657471SMarkus Pfeiffer size_t tlen;
78782657471SMarkus Pfeiffer
78882657471SMarkus Pfeiffer if (msgsz - len > (size_t)msginfo.msgssz)
78982657471SMarkus Pfeiffer tlen = msginfo.msgssz;
79082657471SMarkus Pfeiffer else
79182657471SMarkus Pfeiffer tlen = msgsz - len;
79282657471SMarkus Pfeiffer if (next < 0 || next > msginfo.msgseg) {
79382657471SMarkus Pfeiffer sysv_print_err("out of range free_msgmaps %d #3\n", next);
79482657471SMarkus Pfeiffer exit(-1);
79582657471SMarkus Pfeiffer }
79682657471SMarkus Pfeiffer
79782657471SMarkus Pfeiffer memcpy(auxmsgp, (caddr_t)&msqpptr->msgpool[next * msginfo.msgssz], tlen);
79882657471SMarkus Pfeiffer auxmsgp = (char *)auxmsgp + tlen;
79982657471SMarkus Pfeiffer next = msqpptr->msgmaps[next].next;
80082657471SMarkus Pfeiffer }
80182657471SMarkus Pfeiffer
80282657471SMarkus Pfeiffer /*
80382657471SMarkus Pfeiffer * Done, return the actual number of bytes copied out.
80482657471SMarkus Pfeiffer */
80582657471SMarkus Pfeiffer msg_freehdr(msqpptr, msghdr);
80682657471SMarkus Pfeiffer umtx_wakeup((int *)&msqpptr->gen, 0);
80782657471SMarkus Pfeiffer error = msgsz;
80882657471SMarkus Pfeiffer done:
80982657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr);
81082657471SMarkus Pfeiffer put_shmdata(msqid);
81182657471SMarkus Pfeiffer return(error);
81282657471SMarkus Pfeiffer }
813