xref: /illumos-gate/usr/src/lib/libc/port/rt/mqueue.c (revision a574db851cdc636fc3939b68e80d79fe7fbd57f2)
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