xref: /freebsd/lib/libthr/thread/thr_cancel.c (revision 5e53a4f90f82c4345f277dd87cc9292f26e04a29)
1*5e53a4f9SPedro F. Giffuni /*-
2*5e53a4f9SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*5e53a4f9SPedro F. Giffuni  *
4a091d823SDavid Xu  * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
5a091d823SDavid Xu  * All rights reserved.
6a091d823SDavid Xu  *
7a091d823SDavid Xu  * Redistribution and use in source and binary forms, with or without
8a091d823SDavid Xu  * modification, are permitted provided that the following conditions
9a091d823SDavid Xu  * are met:
10a091d823SDavid Xu  * 1. Redistributions of source code must retain the above copyright
11a091d823SDavid Xu  *    notice unmodified, this list of conditions, and the following
12a091d823SDavid Xu  *    disclaimer.
13a091d823SDavid Xu  * 2. Redistributions in binary form must reproduce the above copyright
14a091d823SDavid Xu  *    notice, this list of conditions and the following disclaimer in the
15a091d823SDavid Xu  *    documentation and/or other materials provided with the distribution.
16a091d823SDavid Xu  *
17a091d823SDavid Xu  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18a091d823SDavid Xu  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19a091d823SDavid Xu  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20a091d823SDavid Xu  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21a091d823SDavid Xu  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22a091d823SDavid Xu  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23a091d823SDavid Xu  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24a091d823SDavid Xu  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25a091d823SDavid Xu  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26a091d823SDavid Xu  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27bb535300SJeff Roberson  */
28bb535300SJeff Roberson 
2932793011SKonstantin Belousov #include <sys/cdefs.h>
3032793011SKonstantin Belousov __FBSDID("$FreeBSD$");
3132793011SKonstantin Belousov 
3237a6356bSDavid Xu #include "namespace.h"
33a091d823SDavid Xu #include <pthread.h>
3437a6356bSDavid Xu #include "un-namespace.h"
35a091d823SDavid Xu 
36a091d823SDavid Xu #include "thr_private.h"
376da7f493SMike Makonnen 
38bb535300SJeff Roberson __weak_reference(_pthread_cancel, pthread_cancel);
39bb535300SJeff Roberson __weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
40bb535300SJeff Roberson __weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
41bb535300SJeff Roberson __weak_reference(_pthread_testcancel, pthread_testcancel);
42bb535300SJeff Roberson 
43f08e1bf6SDavid Xu static inline void
44f08e1bf6SDavid Xu testcancel(struct pthread *curthread)
45f08e1bf6SDavid Xu {
46f08e1bf6SDavid Xu 	if (__predict_false(SHOULD_CANCEL(curthread) &&
47635f917aSDavid Xu 	    !THR_IN_CRITICAL(curthread)))
48f08e1bf6SDavid Xu 		_pthread_exit(PTHREAD_CANCELED);
49f08e1bf6SDavid Xu }
50f08e1bf6SDavid Xu 
51f08e1bf6SDavid Xu void
52f08e1bf6SDavid Xu _thr_testcancel(struct pthread *curthread)
53f08e1bf6SDavid Xu {
54f08e1bf6SDavid Xu 	testcancel(curthread);
55f08e1bf6SDavid Xu }
56f08e1bf6SDavid Xu 
57bb535300SJeff Roberson int
58bb535300SJeff Roberson _pthread_cancel(pthread_t pthread)
59bb535300SJeff Roberson {
60a091d823SDavid Xu 	struct pthread *curthread = _get_curthread();
61a091d823SDavid Xu 	int ret;
62bb535300SJeff Roberson 
63d39d6512SMike Makonnen 	/*
64f08e1bf6SDavid Xu 	 * POSIX says _pthread_cancel should be async cancellation safe.
65a9b764e2SDavid Xu 	 * _thr_find_thread and THR_THREAD_UNLOCK will enter and leave critical
66f08e1bf6SDavid Xu 	 * region automatically.
67d39d6512SMike Makonnen 	 */
68a9b764e2SDavid Xu 	if ((ret = _thr_find_thread(curthread, pthread, 0)) == 0) {
69f08e1bf6SDavid Xu 		if (!pthread->cancel_pending) {
70f08e1bf6SDavid Xu 			pthread->cancel_pending = 1;
7117dce7e1SDavid Xu 			if (pthread->state != PS_DEAD)
72a091d823SDavid Xu 				_thr_send_sig(pthread, SIGCANCEL);
736da7f493SMike Makonnen 		}
74f08e1bf6SDavid Xu 		THR_THREAD_UNLOCK(curthread, pthread);
75f08e1bf6SDavid Xu 	}
76f08e1bf6SDavid Xu 	return (ret);
77a091d823SDavid Xu }
78a091d823SDavid Xu 
79bb535300SJeff Roberson int
80bb535300SJeff Roberson _pthread_setcancelstate(int state, int *oldstate)
81bb535300SJeff Roberson {
82a091d823SDavid Xu 	struct pthread *curthread = _get_curthread();
83f08e1bf6SDavid Xu 	int oldval;
84bb535300SJeff Roberson 
85f08e1bf6SDavid Xu 	oldval = curthread->cancel_enable;
86bb535300SJeff Roberson 	switch (state) {
87bb535300SJeff Roberson 	case PTHREAD_CANCEL_DISABLE:
88f08e1bf6SDavid Xu 		curthread->cancel_enable = 0;
89a091d823SDavid Xu 		break;
90a091d823SDavid Xu 	case PTHREAD_CANCEL_ENABLE:
91f08e1bf6SDavid Xu 		curthread->cancel_enable = 1;
92a0b9cbc8SKonstantin Belousov 		if (curthread->cancel_async)
9302c3c858SDavid Xu 			testcancel(curthread);
94bb535300SJeff Roberson 		break;
95bb535300SJeff Roberson 	default:
96f08e1bf6SDavid Xu 		return (EINVAL);
974cd18a22SMike Makonnen 	}
98bb535300SJeff Roberson 
99f08e1bf6SDavid Xu 	if (oldstate) {
100f08e1bf6SDavid Xu 		*oldstate = oldval ? PTHREAD_CANCEL_ENABLE :
101f08e1bf6SDavid Xu 			PTHREAD_CANCEL_DISABLE;
102f08e1bf6SDavid Xu 	}
103f08e1bf6SDavid Xu 	return (0);
104a091d823SDavid Xu }
105a091d823SDavid Xu 
1064cd18a22SMike Makonnen int
1074cd18a22SMike Makonnen _pthread_setcanceltype(int type, int *oldtype)
1084cd18a22SMike Makonnen {
109a091d823SDavid Xu 	struct pthread	*curthread = _get_curthread();
110f08e1bf6SDavid Xu 	int oldval;
1114cd18a22SMike Makonnen 
112f08e1bf6SDavid Xu 	oldval = curthread->cancel_async;
1134cd18a22SMike Makonnen 	switch (type) {
1144cd18a22SMike Makonnen 	case PTHREAD_CANCEL_ASYNCHRONOUS:
115f08e1bf6SDavid Xu 		curthread->cancel_async = 1;
116a091d823SDavid Xu 		testcancel(curthread);
1174cd18a22SMike Makonnen 		break;
1184cd18a22SMike Makonnen 	case PTHREAD_CANCEL_DEFERRED:
119f08e1bf6SDavid Xu 		curthread->cancel_async = 0;
1204cd18a22SMike Makonnen 		break;
1214cd18a22SMike Makonnen 	default:
122f08e1bf6SDavid Xu 		return (EINVAL);
1234cd18a22SMike Makonnen 	}
124a091d823SDavid Xu 
125f08e1bf6SDavid Xu 	if (oldtype) {
126f08e1bf6SDavid Xu 		*oldtype = oldval ? PTHREAD_CANCEL_ASYNCHRONOUS :
127f08e1bf6SDavid Xu 		 	PTHREAD_CANCEL_DEFERRED;
128f08e1bf6SDavid Xu 	}
129f08e1bf6SDavid Xu 	return (0);
130bb535300SJeff Roberson }
131bb535300SJeff Roberson 
132bb535300SJeff Roberson void
133bb535300SJeff Roberson _pthread_testcancel(void)
134bb535300SJeff Roberson {
135f08e1bf6SDavid Xu 	struct pthread *curthread = _get_curthread();
1366da7f493SMike Makonnen 
13702c3c858SDavid Xu 	testcancel(curthread);
1384cd18a22SMike Makonnen }
139bb535300SJeff Roberson 
140bb535300SJeff Roberson void
141f08e1bf6SDavid Xu _thr_cancel_enter(struct pthread *curthread)
142bb535300SJeff Roberson {
14302c3c858SDavid Xu 	curthread->cancel_point = 1;
144f08e1bf6SDavid Xu 	testcancel(curthread);
145f08e1bf6SDavid Xu }
146635f917aSDavid Xu 
147635f917aSDavid Xu void
14802c3c858SDavid Xu _thr_cancel_enter2(struct pthread *curthread, int maycancel)
149635f917aSDavid Xu {
15002c3c858SDavid Xu 	curthread->cancel_point = 1;
151635f917aSDavid Xu 	if (__predict_false(SHOULD_CANCEL(curthread) &&
152635f917aSDavid Xu 	    !THR_IN_CRITICAL(curthread))) {
153635f917aSDavid Xu 		if (!maycancel)
154635f917aSDavid Xu 			thr_wake(curthread->tid);
155635f917aSDavid Xu 		else
156635f917aSDavid Xu 			_pthread_exit(PTHREAD_CANCELED);
157635f917aSDavid Xu 	}
158f08e1bf6SDavid Xu }
159f08e1bf6SDavid Xu 
160f08e1bf6SDavid Xu void
16102c3c858SDavid Xu _thr_cancel_leave(struct pthread *curthread, int maycancel)
162f08e1bf6SDavid Xu {
16393ea4a71SDavid Xu 	curthread->cancel_point = 0;
164e5c66a0dSDavid Xu 	if (__predict_false(SHOULD_CANCEL(curthread) &&
165e5c66a0dSDavid Xu 	    !THR_IN_CRITICAL(curthread) && maycancel))
166e5c66a0dSDavid Xu 		_pthread_exit(PTHREAD_CANCELED);
1673ce4e91dSDavid Xu }
168f4213b90SDavid Xu 
169f4213b90SDavid Xu void
170f4213b90SDavid Xu _pthread_cancel_enter(int maycancel)
171f4213b90SDavid Xu {
172f4213b90SDavid Xu 	_thr_cancel_enter2(_get_curthread(), maycancel);
173f4213b90SDavid Xu }
174f4213b90SDavid Xu 
175f4213b90SDavid Xu void
176f4213b90SDavid Xu _pthread_cancel_leave(int maycancel)
177f4213b90SDavid Xu {
178f4213b90SDavid Xu 	_thr_cancel_leave(_get_curthread(), maycancel);
179f4213b90SDavid Xu }
180