xref: /freebsd/lib/libthr/thread/thr_cancel.c (revision 751fae1effde32b441dd232a0bf3340a419f2d17)
15e53a4f9SPedro F. Giffuni /*-
25e53a4f9SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
35e53a4f9SPedro 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 
380ab1bfc7SKonstantin Belousov __weak_reference(_thr_cancel, pthread_cancel);
390ab1bfc7SKonstantin Belousov __weak_reference(_thr_cancel, _pthread_cancel);
400ab1bfc7SKonstantin Belousov __weak_reference(_thr_setcancelstate, pthread_setcancelstate);
410ab1bfc7SKonstantin Belousov __weak_reference(_thr_setcancelstate, _pthread_setcancelstate);
420ab1bfc7SKonstantin Belousov __weak_reference(_thr_setcanceltype, pthread_setcanceltype);
430ab1bfc7SKonstantin Belousov __weak_reference(_thr_setcanceltype, _pthread_setcanceltype);
440ab1bfc7SKonstantin Belousov __weak_reference(_Tthr_testcancel, pthread_testcancel);
450ab1bfc7SKonstantin Belousov __weak_reference(_Tthr_testcancel, _pthread_testcancel);
4665174f68SKonstantin Belousov __weak_reference(_Tthr_cancel_enter, _pthread_cancel_enter);
4765174f68SKonstantin Belousov __weak_reference(_Tthr_cancel_leave, _pthread_cancel_leave);
48bb535300SJeff Roberson 
49f08e1bf6SDavid Xu static inline void
50f08e1bf6SDavid Xu testcancel(struct pthread *curthread)
51f08e1bf6SDavid Xu {
52f08e1bf6SDavid Xu 	if (__predict_false(SHOULD_CANCEL(curthread) &&
53635f917aSDavid Xu 	    !THR_IN_CRITICAL(curthread)))
54f08e1bf6SDavid Xu 		_pthread_exit(PTHREAD_CANCELED);
55f08e1bf6SDavid Xu }
56f08e1bf6SDavid Xu 
57f08e1bf6SDavid Xu void
58f08e1bf6SDavid Xu _thr_testcancel(struct pthread *curthread)
59f08e1bf6SDavid Xu {
60f08e1bf6SDavid Xu 	testcancel(curthread);
61f08e1bf6SDavid Xu }
62f08e1bf6SDavid Xu 
63bb535300SJeff Roberson int
640ab1bfc7SKonstantin Belousov _thr_cancel(pthread_t pthread)
65bb535300SJeff Roberson {
66a091d823SDavid Xu 	struct pthread *curthread = _get_curthread();
67a091d823SDavid Xu 	int ret;
68bb535300SJeff Roberson 
69d39d6512SMike Makonnen 	/*
70f08e1bf6SDavid Xu 	 * POSIX says _pthread_cancel should be async cancellation safe.
71a9b764e2SDavid Xu 	 * _thr_find_thread and THR_THREAD_UNLOCK will enter and leave critical
72f08e1bf6SDavid Xu 	 * region automatically.
73d39d6512SMike Makonnen 	 */
74*751fae1eSKonstantin Belousov 	if ((ret = _thr_find_thread(curthread, pthread, 1)) == 0) {
75f08e1bf6SDavid Xu 		if (!pthread->cancel_pending) {
76f08e1bf6SDavid Xu 			pthread->cancel_pending = 1;
7717dce7e1SDavid Xu 			if (pthread->state != PS_DEAD)
78a091d823SDavid Xu 				_thr_send_sig(pthread, SIGCANCEL);
796da7f493SMike Makonnen 		}
80f08e1bf6SDavid Xu 		THR_THREAD_UNLOCK(curthread, pthread);
81f08e1bf6SDavid Xu 	}
82f08e1bf6SDavid Xu 	return (ret);
83a091d823SDavid Xu }
84a091d823SDavid Xu 
85bb535300SJeff Roberson int
860ab1bfc7SKonstantin Belousov _thr_setcancelstate(int state, int *oldstate)
87bb535300SJeff Roberson {
88a091d823SDavid Xu 	struct pthread *curthread = _get_curthread();
89f08e1bf6SDavid Xu 	int oldval;
90bb535300SJeff Roberson 
91f08e1bf6SDavid Xu 	oldval = curthread->cancel_enable;
92bb535300SJeff Roberson 	switch (state) {
93bb535300SJeff Roberson 	case PTHREAD_CANCEL_DISABLE:
94f08e1bf6SDavid Xu 		curthread->cancel_enable = 0;
95a091d823SDavid Xu 		break;
96a091d823SDavid Xu 	case PTHREAD_CANCEL_ENABLE:
97f08e1bf6SDavid Xu 		curthread->cancel_enable = 1;
98a0b9cbc8SKonstantin Belousov 		if (curthread->cancel_async)
9902c3c858SDavid Xu 			testcancel(curthread);
100bb535300SJeff Roberson 		break;
101bb535300SJeff Roberson 	default:
102f08e1bf6SDavid Xu 		return (EINVAL);
1034cd18a22SMike Makonnen 	}
104bb535300SJeff Roberson 
105f08e1bf6SDavid Xu 	if (oldstate) {
106f08e1bf6SDavid Xu 		*oldstate = oldval ? PTHREAD_CANCEL_ENABLE :
107f08e1bf6SDavid Xu 			PTHREAD_CANCEL_DISABLE;
108f08e1bf6SDavid Xu 	}
109f08e1bf6SDavid Xu 	return (0);
110a091d823SDavid Xu }
111a091d823SDavid Xu 
1124cd18a22SMike Makonnen int
1130ab1bfc7SKonstantin Belousov _thr_setcanceltype(int type, int *oldtype)
1144cd18a22SMike Makonnen {
115a091d823SDavid Xu 	struct pthread	*curthread = _get_curthread();
116f08e1bf6SDavid Xu 	int oldval;
1174cd18a22SMike Makonnen 
118f08e1bf6SDavid Xu 	oldval = curthread->cancel_async;
1194cd18a22SMike Makonnen 	switch (type) {
1204cd18a22SMike Makonnen 	case PTHREAD_CANCEL_ASYNCHRONOUS:
121f08e1bf6SDavid Xu 		curthread->cancel_async = 1;
122a091d823SDavid Xu 		testcancel(curthread);
1234cd18a22SMike Makonnen 		break;
1244cd18a22SMike Makonnen 	case PTHREAD_CANCEL_DEFERRED:
125f08e1bf6SDavid Xu 		curthread->cancel_async = 0;
1264cd18a22SMike Makonnen 		break;
1274cd18a22SMike Makonnen 	default:
128f08e1bf6SDavid Xu 		return (EINVAL);
1294cd18a22SMike Makonnen 	}
130a091d823SDavid Xu 
131f08e1bf6SDavid Xu 	if (oldtype) {
132f08e1bf6SDavid Xu 		*oldtype = oldval ? PTHREAD_CANCEL_ASYNCHRONOUS :
133f08e1bf6SDavid Xu 		 	PTHREAD_CANCEL_DEFERRED;
134f08e1bf6SDavid Xu 	}
135f08e1bf6SDavid Xu 	return (0);
136bb535300SJeff Roberson }
137bb535300SJeff Roberson 
138bb535300SJeff Roberson void
1390ab1bfc7SKonstantin Belousov _Tthr_testcancel(void)
140bb535300SJeff Roberson {
141dc356606SJohn Baldwin 	struct pthread *curthread;
1426da7f493SMike Makonnen 
143dc356606SJohn Baldwin 	_thr_check_init();
144dc356606SJohn Baldwin 	curthread = _get_curthread();
14502c3c858SDavid Xu 	testcancel(curthread);
1464cd18a22SMike Makonnen }
147bb535300SJeff Roberson 
148bb535300SJeff Roberson void
149f08e1bf6SDavid Xu _thr_cancel_enter(struct pthread *curthread)
150bb535300SJeff Roberson {
15102c3c858SDavid Xu 	curthread->cancel_point = 1;
152f08e1bf6SDavid Xu 	testcancel(curthread);
153f08e1bf6SDavid Xu }
154635f917aSDavid Xu 
155635f917aSDavid Xu void
15602c3c858SDavid Xu _thr_cancel_enter2(struct pthread *curthread, int maycancel)
157635f917aSDavid Xu {
15802c3c858SDavid Xu 	curthread->cancel_point = 1;
159635f917aSDavid Xu 	if (__predict_false(SHOULD_CANCEL(curthread) &&
160635f917aSDavid Xu 	    !THR_IN_CRITICAL(curthread))) {
161635f917aSDavid Xu 		if (!maycancel)
162635f917aSDavid Xu 			thr_wake(curthread->tid);
163635f917aSDavid Xu 		else
164635f917aSDavid Xu 			_pthread_exit(PTHREAD_CANCELED);
165635f917aSDavid Xu 	}
166f08e1bf6SDavid Xu }
167f08e1bf6SDavid Xu 
168f08e1bf6SDavid Xu void
16902c3c858SDavid Xu _thr_cancel_leave(struct pthread *curthread, int maycancel)
170f08e1bf6SDavid Xu {
17193ea4a71SDavid Xu 	curthread->cancel_point = 0;
172e5c66a0dSDavid Xu 	if (__predict_false(SHOULD_CANCEL(curthread) &&
173e5c66a0dSDavid Xu 	    !THR_IN_CRITICAL(curthread) && maycancel))
174e5c66a0dSDavid Xu 		_pthread_exit(PTHREAD_CANCELED);
1753ce4e91dSDavid Xu }
176f4213b90SDavid Xu 
177f4213b90SDavid Xu void
17865174f68SKonstantin Belousov _Tthr_cancel_enter(int maycancel)
179f4213b90SDavid Xu {
180f4213b90SDavid Xu 	_thr_cancel_enter2(_get_curthread(), maycancel);
181f4213b90SDavid Xu }
182f4213b90SDavid Xu 
183f4213b90SDavid Xu void
18465174f68SKonstantin Belousov _Tthr_cancel_leave(int maycancel)
185f4213b90SDavid Xu {
186f4213b90SDavid Xu 	_thr_cancel_leave(_get_curthread(), maycancel);
187f4213b90SDavid Xu }
188