xref: /freebsd/lib/libthr/thread/thr_cancel.c (revision f08e1bf68286986422c2c96bd7b594898afb7fa7)
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) &&
45f08e1bf6SDavid 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 	if (curthread->cancel_enable) {
147f08e1bf6SDavid Xu 		curthread->cancel_point++;
148f08e1bf6SDavid Xu 		testcancel(curthread);
149f08e1bf6SDavid Xu 	}
150f08e1bf6SDavid Xu }
151f08e1bf6SDavid Xu 
152f08e1bf6SDavid Xu void
153f08e1bf6SDavid Xu _thr_cancel_leave(struct pthread *curthread)
154f08e1bf6SDavid Xu {
155f08e1bf6SDavid Xu 	if (curthread->cancel_enable)
156f08e1bf6SDavid Xu 		curthread->cancel_point--;
157bb535300SJeff Roberson }
158