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$
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
41 static inline void
testcancel(struct pthread * curthread)42 testcancel(struct pthread *curthread)
43 {
44 if (__predict_false(SHOULD_CANCEL(curthread) &&
45 !THR_IN_CRITICAL(curthread)))
46 _pthread_exit(PTHREAD_CANCELED);
47 }
48
49 void
_thr_testcancel(struct pthread * curthread)50 _thr_testcancel(struct pthread *curthread)
51 {
52 testcancel(curthread);
53 }
54
55 int
_pthread_cancel(pthread_t pthread)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_find_thread and THR_THREAD_UNLOCK will enter and leave critical
64 * region automatically.
65 */
66 if ((ret = _thr_find_thread(curthread, pthread, 0)) == 0) {
67 if (!pthread->cancel_pending) {
68 pthread->cancel_pending = 1;
69 if (pthread->state != PS_DEAD)
70 _thr_send_sig(pthread, SIGCANCEL);
71 }
72 THR_THREAD_UNLOCK(curthread, pthread);
73 }
74 return (ret);
75 }
76
77 int
_pthread_setcancelstate(int state,int * oldstate)78 _pthread_setcancelstate(int state, int *oldstate)
79 {
80 struct pthread *curthread = _get_curthread();
81 int oldval;
82
83 oldval = curthread->cancel_enable;
84 switch (state) {
85 case PTHREAD_CANCEL_DISABLE:
86 curthread->cancel_enable = 0;
87 break;
88 case PTHREAD_CANCEL_ENABLE:
89 curthread->cancel_enable = 1;
90 if (curthread->cancel_async)
91 testcancel(curthread);
92 break;
93 default:
94 return (EINVAL);
95 }
96
97 if (oldstate) {
98 *oldstate = oldval ? PTHREAD_CANCEL_ENABLE :
99 PTHREAD_CANCEL_DISABLE;
100 }
101 return (0);
102 }
103
104 int
_pthread_setcanceltype(int type,int * oldtype)105 _pthread_setcanceltype(int type, int *oldtype)
106 {
107 struct pthread *curthread = _get_curthread();
108 int oldval;
109
110 oldval = curthread->cancel_async;
111 switch (type) {
112 case PTHREAD_CANCEL_ASYNCHRONOUS:
113 curthread->cancel_async = 1;
114 testcancel(curthread);
115 break;
116 case PTHREAD_CANCEL_DEFERRED:
117 curthread->cancel_async = 0;
118 break;
119 default:
120 return (EINVAL);
121 }
122
123 if (oldtype) {
124 *oldtype = oldval ? PTHREAD_CANCEL_ASYNCHRONOUS :
125 PTHREAD_CANCEL_DEFERRED;
126 }
127 return (0);
128 }
129
130 void
_pthread_testcancel(void)131 _pthread_testcancel(void)
132 {
133 struct pthread *curthread = _get_curthread();
134
135 testcancel(curthread);
136 }
137
138 void
_thr_cancel_enter(struct pthread * curthread)139 _thr_cancel_enter(struct pthread *curthread)
140 {
141 curthread->cancel_point = 1;
142 testcancel(curthread);
143 }
144
145 void
_thr_cancel_enter2(struct pthread * curthread,int maycancel)146 _thr_cancel_enter2(struct pthread *curthread, int maycancel)
147 {
148 curthread->cancel_point = 1;
149 if (__predict_false(SHOULD_CANCEL(curthread) &&
150 !THR_IN_CRITICAL(curthread))) {
151 if (!maycancel)
152 thr_wake(curthread->tid);
153 else
154 _pthread_exit(PTHREAD_CANCELED);
155 }
156 }
157
158 void
_thr_cancel_leave(struct pthread * curthread,int maycancel)159 _thr_cancel_leave(struct pthread *curthread, int maycancel)
160 {
161 curthread->cancel_point = 0;
162 if (__predict_false(SHOULD_CANCEL(curthread) &&
163 !THR_IN_CRITICAL(curthread) && maycancel))
164 _pthread_exit(PTHREAD_CANCELED);
165 }
166
167 void
_pthread_cancel_enter(int maycancel)168 _pthread_cancel_enter(int maycancel)
169 {
170 _thr_cancel_enter2(_get_curthread(), maycancel);
171 }
172
173 void
_pthread_cancel_leave(int maycancel)174 _pthread_cancel_leave(int maycancel)
175 {
176 _thr_cancel_leave(_get_curthread(), maycancel);
177 }
178