thr_cancel.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice unmodified, this list of conditions, and the following
12 *    disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/lib/libthr/thread/thr_cancel.c 330897 2018-03-14 03:19:51Z eadler $");
31
32#include "namespace.h"
33#include <pthread.h>
34#include "un-namespace.h"
35
36#include "thr_private.h"
37
38__weak_reference(_pthread_cancel, pthread_cancel);
39__weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
40__weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
41__weak_reference(_pthread_testcancel, pthread_testcancel);
42
43static inline void
44testcancel(struct pthread *curthread)
45{
46	if (__predict_false(SHOULD_CANCEL(curthread) &&
47	    !THR_IN_CRITICAL(curthread)))
48		_pthread_exit(PTHREAD_CANCELED);
49}
50
51void
52_thr_testcancel(struct pthread *curthread)
53{
54	testcancel(curthread);
55}
56
57int
58_pthread_cancel(pthread_t pthread)
59{
60	struct pthread *curthread = _get_curthread();
61	int ret;
62
63	/*
64	 * POSIX says _pthread_cancel should be async cancellation safe.
65	 * _thr_find_thread and THR_THREAD_UNLOCK will enter and leave critical
66	 * region automatically.
67	 */
68	if ((ret = _thr_find_thread(curthread, pthread, 0)) == 0) {
69		if (!pthread->cancel_pending) {
70			pthread->cancel_pending = 1;
71			if (pthread->state != PS_DEAD)
72				_thr_send_sig(pthread, SIGCANCEL);
73		}
74		THR_THREAD_UNLOCK(curthread, pthread);
75	}
76	return (ret);
77}
78
79int
80_pthread_setcancelstate(int state, int *oldstate)
81{
82	struct pthread *curthread = _get_curthread();
83	int oldval;
84
85	oldval = curthread->cancel_enable;
86	switch (state) {
87	case PTHREAD_CANCEL_DISABLE:
88		curthread->cancel_enable = 0;
89		break;
90	case PTHREAD_CANCEL_ENABLE:
91		curthread->cancel_enable = 1;
92		if (curthread->cancel_async)
93			testcancel(curthread);
94		break;
95	default:
96		return (EINVAL);
97	}
98
99	if (oldstate) {
100		*oldstate = oldval ? PTHREAD_CANCEL_ENABLE :
101			PTHREAD_CANCEL_DISABLE;
102	}
103	return (0);
104}
105
106int
107_pthread_setcanceltype(int type, int *oldtype)
108{
109	struct pthread	*curthread = _get_curthread();
110	int oldval;
111
112	oldval = curthread->cancel_async;
113	switch (type) {
114	case PTHREAD_CANCEL_ASYNCHRONOUS:
115		curthread->cancel_async = 1;
116		testcancel(curthread);
117		break;
118	case PTHREAD_CANCEL_DEFERRED:
119		curthread->cancel_async = 0;
120		break;
121	default:
122		return (EINVAL);
123	}
124
125	if (oldtype) {
126		*oldtype = oldval ? PTHREAD_CANCEL_ASYNCHRONOUS :
127		 	PTHREAD_CANCEL_DEFERRED;
128	}
129	return (0);
130}
131
132void
133_pthread_testcancel(void)
134{
135	struct pthread *curthread = _get_curthread();
136
137	testcancel(curthread);
138}
139
140void
141_thr_cancel_enter(struct pthread *curthread)
142{
143	curthread->cancel_point = 1;
144	testcancel(curthread);
145}
146
147void
148_thr_cancel_enter2(struct pthread *curthread, int maycancel)
149{
150	curthread->cancel_point = 1;
151	if (__predict_false(SHOULD_CANCEL(curthread) &&
152	    !THR_IN_CRITICAL(curthread))) {
153		if (!maycancel)
154			thr_wake(curthread->tid);
155		else
156			_pthread_exit(PTHREAD_CANCELED);
157	}
158}
159
160void
161_thr_cancel_leave(struct pthread *curthread, int maycancel)
162{
163	curthread->cancel_point = 0;
164	if (__predict_false(SHOULD_CANCEL(curthread) &&
165	    !THR_IN_CRITICAL(curthread) && maycancel))
166		_pthread_exit(PTHREAD_CANCELED);
167}
168
169void
170_pthread_cancel_enter(int maycancel)
171{
172	_thr_cancel_enter2(_get_curthread(), maycancel);
173}
174
175void
176_pthread_cancel_leave(int maycancel)
177{
178	_thr_cancel_leave(_get_curthread(), maycancel);
179}
180