1*82657471SMarkus Pfeiffer /* $FreeBSD: src/sys/kern/sysv_msg.c,v 1.23.2.5 2002/12/31 08:54:53 maxim Exp $ */ 2*82657471SMarkus Pfeiffer 3*82657471SMarkus Pfeiffer /* 4*82657471SMarkus Pfeiffer * Implementation of SVID messages 5*82657471SMarkus Pfeiffer * 6*82657471SMarkus Pfeiffer * Author: Daniel Boulet 7*82657471SMarkus Pfeiffer * 8*82657471SMarkus Pfeiffer * Copyright 1993 Daniel Boulet and RTMX Inc. 9*82657471SMarkus Pfeiffer * Copyright (c) 2013 Larisa Grigore <larisagrigore@gmail.com> 10*82657471SMarkus Pfeiffer * 11*82657471SMarkus Pfeiffer * This system call was implemented by Daniel Boulet under contract from RTMX. 12*82657471SMarkus Pfeiffer * 13*82657471SMarkus Pfeiffer * Redistribution and use in source forms, with and without modification, 14*82657471SMarkus Pfeiffer * are permitted provided that this entire comment appears intact. 15*82657471SMarkus Pfeiffer * 16*82657471SMarkus Pfeiffer * Redistribution in binary form may occur without any restrictions. 17*82657471SMarkus Pfeiffer * Obviously, it would be nice if you gave credit where credit is due 18*82657471SMarkus Pfeiffer * but requiring it would be too onerous. 19*82657471SMarkus Pfeiffer * 20*82657471SMarkus Pfeiffer * This software is provided ``AS IS'' without any warranties of any kind. 21*82657471SMarkus Pfeiffer */ 22*82657471SMarkus Pfeiffer 23*82657471SMarkus Pfeiffer #include "namespace.h" 24*82657471SMarkus Pfeiffer #include <stdio.h> 25*82657471SMarkus Pfeiffer #include <stdlib.h> 26*82657471SMarkus Pfeiffer #include <errno.h> 27*82657471SMarkus Pfeiffer #include <err.h> 28*82657471SMarkus Pfeiffer #include <pthread.h> 29*82657471SMarkus Pfeiffer #include <string.h> 30*82657471SMarkus Pfeiffer #include <stdarg.h> 31*82657471SMarkus Pfeiffer #include <sys/param.h> 32*82657471SMarkus Pfeiffer #include <sys/queue.h> 33*82657471SMarkus Pfeiffer #include <sys/mman.h> 34*82657471SMarkus Pfeiffer #include "un-namespace.h" 35*82657471SMarkus Pfeiffer 36*82657471SMarkus Pfeiffer #include "sysvipc_lock.h" 37*82657471SMarkus Pfeiffer #include "sysvipc_ipc.h" 38*82657471SMarkus Pfeiffer #include "sysvipc_hash.h" 39*82657471SMarkus Pfeiffer #include "sysvipc_msg.h" 40*82657471SMarkus Pfeiffer #include "sysvipc_shm.h" 41*82657471SMarkus Pfeiffer 42*82657471SMarkus Pfeiffer #define SYSV_MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) 43*82657471SMarkus Pfeiffer #define SYSV_MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) 44*82657471SMarkus Pfeiffer #define SYSV_MUTEX_DESTROY(x) if (__isthreaded) _pthread_mutex_destroy(x) 45*82657471SMarkus Pfeiffer 46*82657471SMarkus Pfeiffer extern struct hashtable *shmaddrs; 47*82657471SMarkus Pfeiffer extern struct hashtable *shmres; 48*82657471SMarkus Pfeiffer extern pthread_mutex_t lock_resources; 49*82657471SMarkus Pfeiffer 50*82657471SMarkus Pfeiffer struct msginfo msginfo = { 51*82657471SMarkus Pfeiffer MSGMAX, /* max chars in a message */ 52*82657471SMarkus Pfeiffer MSGMNI, /* # of message queue identifiers */ 53*82657471SMarkus Pfeiffer MSGMNB, /* max chars in a queue */ 54*82657471SMarkus Pfeiffer MSGTQL, /* max messages in system */ 55*82657471SMarkus Pfeiffer MSGSSZ, /* size of a message segment (must be small power of 2 greater than 4) */ 56*82657471SMarkus Pfeiffer MSGSEG /* number of message segments */ 57*82657471SMarkus Pfeiffer }; 58*82657471SMarkus Pfeiffer 59*82657471SMarkus Pfeiffer static int 60*82657471SMarkus Pfeiffer put_shmdata(int id) { 61*82657471SMarkus Pfeiffer struct shm_data *data; 62*82657471SMarkus Pfeiffer int ret = -1; 63*82657471SMarkus Pfeiffer 64*82657471SMarkus Pfeiffer SYSV_MUTEX_LOCK(&lock_resources); 65*82657471SMarkus Pfeiffer data = _hash_lookup(shmres, id); 66*82657471SMarkus Pfeiffer if (!data) { 67*82657471SMarkus Pfeiffer sysv_print_err("something wrong put_shmdata\n"); 68*82657471SMarkus Pfeiffer goto done; /* It should not reach here. */ 69*82657471SMarkus Pfeiffer } 70*82657471SMarkus Pfeiffer 71*82657471SMarkus Pfeiffer data->used--; 72*82657471SMarkus Pfeiffer if (data->used == 0 && data->removed) { 73*82657471SMarkus Pfeiffer sysv_print("really remove the sem\n"); 74*82657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_resources); 75*82657471SMarkus Pfeiffer /* OBS: Even if the shmctl fails (the thread doesn't 76*82657471SMarkus Pfeiffer * have IPC_M permissions), all structures associated 77*82657471SMarkus Pfeiffer * with it will be removed in the current process.*/ 78*82657471SMarkus Pfeiffer shmdt(data->internal); 79*82657471SMarkus Pfeiffer if (data->removed == SEG_ALREADY_REMOVED) 80*82657471SMarkus Pfeiffer return 1; /* The queue was removed 81*82657471SMarkus Pfeiffer by another process so there is nothing else 82*82657471SMarkus Pfeiffer we must do. */ 83*82657471SMarkus Pfeiffer /* Else inform the daemon that the segment is removed. */ 84*82657471SMarkus Pfeiffer return (sysvipc_shmctl(id, IPC_RMID, NULL)); 85*82657471SMarkus Pfeiffer } 86*82657471SMarkus Pfeiffer 87*82657471SMarkus Pfeiffer ret = 0; 88*82657471SMarkus Pfeiffer done: 89*82657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_resources); 90*82657471SMarkus Pfeiffer return (ret); 91*82657471SMarkus Pfeiffer } 92*82657471SMarkus Pfeiffer 93*82657471SMarkus Pfeiffer static struct msqid_pool* 94*82657471SMarkus Pfeiffer get_msqpptr(int msqid, int to_remove, int shm_access) { 95*82657471SMarkus Pfeiffer struct msqid_pool *msqpptr; 96*82657471SMarkus Pfeiffer 97*82657471SMarkus Pfeiffer struct shm_data *shmdata = 98*82657471SMarkus Pfeiffer get_shmdata(msqid, to_remove, shm_access); 99*82657471SMarkus Pfeiffer if (!shmdata) { 100*82657471SMarkus Pfeiffer /* Error is set in get_shmdata. */ 101*82657471SMarkus Pfeiffer return NULL; 102*82657471SMarkus Pfeiffer } 103*82657471SMarkus Pfeiffer 104*82657471SMarkus Pfeiffer msqpptr = (struct msqid_pool *)shmdata->internal; 105*82657471SMarkus Pfeiffer if (!msqpptr) { 106*82657471SMarkus Pfeiffer put_shmdata(msqid); 107*82657471SMarkus Pfeiffer errno = EINVAL; 108*82657471SMarkus Pfeiffer return NULL; 109*82657471SMarkus Pfeiffer } 110*82657471SMarkus Pfeiffer 111*82657471SMarkus Pfeiffer return msqpptr; 112*82657471SMarkus Pfeiffer } 113*82657471SMarkus Pfeiffer 114*82657471SMarkus Pfeiffer static int 115*82657471SMarkus Pfeiffer msqp_exist(int msqid, struct msqid_pool *msqpptr) { 116*82657471SMarkus Pfeiffer /* Was it removed? */ 117*82657471SMarkus Pfeiffer if (msqpptr->gen == -1 || 118*82657471SMarkus Pfeiffer msqpptr->ds.msg_perm.seq != IPCID_TO_SEQ(msqid)) 119*82657471SMarkus Pfeiffer return 0; 120*82657471SMarkus Pfeiffer 121*82657471SMarkus Pfeiffer return 1; 122*82657471SMarkus Pfeiffer } 123*82657471SMarkus Pfeiffer 124*82657471SMarkus Pfeiffer static int 125*82657471SMarkus Pfeiffer try_rwlock_rdlock(int msqid, struct msqid_pool *msqpptr) { 126*82657471SMarkus Pfeiffer sysv_print("try get rd lock\n"); 127*82657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK 128*82657471SMarkus Pfeiffer sysv_rwlock_rdlock(&msqpptr->rwlock); 129*82657471SMarkus Pfeiffer #else 130*82657471SMarkus Pfeiffer sysv_mutex_lock(&msqpptr->mutex); 131*82657471SMarkus Pfeiffer #endif 132*82657471SMarkus Pfeiffer sysv_print("get rd lock\n"); 133*82657471SMarkus Pfeiffer if (!msqp_exist(msqid, msqpptr)) { 134*82657471SMarkus Pfeiffer errno = EINVAL; 135*82657471SMarkus Pfeiffer sysv_print("error rd lock\n"); 136*82657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK 137*82657471SMarkus Pfeiffer sysv_rwlock_unlock(&msqpptr->rwlock); 138*82657471SMarkus Pfeiffer #else 139*82657471SMarkus Pfeiffer sysv_mutex_unlock(&msqpptr->mutex); 140*82657471SMarkus Pfeiffer #endif 141*82657471SMarkus Pfeiffer return -1; 142*82657471SMarkus Pfeiffer } 143*82657471SMarkus Pfeiffer sysv_print("end rd lock\n"); 144*82657471SMarkus Pfeiffer return 0; 145*82657471SMarkus Pfeiffer } 146*82657471SMarkus Pfeiffer 147*82657471SMarkus Pfeiffer static int 148*82657471SMarkus Pfeiffer try_rwlock_wrlock(int msqid, struct msqid_pool *msqpptr) { 149*82657471SMarkus Pfeiffer sysv_print("try get wr lock\n"); 150*82657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK 151*82657471SMarkus Pfeiffer sysv_rwlock_wrlock(&msqpptr->rwlock); 152*82657471SMarkus Pfeiffer #else 153*82657471SMarkus Pfeiffer sysv_mutex_lock(&msqpptr->mutex); 154*82657471SMarkus Pfeiffer #endif 155*82657471SMarkus Pfeiffer sysv_print("get wr lock\n"); 156*82657471SMarkus Pfeiffer if (!msqp_exist(msqid, msqpptr)) { 157*82657471SMarkus Pfeiffer sysv_print("error rw lock\n"); 158*82657471SMarkus Pfeiffer errno = EINVAL; 159*82657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK 160*82657471SMarkus Pfeiffer sysv_rwlock_unlock(&msqpptr->rwlock); 161*82657471SMarkus Pfeiffer #else 162*82657471SMarkus Pfeiffer sysv_mutex_unlock(&msqpptr->mutex); 163*82657471SMarkus Pfeiffer #endif 164*82657471SMarkus Pfeiffer return -1; 165*82657471SMarkus Pfeiffer } 166*82657471SMarkus Pfeiffer sysv_print("end rw lock\n"); 167*82657471SMarkus Pfeiffer return 0; 168*82657471SMarkus Pfeiffer } 169*82657471SMarkus Pfeiffer 170*82657471SMarkus Pfeiffer static int 171*82657471SMarkus Pfeiffer rwlock_unlock(int msqid, struct msqid_pool *msqpptr) { 172*82657471SMarkus Pfeiffer if (!msqp_exist(msqid, msqpptr)) { 173*82657471SMarkus Pfeiffer errno = EINVAL; 174*82657471SMarkus Pfeiffer return -1; 175*82657471SMarkus Pfeiffer } 176*82657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK 177*82657471SMarkus Pfeiffer sysv_rwlock_unlock(&msqpptr->rwlock); 178*82657471SMarkus Pfeiffer #else 179*82657471SMarkus Pfeiffer sysv_mutex_unlock(&msqpptr->mutex); 180*82657471SMarkus Pfeiffer #endif 181*82657471SMarkus Pfeiffer sysv_print("unlock rw lock\n"); 182*82657471SMarkus Pfeiffer return 0; 183*82657471SMarkus Pfeiffer } 184*82657471SMarkus Pfeiffer 185*82657471SMarkus Pfeiffer static void 186*82657471SMarkus Pfeiffer msg_freehdr(struct msqid_pool *msqpptr, struct msg *msghdr) 187*82657471SMarkus Pfeiffer { 188*82657471SMarkus Pfeiffer while (msghdr->msg_ts > 0) { 189*82657471SMarkus Pfeiffer short next; 190*82657471SMarkus Pfeiffer if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg) { 191*82657471SMarkus Pfeiffer sysv_print_err("msghdr->msg_spot out of range"); 192*82657471SMarkus Pfeiffer exit(-1); 193*82657471SMarkus Pfeiffer } 194*82657471SMarkus Pfeiffer next = msqpptr->msgmaps[msghdr->msg_spot].next; 195*82657471SMarkus Pfeiffer msqpptr->msgmaps[msghdr->msg_spot].next = 196*82657471SMarkus Pfeiffer msqpptr->free_msgmaps; 197*82657471SMarkus Pfeiffer msqpptr->free_msgmaps = msghdr->msg_spot; 198*82657471SMarkus Pfeiffer msqpptr->nfree_msgmaps++; 199*82657471SMarkus Pfeiffer msghdr->msg_spot = next; 200*82657471SMarkus Pfeiffer if (msghdr->msg_ts >= msginfo.msgssz) 201*82657471SMarkus Pfeiffer msghdr->msg_ts -= msginfo.msgssz; 202*82657471SMarkus Pfeiffer else 203*82657471SMarkus Pfeiffer msghdr->msg_ts = 0; 204*82657471SMarkus Pfeiffer } 205*82657471SMarkus Pfeiffer if (msghdr->msg_spot != -1) { 206*82657471SMarkus Pfeiffer sysv_print_err("msghdr->msg_spot != -1"); 207*82657471SMarkus Pfeiffer exit(-1); 208*82657471SMarkus Pfeiffer } 209*82657471SMarkus Pfeiffer msghdr->msg_next = msqpptr->free_msghdrs; 210*82657471SMarkus Pfeiffer msqpptr->free_msghdrs = (msghdr - &msqpptr->msghdrs[0]) / 211*82657471SMarkus Pfeiffer sizeof(struct msg); 212*82657471SMarkus Pfeiffer } 213*82657471SMarkus Pfeiffer 214*82657471SMarkus Pfeiffer int 215*82657471SMarkus Pfeiffer sysvipc_msgget(key_t key, int msgflg) { 216*82657471SMarkus Pfeiffer int msqid; 217*82657471SMarkus Pfeiffer void *shmaddr; 218*82657471SMarkus Pfeiffer size_t size = sizeof(struct msqid_pool); 219*82657471SMarkus Pfeiffer 220*82657471SMarkus Pfeiffer msqid = _shmget(key, size, msgflg, MSGGET); 221*82657471SMarkus Pfeiffer if (msqid == -1) 222*82657471SMarkus Pfeiffer goto done; 223*82657471SMarkus Pfeiffer 224*82657471SMarkus Pfeiffer /* If the msg is in process of being removed there are two cases: 225*82657471SMarkus Pfeiffer * - the daemon knows that and it will handle this situation. 226*82657471SMarkus Pfeiffer * - one of the threads from this address space remove it and the daemon 227*82657471SMarkus Pfeiffer * wasn't announced yet; in this scenario, the msg is marked 228*82657471SMarkus Pfeiffer * using "removed" field of shm_data and future calls will return 229*82657471SMarkus Pfeiffer * EIDRM error. 230*82657471SMarkus Pfeiffer */ 231*82657471SMarkus Pfeiffer 232*82657471SMarkus Pfeiffer #if 0 233*82657471SMarkus Pfeiffer /* Set access type. */ 234*82657471SMarkus Pfeiffer shm_access = semflg & (IPC_W | IPC_R); 235*82657471SMarkus Pfeiffer if(set_shmdata_access(semid, shm_access) != 0) { 236*82657471SMarkus Pfeiffer /* errno already set. */ 237*82657471SMarkus Pfeiffer goto done; 238*82657471SMarkus Pfeiffer } 239*82657471SMarkus Pfeiffer #endif 240*82657471SMarkus Pfeiffer 241*82657471SMarkus Pfeiffer shmaddr = sysvipc_shmat(msqid, NULL, 0); 242*82657471SMarkus Pfeiffer if (!shmaddr) { 243*82657471SMarkus Pfeiffer msqid = -1; 244*82657471SMarkus Pfeiffer sysvipc_shmctl(msqid, IPC_RMID, NULL); 245*82657471SMarkus Pfeiffer goto done; 246*82657471SMarkus Pfeiffer } 247*82657471SMarkus Pfeiffer sysv_print("shmaddr = %lx\n", (unsigned long)shmaddr); 248*82657471SMarkus Pfeiffer 249*82657471SMarkus Pfeiffer done: 250*82657471SMarkus Pfeiffer return msqid; 251*82657471SMarkus Pfeiffer } 252*82657471SMarkus Pfeiffer 253*82657471SMarkus Pfeiffer int 254*82657471SMarkus Pfeiffer sysvipc_msgctl(int msqid, int cmd, struct msqid_ds *buf) { 255*82657471SMarkus Pfeiffer int error; 256*82657471SMarkus Pfeiffer struct msqid_pool *msqpptr = NULL; 257*82657471SMarkus Pfeiffer struct shmid_ds shmds; 258*82657471SMarkus Pfeiffer int shm_access = 0; 259*82657471SMarkus Pfeiffer 260*82657471SMarkus Pfeiffer error = 0; 261*82657471SMarkus Pfeiffer 262*82657471SMarkus Pfeiffer switch (cmd) { 263*82657471SMarkus Pfeiffer case IPC_SET: /* Originally was IPC_M but this is checked 264*82657471SMarkus Pfeiffer by daemon. */ 265*82657471SMarkus Pfeiffer shm_access = IPC_W; 266*82657471SMarkus Pfeiffer break; 267*82657471SMarkus Pfeiffer case IPC_STAT: 268*82657471SMarkus Pfeiffer shm_access = IPC_R; 269*82657471SMarkus Pfeiffer break; 270*82657471SMarkus Pfeiffer default: 271*82657471SMarkus Pfeiffer break; 272*82657471SMarkus Pfeiffer } 273*82657471SMarkus Pfeiffer 274*82657471SMarkus Pfeiffer msqpptr = get_msqpptr(msqid, cmd==IPC_RMID, shm_access); 275*82657471SMarkus Pfeiffer if (!msqpptr) { 276*82657471SMarkus Pfeiffer errno = EINVAL; 277*82657471SMarkus Pfeiffer return -1; 278*82657471SMarkus Pfeiffer } 279*82657471SMarkus Pfeiffer 280*82657471SMarkus Pfeiffer switch (cmd) { 281*82657471SMarkus Pfeiffer case IPC_RMID: 282*82657471SMarkus Pfeiffer /* Mark that the segment is removed. This is done in 283*82657471SMarkus Pfeiffer * get_msqpptr call in order to announce other processes. 284*82657471SMarkus Pfeiffer * It will be actually removed after put_shmdata call and 285*82657471SMarkus Pfeiffer * not other thread from this address space use shm_data 286*82657471SMarkus Pfeiffer * structure. 287*82657471SMarkus Pfeiffer */ 288*82657471SMarkus Pfeiffer break; 289*82657471SMarkus Pfeiffer case IPC_SET: 290*82657471SMarkus Pfeiffer error = try_rwlock_rdlock(msqid, msqpptr); 291*82657471SMarkus Pfeiffer if (error) 292*82657471SMarkus Pfeiffer break; 293*82657471SMarkus Pfeiffer if (buf->msg_qbytes == 0) { 294*82657471SMarkus Pfeiffer sysv_print_err("can't reduce msg_qbytes to 0\n"); 295*82657471SMarkus Pfeiffer errno = EINVAL; /* non-standard errno! */ 296*82657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr); 297*82657471SMarkus Pfeiffer break; 298*82657471SMarkus Pfeiffer } 299*82657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr); 300*82657471SMarkus Pfeiffer 301*82657471SMarkus Pfeiffer memset(&shmds, 0, sizeof(shmds)/sizeof(unsigned char)); 302*82657471SMarkus Pfeiffer memcpy(&shmds.shm_perm, &buf->msg_perm, 303*82657471SMarkus Pfeiffer sizeof(struct ipc_perm)); 304*82657471SMarkus Pfeiffer error = sysvipc_shmctl(msqid, cmd, &shmds); 305*82657471SMarkus Pfeiffer if (error) 306*82657471SMarkus Pfeiffer break; 307*82657471SMarkus Pfeiffer 308*82657471SMarkus Pfeiffer /* There is no need to check if we have right to modify the 309*82657471SMarkus Pfeiffer * size because we have right to change other fileds. */ 310*82657471SMarkus Pfeiffer 311*82657471SMarkus Pfeiffer if (round_page(buf->msg_qbytes) != 312*82657471SMarkus Pfeiffer round_page(msqpptr->ds.msg_qbytes)) { 313*82657471SMarkus Pfeiffer sysv_print("change msg size\n"); 314*82657471SMarkus Pfeiffer /* TODO same as in semundo_adjust only 315*82657471SMarkus Pfeiffer * that there is no way to inform other 316*82657471SMarkus Pfeiffer * processes about the change. */ 317*82657471SMarkus Pfeiffer } 318*82657471SMarkus Pfeiffer 319*82657471SMarkus Pfeiffer error = try_rwlock_wrlock(msqid, msqpptr); 320*82657471SMarkus Pfeiffer if (error) 321*82657471SMarkus Pfeiffer break; 322*82657471SMarkus Pfeiffer msqpptr->ds.msg_qbytes = buf->msg_qbytes; 323*82657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr); 324*82657471SMarkus Pfeiffer /* OBS: didn't update ctime and mode as in kernel implementation 325*82657471SMarkus Pfeiffer * it is done. Those fields are already updated for shmid_ds 326*82657471SMarkus Pfeiffer * struct when calling shmctl 327*82657471SMarkus Pfeiffer */ 328*82657471SMarkus Pfeiffer break; 329*82657471SMarkus Pfeiffer 330*82657471SMarkus Pfeiffer case IPC_STAT: 331*82657471SMarkus Pfeiffer error = sysvipc_shmctl(msqid, cmd, &shmds); 332*82657471SMarkus Pfeiffer if (error) 333*82657471SMarkus Pfeiffer break; 334*82657471SMarkus Pfeiffer 335*82657471SMarkus Pfeiffer memcpy(&buf->msg_perm, &shmds.shm_perm, 336*82657471SMarkus Pfeiffer sizeof(struct ipc_perm)); 337*82657471SMarkus Pfeiffer buf->msg_ctime = shmds.shm_ctime; 338*82657471SMarkus Pfeiffer 339*82657471SMarkus Pfeiffer /* Read fields that are not kept in shmds. */ 340*82657471SMarkus Pfeiffer error = try_rwlock_rdlock(msqid, msqpptr); 341*82657471SMarkus Pfeiffer if (error) 342*82657471SMarkus Pfeiffer break; 343*82657471SMarkus Pfeiffer buf->msg_first = (struct msg *)(u_long) 344*82657471SMarkus Pfeiffer msqpptr->ds.first.msg_first_index; 345*82657471SMarkus Pfeiffer buf->msg_last = (struct msg *)(u_long) 346*82657471SMarkus Pfeiffer msqpptr->ds.last.msg_last_index; 347*82657471SMarkus Pfeiffer buf->msg_cbytes = msqpptr->ds.msg_cbytes; 348*82657471SMarkus Pfeiffer buf->msg_qnum = msqpptr->ds.msg_qnum; 349*82657471SMarkus Pfeiffer buf->msg_qbytes = msqpptr->ds.msg_qbytes; 350*82657471SMarkus Pfeiffer buf->msg_lspid = msqpptr->ds.msg_lspid; 351*82657471SMarkus Pfeiffer buf->msg_lrpid = msqpptr->ds.msg_lrpid; 352*82657471SMarkus Pfeiffer buf->msg_stime = msqpptr->ds.msg_stime; 353*82657471SMarkus Pfeiffer buf->msg_rtime = msqpptr->ds.msg_rtime; 354*82657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr); 355*82657471SMarkus Pfeiffer break; 356*82657471SMarkus Pfeiffer default: 357*82657471SMarkus Pfeiffer sysv_print_err("invalid command %d\n", cmd); 358*82657471SMarkus Pfeiffer errno = EINVAL; 359*82657471SMarkus Pfeiffer break; 360*82657471SMarkus Pfeiffer } 361*82657471SMarkus Pfeiffer 362*82657471SMarkus Pfeiffer put_shmdata(msqid); 363*82657471SMarkus Pfeiffer 364*82657471SMarkus Pfeiffer return(error); 365*82657471SMarkus Pfeiffer } 366*82657471SMarkus Pfeiffer 367*82657471SMarkus Pfeiffer int 368*82657471SMarkus Pfeiffer sysvipc_msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg) 369*82657471SMarkus Pfeiffer { 370*82657471SMarkus Pfeiffer int segs_needed, error; 371*82657471SMarkus Pfeiffer struct msg *msghdr; 372*82657471SMarkus Pfeiffer struct msqid_pool *msqpptr, *auxmsqpptr; 373*82657471SMarkus Pfeiffer struct msqid_ds_internal *msqptr; 374*82657471SMarkus Pfeiffer short next; 375*82657471SMarkus Pfeiffer int val_to_sleep; 376*82657471SMarkus Pfeiffer char *auxmsgp = (char *)msgp; 377*82657471SMarkus Pfeiffer int _index; 378*82657471SMarkus Pfeiffer 379*82657471SMarkus Pfeiffer sysv_print("call to msgsnd(%d, %ld, %d)\n", msqid, msgsz, msgflg); 380*82657471SMarkus Pfeiffer 381*82657471SMarkus Pfeiffer /*if (!jail_sysvipc_allowed && td->td_ucred->cr_prison != NULL) 382*82657471SMarkus Pfeiffer return (ENOSYS); 383*82657471SMarkus Pfeiffer */ 384*82657471SMarkus Pfeiffer if (!msgp) { 385*82657471SMarkus Pfeiffer errno = EINVAL; 386*82657471SMarkus Pfeiffer return -1; 387*82657471SMarkus Pfeiffer } 388*82657471SMarkus Pfeiffer 389*82657471SMarkus Pfeiffer msqpptr = get_msqpptr(msqid, 0, IPC_W); 390*82657471SMarkus Pfeiffer if (!msqpptr) { 391*82657471SMarkus Pfeiffer errno = EINVAL; 392*82657471SMarkus Pfeiffer return -1; 393*82657471SMarkus Pfeiffer } 394*82657471SMarkus Pfeiffer error = -1; 395*82657471SMarkus Pfeiffer 396*82657471SMarkus Pfeiffer if (try_rwlock_wrlock(msqid, msqpptr) == -1) { 397*82657471SMarkus Pfeiffer errno = EIDRM; 398*82657471SMarkus Pfeiffer goto done; 399*82657471SMarkus Pfeiffer } 400*82657471SMarkus Pfeiffer 401*82657471SMarkus Pfeiffer msqptr = &msqpptr->ds; 402*82657471SMarkus Pfeiffer 403*82657471SMarkus Pfeiffer segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz; 404*82657471SMarkus Pfeiffer sysv_print("msgsz=%ld, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz, 405*82657471SMarkus Pfeiffer segs_needed); 406*82657471SMarkus Pfeiffer for (;;) { 407*82657471SMarkus Pfeiffer int need_more_resources = 0; 408*82657471SMarkus Pfeiffer 409*82657471SMarkus Pfeiffer if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) { 410*82657471SMarkus Pfeiffer sysv_print("msgsz + msg_cbytes > msg_qbytes\n"); 411*82657471SMarkus Pfeiffer need_more_resources = 1; 412*82657471SMarkus Pfeiffer } 413*82657471SMarkus Pfeiffer 414*82657471SMarkus Pfeiffer if (segs_needed > msqpptr->nfree_msgmaps) { 415*82657471SMarkus Pfeiffer sysv_print("segs_needed > nfree_msgmaps (= %d)\n", 416*82657471SMarkus Pfeiffer msqpptr->nfree_msgmaps); 417*82657471SMarkus Pfeiffer need_more_resources = 1; 418*82657471SMarkus Pfeiffer } 419*82657471SMarkus Pfeiffer 420*82657471SMarkus Pfeiffer if (msqpptr->free_msghdrs == -1) { 421*82657471SMarkus Pfeiffer sysv_print("no more msghdrs\n"); 422*82657471SMarkus Pfeiffer need_more_resources = 1; 423*82657471SMarkus Pfeiffer } 424*82657471SMarkus Pfeiffer 425*82657471SMarkus Pfeiffer if (need_more_resources) { 426*82657471SMarkus Pfeiffer if ((msgflg & IPC_NOWAIT) != 0) { 427*82657471SMarkus Pfeiffer sysv_print_err("need more resources but caller doesn't want to wait\n"); 428*82657471SMarkus Pfeiffer errno = EAGAIN; 429*82657471SMarkus Pfeiffer goto done; 430*82657471SMarkus Pfeiffer } 431*82657471SMarkus Pfeiffer 432*82657471SMarkus Pfeiffer sysv_print("goodnight\n"); 433*82657471SMarkus Pfeiffer val_to_sleep = msqpptr->gen; 434*82657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr); 435*82657471SMarkus Pfeiffer put_shmdata(msqid); 436*82657471SMarkus Pfeiffer 437*82657471SMarkus Pfeiffer if (umtx_sleep((int *)&msqpptr->gen, val_to_sleep, SYSV_TIMEOUT) != 0) { 438*82657471SMarkus Pfeiffer sysv_print_err("msgsnd: interrupted system call\n"); 439*82657471SMarkus Pfeiffer errno = EINTR; 440*82657471SMarkus Pfeiffer goto done; 441*82657471SMarkus Pfeiffer } 442*82657471SMarkus Pfeiffer 443*82657471SMarkus Pfeiffer /* Check if another thread didn't remove the msg queue. */ 444*82657471SMarkus Pfeiffer auxmsqpptr = get_msqpptr(msqid, 0, IPC_W); 445*82657471SMarkus Pfeiffer if (!auxmsqpptr) { 446*82657471SMarkus Pfeiffer errno = EIDRM; 447*82657471SMarkus Pfeiffer return -1; 448*82657471SMarkus Pfeiffer } 449*82657471SMarkus Pfeiffer 450*82657471SMarkus Pfeiffer if (auxmsqpptr != msqpptr) { 451*82657471SMarkus Pfeiffer errno = EIDRM; 452*82657471SMarkus Pfeiffer goto done; 453*82657471SMarkus Pfeiffer } 454*82657471SMarkus Pfeiffer 455*82657471SMarkus Pfeiffer /* Check if another process didn't remove the queue. */ 456*82657471SMarkus Pfeiffer if (try_rwlock_wrlock(msqid, msqpptr) == -1) { 457*82657471SMarkus Pfeiffer errno = EIDRM; 458*82657471SMarkus Pfeiffer goto done; 459*82657471SMarkus Pfeiffer } 460*82657471SMarkus Pfeiffer 461*82657471SMarkus Pfeiffer if (msqptr != &msqpptr->ds) { 462*82657471SMarkus Pfeiffer sysv_print("msqptr != &msqpptr->ds"); 463*82657471SMarkus Pfeiffer exit(-1); 464*82657471SMarkus Pfeiffer } 465*82657471SMarkus Pfeiffer 466*82657471SMarkus Pfeiffer } else { 467*82657471SMarkus Pfeiffer sysv_print("got all the resources that we need\n"); 468*82657471SMarkus Pfeiffer break; 469*82657471SMarkus Pfeiffer } 470*82657471SMarkus Pfeiffer } 471*82657471SMarkus Pfeiffer 472*82657471SMarkus Pfeiffer /* 473*82657471SMarkus Pfeiffer * We have the resources that we need. 474*82657471SMarkus Pfeiffer * Make sure! 475*82657471SMarkus Pfeiffer */ 476*82657471SMarkus Pfeiffer #if 0 477*82657471SMarkus Pfeiffer if (segs_needed > nfree_msgmaps) { 478*82657471SMarkus Pfeiffer sysv_print_err("segs_needed > nfree_msgmaps"); 479*82657471SMarkus Pfeiffer exit(-1); 480*82657471SMarkus Pfeiffer } 481*82657471SMarkus Pfeiffer #endif 482*82657471SMarkus Pfeiffer if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) { 483*82657471SMarkus Pfeiffer sysv_print_err("msgsz + msg_cbytes > msg_qbytes"); 484*82657471SMarkus Pfeiffer exit(-1); 485*82657471SMarkus Pfeiffer } 486*82657471SMarkus Pfeiffer 487*82657471SMarkus Pfeiffer /* 488*82657471SMarkus Pfeiffer * Allocate a message header 489*82657471SMarkus Pfeiffer */ 490*82657471SMarkus Pfeiffer msghdr = &msqpptr->msghdrs[msqpptr->free_msghdrs]; 491*82657471SMarkus Pfeiffer msqpptr->free_msghdrs = msghdr->msg_next; 492*82657471SMarkus Pfeiffer msghdr->msg_spot = -1; 493*82657471SMarkus Pfeiffer msghdr->msg_ts = msgsz; 494*82657471SMarkus Pfeiffer 495*82657471SMarkus Pfeiffer /* 496*82657471SMarkus Pfeiffer * Allocate space for the message 497*82657471SMarkus Pfeiffer */ 498*82657471SMarkus Pfeiffer while (segs_needed > 0) { 499*82657471SMarkus Pfeiffer next = msqpptr->free_msgmaps; 500*82657471SMarkus Pfeiffer if (next < 0 || next > msginfo.msgseg) { 501*82657471SMarkus Pfeiffer sysv_print_err("out of range free_msgmaps %d #1\n", next); 502*82657471SMarkus Pfeiffer exit(-1); 503*82657471SMarkus Pfeiffer } 504*82657471SMarkus Pfeiffer 505*82657471SMarkus Pfeiffer msqpptr->free_msgmaps = msqpptr->msgmaps[next].next; 506*82657471SMarkus Pfeiffer msqpptr->nfree_msgmaps--; 507*82657471SMarkus Pfeiffer msqpptr->msgmaps[next].next = msghdr->msg_spot; 508*82657471SMarkus Pfeiffer msghdr->msg_spot = next; 509*82657471SMarkus Pfeiffer segs_needed--; 510*82657471SMarkus Pfeiffer } 511*82657471SMarkus Pfeiffer 512*82657471SMarkus Pfeiffer /* 513*82657471SMarkus Pfeiffer * Copy in the message type 514*82657471SMarkus Pfeiffer */ 515*82657471SMarkus Pfeiffer memcpy(&msghdr->msg_type, auxmsgp, sizeof(msghdr->msg_type)); 516*82657471SMarkus Pfeiffer auxmsgp = (char *)auxmsgp + sizeof(msghdr->msg_type); 517*82657471SMarkus Pfeiffer 518*82657471SMarkus Pfeiffer /* 519*82657471SMarkus Pfeiffer * Validate the message type 520*82657471SMarkus Pfeiffer */ 521*82657471SMarkus Pfeiffer sysv_print("msg_type = %ld\n", msghdr->msg_type); 522*82657471SMarkus Pfeiffer 523*82657471SMarkus Pfeiffer if (msghdr->msg_type < 1) { 524*82657471SMarkus Pfeiffer msg_freehdr(msqpptr, msghdr); 525*82657471SMarkus Pfeiffer umtx_wakeup((int *)&msqpptr->gen, 0); 526*82657471SMarkus Pfeiffer sysv_print_err("mtype (%ld) < 1\n", msghdr->msg_type); 527*82657471SMarkus Pfeiffer errno = EINVAL; 528*82657471SMarkus Pfeiffer goto done; 529*82657471SMarkus Pfeiffer } 530*82657471SMarkus Pfeiffer 531*82657471SMarkus Pfeiffer /* 532*82657471SMarkus Pfeiffer * Copy in the message body 533*82657471SMarkus Pfeiffer */ 534*82657471SMarkus Pfeiffer next = msghdr->msg_spot; 535*82657471SMarkus Pfeiffer while (msgsz > 0) { 536*82657471SMarkus Pfeiffer size_t tlen; 537*82657471SMarkus Pfeiffer if (msgsz > (size_t)msginfo.msgssz) 538*82657471SMarkus Pfeiffer tlen = msginfo.msgssz; 539*82657471SMarkus Pfeiffer else 540*82657471SMarkus Pfeiffer tlen = msgsz; 541*82657471SMarkus Pfeiffer if (next < 0 || next > msginfo.msgseg) { 542*82657471SMarkus Pfeiffer sysv_print_err("out of range free_msgmaps %d #2\n", next); 543*82657471SMarkus Pfeiffer exit(-1); 544*82657471SMarkus Pfeiffer } 545*82657471SMarkus Pfeiffer 546*82657471SMarkus Pfeiffer memcpy(&msqpptr->msgpool[next * msginfo.msgssz], auxmsgp, tlen); 547*82657471SMarkus Pfeiffer msgsz -= tlen; 548*82657471SMarkus Pfeiffer auxmsgp = (char *)auxmsgp + tlen; 549*82657471SMarkus Pfeiffer next = msqpptr->msgmaps[next].next; 550*82657471SMarkus Pfeiffer } 551*82657471SMarkus Pfeiffer 552*82657471SMarkus Pfeiffer /* 553*82657471SMarkus Pfeiffer * Put the message into the queue 554*82657471SMarkus Pfeiffer */ 555*82657471SMarkus Pfeiffer _index = (msghdr - &msqpptr->msghdrs[0]) / 556*82657471SMarkus Pfeiffer sizeof(struct msg); 557*82657471SMarkus Pfeiffer sysv_print("index_msghdr = %d\n", _index); 558*82657471SMarkus Pfeiffer if (msqptr->first.msg_first_index == -1) { 559*82657471SMarkus Pfeiffer msqptr->first.msg_first_index = _index; 560*82657471SMarkus Pfeiffer msqptr->last.msg_last_index = _index; 561*82657471SMarkus Pfeiffer } else { 562*82657471SMarkus Pfeiffer msqpptr->msghdrs[msqptr->last.msg_last_index].msg_next = _index; 563*82657471SMarkus Pfeiffer msqptr->last.msg_last_index = _index; 564*82657471SMarkus Pfeiffer } 565*82657471SMarkus Pfeiffer msqpptr->msghdrs[msqptr->last.msg_last_index].msg_next = -1; 566*82657471SMarkus Pfeiffer 567*82657471SMarkus Pfeiffer msqptr->msg_cbytes += msghdr->msg_ts; 568*82657471SMarkus Pfeiffer msqptr->msg_qnum++; 569*82657471SMarkus Pfeiffer msqptr->msg_lspid = getpid(); 570*82657471SMarkus Pfeiffer msqptr->msg_stime = time(NULL); 571*82657471SMarkus Pfeiffer 572*82657471SMarkus Pfeiffer umtx_wakeup((int *)&msqpptr->gen, 0); 573*82657471SMarkus Pfeiffer error = 0; 574*82657471SMarkus Pfeiffer 575*82657471SMarkus Pfeiffer done: 576*82657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr); 577*82657471SMarkus Pfeiffer put_shmdata(msqid); 578*82657471SMarkus Pfeiffer return(error); 579*82657471SMarkus Pfeiffer } 580*82657471SMarkus Pfeiffer 581*82657471SMarkus Pfeiffer int 582*82657471SMarkus Pfeiffer sysvipc_msgrcv(int msqid, void *msgp, size_t msgsz, long mtype, int msgflg) 583*82657471SMarkus Pfeiffer { 584*82657471SMarkus Pfeiffer size_t len; 585*82657471SMarkus Pfeiffer struct msqid_pool *msqpptr, *auxmsqpptr; 586*82657471SMarkus Pfeiffer struct msqid_ds_internal *msqptr; 587*82657471SMarkus Pfeiffer struct msg *msghdr; 588*82657471SMarkus Pfeiffer short msghdr_index; 589*82657471SMarkus Pfeiffer int error; 590*82657471SMarkus Pfeiffer short next; 591*82657471SMarkus Pfeiffer int val_to_sleep; 592*82657471SMarkus Pfeiffer char *auxmsgp = (char *)msgp; 593*82657471SMarkus Pfeiffer 594*82657471SMarkus Pfeiffer sysv_print("call to msgrcv(%d, %ld, %ld, %d)\n", msqid, msgsz, mtype, msgflg); 595*82657471SMarkus Pfeiffer /* 596*82657471SMarkus Pfeiffer if (!jail_sysvipc_allowed && td->td_ucred->cr_prison != NULL) 597*82657471SMarkus Pfeiffer return (ENOSYS); 598*82657471SMarkus Pfeiffer */ 599*82657471SMarkus Pfeiffer 600*82657471SMarkus Pfeiffer if (!msgp) { 601*82657471SMarkus Pfeiffer errno = EINVAL; 602*82657471SMarkus Pfeiffer return -1; 603*82657471SMarkus Pfeiffer } 604*82657471SMarkus Pfeiffer 605*82657471SMarkus Pfeiffer msqpptr = get_msqpptr(msqid, 0, IPC_R); 606*82657471SMarkus Pfeiffer if (!msqpptr) { 607*82657471SMarkus Pfeiffer errno = EINVAL; 608*82657471SMarkus Pfeiffer return -1; 609*82657471SMarkus Pfeiffer } 610*82657471SMarkus Pfeiffer 611*82657471SMarkus Pfeiffer error = -1; 612*82657471SMarkus Pfeiffer 613*82657471SMarkus Pfeiffer if (try_rwlock_wrlock(msqid, msqpptr) == -1) { 614*82657471SMarkus Pfeiffer errno = EIDRM; 615*82657471SMarkus Pfeiffer goto done; 616*82657471SMarkus Pfeiffer } 617*82657471SMarkus Pfeiffer 618*82657471SMarkus Pfeiffer msqptr = &msqpptr->ds; 619*82657471SMarkus Pfeiffer 620*82657471SMarkus Pfeiffer msghdr_index = -1; 621*82657471SMarkus Pfeiffer while (msghdr_index == -1) { 622*82657471SMarkus Pfeiffer if (mtype == 0) { 623*82657471SMarkus Pfeiffer msghdr_index = msqptr->first.msg_first_index; 624*82657471SMarkus Pfeiffer msghdr = &msqpptr->msghdrs[msghdr_index]; 625*82657471SMarkus Pfeiffer if (msghdr_index != -1) { 626*82657471SMarkus Pfeiffer if (msgsz < msghdr->msg_ts && 627*82657471SMarkus Pfeiffer (msgflg & MSG_NOERROR) == 0) { 628*82657471SMarkus Pfeiffer sysv_print_err("first message on the queue is too big" 629*82657471SMarkus Pfeiffer "(want %d, got %d)\n", 630*82657471SMarkus Pfeiffer msgsz, msghdr->msg_ts); 631*82657471SMarkus Pfeiffer errno = E2BIG; 632*82657471SMarkus Pfeiffer goto done; 633*82657471SMarkus Pfeiffer } 634*82657471SMarkus Pfeiffer if (msqptr->first.msg_first_index == msqptr->last.msg_last_index) { 635*82657471SMarkus Pfeiffer msqptr->first.msg_first_index = -1; 636*82657471SMarkus Pfeiffer msqptr->last.msg_last_index = -1; 637*82657471SMarkus Pfeiffer } else { 638*82657471SMarkus Pfeiffer msqptr->first.msg_first_index = msghdr->msg_next; 639*82657471SMarkus Pfeiffer if (msqptr->first.msg_first_index == -1) { 640*82657471SMarkus Pfeiffer sysv_print_err("first.msg_first_index/last screwed up #1"); 641*82657471SMarkus Pfeiffer exit(-1); 642*82657471SMarkus Pfeiffer } 643*82657471SMarkus Pfeiffer } 644*82657471SMarkus Pfeiffer } 645*82657471SMarkus Pfeiffer } else { 646*82657471SMarkus Pfeiffer short previous; 647*82657471SMarkus Pfeiffer short prev; 648*82657471SMarkus Pfeiffer previous = -1; 649*82657471SMarkus Pfeiffer prev = msqptr->first.msg_first_index; 650*82657471SMarkus Pfeiffer while ((msghdr_index = prev) != -1) { 651*82657471SMarkus Pfeiffer msghdr = &msqpptr->msghdrs[msghdr_index]; 652*82657471SMarkus Pfeiffer /* 653*82657471SMarkus Pfeiffer * Is this message's type an exact match or is 654*82657471SMarkus Pfeiffer * this message's type less than or equal to 655*82657471SMarkus Pfeiffer * the absolute value of a negative mtype? 656*82657471SMarkus Pfeiffer * Note that the second half of this test can 657*82657471SMarkus Pfeiffer * NEVER be true if mtype is positive since 658*82657471SMarkus Pfeiffer * msg_type is always positive! 659*82657471SMarkus Pfeiffer */ 660*82657471SMarkus Pfeiffer if (mtype == msghdr->msg_type || 661*82657471SMarkus Pfeiffer msghdr->msg_type <= -mtype) { 662*82657471SMarkus Pfeiffer sysv_print("found message type %d, requested %d\n", 663*82657471SMarkus Pfeiffer msghdr->msg_type, mtype); 664*82657471SMarkus Pfeiffer if (msgsz < msghdr->msg_ts && 665*82657471SMarkus Pfeiffer (msgflg & MSG_NOERROR) == 0) { 666*82657471SMarkus Pfeiffer sysv_print_err("requested message on the queue" 667*82657471SMarkus Pfeiffer " is too big (want %d, got %d)\n", 668*82657471SMarkus Pfeiffer msgsz, msghdr->msg_ts); 669*82657471SMarkus Pfeiffer errno = E2BIG; 670*82657471SMarkus Pfeiffer goto done; 671*82657471SMarkus Pfeiffer } 672*82657471SMarkus Pfeiffer prev = msghdr->msg_next; 673*82657471SMarkus Pfeiffer if (msghdr_index == msqptr->last.msg_last_index) { 674*82657471SMarkus Pfeiffer if (previous == -1) { 675*82657471SMarkus Pfeiffer msqptr->first.msg_first_index = -1; 676*82657471SMarkus Pfeiffer msqptr->last.msg_last_index = -1; 677*82657471SMarkus Pfeiffer } else { 678*82657471SMarkus Pfeiffer msqptr->last.msg_last_index = previous; 679*82657471SMarkus Pfeiffer } 680*82657471SMarkus Pfeiffer } 681*82657471SMarkus Pfeiffer break; 682*82657471SMarkus Pfeiffer } 683*82657471SMarkus Pfeiffer previous = msghdr_index; 684*82657471SMarkus Pfeiffer prev = msghdr->msg_next; 685*82657471SMarkus Pfeiffer } 686*82657471SMarkus Pfeiffer } 687*82657471SMarkus Pfeiffer 688*82657471SMarkus Pfeiffer /* 689*82657471SMarkus Pfeiffer * We've either extracted the msghdr for the appropriate 690*82657471SMarkus Pfeiffer * message or there isn't one. 691*82657471SMarkus Pfeiffer * If there is one then bail out of this loop. 692*82657471SMarkus Pfeiffer */ 693*82657471SMarkus Pfeiffer if (msghdr_index != -1) 694*82657471SMarkus Pfeiffer break; 695*82657471SMarkus Pfeiffer 696*82657471SMarkus Pfeiffer /* 697*82657471SMarkus Pfeiffer * No message found. Does the user want to wait? 698*82657471SMarkus Pfeiffer */ 699*82657471SMarkus Pfeiffer if ((msgflg & IPC_NOWAIT) != 0) { 700*82657471SMarkus Pfeiffer sysv_print_err("no appropriate message found (mtype=%d)\n", 701*82657471SMarkus Pfeiffer mtype); 702*82657471SMarkus Pfeiffer errno = ENOMSG; 703*82657471SMarkus Pfeiffer goto done; 704*82657471SMarkus Pfeiffer } 705*82657471SMarkus Pfeiffer 706*82657471SMarkus Pfeiffer /* 707*82657471SMarkus Pfeiffer * Wait for something to happen 708*82657471SMarkus Pfeiffer */ 709*82657471SMarkus Pfeiffer sysv_print("goodnight\n"); 710*82657471SMarkus Pfeiffer val_to_sleep = msqpptr->gen; 711*82657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr); 712*82657471SMarkus Pfeiffer put_shmdata(msqid); 713*82657471SMarkus Pfeiffer 714*82657471SMarkus Pfeiffer /* We don't sleep more than SYSV_TIMEOUT because we could 715*82657471SMarkus Pfeiffer * go to sleep after another process calls wakeup and remain 716*82657471SMarkus Pfeiffer * blocked. 717*82657471SMarkus Pfeiffer */ 718*82657471SMarkus Pfeiffer if (umtx_sleep((int *)&msqpptr->gen, val_to_sleep, SYSV_TIMEOUT) != 0) { 719*82657471SMarkus Pfeiffer sysv_print_err("msgrcv: interrupted system call\n"); 720*82657471SMarkus Pfeiffer errno = EINTR; 721*82657471SMarkus Pfeiffer goto done; 722*82657471SMarkus Pfeiffer } 723*82657471SMarkus Pfeiffer sysv_print("msgrcv: good morning (error=%d)\n", errno); 724*82657471SMarkus Pfeiffer 725*82657471SMarkus Pfeiffer /* Check if another thread didn't remove the msg queue. */ 726*82657471SMarkus Pfeiffer auxmsqpptr = get_msqpptr(msqid, 0, IPC_R); 727*82657471SMarkus Pfeiffer if (!auxmsqpptr) { 728*82657471SMarkus Pfeiffer errno = EIDRM; 729*82657471SMarkus Pfeiffer return -1; 730*82657471SMarkus Pfeiffer } 731*82657471SMarkus Pfeiffer 732*82657471SMarkus Pfeiffer if (auxmsqpptr != msqpptr) { 733*82657471SMarkus Pfeiffer errno = EIDRM; 734*82657471SMarkus Pfeiffer goto done; 735*82657471SMarkus Pfeiffer } 736*82657471SMarkus Pfeiffer 737*82657471SMarkus Pfeiffer /* Check if another process didn't remove the msg queue. */ 738*82657471SMarkus Pfeiffer if (try_rwlock_wrlock(msqid, msqpptr) == -1) { 739*82657471SMarkus Pfeiffer errno = EIDRM; 740*82657471SMarkus Pfeiffer goto done; 741*82657471SMarkus Pfeiffer } 742*82657471SMarkus Pfeiffer 743*82657471SMarkus Pfeiffer if (msqptr != &msqpptr->ds) { 744*82657471SMarkus Pfeiffer sysv_print_err("msqptr != &msqpptr->ds"); 745*82657471SMarkus Pfeiffer exit(-1); 746*82657471SMarkus Pfeiffer } 747*82657471SMarkus Pfeiffer } 748*82657471SMarkus Pfeiffer 749*82657471SMarkus Pfeiffer /* 750*82657471SMarkus Pfeiffer * Return the message to the user. 751*82657471SMarkus Pfeiffer */ 752*82657471SMarkus Pfeiffer msqptr->msg_cbytes -= msghdr->msg_ts; 753*82657471SMarkus Pfeiffer msqptr->msg_qnum--; 754*82657471SMarkus Pfeiffer msqptr->msg_lrpid = getpid(); 755*82657471SMarkus Pfeiffer msqptr->msg_rtime = time(NULL); 756*82657471SMarkus Pfeiffer 757*82657471SMarkus Pfeiffer /* 758*82657471SMarkus Pfeiffer * Make msgsz the actual amount that we'll be returning. 759*82657471SMarkus Pfeiffer * Note that this effectively truncates the message if it is too long 760*82657471SMarkus Pfeiffer * (since msgsz is never increased). 761*82657471SMarkus Pfeiffer */ 762*82657471SMarkus Pfeiffer sysv_print("found a message, msgsz=%d, msg_ts=%d\n", msgsz, 763*82657471SMarkus Pfeiffer msghdr->msg_ts); 764*82657471SMarkus Pfeiffer if (msgsz > msghdr->msg_ts) 765*82657471SMarkus Pfeiffer msgsz = msghdr->msg_ts; 766*82657471SMarkus Pfeiffer 767*82657471SMarkus Pfeiffer /* 768*82657471SMarkus Pfeiffer * Return the type to the user. 769*82657471SMarkus Pfeiffer */ 770*82657471SMarkus Pfeiffer memcpy(auxmsgp, (caddr_t)&(msghdr->msg_type), sizeof(msghdr->msg_type)); 771*82657471SMarkus Pfeiffer auxmsgp = (char *)auxmsgp + sizeof(msghdr->msg_type); 772*82657471SMarkus Pfeiffer 773*82657471SMarkus Pfeiffer /* 774*82657471SMarkus Pfeiffer * Return the segments to the user 775*82657471SMarkus Pfeiffer */ 776*82657471SMarkus Pfeiffer next = msghdr->msg_spot; 777*82657471SMarkus Pfeiffer for (len = 0; len < msgsz; len += msginfo.msgssz) { 778*82657471SMarkus Pfeiffer size_t tlen; 779*82657471SMarkus Pfeiffer 780*82657471SMarkus Pfeiffer if (msgsz - len > (size_t)msginfo.msgssz) 781*82657471SMarkus Pfeiffer tlen = msginfo.msgssz; 782*82657471SMarkus Pfeiffer else 783*82657471SMarkus Pfeiffer tlen = msgsz - len; 784*82657471SMarkus Pfeiffer if (next < 0 || next > msginfo.msgseg) { 785*82657471SMarkus Pfeiffer sysv_print_err("out of range free_msgmaps %d #3\n", next); 786*82657471SMarkus Pfeiffer exit(-1); 787*82657471SMarkus Pfeiffer } 788*82657471SMarkus Pfeiffer 789*82657471SMarkus Pfeiffer memcpy(auxmsgp, (caddr_t)&msqpptr->msgpool[next * msginfo.msgssz], tlen); 790*82657471SMarkus Pfeiffer auxmsgp = (char *)auxmsgp + tlen; 791*82657471SMarkus Pfeiffer next = msqpptr->msgmaps[next].next; 792*82657471SMarkus Pfeiffer } 793*82657471SMarkus Pfeiffer 794*82657471SMarkus Pfeiffer /* 795*82657471SMarkus Pfeiffer * Done, return the actual number of bytes copied out. 796*82657471SMarkus Pfeiffer */ 797*82657471SMarkus Pfeiffer msg_freehdr(msqpptr, msghdr); 798*82657471SMarkus Pfeiffer umtx_wakeup((int *)&msqpptr->gen, 0); 799*82657471SMarkus Pfeiffer error = msgsz; 800*82657471SMarkus Pfeiffer done: 801*82657471SMarkus Pfeiffer rwlock_unlock(msqid, msqpptr); 802*82657471SMarkus Pfeiffer put_shmdata(msqid); 803*82657471SMarkus Pfeiffer return(error); 804*82657471SMarkus Pfeiffer } 805