1112918Sjeff/*
2144518Sdavidxu * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
3144518Sdavidxu * All rights reserved.
4144518Sdavidxu *
5144518Sdavidxu * Redistribution and use in source and binary forms, with or without
6144518Sdavidxu * modification, are permitted provided that the following conditions
7144518Sdavidxu * are met:
8144518Sdavidxu * 1. Redistributions of source code must retain the above copyright
9144518Sdavidxu *    notice unmodified, this list of conditions, and the following
10144518Sdavidxu *    disclaimer.
11144518Sdavidxu * 2. Redistributions in binary form must reproduce the above copyright
12144518Sdavidxu *    notice, this list of conditions and the following disclaimer in the
13144518Sdavidxu *    documentation and/or other materials provided with the distribution.
14144518Sdavidxu *
15144518Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16144518Sdavidxu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17144518Sdavidxu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18144518Sdavidxu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19144518Sdavidxu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20144518Sdavidxu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21144518Sdavidxu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22144518Sdavidxu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23144518Sdavidxu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24144518Sdavidxu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25144518Sdavidxu *
26112918Sjeff * $FreeBSD: stable/10/lib/libthr/thread/thr_cancel.c 332633 2018-04-16 20:45:21Z jhb $
27144518Sdavidxu *
28112918Sjeff */
29144518Sdavidxu
30157457Sdavidxu#include "namespace.h"
31112918Sjeff#include <pthread.h>
32157457Sdavidxu#include "un-namespace.h"
33144518Sdavidxu
34112918Sjeff#include "thr_private.h"
35112918Sjeff
36112918Sjeff__weak_reference(_pthread_cancel, pthread_cancel);
37112918Sjeff__weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
38112918Sjeff__weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
39112918Sjeff__weak_reference(_pthread_testcancel, pthread_testcancel);
40112918Sjeff
41164583Sdavidxustatic inline void
42164583Sdavidxutestcancel(struct pthread *curthread)
43164583Sdavidxu{
44164583Sdavidxu	if (__predict_false(SHOULD_CANCEL(curthread) &&
45211524Sdavidxu	    !THR_IN_CRITICAL(curthread)))
46164583Sdavidxu		_pthread_exit(PTHREAD_CANCELED);
47164583Sdavidxu}
48164583Sdavidxu
49164583Sdavidxuvoid
50164583Sdavidxu_thr_testcancel(struct pthread *curthread)
51164583Sdavidxu{
52164583Sdavidxu	testcancel(curthread);
53164583Sdavidxu}
54164583Sdavidxu
55112918Sjeffint
56112918Sjeff_pthread_cancel(pthread_t pthread)
57112918Sjeff{
58144518Sdavidxu	struct pthread *curthread = _get_curthread();
59144518Sdavidxu	int ret;
60112918Sjeff
61115307Smtm	/*
62164583Sdavidxu	 * POSIX says _pthread_cancel should be async cancellation safe.
63212536Sdavidxu	 * _thr_find_thread and THR_THREAD_UNLOCK will enter and leave critical
64164583Sdavidxu	 * region automatically.
65115307Smtm	 */
66212536Sdavidxu	if ((ret = _thr_find_thread(curthread, pthread, 0)) == 0) {
67164583Sdavidxu		if (!pthread->cancel_pending) {
68164583Sdavidxu			pthread->cancel_pending = 1;
69212312Sdavidxu			if (pthread->state != PS_DEAD)
70164583Sdavidxu				_thr_send_sig(pthread, SIGCANCEL);
71164583Sdavidxu		}
72164583Sdavidxu		THR_THREAD_UNLOCK(curthread, pthread);
73144518Sdavidxu	}
74164583Sdavidxu	return (ret);
75112918Sjeff}
76112918Sjeff
77112918Sjeffint
78112918Sjeff_pthread_setcancelstate(int state, int *oldstate)
79112918Sjeff{
80144518Sdavidxu	struct pthread *curthread = _get_curthread();
81164583Sdavidxu	int oldval;
82112918Sjeff
83164583Sdavidxu	oldval = curthread->cancel_enable;
84112918Sjeff	switch (state) {
85144518Sdavidxu	case PTHREAD_CANCEL_DISABLE:
86164583Sdavidxu		curthread->cancel_enable = 0;
87144518Sdavidxu		break;
88112918Sjeff	case PTHREAD_CANCEL_ENABLE:
89164583Sdavidxu		curthread->cancel_enable = 1;
90251985Skib		if (curthread->cancel_async)
91251985Skib			testcancel(curthread);
92112918Sjeff		break;
93112918Sjeff	default:
94164583Sdavidxu		return (EINVAL);
95112918Sjeff	}
96144518Sdavidxu
97164583Sdavidxu	if (oldstate) {
98164583Sdavidxu		*oldstate = oldval ? PTHREAD_CANCEL_ENABLE :
99164583Sdavidxu			PTHREAD_CANCEL_DISABLE;
100164583Sdavidxu	}
101164583Sdavidxu	return (0);
102112918Sjeff}
103112918Sjeff
104112918Sjeffint
105112918Sjeff_pthread_setcanceltype(int type, int *oldtype)
106112918Sjeff{
107144518Sdavidxu	struct pthread	*curthread = _get_curthread();
108164583Sdavidxu	int oldval;
109112918Sjeff
110164583Sdavidxu	oldval = curthread->cancel_async;
111112918Sjeff	switch (type) {
112112918Sjeff	case PTHREAD_CANCEL_ASYNCHRONOUS:
113164583Sdavidxu		curthread->cancel_async = 1;
114144518Sdavidxu		testcancel(curthread);
115112918Sjeff		break;
116112918Sjeff	case PTHREAD_CANCEL_DEFERRED:
117164583Sdavidxu		curthread->cancel_async = 0;
118112918Sjeff		break;
119112918Sjeff	default:
120164583Sdavidxu		return (EINVAL);
121112918Sjeff	}
122144518Sdavidxu
123164583Sdavidxu	if (oldtype) {
124164583Sdavidxu		*oldtype = oldval ? PTHREAD_CANCEL_ASYNCHRONOUS :
125164583Sdavidxu		 	PTHREAD_CANCEL_DEFERRED;
126164583Sdavidxu	}
127164583Sdavidxu	return (0);
128112918Sjeff}
129112918Sjeff
130112918Sjeffvoid
131112918Sjeff_pthread_testcancel(void)
132112918Sjeff{
133332633Sjhb	struct pthread *curthread;
134164583Sdavidxu
135332633Sjhb	_thr_check_init();
136332633Sjhb	curthread = _get_curthread();
137212076Sdavidxu	testcancel(curthread);
138115033Smtm}
139115033Smtm
140164583Sdavidxuvoid
141144518Sdavidxu_thr_cancel_enter(struct pthread *curthread)
142115033Smtm{
143212076Sdavidxu	curthread->cancel_point = 1;
144212076Sdavidxu	testcancel(curthread);
145211524Sdavidxu}
146211524Sdavidxu
147211524Sdavidxuvoid
148212076Sdavidxu_thr_cancel_enter2(struct pthread *curthread, int maycancel)
149211524Sdavidxu{
150212076Sdavidxu	curthread->cancel_point = 1;
151211524Sdavidxu	if (__predict_false(SHOULD_CANCEL(curthread) &&
152211524Sdavidxu	    !THR_IN_CRITICAL(curthread))) {
153211524Sdavidxu		if (!maycancel)
154211524Sdavidxu			thr_wake(curthread->tid);
155211524Sdavidxu		else
156211524Sdavidxu			_pthread_exit(PTHREAD_CANCELED);
157112918Sjeff	}
158112918Sjeff}
159112918Sjeff
160112918Sjeffvoid
161212076Sdavidxu_thr_cancel_leave(struct pthread *curthread, int maycancel)
162112918Sjeff{
163213096Sdavidxu	curthread->cancel_point = 0;
164213100Sdavidxu	if (__predict_false(SHOULD_CANCEL(curthread) &&
165213100Sdavidxu	    !THR_IN_CRITICAL(curthread) && maycancel))
166213100Sdavidxu		_pthread_exit(PTHREAD_CANCELED);
167164877Sdavidxu}
168213153Sdavidxu
169213153Sdavidxuvoid
170213153Sdavidxu_pthread_cancel_enter(int maycancel)
171213153Sdavidxu{
172213153Sdavidxu	_thr_cancel_enter2(_get_curthread(), maycancel);
173213153Sdavidxu}
174213153Sdavidxu
175213153Sdavidxuvoid
176213153Sdavidxu_pthread_cancel_leave(int maycancel)
177213153Sdavidxu{
178213153Sdavidxu	_thr_cancel_leave(_get_curthread(), maycancel);
179213153Sdavidxu}
180