MFC - Fix logic when using the umtx_*_err() functions.
[dragonfly.git] / lib / libthread_xu / thread / thr_cancel.c
blob16d8f409efa07744f4abb7547ea09de87c3d93cb
1 /*
2 * Copyright (c) 2005, David Xu<davidxu@freebsd.org>
3 * All rights reserved.
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.
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.
26 * $DragonFly: src/lib/libthread_xu/thread/thr_cancel.c,v 1.4 2006/04/06 13:03:09 davidxu Exp $
29 #include "namespace.h"
30 #include <machine/tls.h>
31 #include <pthread.h>
32 #include "un-namespace.h"
34 #include "thr_private.h"
36 int _pthread_setcanceltype(int type, int *oldtype);
38 int
39 _pthread_cancel(pthread_t pthread)
41 struct pthread *curthread = tls_get_curthread();
42 int oldval, newval = 0;
43 int oldtype;
44 int ret;
47 * POSIX says _pthread_cancel should be async cancellation safe,
48 * so we temporarily disable async cancellation.
50 _pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
51 if ((ret = _thr_ref_add(curthread, pthread, 0)) != 0) {
52 _pthread_setcanceltype(oldtype, NULL);
53 return (ret);
56 do {
57 oldval = pthread->cancelflags;
58 if (oldval & THR_CANCEL_NEEDED)
59 break;
60 newval = oldval | THR_CANCEL_NEEDED;
61 } while (!atomic_cmpset_acq_int(&pthread->cancelflags, oldval, newval));
63 if (!(oldval & THR_CANCEL_NEEDED) && SHOULD_ASYNC_CANCEL(newval))
64 _thr_send_sig(pthread, SIGCANCEL);
66 _thr_ref_delete(curthread, pthread);
67 _pthread_setcanceltype(oldtype, NULL);
68 return (0);
71 static inline void
72 testcancel(struct pthread *curthread)
74 int newval;
76 newval = curthread->cancelflags;
77 if (SHOULD_CANCEL(newval))
78 _pthread_exit(PTHREAD_CANCELED);
81 int
82 _pthread_setcancelstate(int state, int *oldstate)
84 struct pthread *curthread = tls_get_curthread();
85 int oldval, ret;
87 oldval = curthread->cancelflags;
88 if (oldstate != NULL)
89 *oldstate = ((oldval & THR_CANCEL_DISABLE) ?
90 PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE);
91 switch (state) {
92 case PTHREAD_CANCEL_DISABLE:
93 atomic_set_int(&curthread->cancelflags, THR_CANCEL_DISABLE);
94 ret = 0;
95 break;
96 case PTHREAD_CANCEL_ENABLE:
97 atomic_clear_int(&curthread->cancelflags, THR_CANCEL_DISABLE);
98 testcancel(curthread);
99 ret = 0;
100 break;
101 default:
102 ret = EINVAL;
105 return (ret);
109 _pthread_setcanceltype(int type, int *oldtype)
111 struct pthread *curthread = tls_get_curthread();
112 int oldval, ret;
114 oldval = curthread->cancelflags;
115 if (oldtype != NULL)
116 *oldtype = ((oldval & THR_CANCEL_AT_POINT) ?
117 PTHREAD_CANCEL_ASYNCHRONOUS :
118 PTHREAD_CANCEL_DEFERRED);
119 switch (type) {
120 case PTHREAD_CANCEL_ASYNCHRONOUS:
121 atomic_set_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
122 testcancel(curthread);
123 ret = 0;
124 break;
125 case PTHREAD_CANCEL_DEFERRED:
126 atomic_clear_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
127 ret = 0;
128 break;
129 default:
130 ret = EINVAL;
133 return (ret);
136 void
137 _pthread_testcancel(void)
139 testcancel(tls_get_curthread());
143 _thr_cancel_enter(struct pthread *curthread)
145 int oldval;
147 oldval = curthread->cancelflags;
148 if (!(oldval & THR_CANCEL_AT_POINT)) {
149 atomic_set_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
150 testcancel(curthread);
152 return (oldval);
155 void
156 _thr_cancel_leave(struct pthread *curthread, int previous)
158 if (!(previous & THR_CANCEL_AT_POINT))
159 atomic_clear_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
162 __strong_reference(_pthread_cancel, pthread_cancel);
163 __strong_reference(_pthread_setcancelstate, pthread_setcancelstate);
164 __strong_reference(_pthread_setcanceltype, pthread_setcanceltype);
165 __strong_reference(_pthread_testcancel, pthread_testcancel);