1/*
2 * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of any co-contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD$
30 */
31
32#include "namespace.h"
33#include <sys/param.h>
34#include <sys/types.h>
35#include <sys/signalvar.h>
36#include <errno.h>
37#include <signal.h>
38#include <string.h>
39#include <pthread.h>
40#include "un-namespace.h"
41#include "thr_private.h"
42
43__weak_reference(_pthread_sigmask, pthread_sigmask);
44
45int
46_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
47{
48	struct pthread *curthread = _get_curthread();
49	sigset_t oldset, newset;
50	int ret;
51
52	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
53		ret = __sys_sigprocmask(how, set, oset);
54		if (ret != 0)
55			ret = errno;
56		/* Get a fresh copy */
57		__sys_sigprocmask(SIG_SETMASK, NULL, &curthread->sigmask);
58		return (ret);
59	}
60
61	if (set)
62		newset = *set;
63
64	THR_SCHED_LOCK(curthread, curthread);
65
66	ret = 0;
67	if (oset != NULL)
68		/* Return the current mask: */
69		oldset = curthread->sigmask;
70
71	/* Check if a new signal set was provided by the caller: */
72	if (set != NULL) {
73		/* Process according to what to do: */
74		switch (how) {
75		/* Block signals: */
76		case SIG_BLOCK:
77			/* Add signals to the existing mask: */
78			SIGSETOR(curthread->sigmask, newset);
79			break;
80
81		/* Unblock signals: */
82		case SIG_UNBLOCK:
83			/* Clear signals from the existing mask: */
84			SIGSETNAND(curthread->sigmask, newset);
85			break;
86
87		/* Set the signal process mask: */
88		case SIG_SETMASK:
89			/* Set the new mask: */
90			curthread->sigmask = newset;
91			break;
92
93		/* Trap invalid actions: */
94		default:
95			/* Return an invalid argument: */
96			ret = EINVAL;
97			break;
98		}
99		SIG_CANTMASK(curthread->sigmask);
100		THR_SCHED_UNLOCK(curthread, curthread);
101
102		/*
103		 * Run down any pending signals:
104		 */
105		if (ret == 0)
106		    _thr_sig_check_pending(curthread);
107	} else
108		THR_SCHED_UNLOCK(curthread, curthread);
109
110	if (ret == 0 && oset != NULL)
111		*oset = oldset;
112	return (ret);
113}
114