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