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 212536 2010-09-13 07:03:01Z 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_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
77int
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 testcancel(curthread);
91 break;
92 default:
93 return (EINVAL);
94 }
95
96 if (oldstate) {
97 *oldstate = oldval ? PTHREAD_CANCEL_ENABLE :
98 PTHREAD_CANCEL_DISABLE;
99 }
100 return (0);
101}
102
103int
104_pthread_setcanceltype(int type, int *oldtype)
105{
106 struct pthread *curthread = _get_curthread();
107 int oldval;
108
109 oldval = curthread->cancel_async;
110 switch (type) {
111 case PTHREAD_CANCEL_ASYNCHRONOUS:
112 curthread->cancel_async = 1;
113 testcancel(curthread);
114 break;
115 case PTHREAD_CANCEL_DEFERRED:
116 curthread->cancel_async = 0;
117 break;
118 default:
119 return (EINVAL);
120 }
121
122 if (oldtype) {
123 *oldtype = oldval ? PTHREAD_CANCEL_ASYNCHRONOUS :
124 PTHREAD_CANCEL_DEFERRED;
125 }
126 return (0);
127}
128
129void
130_pthread_testcancel(void)
131{
132 struct pthread *curthread = _get_curthread();
133
134 curthread->cancel_point = 1;
135 testcancel(curthread);
136 curthread->cancel_point = 0;
137}
138
139void
140_thr_cancel_enter(struct pthread *curthread)
141{
142 curthread->cancel_point = 1;
143 testcancel(curthread);
144}
145
146void
147_thr_cancel_enter2(struct pthread *curthread, int maycancel)
148{
149 curthread->cancel_point = 1;
150 if (__predict_false(SHOULD_CANCEL(curthread) &&
151 !THR_IN_CRITICAL(curthread))) {
152 if (!maycancel)
153 thr_wake(curthread->tid);
154 else
155 _pthread_exit(PTHREAD_CANCELED);
156 }
157}
158
159void
160_thr_cancel_leave(struct pthread *curthread, int maycancel)
161{
162 if (maycancel)
163 testcancel(curthread);
164 curthread->cancel_point = 0;
165}
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 212536 2010-09-13 07:03:01Z 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_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
77int
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 testcancel(curthread);
91 break;
92 default:
93 return (EINVAL);
94 }
95
96 if (oldstate) {
97 *oldstate = oldval ? PTHREAD_CANCEL_ENABLE :
98 PTHREAD_CANCEL_DISABLE;
99 }
100 return (0);
101}
102
103int
104_pthread_setcanceltype(int type, int *oldtype)
105{
106 struct pthread *curthread = _get_curthread();
107 int oldval;
108
109 oldval = curthread->cancel_async;
110 switch (type) {
111 case PTHREAD_CANCEL_ASYNCHRONOUS:
112 curthread->cancel_async = 1;
113 testcancel(curthread);
114 break;
115 case PTHREAD_CANCEL_DEFERRED:
116 curthread->cancel_async = 0;
117 break;
118 default:
119 return (EINVAL);
120 }
121
122 if (oldtype) {
123 *oldtype = oldval ? PTHREAD_CANCEL_ASYNCHRONOUS :
124 PTHREAD_CANCEL_DEFERRED;
125 }
126 return (0);
127}
128
129void
130_pthread_testcancel(void)
131{
132 struct pthread *curthread = _get_curthread();
133
134 curthread->cancel_point = 1;
135 testcancel(curthread);
136 curthread->cancel_point = 0;
137}
138
139void
140_thr_cancel_enter(struct pthread *curthread)
141{
142 curthread->cancel_point = 1;
143 testcancel(curthread);
144}
145
146void
147_thr_cancel_enter2(struct pthread *curthread, int maycancel)
148{
149 curthread->cancel_point = 1;
150 if (__predict_false(SHOULD_CANCEL(curthread) &&
151 !THR_IN_CRITICAL(curthread))) {
152 if (!maycancel)
153 thr_wake(curthread->tid);
154 else
155 _pthread_exit(PTHREAD_CANCELED);
156 }
157}
158
159void
160_thr_cancel_leave(struct pthread *curthread, int maycancel)
161{
162 if (maycancel)
163 testcancel(curthread);
164 curthread->cancel_point = 0;
165}