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