xref: /freebsd/lib/libthr/thread/thr_cancel.c (revision 635f917a9d024248ee484721dd1d1c899c44e8d0)
1bb535300SJeff Roberson /*
2a091d823SDavid Xu  * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
3a091d823SDavid Xu  * All rights reserved.
4a091d823SDavid Xu  *
5a091d823SDavid Xu  * Redistribution and use in source and binary forms, with or without
6a091d823SDavid Xu  * modification, are permitted provided that the following conditions
7a091d823SDavid Xu  * are met:
8a091d823SDavid Xu  * 1. Redistributions of source code must retain the above copyright
9a091d823SDavid Xu  *    notice unmodified, this list of conditions, and the following
10a091d823SDavid Xu  *    disclaimer.
11a091d823SDavid Xu  * 2. Redistributions in binary form must reproduce the above copyright
12a091d823SDavid Xu  *    notice, this list of conditions and the following disclaimer in the
13a091d823SDavid Xu  *    documentation and/or other materials provided with the distribution.
14a091d823SDavid Xu  *
15a091d823SDavid Xu  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16a091d823SDavid Xu  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17a091d823SDavid Xu  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18a091d823SDavid Xu  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19a091d823SDavid Xu  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20a091d823SDavid Xu  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21a091d823SDavid Xu  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22a091d823SDavid Xu  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23a091d823SDavid Xu  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24a091d823SDavid Xu  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25a091d823SDavid Xu  *
26bb535300SJeff Roberson  * $FreeBSD$
27a091d823SDavid Xu  *
28bb535300SJeff Roberson  */
29bb535300SJeff Roberson 
3037a6356bSDavid Xu #include "namespace.h"
31a091d823SDavid Xu #include <pthread.h>
3237a6356bSDavid Xu #include "un-namespace.h"
33a091d823SDavid Xu 
34a091d823SDavid Xu #include "thr_private.h"
356da7f493SMike Makonnen 
36bb535300SJeff Roberson __weak_reference(_pthread_cancel, pthread_cancel);
37bb535300SJeff Roberson __weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
38bb535300SJeff Roberson __weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
39bb535300SJeff Roberson __weak_reference(_pthread_testcancel, pthread_testcancel);
40bb535300SJeff Roberson 
41f08e1bf6SDavid Xu static inline void
42f08e1bf6SDavid Xu testcancel(struct pthread *curthread)
43f08e1bf6SDavid Xu {
44f08e1bf6SDavid Xu 	if (__predict_false(SHOULD_CANCEL(curthread) &&
45*635f917aSDavid Xu 	    !THR_IN_CRITICAL(curthread)))
46f08e1bf6SDavid Xu 		_pthread_exit(PTHREAD_CANCELED);
47f08e1bf6SDavid Xu }
48f08e1bf6SDavid Xu 
49f08e1bf6SDavid Xu void
50f08e1bf6SDavid Xu _thr_testcancel(struct pthread *curthread)
51f08e1bf6SDavid Xu {
52f08e1bf6SDavid Xu 	testcancel(curthread);
53f08e1bf6SDavid Xu }
54f08e1bf6SDavid Xu 
55bb535300SJeff Roberson int
56bb535300SJeff Roberson _pthread_cancel(pthread_t pthread)
57bb535300SJeff Roberson {
58a091d823SDavid Xu 	struct pthread *curthread = _get_curthread();
59a091d823SDavid Xu 	int ret;
60bb535300SJeff Roberson 
61d39d6512SMike Makonnen 	/*
62f08e1bf6SDavid Xu 	 * POSIX says _pthread_cancel should be async cancellation safe.
63f08e1bf6SDavid Xu 	 * _thr_ref_add and _thr_ref_delete will enter and leave critical
64f08e1bf6SDavid Xu 	 * region automatically.
65d39d6512SMike Makonnen 	 */
66f08e1bf6SDavid Xu 	if ((ret = _thr_ref_add(curthread, pthread, 0)) == 0) {
67f08e1bf6SDavid Xu 		THR_THREAD_LOCK(curthread, pthread);
68f08e1bf6SDavid Xu 		if (!pthread->cancel_pending) {
69f08e1bf6SDavid Xu 			pthread->cancel_pending = 1;
70f08e1bf6SDavid Xu 			if (pthread->cancel_enable)
71a091d823SDavid Xu 				_thr_send_sig(pthread, SIGCANCEL);
726da7f493SMike Makonnen 		}
73f08e1bf6SDavid Xu 		THR_THREAD_UNLOCK(curthread, pthread);
74f08e1bf6SDavid Xu 		_thr_ref_delete(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 		THR_LOCK(curthread);
89f08e1bf6SDavid Xu 		curthread->cancel_enable = 0;
90f08e1bf6SDavid Xu 		THR_UNLOCK(curthread);
91a091d823SDavid Xu 		break;
92a091d823SDavid Xu 	case PTHREAD_CANCEL_ENABLE:
93f08e1bf6SDavid Xu 		THR_LOCK(curthread);
94f08e1bf6SDavid Xu 		curthread->cancel_enable = 1;
95f08e1bf6SDavid Xu 		THR_UNLOCK(curthread);
96bb535300SJeff Roberson 		break;
97bb535300SJeff Roberson 	default:
98f08e1bf6SDavid Xu 		return (EINVAL);
994cd18a22SMike Makonnen 	}
100bb535300SJeff Roberson 
101f08e1bf6SDavid Xu 	if (oldstate) {
102f08e1bf6SDavid Xu 		*oldstate = oldval ? PTHREAD_CANCEL_ENABLE :
103f08e1bf6SDavid Xu 			PTHREAD_CANCEL_DISABLE;
104f08e1bf6SDavid Xu 	}
105f08e1bf6SDavid Xu 	return (0);
106a091d823SDavid Xu }
107a091d823SDavid Xu 
1084cd18a22SMike Makonnen int
1094cd18a22SMike Makonnen _pthread_setcanceltype(int type, int *oldtype)
1104cd18a22SMike Makonnen {
111a091d823SDavid Xu 	struct pthread	*curthread = _get_curthread();
112f08e1bf6SDavid Xu 	int oldval;
1134cd18a22SMike Makonnen 
114f08e1bf6SDavid Xu 	oldval = curthread->cancel_async;
1154cd18a22SMike Makonnen 	switch (type) {
1164cd18a22SMike Makonnen 	case PTHREAD_CANCEL_ASYNCHRONOUS:
117f08e1bf6SDavid Xu 		curthread->cancel_async = 1;
118a091d823SDavid Xu 		testcancel(curthread);
1194cd18a22SMike Makonnen 		break;
1204cd18a22SMike Makonnen 	case PTHREAD_CANCEL_DEFERRED:
121f08e1bf6SDavid Xu 		curthread->cancel_async = 0;
1224cd18a22SMike Makonnen 		break;
1234cd18a22SMike Makonnen 	default:
124f08e1bf6SDavid Xu 		return (EINVAL);
1254cd18a22SMike Makonnen 	}
126a091d823SDavid Xu 
127f08e1bf6SDavid Xu 	if (oldtype) {
128f08e1bf6SDavid Xu 		*oldtype = oldval ? PTHREAD_CANCEL_ASYNCHRONOUS :
129f08e1bf6SDavid Xu 		 	PTHREAD_CANCEL_DEFERRED;
130f08e1bf6SDavid Xu 	}
131f08e1bf6SDavid Xu 	return (0);
132bb535300SJeff Roberson }
133bb535300SJeff Roberson 
134bb535300SJeff Roberson void
135bb535300SJeff Roberson _pthread_testcancel(void)
136bb535300SJeff Roberson {
137f08e1bf6SDavid Xu 	struct pthread *curthread = _get_curthread();
1386da7f493SMike Makonnen 
139f08e1bf6SDavid Xu 	_thr_cancel_enter(curthread);
140f08e1bf6SDavid Xu 	_thr_cancel_leave(curthread);
1414cd18a22SMike Makonnen }
142bb535300SJeff Roberson 
143bb535300SJeff Roberson void
144f08e1bf6SDavid Xu _thr_cancel_enter(struct pthread *curthread)
145bb535300SJeff Roberson {
146f08e1bf6SDavid Xu 	curthread->cancel_point++;
147*635f917aSDavid Xu 	if (curthread->cancel_enable)
148f08e1bf6SDavid Xu 		testcancel(curthread);
149f08e1bf6SDavid Xu }
150*635f917aSDavid Xu 
151*635f917aSDavid Xu void
152*635f917aSDavid Xu _thr_cancel_enter_defer(struct pthread *curthread, int maycancel)
153*635f917aSDavid Xu {
154*635f917aSDavid Xu 	curthread->cancel_defer++;
155*635f917aSDavid Xu 	curthread->cancel_point++;
156*635f917aSDavid Xu 	if (__predict_false(SHOULD_CANCEL(curthread) &&
157*635f917aSDavid Xu 	    !THR_IN_CRITICAL(curthread))) {
158*635f917aSDavid Xu 		if (!maycancel)
159*635f917aSDavid Xu 			thr_wake(curthread->tid);
160*635f917aSDavid Xu 		else
161*635f917aSDavid Xu 			_pthread_exit(PTHREAD_CANCELED);
162*635f917aSDavid Xu 	}
163f08e1bf6SDavid Xu }
164f08e1bf6SDavid Xu 
165f08e1bf6SDavid Xu void
166f08e1bf6SDavid Xu _thr_cancel_leave(struct pthread *curthread)
167f08e1bf6SDavid Xu {
168f08e1bf6SDavid Xu 	curthread->cancel_point--;
169bb535300SJeff Roberson }
1702bd2c907SDavid Xu 
1712bd2c907SDavid Xu void
172*635f917aSDavid Xu _thr_cancel_leave2(struct pthread *curthread, int maycancel)
1732bd2c907SDavid Xu {
174*635f917aSDavid Xu 	if (curthread->cancel_enable && maycancel)
1752bd2c907SDavid Xu 		testcancel(curthread);
176*635f917aSDavid Xu 	curthread->cancel_point--;
1772bd2c907SDavid Xu }
1782bd2c907SDavid Xu 
1792bd2c907SDavid Xu void
180*635f917aSDavid Xu _thr_cancel_leave_defer(struct pthread *curthread, int maycancel)
1812bd2c907SDavid Xu {
182*635f917aSDavid Xu 	if (curthread->cancel_enable && maycancel)
1832bd2c907SDavid Xu 		testcancel(curthread);
1842bd2c907SDavid Xu 	curthread->cancel_point--;
185*635f917aSDavid Xu 	curthread->cancel_defer--;
1863ce4e91dSDavid Xu }
187