1123974Sdavidxu/*-
2123974Sdavidxu * Copyright (c) 2003 David Xu <davidxu@freebsd.org>
3123974Sdavidxu * All rights reserved.
4123974Sdavidxu *
5123974Sdavidxu * Redistribution and use in source and binary forms, with or without
6123974Sdavidxu * modification, are permitted provided that the following conditions
7123974Sdavidxu * are met:
8123974Sdavidxu * 1. Redistributions of source code must retain the above copyright
9123974Sdavidxu *    notice, this list of conditions and the following disclaimer.
10123974Sdavidxu * 2. Redistributions in binary form must reproduce the above copyright
11123974Sdavidxu *    notice, this list of conditions and the following disclaimer in the
12123974Sdavidxu *    documentation and/or other materials provided with the distribution.
13123974Sdavidxu *
14123974Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15123974Sdavidxu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16123974Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17123974Sdavidxu * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18123974Sdavidxu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19123974Sdavidxu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20123974Sdavidxu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21123974Sdavidxu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22123974Sdavidxu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23123974Sdavidxu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24123974Sdavidxu * SUCH DAMAGE.
25123974Sdavidxu */
26123974Sdavidxu
27123974Sdavidxu#include <sys/cdefs.h>
28123974Sdavidxu__FBSDID("$FreeBSD$");
29123974Sdavidxu
30174112Sdeischen#include "namespace.h"
31123974Sdavidxu#include <errno.h>
32123974Sdavidxu#include <signal.h>
33174112Sdeischen#include "un-namespace.h"
34123974Sdavidxu#include "thr_private.h"
35123974Sdavidxu
36174112Sdeischenint	_sigaltstack(stack_t *_ss, stack_t *_oss);
37174112Sdeischen
38123974Sdavidxu__weak_reference(_sigaltstack, sigaltstack);
39123974Sdavidxu
40123974Sdavidxuint
41123974Sdavidxu_sigaltstack(stack_t *_ss, stack_t *_oss)
42123974Sdavidxu{
43123974Sdavidxu	struct pthread *curthread = _get_curthread();
44123974Sdavidxu	stack_t ss, oss;
45123974Sdavidxu	int oonstack, errsave, ret;
46123974Sdavidxu	kse_critical_t crit;
47123974Sdavidxu
48123974Sdavidxu	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
49123974Sdavidxu		crit = _kse_critical_enter();
50123974Sdavidxu		ret = __sys_sigaltstack(_ss, _oss);
51123974Sdavidxu		errsave = errno;
52123974Sdavidxu		/* Get a copy */
53123974Sdavidxu		if (ret == 0 && _ss != NULL)
54123974Sdavidxu			curthread->sigstk = *_ss;
55123974Sdavidxu		_kse_critical_leave(crit);
56123974Sdavidxu		errno = errsave;
57123974Sdavidxu		return (ret);
58123974Sdavidxu	}
59123974Sdavidxu
60123974Sdavidxu	if (_ss)
61123974Sdavidxu		ss = *_ss;
62123974Sdavidxu	if (_oss)
63123974Sdavidxu		oss = *_oss;
64123974Sdavidxu
65123974Sdavidxu	/* Should get and set stack in atomic way */
66123974Sdavidxu	crit = _kse_critical_enter();
67123974Sdavidxu	oonstack = _thr_sigonstack(&ss);
68123974Sdavidxu	if (_oss != NULL) {
69123974Sdavidxu		oss = curthread->sigstk;
70123974Sdavidxu		oss.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE)
71123974Sdavidxu		    ? SS_DISABLE : ((oonstack) ? SS_ONSTACK : 0);
72123974Sdavidxu	}
73123974Sdavidxu
74123974Sdavidxu	if (_ss != NULL) {
75123974Sdavidxu		if (oonstack) {
76123974Sdavidxu			_kse_critical_leave(crit);
77124056Sdavidxu			errno = EPERM;
78124056Sdavidxu			return (-1);
79123974Sdavidxu		}
80123974Sdavidxu		if ((ss.ss_flags & ~SS_DISABLE) != 0) {
81123974Sdavidxu			_kse_critical_leave(crit);
82124056Sdavidxu			errno = EINVAL;
83124056Sdavidxu			return (-1);
84123974Sdavidxu		}
85123974Sdavidxu		if (!(ss.ss_flags & SS_DISABLE)) {
86123974Sdavidxu			if (ss.ss_size < MINSIGSTKSZ) {
87123974Sdavidxu				_kse_critical_leave(crit);
88124056Sdavidxu				errno = ENOMEM;
89124056Sdavidxu				return (-1);
90123974Sdavidxu			}
91123974Sdavidxu			curthread->sigstk = ss;
92123974Sdavidxu		} else {
93123974Sdavidxu			curthread->sigstk.ss_flags |= SS_DISABLE;
94123974Sdavidxu		}
95123974Sdavidxu	}
96123974Sdavidxu	_kse_critical_leave(crit);
97123974Sdavidxu	if (_oss != NULL)
98123974Sdavidxu		*_oss = oss;
99123974Sdavidxu	return (0);
100123974Sdavidxu}
101123974Sdavidxu
102123974Sdavidxuint
103123974Sdavidxu_thr_sigonstack(void *sp)
104123974Sdavidxu{
105123974Sdavidxu	struct pthread *curthread = _get_curthread();
106123974Sdavidxu
107123974Sdavidxu	return ((curthread->sigstk.ss_flags & SS_DISABLE) == 0 ?
108123974Sdavidxu	    (((size_t)sp - (size_t)curthread->sigstk.ss_sp) < curthread->sigstk.ss_size)
109123974Sdavidxu	    : 0);
110123974Sdavidxu}
111123974Sdavidxu
112