]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - lib/libthr/thread/thr_cancel.c
MFC 331324: Ensure thread library is initialized in pthread_testcancel().
[FreeBSD/stable/10.git] / lib / libthr / thread / thr_cancel.c
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
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
50 _thr_testcancel(struct pthread *curthread)
51 {
52         testcancel(curthread);
53 }
54
55 int
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
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
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
131 _pthread_testcancel(void)
132 {
133         struct pthread *curthread;
134
135         _thr_check_init();
136         curthread = _get_curthread();
137         testcancel(curthread);
138 }
139
140 void
141 _thr_cancel_enter(struct pthread *curthread)
142 {
143         curthread->cancel_point = 1;
144         testcancel(curthread);
145 }
146
147 void
148 _thr_cancel_enter2(struct pthread *curthread, int maycancel)
149 {
150         curthread->cancel_point = 1;
151         if (__predict_false(SHOULD_CANCEL(curthread) &&
152             !THR_IN_CRITICAL(curthread))) {
153                 if (!maycancel)
154                         thr_wake(curthread->tid);
155                 else
156                         _pthread_exit(PTHREAD_CANCELED);
157         }
158 }
159
160 void
161 _thr_cancel_leave(struct pthread *curthread, int maycancel)
162 {
163         curthread->cancel_point = 0;
164         if (__predict_false(SHOULD_CANCEL(curthread) &&
165             !THR_IN_CRITICAL(curthread) && maycancel))
166                 _pthread_exit(PTHREAD_CANCELED);
167 }
168
169 void
170 _pthread_cancel_enter(int maycancel)
171 {
172         _thr_cancel_enter2(_get_curthread(), maycancel);
173 }
174
175 void
176 _pthread_cancel_leave(int maycancel)
177 {
178         _thr_cancel_leave(_get_curthread(), maycancel);
179 }