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