17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 534709573Sraf * Common Development and Distribution License (the "License"). 634709573Sraf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21e8031f0aSraf 227c478bd9Sstevel@tonic-gate /* 23*a574db85Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #pragma weak mq_open = _mq_open 307c478bd9Sstevel@tonic-gate #pragma weak mq_close = _mq_close 317c478bd9Sstevel@tonic-gate #pragma weak mq_unlink = _mq_unlink 327c478bd9Sstevel@tonic-gate #pragma weak mq_send = _mq_send 337c478bd9Sstevel@tonic-gate #pragma weak mq_timedsend = _mq_timedsend 347c478bd9Sstevel@tonic-gate #pragma weak mq_reltimedsend_np = _mq_reltimedsend_np 357c478bd9Sstevel@tonic-gate #pragma weak mq_receive = _mq_receive 367c478bd9Sstevel@tonic-gate #pragma weak mq_timedreceive = _mq_timedreceive 377c478bd9Sstevel@tonic-gate #pragma weak mq_reltimedreceive_np = _mq_reltimedreceive_np 387c478bd9Sstevel@tonic-gate #pragma weak mq_notify = _mq_notify 397c478bd9Sstevel@tonic-gate #pragma weak mq_setattr = _mq_setattr 407c478bd9Sstevel@tonic-gate #pragma weak mq_getattr = _mq_getattr 417c478bd9Sstevel@tonic-gate 42f841f6adSraf #include "synonyms.h" 43f841f6adSraf #include "mtlib.h" 447c478bd9Sstevel@tonic-gate #define _KMEMUSER 457c478bd9Sstevel@tonic-gate #include <sys/param.h> /* _MQ_OPEN_MAX, _MQ_PRIO_MAX, _SEM_VALUE_MAX */ 467c478bd9Sstevel@tonic-gate #undef _KMEMUSER 477c478bd9Sstevel@tonic-gate #include <mqueue.h> 487c478bd9Sstevel@tonic-gate #include <sys/types.h> 497c478bd9Sstevel@tonic-gate #include <sys/file.h> 507c478bd9Sstevel@tonic-gate #include <sys/mman.h> 517c478bd9Sstevel@tonic-gate #include <errno.h> 527c478bd9Sstevel@tonic-gate #include <stdarg.h> 537c478bd9Sstevel@tonic-gate #include <limits.h> 547c478bd9Sstevel@tonic-gate #include <pthread.h> 557c478bd9Sstevel@tonic-gate #include <assert.h> 567c478bd9Sstevel@tonic-gate #include <string.h> 577c478bd9Sstevel@tonic-gate #include <unistd.h> 587c478bd9Sstevel@tonic-gate #include <stdlib.h> 597c478bd9Sstevel@tonic-gate #include <sys/stat.h> 607c478bd9Sstevel@tonic-gate #include <inttypes.h> 61f841f6adSraf #include "sigev_thread.h" 627c478bd9Sstevel@tonic-gate #include "pos4obj.h" 63f841f6adSraf 64f841f6adSraf /* 65f841f6adSraf * Default values per message queue 66f841f6adSraf */ 67f841f6adSraf #define MQ_MAXMSG 128 68f841f6adSraf #define MQ_MAXSIZE 1024 69f841f6adSraf 70f841f6adSraf #define MQ_MAGIC 0x4d534751 /* "MSGQ" */ 71f841f6adSraf 72f841f6adSraf /* 73f841f6adSraf * Message header which is part of messages in link list 74f841f6adSraf */ 75f841f6adSraf typedef struct { 76f841f6adSraf uint64_t msg_next; /* offset of next message in the link */ 77f841f6adSraf uint64_t msg_len; /* length of the message */ 78f841f6adSraf } msghdr_t; 79f841f6adSraf 80f841f6adSraf /* 81f841f6adSraf * message queue description 82f841f6adSraf */ 83f841f6adSraf struct mq_dn { 84f841f6adSraf size_t mqdn_flags; /* open description flags */ 85f841f6adSraf }; 86f841f6adSraf 87f841f6adSraf /* 88f841f6adSraf * message queue descriptor structure 89f841f6adSraf */ 90f841f6adSraf typedef struct mq_des { 91f841f6adSraf struct mq_des *mqd_next; /* list of all open mq descriptors, */ 92f841f6adSraf struct mq_des *mqd_prev; /* needed for fork-safety */ 93f841f6adSraf int mqd_magic; /* magic # to identify mq_des */ 94f841f6adSraf int mqd_flags; /* operation flag per open */ 95f841f6adSraf struct mq_header *mqd_mq; /* address pointer of message Q */ 96f841f6adSraf struct mq_dn *mqd_mqdn; /* open description */ 97f841f6adSraf thread_communication_data_t *mqd_tcd; /* SIGEV_THREAD notification */ 98f841f6adSraf } mqdes_t; 99f841f6adSraf 100f841f6adSraf /* 101f841f6adSraf * message queue common header, part of the mmap()ed file. 102f841f6adSraf * Since message queues may be shared between 32- and 64-bit processes, 103f841f6adSraf * care must be taken to make sure that the elements of this structure 104f841f6adSraf * are identical for both _LP64 and _ILP32 cases. 105f841f6adSraf */ 106f841f6adSraf typedef struct mq_header { 107f841f6adSraf /* first field must be mq_totsize, DO NOT insert before this */ 108f841f6adSraf int64_t mq_totsize; /* total size of the Queue */ 109f841f6adSraf int64_t mq_maxsz; /* max size of each message */ 110f841f6adSraf uint32_t mq_maxmsg; /* max messages in the queue */ 111f841f6adSraf uint32_t mq_maxprio; /* maximum mqueue priority */ 112f841f6adSraf uint32_t mq_curmaxprio; /* current maximum MQ priority */ 113f841f6adSraf uint32_t mq_mask; /* priority bitmask */ 114f841f6adSraf uint64_t mq_freep; /* free message's head pointer */ 115f841f6adSraf uint64_t mq_headpp; /* pointer to head pointers */ 116f841f6adSraf uint64_t mq_tailpp; /* pointer to tail pointers */ 117f841f6adSraf signotify_id_t mq_sigid; /* notification id (3 int's) */ 118f841f6adSraf uint32_t mq_ntype; /* notification type (SIGEV_*) */ 119f841f6adSraf uint64_t mq_des; /* pointer to msg Q descriptor */ 120f841f6adSraf mutex_t mq_exclusive; /* acquire for exclusive access */ 121f841f6adSraf sem_t mq_rblocked; /* number of processes rblocked */ 122f841f6adSraf sem_t mq_notfull; /* mq_send()'s block on this */ 123f841f6adSraf sem_t mq_notempty; /* mq_receive()'s block on this */ 124f841f6adSraf sem_t mq_spawner; /* spawner thread blocks on this */ 125f841f6adSraf } mqhdr_t; 1267c478bd9Sstevel@tonic-gate 12706a502e8Scasper /* 12806a502e8Scasper * The code assumes that _MQ_OPEN_MAX == -1 or "no fixed implementation limit". 12906a502e8Scasper * If this assumption is somehow invalidated, mq_open() needs to be changed 13006a502e8Scasper * back to the old version which kept a count and enforced a limit. 13106a502e8Scasper * We make sure that this is pointed out to those changing <sys/param.h> 13206a502e8Scasper * by checking _MQ_OPEN_MAX at compile time. 13306a502e8Scasper */ 13406a502e8Scasper #if _MQ_OPEN_MAX != -1 135f841f6adSraf #error "mq_open() no longer enforces _MQ_OPEN_MAX and needs fixing." 13606a502e8Scasper #endif 13706a502e8Scasper 1387c478bd9Sstevel@tonic-gate #define MQ_ALIGNSIZE 8 /* 64-bit alignment */ 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate #ifdef DEBUG 141f841f6adSraf #define MQ_ASSERT(x) assert(x); 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate #define MQ_ASSERT_PTR(_m, _p) \ 1447c478bd9Sstevel@tonic-gate assert((_p) != NULL && !((uintptr_t)(_p) & (MQ_ALIGNSIZE -1)) && \ 1457c478bd9Sstevel@tonic-gate !((uintptr_t)_m + (uintptr_t)(_p) >= (uintptr_t)_m + \ 1467c478bd9Sstevel@tonic-gate _m->mq_totsize)); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate #define MQ_ASSERT_SEMVAL_LEQ(sem, val) { \ 1497c478bd9Sstevel@tonic-gate int _val; \ 1507c478bd9Sstevel@tonic-gate (void) sem_getvalue((sem), &_val); \ 1517c478bd9Sstevel@tonic-gate assert((_val) <= val); } 1527c478bd9Sstevel@tonic-gate #else 1537c478bd9Sstevel@tonic-gate #define MQ_ASSERT(x) 1547c478bd9Sstevel@tonic-gate #define MQ_ASSERT_PTR(_m, _p) 1557c478bd9Sstevel@tonic-gate #define MQ_ASSERT_SEMVAL_LEQ(sem, val) 1567c478bd9Sstevel@tonic-gate #endif 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate #define MQ_PTR(m, n) ((msghdr_t *)((uintptr_t)m + (uintptr_t)n)) 1597c478bd9Sstevel@tonic-gate #define HEAD_PTR(m, n) ((uint64_t *)((uintptr_t)m + \ 1607c478bd9Sstevel@tonic-gate (uintptr_t)m->mq_headpp + n * sizeof (uint64_t))) 1617c478bd9Sstevel@tonic-gate #define TAIL_PTR(m, n) ((uint64_t *)((uintptr_t)m + \ 1627c478bd9Sstevel@tonic-gate (uintptr_t)m->mq_tailpp + n * sizeof (uint64_t))) 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate #define MQ_RESERVED ((mqdes_t *)-1) 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate #define ABS_TIME 0 1677c478bd9Sstevel@tonic-gate #define REL_TIME 1 1687c478bd9Sstevel@tonic-gate 169f841f6adSraf static mutex_t mq_list_lock = DEFAULTMUTEX; 170f841f6adSraf static mqdes_t *mq_list = NULL; 171f841f6adSraf 172f841f6adSraf extern int __signotify(int cmd, siginfo_t *sigonfo, signotify_id_t *sn_id); 17334709573Sraf 1747c478bd9Sstevel@tonic-gate static int 1757c478bd9Sstevel@tonic-gate mq_is_valid(mqdes_t *mqdp) 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate /* 17806a502e8Scasper * Any use of a message queue after it was closed is 17906a502e8Scasper * undefined. But the standard strongly favours EBADF 18006a502e8Scasper * returns. Before we dereference which could be fatal, 18106a502e8Scasper * we first do some pointer sanity checks. 1827c478bd9Sstevel@tonic-gate */ 18306a502e8Scasper if (mqdp != NULL && mqdp != MQ_RESERVED && 18406a502e8Scasper ((uintptr_t)mqdp & 0x7) == 0) { 18506a502e8Scasper return (mqdp->mqd_magic == MQ_MAGIC); 1867c478bd9Sstevel@tonic-gate } 18706a502e8Scasper 1887c478bd9Sstevel@tonic-gate return (0); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate static void 1927c478bd9Sstevel@tonic-gate mq_init(mqhdr_t *mqhp, size_t msgsize, ssize_t maxmsg) 1937c478bd9Sstevel@tonic-gate { 1947c478bd9Sstevel@tonic-gate int i; 1957c478bd9Sstevel@tonic-gate uint64_t temp; 1967c478bd9Sstevel@tonic-gate uint64_t currentp; 1977c478bd9Sstevel@tonic-gate uint64_t nextp; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * We only need to initialize the non-zero fields. The use of 2017c478bd9Sstevel@tonic-gate * ftruncate() on the message queue file assures that the 2027c478bd9Sstevel@tonic-gate * pages will be zfod. 2037c478bd9Sstevel@tonic-gate */ 20434709573Sraf (void) mutex_init(&mqhp->mq_exclusive, USYNC_PROCESS, NULL); 2057c478bd9Sstevel@tonic-gate (void) sem_init(&mqhp->mq_rblocked, 1, 0); 2067c478bd9Sstevel@tonic-gate (void) sem_init(&mqhp->mq_notempty, 1, 0); 20734709573Sraf (void) sem_init(&mqhp->mq_spawner, 1, 0); 2087c478bd9Sstevel@tonic-gate (void) sem_init(&mqhp->mq_notfull, 1, (uint_t)maxmsg); 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate mqhp->mq_maxsz = msgsize; 2117c478bd9Sstevel@tonic-gate mqhp->mq_maxmsg = maxmsg; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate * As of this writing (1997), there are 32 message queue priorities. 21534709573Sraf * If this is to change, then the size of the mq_mask will 21634709573Sraf * also have to change. If DEBUG is defined, assert that 2177c478bd9Sstevel@tonic-gate * _MQ_PRIO_MAX hasn't changed. 2187c478bd9Sstevel@tonic-gate */ 2197c478bd9Sstevel@tonic-gate mqhp->mq_maxprio = _MQ_PRIO_MAX; 22034709573Sraf #if defined(DEBUG) 22134709573Sraf /* LINTED always true */ 2227c478bd9Sstevel@tonic-gate MQ_ASSERT(sizeof (mqhp->mq_mask) * 8 >= _MQ_PRIO_MAX); 22334709573Sraf #endif 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* 2267c478bd9Sstevel@tonic-gate * Since the message queue can be mapped into different 2277c478bd9Sstevel@tonic-gate * virtual address ranges by different processes, we don't 2287c478bd9Sstevel@tonic-gate * keep track of pointers, only offsets into the shared region. 2297c478bd9Sstevel@tonic-gate */ 2307c478bd9Sstevel@tonic-gate mqhp->mq_headpp = sizeof (mqhdr_t); 2317c478bd9Sstevel@tonic-gate mqhp->mq_tailpp = mqhp->mq_headpp + 232*a574db85Sraf mqhp->mq_maxprio * sizeof (uint64_t); 2337c478bd9Sstevel@tonic-gate mqhp->mq_freep = mqhp->mq_tailpp + 234*a574db85Sraf mqhp->mq_maxprio * sizeof (uint64_t); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate currentp = mqhp->mq_freep; 2377c478bd9Sstevel@tonic-gate MQ_PTR(mqhp, currentp)->msg_next = 0; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate temp = (mqhp->mq_maxsz + MQ_ALIGNSIZE - 1) & ~(MQ_ALIGNSIZE - 1); 2407c478bd9Sstevel@tonic-gate for (i = 1; i < mqhp->mq_maxmsg; i++) { 2417c478bd9Sstevel@tonic-gate nextp = currentp + sizeof (msghdr_t) + temp; 2427c478bd9Sstevel@tonic-gate MQ_PTR(mqhp, currentp)->msg_next = nextp; 2437c478bd9Sstevel@tonic-gate MQ_PTR(mqhp, nextp)->msg_next = 0; 2447c478bd9Sstevel@tonic-gate currentp = nextp; 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate static size_t 2497c478bd9Sstevel@tonic-gate mq_getmsg(mqhdr_t *mqhp, char *msgp, uint_t *msg_prio) 2507c478bd9Sstevel@tonic-gate { 2517c478bd9Sstevel@tonic-gate uint64_t currentp; 2527c478bd9Sstevel@tonic-gate msghdr_t *curbuf; 2537c478bd9Sstevel@tonic-gate uint64_t *headpp; 2547c478bd9Sstevel@tonic-gate uint64_t *tailpp; 2557c478bd9Sstevel@tonic-gate 25634709573Sraf MQ_ASSERT(MUTEX_HELD(&mqhp->mq_exclusive)); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate * Get the head and tail pointers for the queue of maximum 2607c478bd9Sstevel@tonic-gate * priority. We shouldn't be here unless there is a message for 2617c478bd9Sstevel@tonic-gate * us, so it's fair to assert that both the head and tail 2627c478bd9Sstevel@tonic-gate * pointers are non-NULL. 2637c478bd9Sstevel@tonic-gate */ 2647c478bd9Sstevel@tonic-gate headpp = HEAD_PTR(mqhp, mqhp->mq_curmaxprio); 2657c478bd9Sstevel@tonic-gate tailpp = TAIL_PTR(mqhp, mqhp->mq_curmaxprio); 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate if (msg_prio != NULL) 2687c478bd9Sstevel@tonic-gate *msg_prio = mqhp->mq_curmaxprio; 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate currentp = *headpp; 2717c478bd9Sstevel@tonic-gate MQ_ASSERT_PTR(mqhp, currentp); 2727c478bd9Sstevel@tonic-gate curbuf = MQ_PTR(mqhp, currentp); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate if ((*headpp = curbuf->msg_next) == NULL) { 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * We just nuked the last message in this priority's queue. 2777c478bd9Sstevel@tonic-gate * Twiddle this priority's bit, and then find the next bit 2787c478bd9Sstevel@tonic-gate * tipped. 2797c478bd9Sstevel@tonic-gate */ 2807c478bd9Sstevel@tonic-gate uint_t prio = mqhp->mq_curmaxprio; 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate mqhp->mq_mask &= ~(1u << prio); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate for (; prio != 0; prio--) 2857c478bd9Sstevel@tonic-gate if (mqhp->mq_mask & (1u << prio)) 2867c478bd9Sstevel@tonic-gate break; 2877c478bd9Sstevel@tonic-gate mqhp->mq_curmaxprio = prio; 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate *tailpp = NULL; 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate /* 2937c478bd9Sstevel@tonic-gate * Copy the message, and put the buffer back on the free list. 2947c478bd9Sstevel@tonic-gate */ 2957c478bd9Sstevel@tonic-gate (void) memcpy(msgp, (char *)&curbuf[1], curbuf->msg_len); 2967c478bd9Sstevel@tonic-gate curbuf->msg_next = mqhp->mq_freep; 2977c478bd9Sstevel@tonic-gate mqhp->mq_freep = currentp; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate return (curbuf->msg_len); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate static void 3047c478bd9Sstevel@tonic-gate mq_putmsg(mqhdr_t *mqhp, const char *msgp, ssize_t len, uint_t prio) 3057c478bd9Sstevel@tonic-gate { 3067c478bd9Sstevel@tonic-gate uint64_t currentp; 3077c478bd9Sstevel@tonic-gate msghdr_t *curbuf; 3087c478bd9Sstevel@tonic-gate uint64_t *headpp; 3097c478bd9Sstevel@tonic-gate uint64_t *tailpp; 3107c478bd9Sstevel@tonic-gate 31134709573Sraf MQ_ASSERT(MUTEX_HELD(&mqhp->mq_exclusive)); 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate /* 3147c478bd9Sstevel@tonic-gate * Grab a free message block, and link it in. We shouldn't 3157c478bd9Sstevel@tonic-gate * be here unless there is room in the queue for us; it's 3167c478bd9Sstevel@tonic-gate * fair to assert that the free pointer is non-NULL. 3177c478bd9Sstevel@tonic-gate */ 3187c478bd9Sstevel@tonic-gate currentp = mqhp->mq_freep; 3197c478bd9Sstevel@tonic-gate MQ_ASSERT_PTR(mqhp, currentp); 3207c478bd9Sstevel@tonic-gate curbuf = MQ_PTR(mqhp, currentp); 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate /* 3237c478bd9Sstevel@tonic-gate * Remove a message from the free list, and copy in the new contents. 3247c478bd9Sstevel@tonic-gate */ 3257c478bd9Sstevel@tonic-gate mqhp->mq_freep = curbuf->msg_next; 3267c478bd9Sstevel@tonic-gate curbuf->msg_next = NULL; 3277c478bd9Sstevel@tonic-gate (void) memcpy((char *)&curbuf[1], msgp, len); 3287c478bd9Sstevel@tonic-gate curbuf->msg_len = len; 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate headpp = HEAD_PTR(mqhp, prio); 3317c478bd9Sstevel@tonic-gate tailpp = TAIL_PTR(mqhp, prio); 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate if (*tailpp == 0) { 3347c478bd9Sstevel@tonic-gate /* 3357c478bd9Sstevel@tonic-gate * This is the first message on this queue. Set the 3367c478bd9Sstevel@tonic-gate * head and tail pointers, and tip the appropriate bit 3377c478bd9Sstevel@tonic-gate * in the priority mask. 3387c478bd9Sstevel@tonic-gate */ 3397c478bd9Sstevel@tonic-gate *headpp = currentp; 3407c478bd9Sstevel@tonic-gate *tailpp = currentp; 3417c478bd9Sstevel@tonic-gate mqhp->mq_mask |= (1u << prio); 3427c478bd9Sstevel@tonic-gate if (prio > mqhp->mq_curmaxprio) 3437c478bd9Sstevel@tonic-gate mqhp->mq_curmaxprio = prio; 3447c478bd9Sstevel@tonic-gate } else { 3457c478bd9Sstevel@tonic-gate MQ_ASSERT_PTR(mqhp, *tailpp); 3467c478bd9Sstevel@tonic-gate MQ_PTR(mqhp, *tailpp)->msg_next = currentp; 3477c478bd9Sstevel@tonic-gate *tailpp = currentp; 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate mqd_t 3527c478bd9Sstevel@tonic-gate _mq_open(const char *path, int oflag, /* mode_t mode, mq_attr *attr */ ...) 3537c478bd9Sstevel@tonic-gate { 3547c478bd9Sstevel@tonic-gate va_list ap; 3557c478bd9Sstevel@tonic-gate mode_t mode; 3567c478bd9Sstevel@tonic-gate struct mq_attr *attr; 3577c478bd9Sstevel@tonic-gate int fd; 3587c478bd9Sstevel@tonic-gate int err; 3597c478bd9Sstevel@tonic-gate int cr_flag = 0; 3607c478bd9Sstevel@tonic-gate int locked = 0; 3617c478bd9Sstevel@tonic-gate uint64_t total_size; 3627c478bd9Sstevel@tonic-gate size_t msgsize; 3637c478bd9Sstevel@tonic-gate ssize_t maxmsg; 3647c478bd9Sstevel@tonic-gate uint64_t temp; 3657c478bd9Sstevel@tonic-gate void *ptr; 3667c478bd9Sstevel@tonic-gate mqdes_t *mqdp; 3677c478bd9Sstevel@tonic-gate mqhdr_t *mqhp; 3687c478bd9Sstevel@tonic-gate struct mq_dn *mqdnp; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate if (__pos4obj_check(path) == -1) 3717c478bd9Sstevel@tonic-gate return ((mqd_t)-1); 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate /* acquire MSGQ lock to have atomic operation */ 3747c478bd9Sstevel@tonic-gate if (__pos4obj_lock(path, MQ_LOCK_TYPE) < 0) 3757c478bd9Sstevel@tonic-gate goto out; 3767c478bd9Sstevel@tonic-gate locked = 1; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate va_start(ap, oflag); 3797c478bd9Sstevel@tonic-gate /* filter oflag to have READ/WRITE/CREATE modes only */ 3807c478bd9Sstevel@tonic-gate oflag = oflag & (O_RDONLY|O_WRONLY|O_RDWR|O_CREAT|O_EXCL|O_NONBLOCK); 3817c478bd9Sstevel@tonic-gate if ((oflag & O_CREAT) != 0) { 3827c478bd9Sstevel@tonic-gate mode = va_arg(ap, mode_t); 3837c478bd9Sstevel@tonic-gate attr = va_arg(ap, struct mq_attr *); 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate va_end(ap); 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate if ((fd = __pos4obj_open(path, MQ_PERM_TYPE, oflag, 3887c478bd9Sstevel@tonic-gate mode, &cr_flag)) < 0) 3897c478bd9Sstevel@tonic-gate goto out; 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate /* closing permission file */ 3927c478bd9Sstevel@tonic-gate (void) __close_nc(fd); 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* Try to open/create data file */ 3957c478bd9Sstevel@tonic-gate if (cr_flag) { 3967c478bd9Sstevel@tonic-gate cr_flag = PFILE_CREATE; 3977c478bd9Sstevel@tonic-gate if (attr == NULL) { 3987c478bd9Sstevel@tonic-gate maxmsg = MQ_MAXMSG; 3997c478bd9Sstevel@tonic-gate msgsize = MQ_MAXSIZE; 4007c478bd9Sstevel@tonic-gate } else if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0) { 4017c478bd9Sstevel@tonic-gate errno = EINVAL; 4027c478bd9Sstevel@tonic-gate goto out; 4037c478bd9Sstevel@tonic-gate } else if (attr->mq_maxmsg > _SEM_VALUE_MAX) { 4047c478bd9Sstevel@tonic-gate errno = ENOSPC; 4057c478bd9Sstevel@tonic-gate goto out; 4067c478bd9Sstevel@tonic-gate } else { 4077c478bd9Sstevel@tonic-gate maxmsg = attr->mq_maxmsg; 4087c478bd9Sstevel@tonic-gate msgsize = attr->mq_msgsize; 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* adjust for message size at word boundary */ 4127c478bd9Sstevel@tonic-gate temp = (msgsize + MQ_ALIGNSIZE - 1) & ~(MQ_ALIGNSIZE - 1); 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate total_size = sizeof (mqhdr_t) + 415*a574db85Sraf maxmsg * (temp + sizeof (msghdr_t)) + 416*a574db85Sraf 2 * _MQ_PRIO_MAX * sizeof (uint64_t); 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate if (total_size > SSIZE_MAX) { 4197c478bd9Sstevel@tonic-gate errno = ENOSPC; 4207c478bd9Sstevel@tonic-gate goto out; 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate /* 4247c478bd9Sstevel@tonic-gate * data file is opened with read/write to those 4257c478bd9Sstevel@tonic-gate * who have read or write permission 4267c478bd9Sstevel@tonic-gate */ 4277c478bd9Sstevel@tonic-gate mode = mode | (mode & 0444) >> 1 | (mode & 0222) << 1; 4287c478bd9Sstevel@tonic-gate if ((fd = __pos4obj_open(path, MQ_DATA_TYPE, 4297c478bd9Sstevel@tonic-gate (O_RDWR|O_CREAT|O_EXCL), mode, &err)) < 0) 4307c478bd9Sstevel@tonic-gate goto out; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate cr_flag |= DFILE_CREATE | DFILE_OPEN; 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* force permissions to avoid umask effect */ 4357c478bd9Sstevel@tonic-gate if (fchmod(fd, mode) < 0) 4367c478bd9Sstevel@tonic-gate goto out; 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate if (ftruncate64(fd, (off64_t)total_size) < 0) 4397c478bd9Sstevel@tonic-gate goto out; 4407c478bd9Sstevel@tonic-gate } else { 4417c478bd9Sstevel@tonic-gate if ((fd = __pos4obj_open(path, MQ_DATA_TYPE, 4427c478bd9Sstevel@tonic-gate O_RDWR, 0666, &err)) < 0) 4437c478bd9Sstevel@tonic-gate goto out; 4447c478bd9Sstevel@tonic-gate cr_flag = DFILE_OPEN; 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* Message queue has not been initialized yet */ 4477c478bd9Sstevel@tonic-gate if (read(fd, &total_size, sizeof (total_size)) != 4487c478bd9Sstevel@tonic-gate sizeof (total_size) || total_size == 0) { 4497c478bd9Sstevel@tonic-gate errno = ENOENT; 4507c478bd9Sstevel@tonic-gate goto out; 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate /* Message queue too big for this process to handle */ 4547c478bd9Sstevel@tonic-gate if (total_size > SSIZE_MAX) { 4557c478bd9Sstevel@tonic-gate errno = EFBIG; 4567c478bd9Sstevel@tonic-gate goto out; 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate if ((mqdp = (mqdes_t *)malloc(sizeof (mqdes_t))) == NULL) { 4617c478bd9Sstevel@tonic-gate errno = ENOMEM; 4627c478bd9Sstevel@tonic-gate goto out; 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate cr_flag |= ALLOC_MEM; 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate if ((ptr = mmap64(NULL, total_size, PROT_READ|PROT_WRITE, 4677c478bd9Sstevel@tonic-gate MAP_SHARED, fd, (off64_t)0)) == MAP_FAILED) 4687c478bd9Sstevel@tonic-gate goto out; 4697c478bd9Sstevel@tonic-gate mqhp = ptr; 4707c478bd9Sstevel@tonic-gate cr_flag |= DFILE_MMAP; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate /* closing data file */ 4737c478bd9Sstevel@tonic-gate (void) __close_nc(fd); 4747c478bd9Sstevel@tonic-gate cr_flag &= ~DFILE_OPEN; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate /* 4777c478bd9Sstevel@tonic-gate * create, unlink, size, mmap, and close description file 4787c478bd9Sstevel@tonic-gate * all for a flag word in anonymous shared memory 4797c478bd9Sstevel@tonic-gate */ 4807c478bd9Sstevel@tonic-gate if ((fd = __pos4obj_open(path, MQ_DSCN_TYPE, O_RDWR | O_CREAT, 4817c478bd9Sstevel@tonic-gate 0666, &err)) < 0) 4827c478bd9Sstevel@tonic-gate goto out; 4837c478bd9Sstevel@tonic-gate cr_flag |= DFILE_OPEN; 4847c478bd9Sstevel@tonic-gate (void) __pos4obj_unlink(path, MQ_DSCN_TYPE); 4857c478bd9Sstevel@tonic-gate if (ftruncate64(fd, (off64_t)sizeof (struct mq_dn)) < 0) 4867c478bd9Sstevel@tonic-gate goto out; 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate if ((ptr = mmap64(NULL, sizeof (struct mq_dn), 4897c478bd9Sstevel@tonic-gate PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off64_t)0)) == MAP_FAILED) 4907c478bd9Sstevel@tonic-gate goto out; 4917c478bd9Sstevel@tonic-gate mqdnp = ptr; 4927c478bd9Sstevel@tonic-gate cr_flag |= MQDNP_MMAP; 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate (void) __close_nc(fd); 4957c478bd9Sstevel@tonic-gate cr_flag &= ~DFILE_OPEN; 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate /* 4987c478bd9Sstevel@tonic-gate * we follow the same strategy as filesystem open() routine, 4997c478bd9Sstevel@tonic-gate * where fcntl.h flags are changed to flags defined in file.h. 5007c478bd9Sstevel@tonic-gate */ 5017c478bd9Sstevel@tonic-gate mqdp->mqd_flags = (oflag - FOPEN) & (FREAD|FWRITE); 5027c478bd9Sstevel@tonic-gate mqdnp->mqdn_flags = (oflag - FOPEN) & (FNONBLOCK); 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate /* new message queue requires initialization */ 5057c478bd9Sstevel@tonic-gate if ((cr_flag & DFILE_CREATE) != 0) { 5067c478bd9Sstevel@tonic-gate /* message queue header has to be initialized */ 5077c478bd9Sstevel@tonic-gate mq_init(mqhp, msgsize, maxmsg); 5087c478bd9Sstevel@tonic-gate mqhp->mq_totsize = total_size; 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate mqdp->mqd_mq = mqhp; 5117c478bd9Sstevel@tonic-gate mqdp->mqd_mqdn = mqdnp; 5127c478bd9Sstevel@tonic-gate mqdp->mqd_magic = MQ_MAGIC; 51334709573Sraf mqdp->mqd_tcd = NULL; 51434709573Sraf if (__pos4obj_unlock(path, MQ_LOCK_TYPE) == 0) { 515f841f6adSraf lmutex_lock(&mq_list_lock); 51634709573Sraf mqdp->mqd_next = mq_list; 51734709573Sraf mqdp->mqd_prev = NULL; 51834709573Sraf if (mq_list) 51934709573Sraf mq_list->mqd_prev = mqdp; 52034709573Sraf mq_list = mqdp; 521f841f6adSraf lmutex_unlock(&mq_list_lock); 5227c478bd9Sstevel@tonic-gate return ((mqd_t)mqdp); 52334709573Sraf } 52406a502e8Scasper 5257c478bd9Sstevel@tonic-gate locked = 0; /* fall into the error case */ 5267c478bd9Sstevel@tonic-gate out: 5277c478bd9Sstevel@tonic-gate err = errno; 5287c478bd9Sstevel@tonic-gate if ((cr_flag & DFILE_OPEN) != 0) 5297c478bd9Sstevel@tonic-gate (void) __close_nc(fd); 5307c478bd9Sstevel@tonic-gate if ((cr_flag & DFILE_CREATE) != 0) 5317c478bd9Sstevel@tonic-gate (void) __pos4obj_unlink(path, MQ_DATA_TYPE); 5327c478bd9Sstevel@tonic-gate if ((cr_flag & PFILE_CREATE) != 0) 5337c478bd9Sstevel@tonic-gate (void) __pos4obj_unlink(path, MQ_PERM_TYPE); 5347c478bd9Sstevel@tonic-gate if ((cr_flag & ALLOC_MEM) != 0) 5357c478bd9Sstevel@tonic-gate free((void *)mqdp); 5367c478bd9Sstevel@tonic-gate if ((cr_flag & DFILE_MMAP) != 0) 5377c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)mqhp, (size_t)total_size); 5387c478bd9Sstevel@tonic-gate if ((cr_flag & MQDNP_MMAP) != 0) 5397c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)mqdnp, sizeof (struct mq_dn)); 5407c478bd9Sstevel@tonic-gate if (locked) 5417c478bd9Sstevel@tonic-gate (void) __pos4obj_unlock(path, MQ_LOCK_TYPE); 5427c478bd9Sstevel@tonic-gate errno = err; 5437c478bd9Sstevel@tonic-gate return ((mqd_t)-1); 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate 546f841f6adSraf static void 547f841f6adSraf mq_close_cleanup(mqdes_t *mqdp) 548f841f6adSraf { 549f841f6adSraf mqhdr_t *mqhp = mqdp->mqd_mq; 550f841f6adSraf struct mq_dn *mqdnp = mqdp->mqd_mqdn; 551f841f6adSraf 552f841f6adSraf /* invalidate the descriptor before freeing it */ 553f841f6adSraf mqdp->mqd_magic = 0; 554f841f6adSraf (void) mutex_unlock(&mqhp->mq_exclusive); 555f841f6adSraf 556f841f6adSraf lmutex_lock(&mq_list_lock); 557f841f6adSraf if (mqdp->mqd_next) 558f841f6adSraf mqdp->mqd_next->mqd_prev = mqdp->mqd_prev; 559f841f6adSraf if (mqdp->mqd_prev) 560f841f6adSraf mqdp->mqd_prev->mqd_next = mqdp->mqd_next; 561f841f6adSraf if (mq_list == mqdp) 562f841f6adSraf mq_list = mqdp->mqd_next; 563f841f6adSraf lmutex_unlock(&mq_list_lock); 564f841f6adSraf 565f841f6adSraf free(mqdp); 566f841f6adSraf (void) munmap((caddr_t)mqdnp, sizeof (struct mq_dn)); 567f841f6adSraf (void) munmap((caddr_t)mqhp, (size_t)mqhp->mq_totsize); 568f841f6adSraf } 569f841f6adSraf 5707c478bd9Sstevel@tonic-gate int 5717c478bd9Sstevel@tonic-gate _mq_close(mqd_t mqdes) 5727c478bd9Sstevel@tonic-gate { 5737c478bd9Sstevel@tonic-gate mqdes_t *mqdp = (mqdes_t *)mqdes; 5747c478bd9Sstevel@tonic-gate mqhdr_t *mqhp; 57534709573Sraf thread_communication_data_t *tcdp; 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate if (!mq_is_valid(mqdp)) { 5787c478bd9Sstevel@tonic-gate errno = EBADF; 5797c478bd9Sstevel@tonic-gate return (-1); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate mqhp = mqdp->mqd_mq; 58334709573Sraf (void) mutex_lock(&mqhp->mq_exclusive); 584f841f6adSraf 5857c478bd9Sstevel@tonic-gate if (mqhp->mq_des == (uintptr_t)mqdp && 5867c478bd9Sstevel@tonic-gate mqhp->mq_sigid.sn_pid == getpid()) { 58734709573Sraf /* notification is set for this descriptor, remove it */ 5887c478bd9Sstevel@tonic-gate (void) __signotify(SN_CANCEL, NULL, &mqhp->mq_sigid); 58934709573Sraf mqhp->mq_ntype = 0; 5907c478bd9Sstevel@tonic-gate mqhp->mq_des = 0; 5917c478bd9Sstevel@tonic-gate } 592f841f6adSraf 593f841f6adSraf pthread_cleanup_push(mq_close_cleanup, mqdp); 59434709573Sraf if ((tcdp = mqdp->mqd_tcd) != NULL) { 59534709573Sraf mqdp->mqd_tcd = NULL; 596f841f6adSraf del_sigev_mq(tcdp); /* possible cancellation point */ 59734709573Sraf } 598f841f6adSraf pthread_cleanup_pop(1); /* finish in the cleanup handler */ 5997c478bd9Sstevel@tonic-gate 600f841f6adSraf return (0); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate int 6047c478bd9Sstevel@tonic-gate _mq_unlink(const char *path) 6057c478bd9Sstevel@tonic-gate { 6067c478bd9Sstevel@tonic-gate int err; 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate if (__pos4obj_check(path) < 0) 6097c478bd9Sstevel@tonic-gate return (-1); 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate if (__pos4obj_lock(path, MQ_LOCK_TYPE) < 0) { 6127c478bd9Sstevel@tonic-gate return (-1); 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate err = __pos4obj_unlink(path, MQ_PERM_TYPE); 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate if (err == 0 || (err == -1 && errno == EEXIST)) { 6187c478bd9Sstevel@tonic-gate errno = 0; 6197c478bd9Sstevel@tonic-gate err = __pos4obj_unlink(path, MQ_DATA_TYPE); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate if (__pos4obj_unlock(path, MQ_LOCK_TYPE) < 0) 6237c478bd9Sstevel@tonic-gate return (-1); 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate return (err); 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate static int 6307c478bd9Sstevel@tonic-gate __mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, 6317c478bd9Sstevel@tonic-gate uint_t msg_prio, const timespec_t *timeout, int abs_rel) 6327c478bd9Sstevel@tonic-gate { 6337c478bd9Sstevel@tonic-gate mqdes_t *mqdp = (mqdes_t *)mqdes; 6347c478bd9Sstevel@tonic-gate mqhdr_t *mqhp; 6357c478bd9Sstevel@tonic-gate int err; 6367c478bd9Sstevel@tonic-gate int notify = 0; 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate /* 6397c478bd9Sstevel@tonic-gate * sem_*wait() does cancellation, if called. 6407c478bd9Sstevel@tonic-gate * pthread_testcancel() ensures that cancellation takes place if 6417c478bd9Sstevel@tonic-gate * there is a cancellation pending when mq_*send() is called. 6427c478bd9Sstevel@tonic-gate */ 6437c478bd9Sstevel@tonic-gate pthread_testcancel(); 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate if (!mq_is_valid(mqdp) || (mqdp->mqd_flags & FWRITE) == 0) { 6467c478bd9Sstevel@tonic-gate errno = EBADF; 6477c478bd9Sstevel@tonic-gate return (-1); 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate mqhp = mqdp->mqd_mq; 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate if (msg_prio >= mqhp->mq_maxprio) { 6537c478bd9Sstevel@tonic-gate errno = EINVAL; 6547c478bd9Sstevel@tonic-gate return (-1); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate if (msg_len > mqhp->mq_maxsz) { 6577c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 6587c478bd9Sstevel@tonic-gate return (-1); 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate 66134709573Sraf if (mqdp->mqd_mqdn->mqdn_flags & O_NONBLOCK) 6627c478bd9Sstevel@tonic-gate err = sem_trywait(&mqhp->mq_notfull); 6637c478bd9Sstevel@tonic-gate else { 6647c478bd9Sstevel@tonic-gate /* 6657c478bd9Sstevel@tonic-gate * We might get cancelled here... 6667c478bd9Sstevel@tonic-gate */ 6677c478bd9Sstevel@tonic-gate if (timeout == NULL) 6687c478bd9Sstevel@tonic-gate err = sem_wait(&mqhp->mq_notfull); 6697c478bd9Sstevel@tonic-gate else if (abs_rel == ABS_TIME) 6707c478bd9Sstevel@tonic-gate err = sem_timedwait(&mqhp->mq_notfull, timeout); 6717c478bd9Sstevel@tonic-gate else 6727c478bd9Sstevel@tonic-gate err = sem_reltimedwait_np(&mqhp->mq_notfull, timeout); 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate if (err == -1) { 6757c478bd9Sstevel@tonic-gate /* 6767c478bd9Sstevel@tonic-gate * errno has been set to EAGAIN / EINTR / ETIMEDOUT 6777c478bd9Sstevel@tonic-gate * by sem_*wait(), so we can just return. 6787c478bd9Sstevel@tonic-gate */ 6797c478bd9Sstevel@tonic-gate return (-1); 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate /* 6837c478bd9Sstevel@tonic-gate * By the time we're here, we know that we've got the capacity 6847c478bd9Sstevel@tonic-gate * to add to the queue...now acquire the exclusive lock. 6857c478bd9Sstevel@tonic-gate */ 68634709573Sraf (void) mutex_lock(&mqhp->mq_exclusive); 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate /* 6897c478bd9Sstevel@tonic-gate * Now determine if we want to kick the notification. POSIX 6907c478bd9Sstevel@tonic-gate * requires that if a process has registered for notification, 6917c478bd9Sstevel@tonic-gate * we must kick it when the queue makes an empty to non-empty 6927c478bd9Sstevel@tonic-gate * transition, and there are no blocked receivers. Note that 6937c478bd9Sstevel@tonic-gate * this mechanism does _not_ guarantee that the kicked process 69434709573Sraf * will be able to receive a message without blocking; 69534709573Sraf * another receiver could intervene in the meantime. Thus, 69634709573Sraf * the notification mechanism is inherently racy; all we can 69734709573Sraf * do is hope to minimize the window as much as possible. 69834709573Sraf * In general, we want to avoid kicking the notification when 69934709573Sraf * there are clearly receivers blocked. We'll determine if 70034709573Sraf * we want to kick the notification before the mq_putmsg(), 70134709573Sraf * but the actual signotify() won't be done until the message 70234709573Sraf * is on the queue. 7037c478bd9Sstevel@tonic-gate */ 7047c478bd9Sstevel@tonic-gate if (mqhp->mq_sigid.sn_pid != 0) { 7057c478bd9Sstevel@tonic-gate int nmessages, nblocked; 70634709573Sraf 7077c478bd9Sstevel@tonic-gate (void) sem_getvalue(&mqhp->mq_notempty, &nmessages); 7087c478bd9Sstevel@tonic-gate (void) sem_getvalue(&mqhp->mq_rblocked, &nblocked); 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate if (nmessages == 0 && nblocked == 0) 7117c478bd9Sstevel@tonic-gate notify = 1; 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate mq_putmsg(mqhp, msg_ptr, (ssize_t)msg_len, msg_prio); 7157c478bd9Sstevel@tonic-gate (void) sem_post(&mqhp->mq_notempty); 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate if (notify) { 71834709573Sraf /* notify and also delete the registration */ 7197c478bd9Sstevel@tonic-gate (void) __signotify(SN_SEND, NULL, &mqhp->mq_sigid); 72034709573Sraf if (mqhp->mq_ntype == SIGEV_THREAD || 72134709573Sraf mqhp->mq_ntype == SIGEV_PORT) 72234709573Sraf (void) sem_post(&mqhp->mq_spawner); 72334709573Sraf mqhp->mq_ntype = 0; 7247c478bd9Sstevel@tonic-gate mqhp->mq_des = 0; 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate MQ_ASSERT_SEMVAL_LEQ(&mqhp->mq_notempty, ((int)mqhp->mq_maxmsg)); 72834709573Sraf (void) mutex_unlock(&mqhp->mq_exclusive); 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate return (0); 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate int 7347c478bd9Sstevel@tonic-gate _mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, uint_t msg_prio) 7357c478bd9Sstevel@tonic-gate { 7367c478bd9Sstevel@tonic-gate return (__mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, 737*a574db85Sraf NULL, ABS_TIME)); 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate int 7417c478bd9Sstevel@tonic-gate _mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, 7427c478bd9Sstevel@tonic-gate uint_t msg_prio, const timespec_t *abs_timeout) 7437c478bd9Sstevel@tonic-gate { 7447c478bd9Sstevel@tonic-gate return (__mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, 745*a574db85Sraf abs_timeout, ABS_TIME)); 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate int 7497c478bd9Sstevel@tonic-gate _mq_reltimedsend_np(mqd_t mqdes, const char *msg_ptr, size_t msg_len, 7507c478bd9Sstevel@tonic-gate uint_t msg_prio, const timespec_t *rel_timeout) 7517c478bd9Sstevel@tonic-gate { 7527c478bd9Sstevel@tonic-gate return (__mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, 753*a574db85Sraf rel_timeout, REL_TIME)); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate static void 7577c478bd9Sstevel@tonic-gate decrement_rblocked(mqhdr_t *mqhp) 7587c478bd9Sstevel@tonic-gate { 759*a574db85Sraf int cancel_state; 7607c478bd9Sstevel@tonic-gate 761*a574db85Sraf (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); 7627c478bd9Sstevel@tonic-gate while (sem_wait(&mqhp->mq_rblocked) == -1) 7637c478bd9Sstevel@tonic-gate continue; 764*a574db85Sraf (void) pthread_setcancelstate(cancel_state, NULL); 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate static ssize_t 7687c478bd9Sstevel@tonic-gate __mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, 7697c478bd9Sstevel@tonic-gate uint_t *msg_prio, const timespec_t *timeout, int abs_rel) 7707c478bd9Sstevel@tonic-gate { 7717c478bd9Sstevel@tonic-gate mqdes_t *mqdp = (mqdes_t *)mqdes; 7727c478bd9Sstevel@tonic-gate mqhdr_t *mqhp; 7737c478bd9Sstevel@tonic-gate ssize_t msg_size; 7747c478bd9Sstevel@tonic-gate int err; 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate /* 7777c478bd9Sstevel@tonic-gate * sem_*wait() does cancellation, if called. 7787c478bd9Sstevel@tonic-gate * pthread_testcancel() ensures that cancellation takes place if 7797c478bd9Sstevel@tonic-gate * there is a cancellation pending when mq_*receive() is called. 7807c478bd9Sstevel@tonic-gate */ 7817c478bd9Sstevel@tonic-gate pthread_testcancel(); 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate if (!mq_is_valid(mqdp) || (mqdp->mqd_flags & FREAD) == 0) { 7847c478bd9Sstevel@tonic-gate errno = EBADF; 7857c478bd9Sstevel@tonic-gate return (ssize_t)(-1); 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate mqhp = mqdp->mqd_mq; 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate if (msg_len < mqhp->mq_maxsz) { 7917c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 7927c478bd9Sstevel@tonic-gate return (ssize_t)(-1); 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate /* 7967c478bd9Sstevel@tonic-gate * The semaphoring scheme for mq_[timed]receive is a little hairy 7977c478bd9Sstevel@tonic-gate * thanks to POSIX.1b's arcane notification mechanism. First, 7987c478bd9Sstevel@tonic-gate * we try to take the common case and do a sem_trywait(). 7997c478bd9Sstevel@tonic-gate * If that doesn't work, and O_NONBLOCK hasn't been set, 8007c478bd9Sstevel@tonic-gate * then note that we're going to sleep by incrementing the rblocked 8017c478bd9Sstevel@tonic-gate * semaphore. We decrement that semaphore after waking up. 8027c478bd9Sstevel@tonic-gate */ 8037c478bd9Sstevel@tonic-gate if (sem_trywait(&mqhp->mq_notempty) == -1) { 8047c478bd9Sstevel@tonic-gate if ((mqdp->mqd_mqdn->mqdn_flags & O_NONBLOCK) != 0) { 8057c478bd9Sstevel@tonic-gate /* 8067c478bd9Sstevel@tonic-gate * errno has been set to EAGAIN or EINTR by 8077c478bd9Sstevel@tonic-gate * sem_trywait(), so we can just return. 8087c478bd9Sstevel@tonic-gate */ 8097c478bd9Sstevel@tonic-gate return (-1); 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate /* 8127c478bd9Sstevel@tonic-gate * If we're here, then we're probably going to block... 8137c478bd9Sstevel@tonic-gate * increment the rblocked semaphore. If we get 8147c478bd9Sstevel@tonic-gate * cancelled, decrement_rblocked() will decrement it. 8157c478bd9Sstevel@tonic-gate */ 8167c478bd9Sstevel@tonic-gate (void) sem_post(&mqhp->mq_rblocked); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate pthread_cleanup_push(decrement_rblocked, mqhp); 8197c478bd9Sstevel@tonic-gate if (timeout == NULL) 8207c478bd9Sstevel@tonic-gate err = sem_wait(&mqhp->mq_notempty); 8217c478bd9Sstevel@tonic-gate else if (abs_rel == ABS_TIME) 8227c478bd9Sstevel@tonic-gate err = sem_timedwait(&mqhp->mq_notempty, timeout); 8237c478bd9Sstevel@tonic-gate else 8247c478bd9Sstevel@tonic-gate err = sem_reltimedwait_np(&mqhp->mq_notempty, timeout); 8257c478bd9Sstevel@tonic-gate pthread_cleanup_pop(1); 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate if (err == -1) { 8287c478bd9Sstevel@tonic-gate /* 8297c478bd9Sstevel@tonic-gate * We took a signal or timeout while waiting 8307c478bd9Sstevel@tonic-gate * on mq_notempty... 8317c478bd9Sstevel@tonic-gate */ 8327c478bd9Sstevel@tonic-gate return (-1); 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate 83634709573Sraf (void) mutex_lock(&mqhp->mq_exclusive); 8377c478bd9Sstevel@tonic-gate msg_size = mq_getmsg(mqhp, msg_ptr, msg_prio); 8387c478bd9Sstevel@tonic-gate (void) sem_post(&mqhp->mq_notfull); 8397c478bd9Sstevel@tonic-gate MQ_ASSERT_SEMVAL_LEQ(&mqhp->mq_notfull, ((int)mqhp->mq_maxmsg)); 84034709573Sraf (void) mutex_unlock(&mqhp->mq_exclusive); 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate return (msg_size); 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate ssize_t 8467c478bd9Sstevel@tonic-gate _mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, uint_t *msg_prio) 8477c478bd9Sstevel@tonic-gate { 8487c478bd9Sstevel@tonic-gate return (__mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, 849*a574db85Sraf NULL, ABS_TIME)); 8507c478bd9Sstevel@tonic-gate } 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate ssize_t 8537c478bd9Sstevel@tonic-gate _mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, 8547c478bd9Sstevel@tonic-gate uint_t *msg_prio, const timespec_t *abs_timeout) 8557c478bd9Sstevel@tonic-gate { 8567c478bd9Sstevel@tonic-gate return (__mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, 857*a574db85Sraf abs_timeout, ABS_TIME)); 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate ssize_t 8617c478bd9Sstevel@tonic-gate _mq_reltimedreceive_np(mqd_t mqdes, char *msg_ptr, size_t msg_len, 8627c478bd9Sstevel@tonic-gate uint_t *msg_prio, const timespec_t *rel_timeout) 8637c478bd9Sstevel@tonic-gate { 8647c478bd9Sstevel@tonic-gate return (__mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, 865*a574db85Sraf rel_timeout, REL_TIME)); 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate 86834709573Sraf /* 86934709573Sraf * Only used below, in _mq_notify(). 87034709573Sraf * We already have a spawner thread. 87134709573Sraf * Verify that the attributes match; cancel it if necessary. 87234709573Sraf */ 87334709573Sraf static int 87434709573Sraf cancel_if_necessary(thread_communication_data_t *tcdp, 87534709573Sraf const struct sigevent *sigevp) 87634709573Sraf { 87734709573Sraf int do_cancel = !_pthread_attr_equal(tcdp->tcd_attrp, 878*a574db85Sraf sigevp->sigev_notify_attributes); 87934709573Sraf 88034709573Sraf if (do_cancel) { 88134709573Sraf /* 88234709573Sraf * Attributes don't match, cancel the spawner thread. 88334709573Sraf */ 88434709573Sraf (void) pthread_cancel(tcdp->tcd_server_id); 88534709573Sraf } else { 88634709573Sraf /* 88734709573Sraf * Reuse the existing spawner thread with possibly 88834709573Sraf * changed notification function and value. 88934709573Sraf */ 89034709573Sraf tcdp->tcd_notif.sigev_notify = SIGEV_THREAD; 89134709573Sraf tcdp->tcd_notif.sigev_signo = 0; 89234709573Sraf tcdp->tcd_notif.sigev_value = sigevp->sigev_value; 89334709573Sraf tcdp->tcd_notif.sigev_notify_function = 894*a574db85Sraf sigevp->sigev_notify_function; 89534709573Sraf } 89634709573Sraf 89734709573Sraf return (do_cancel); 89834709573Sraf } 89934709573Sraf 9007c478bd9Sstevel@tonic-gate int 90134709573Sraf _mq_notify(mqd_t mqdes, const struct sigevent *sigevp) 9027c478bd9Sstevel@tonic-gate { 9037c478bd9Sstevel@tonic-gate mqdes_t *mqdp = (mqdes_t *)mqdes; 9047c478bd9Sstevel@tonic-gate mqhdr_t *mqhp; 90534709573Sraf thread_communication_data_t *tcdp; 9067c478bd9Sstevel@tonic-gate siginfo_t mq_siginfo; 90734709573Sraf struct sigevent sigevent; 90834709573Sraf struct stat64 statb; 90934709573Sraf port_notify_t *pn; 91034709573Sraf void *userval; 911f841f6adSraf int rval = -1; 91234709573Sraf int ntype; 91334709573Sraf int port; 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate if (!mq_is_valid(mqdp)) { 9167c478bd9Sstevel@tonic-gate errno = EBADF; 9177c478bd9Sstevel@tonic-gate return (-1); 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate mqhp = mqdp->mqd_mq; 9217c478bd9Sstevel@tonic-gate 92234709573Sraf (void) mutex_lock(&mqhp->mq_exclusive); 9237c478bd9Sstevel@tonic-gate 92434709573Sraf if (sigevp == NULL) { /* remove notification */ 9257c478bd9Sstevel@tonic-gate if (mqhp->mq_des == (uintptr_t)mqdp && 9267c478bd9Sstevel@tonic-gate mqhp->mq_sigid.sn_pid == getpid()) { 92734709573Sraf /* notification is set for this descriptor, remove it */ 9287c478bd9Sstevel@tonic-gate (void) __signotify(SN_CANCEL, NULL, &mqhp->mq_sigid); 92934709573Sraf if ((tcdp = mqdp->mqd_tcd) != NULL) { 930f841f6adSraf sig_mutex_lock(&tcdp->tcd_lock); 93134709573Sraf if (tcdp->tcd_msg_enabled) { 93234709573Sraf /* cancel the spawner thread */ 93334709573Sraf tcdp = mqdp->mqd_tcd; 93434709573Sraf mqdp->mqd_tcd = NULL; 93534709573Sraf (void) pthread_cancel( 93634709573Sraf tcdp->tcd_server_id); 93734709573Sraf } 938f841f6adSraf sig_mutex_unlock(&tcdp->tcd_lock); 93934709573Sraf } 94034709573Sraf mqhp->mq_ntype = 0; 9417c478bd9Sstevel@tonic-gate mqhp->mq_des = 0; 9427c478bd9Sstevel@tonic-gate } else { 94334709573Sraf /* notification is not set for this descriptor */ 9447c478bd9Sstevel@tonic-gate errno = EBUSY; 9457c478bd9Sstevel@tonic-gate goto bad; 9467c478bd9Sstevel@tonic-gate } 94734709573Sraf } else { /* register notification with this process */ 94834709573Sraf switch (ntype = sigevp->sigev_notify) { 94934709573Sraf case SIGEV_THREAD: 95034709573Sraf userval = sigevp->sigev_value.sival_ptr; 95134709573Sraf port = -1; 95234709573Sraf break; 95334709573Sraf case SIGEV_PORT: 95434709573Sraf pn = sigevp->sigev_value.sival_ptr; 95534709573Sraf userval = pn->portnfy_user; 95634709573Sraf port = pn->portnfy_port; 95734709573Sraf if (fstat64(port, &statb) != 0 || 95834709573Sraf !S_ISPORT(statb.st_mode)) { 95934709573Sraf errno = EBADF; 96034709573Sraf goto bad; 96134709573Sraf } 96234709573Sraf (void) memset(&sigevent, 0, sizeof (sigevent)); 96334709573Sraf sigevent.sigev_notify = SIGEV_PORT; 96434709573Sraf sigevp = &sigevent; 96534709573Sraf break; 96634709573Sraf } 96734709573Sraf switch (ntype) { 9687c478bd9Sstevel@tonic-gate case SIGEV_NONE: 9697c478bd9Sstevel@tonic-gate mq_siginfo.si_signo = 0; 9707c478bd9Sstevel@tonic-gate mq_siginfo.si_code = SI_MESGQ; 9717c478bd9Sstevel@tonic-gate break; 9727c478bd9Sstevel@tonic-gate case SIGEV_SIGNAL: 97334709573Sraf mq_siginfo.si_signo = sigevp->sigev_signo; 97434709573Sraf mq_siginfo.si_value = sigevp->sigev_value; 9757c478bd9Sstevel@tonic-gate mq_siginfo.si_code = SI_MESGQ; 9767c478bd9Sstevel@tonic-gate break; 9777c478bd9Sstevel@tonic-gate case SIGEV_THREAD: 97834709573Sraf if ((tcdp = mqdp->mqd_tcd) != NULL && 97934709573Sraf cancel_if_necessary(tcdp, sigevp)) 98034709573Sraf mqdp->mqd_tcd = NULL; 98134709573Sraf /* FALLTHROUGH */ 98234709573Sraf case SIGEV_PORT: 98334709573Sraf if ((tcdp = mqdp->mqd_tcd) == NULL) { 98434709573Sraf /* we must create a spawner thread */ 98534709573Sraf tcdp = setup_sigev_handler(sigevp, MQ); 98634709573Sraf if (tcdp == NULL) { 98734709573Sraf errno = EBADF; 98834709573Sraf goto bad; 98934709573Sraf } 99034709573Sraf tcdp->tcd_msg_enabled = 0; 99134709573Sraf tcdp->tcd_msg_closing = 0; 99234709573Sraf tcdp->tcd_msg_avail = &mqhp->mq_spawner; 99334709573Sraf if (launch_spawner(tcdp) != 0) { 99434709573Sraf free_sigev_handler(tcdp); 99534709573Sraf goto bad; 99634709573Sraf } 99734709573Sraf mqdp->mqd_tcd = tcdp; 99834709573Sraf } 99934709573Sraf mq_siginfo.si_signo = 0; 100034709573Sraf mq_siginfo.si_code = SI_MESGQ; 100134709573Sraf break; 10027c478bd9Sstevel@tonic-gate default: 10037c478bd9Sstevel@tonic-gate errno = EINVAL; 10047c478bd9Sstevel@tonic-gate goto bad; 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate 100734709573Sraf /* register notification */ 10087c478bd9Sstevel@tonic-gate if (__signotify(SN_PROC, &mq_siginfo, &mqhp->mq_sigid) < 0) 10097c478bd9Sstevel@tonic-gate goto bad; 101034709573Sraf mqhp->mq_ntype = ntype; 10117c478bd9Sstevel@tonic-gate mqhp->mq_des = (uintptr_t)mqdp; 101234709573Sraf switch (ntype) { 101334709573Sraf case SIGEV_THREAD: 101434709573Sraf case SIGEV_PORT: 101534709573Sraf tcdp->tcd_port = port; 101634709573Sraf tcdp->tcd_msg_object = mqdp; 101734709573Sraf tcdp->tcd_msg_userval = userval; 1018f841f6adSraf sig_mutex_lock(&tcdp->tcd_lock); 101934709573Sraf tcdp->tcd_msg_enabled = ntype; 1020f841f6adSraf sig_mutex_unlock(&tcdp->tcd_lock); 102134709573Sraf (void) cond_broadcast(&tcdp->tcd_cv); 102234709573Sraf break; 102334709573Sraf } 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate 1026f841f6adSraf rval = 0; /* success */ 10277c478bd9Sstevel@tonic-gate bad: 102834709573Sraf (void) mutex_unlock(&mqhp->mq_exclusive); 1029f841f6adSraf return (rval); 10307c478bd9Sstevel@tonic-gate } 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate int 10337c478bd9Sstevel@tonic-gate _mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat, struct mq_attr *omqstat) 10347c478bd9Sstevel@tonic-gate { 10357c478bd9Sstevel@tonic-gate mqdes_t *mqdp = (mqdes_t *)mqdes; 10367c478bd9Sstevel@tonic-gate mqhdr_t *mqhp; 10377c478bd9Sstevel@tonic-gate uint_t flag = 0; 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate if (!mq_is_valid(mqdp)) { 10407c478bd9Sstevel@tonic-gate errno = EBADF; 10417c478bd9Sstevel@tonic-gate return (-1); 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate /* store current attributes */ 10457c478bd9Sstevel@tonic-gate if (omqstat != NULL) { 10467c478bd9Sstevel@tonic-gate int count; 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate mqhp = mqdp->mqd_mq; 10497c478bd9Sstevel@tonic-gate omqstat->mq_flags = mqdp->mqd_mqdn->mqdn_flags; 10507c478bd9Sstevel@tonic-gate omqstat->mq_maxmsg = (long)mqhp->mq_maxmsg; 10517c478bd9Sstevel@tonic-gate omqstat->mq_msgsize = (long)mqhp->mq_maxsz; 10527c478bd9Sstevel@tonic-gate (void) sem_getvalue(&mqhp->mq_notempty, &count); 10537c478bd9Sstevel@tonic-gate omqstat->mq_curmsgs = count; 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate /* set description attributes */ 10577c478bd9Sstevel@tonic-gate if ((mqstat->mq_flags & O_NONBLOCK) != 0) 10587c478bd9Sstevel@tonic-gate flag = FNONBLOCK; 10597c478bd9Sstevel@tonic-gate mqdp->mqd_mqdn->mqdn_flags = flag; 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate return (0); 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate int 10657c478bd9Sstevel@tonic-gate _mq_getattr(mqd_t mqdes, struct mq_attr *mqstat) 10667c478bd9Sstevel@tonic-gate { 10677c478bd9Sstevel@tonic-gate mqdes_t *mqdp = (mqdes_t *)mqdes; 10687c478bd9Sstevel@tonic-gate mqhdr_t *mqhp; 10697c478bd9Sstevel@tonic-gate int count; 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate if (!mq_is_valid(mqdp)) { 10727c478bd9Sstevel@tonic-gate errno = EBADF; 10737c478bd9Sstevel@tonic-gate return (-1); 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate mqhp = mqdp->mqd_mq; 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate mqstat->mq_flags = mqdp->mqd_mqdn->mqdn_flags; 10797c478bd9Sstevel@tonic-gate mqstat->mq_maxmsg = (long)mqhp->mq_maxmsg; 10807c478bd9Sstevel@tonic-gate mqstat->mq_msgsize = (long)mqhp->mq_maxsz; 10817c478bd9Sstevel@tonic-gate (void) sem_getvalue(&mqhp->mq_notempty, &count); 10827c478bd9Sstevel@tonic-gate mqstat->mq_curmsgs = count; 10837c478bd9Sstevel@tonic-gate return (0); 10847c478bd9Sstevel@tonic-gate } 1085f841f6adSraf 1086f841f6adSraf /* 1087f841f6adSraf * Cleanup after fork1() in the child process. 1088f841f6adSraf */ 1089f841f6adSraf void 1090f841f6adSraf postfork1_child_sigev_mq(void) 1091f841f6adSraf { 1092f841f6adSraf thread_communication_data_t *tcdp; 1093f841f6adSraf mqdes_t *mqdp; 1094f841f6adSraf 1095f841f6adSraf for (mqdp = mq_list; mqdp; mqdp = mqdp->mqd_next) { 1096f841f6adSraf if ((tcdp = mqdp->mqd_tcd) != NULL) { 1097f841f6adSraf mqdp->mqd_tcd = NULL; 1098f841f6adSraf tcd_teardown(tcdp); 1099f841f6adSraf } 1100f841f6adSraf } 1101f841f6adSraf } 1102