xref: /freebsd/lib/libthr/thread/thr_cancel.c (revision 4cd18a22d554e7205ddf0408badbda02411ed51e)
1bb535300SJeff Roberson /*
2bb535300SJeff Roberson  * David Leonard <d@openbsd.org>, 1999. Public domain.
3bb535300SJeff Roberson  * $FreeBSD$
4bb535300SJeff Roberson  */
5bb535300SJeff Roberson #include <sys/errno.h>
6bb535300SJeff Roberson #include <pthread.h>
77d9d7ca2SMike Makonnen #include <stdlib.h>
8bb535300SJeff Roberson #include "thr_private.h"
9bb535300SJeff Roberson 
106da7f493SMike Makonnen /*
116da7f493SMike Makonnen  * Static prototypes
126da7f493SMike Makonnen  */
136da7f493SMike Makonnen static void	testcancel(void);
146da7f493SMike Makonnen 
15bb535300SJeff Roberson __weak_reference(_pthread_cancel, pthread_cancel);
16bb535300SJeff Roberson __weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
17bb535300SJeff Roberson __weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
18bb535300SJeff Roberson __weak_reference(_pthread_testcancel, pthread_testcancel);
19bb535300SJeff Roberson 
204cd18a22SMike Makonnen /*
214cd18a22SMike Makonnen  * Posix requires this function to be async-cancel-safe, so it
224cd18a22SMike Makonnen  * may not aquire any type of resource or call any functions
234cd18a22SMike Makonnen  * that might do so.
244cd18a22SMike Makonnen  */
25bb535300SJeff Roberson int
26bb535300SJeff Roberson _pthread_cancel(pthread_t pthread)
27bb535300SJeff Roberson {
284cd18a22SMike Makonnen 	/* Don't continue if cancellation has already been set. */
294cd18a22SMike Makonnen 	if (atomic_cmpset_int(&pthread->cancellation, (int)CS_NULL,
304cd18a22SMike Makonnen 	    (int)CS_PENDING) != 1)
314cd18a22SMike Makonnen 		return (0);
32bb535300SJeff Roberson 
33d39d6512SMike Makonnen 	/*
344cd18a22SMike Makonnen 	 * Only wakeup threads that are in cancellation points or
354cd18a22SMike Makonnen 	 * have set async cancel.
364cd18a22SMike Makonnen 	 * XXX - access to pthread->flags is not safe. We should just
374cd18a22SMike Makonnen 	 *	 unconditionally wake the thread and make sure that
384cd18a22SMike Makonnen 	 *	 the the library correctly handles spurious wakeups.
39d39d6512SMike Makonnen 	 */
404cd18a22SMike Makonnen 	if ((pthread->cancellationpoint || pthread->cancelmode == M_ASYNC) &&
414cd18a22SMike Makonnen 	    (pthread->flags & PTHREAD_FLAGS_NOT_RUNNING) != 0)
424cd18a22SMike Makonnen 		PTHREAD_WAKE(pthread);
434cd18a22SMike Makonnen 	return (0);
446da7f493SMike Makonnen }
456da7f493SMike Makonnen 
466da7f493SMike Makonnen /*
474cd18a22SMike Makonnen  * Posix requires this function to be async-cancel-safe, so it
484cd18a22SMike Makonnen  * may not aquire any type of resource or call any functions
494cd18a22SMike Makonnen  * that might do so.
506da7f493SMike Makonnen  */
51bb535300SJeff Roberson int
52bb535300SJeff Roberson _pthread_setcancelstate(int state, int *oldstate)
53bb535300SJeff Roberson {
544cd18a22SMike Makonnen 	int ostate;
55bb535300SJeff Roberson 
564cd18a22SMike Makonnen 	ostate = (curthread->cancelmode == M_OFF) ? PTHREAD_CANCEL_DISABLE :
574cd18a22SMike Makonnen 	    PTHREAD_CANCEL_ENABLE;
58bb535300SJeff Roberson 	switch (state) {
59bb535300SJeff Roberson 	case PTHREAD_CANCEL_ENABLE:
604cd18a22SMike Makonnen 		curthread->cancelmode = curthread->cancelstate;
61bb535300SJeff Roberson 		break;
62bb535300SJeff Roberson 	case PTHREAD_CANCEL_DISABLE:
634cd18a22SMike Makonnen 		if (curthread->cancelmode != M_OFF) {
644cd18a22SMike Makonnen 			curthread->cancelstate = curthread->cancelmode;
654cd18a22SMike Makonnen 			curthread->cancelmode = M_OFF;
66bb535300SJeff Roberson 		}
67bb535300SJeff Roberson 		break;
68bb535300SJeff Roberson 	default:
69bb535300SJeff Roberson 		return (EINVAL);
70bb535300SJeff Roberson 	}
714cd18a22SMike Makonnen 	if (oldstate != NULL)
724cd18a22SMike Makonnen 		*oldstate = ostate;
734cd18a22SMike Makonnen 	return (0);
744cd18a22SMike Makonnen }
75bb535300SJeff Roberson 
764cd18a22SMike Makonnen /*
774cd18a22SMike Makonnen  * Posix requires this function to be async-cancel-safe, so it
784cd18a22SMike Makonnen  * may not aquire any type of resource or call any functions that
794cd18a22SMike Makonnen  * might do so.
804cd18a22SMike Makonnen  */
814cd18a22SMike Makonnen int
824cd18a22SMike Makonnen _pthread_setcanceltype(int type, int *oldtype)
834cd18a22SMike Makonnen {
844cd18a22SMike Makonnen 	enum cancel_mode omode;
854cd18a22SMike Makonnen 
864cd18a22SMike Makonnen 	omode = curthread->cancelstate;
874cd18a22SMike Makonnen 	switch (type) {
884cd18a22SMike Makonnen 	case PTHREAD_CANCEL_ASYNCHRONOUS:
894cd18a22SMike Makonnen 		if (curthread->cancelmode != M_OFF)
904cd18a22SMike Makonnen 			curthread->cancelmode = M_ASYNC;
914cd18a22SMike Makonnen 		curthread->cancelstate = M_ASYNC;
924cd18a22SMike Makonnen 		break;
934cd18a22SMike Makonnen 	case PTHREAD_CANCEL_DEFERRED:
944cd18a22SMike Makonnen 		if (curthread->cancelmode != M_OFF)
954cd18a22SMike Makonnen 			curthread->cancelmode = M_DEFERRED;
964cd18a22SMike Makonnen 		curthread->cancelstate = M_DEFERRED;
974cd18a22SMike Makonnen 		break;
984cd18a22SMike Makonnen 	default:
994cd18a22SMike Makonnen 		return (EINVAL);
1004cd18a22SMike Makonnen 	}
1014cd18a22SMike Makonnen 	if (oldtype != NULL) {
1024cd18a22SMike Makonnen 		if (omode == M_DEFERRED)
1034cd18a22SMike Makonnen 			*oldtype = PTHREAD_CANCEL_DEFERRED;
1044cd18a22SMike Makonnen 		else if (omode == M_ASYNC)
1054cd18a22SMike Makonnen 			*oldtype = PTHREAD_CANCEL_ASYNCHRONOUS;
1064cd18a22SMike Makonnen 	}
107bb535300SJeff Roberson 	return (0);
108bb535300SJeff Roberson }
109bb535300SJeff Roberson 
110bb535300SJeff Roberson void
111bb535300SJeff Roberson _pthread_testcancel(void)
112bb535300SJeff Roberson {
1136da7f493SMike Makonnen 	testcancel();
1146da7f493SMike Makonnen }
1156da7f493SMike Makonnen 
1166da7f493SMike Makonnen static void
1176da7f493SMike Makonnen testcancel()
1186da7f493SMike Makonnen {
1194cd18a22SMike Makonnen 	if (curthread->cancelmode != M_OFF) {
1206da7f493SMike Makonnen 
1214cd18a22SMike Makonnen 		/* Cleanup a canceled thread only once. */
1224cd18a22SMike Makonnen 		if (atomic_cmpset_int(&curthread->cancellation,
1234cd18a22SMike Makonnen 		    (int)CS_PENDING, (int)CS_SET) == 1) {
124bb535300SJeff Roberson 			_thread_exit_cleanup();
125bb535300SJeff Roberson 			pthread_exit(PTHREAD_CANCELED);
126bb535300SJeff Roberson 			PANIC("cancel");
127bb535300SJeff Roberson 		}
128bb535300SJeff Roberson 	}
1294cd18a22SMike Makonnen }
130bb535300SJeff Roberson 
131bb535300SJeff Roberson void
132bb535300SJeff Roberson _thread_enter_cancellation_point(void)
133bb535300SJeff Roberson {
1346da7f493SMike Makonnen 	testcancel();
1354cd18a22SMike Makonnen 	curthread->cancellationpoint = 1;
136bb535300SJeff Roberson }
137bb535300SJeff Roberson 
138bb535300SJeff Roberson void
139bb535300SJeff Roberson _thread_leave_cancellation_point(void)
140bb535300SJeff Roberson {
1414cd18a22SMike Makonnen 	curthread->cancellationpoint = 0;
1426da7f493SMike Makonnen 	testcancel();
143bb535300SJeff Roberson }
144