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> 7bb535300SJeff Roberson #include "thr_private.h" 8bb535300SJeff Roberson 9bb535300SJeff Roberson __weak_reference(_pthread_cancel, pthread_cancel); 10bb535300SJeff Roberson __weak_reference(_pthread_setcancelstate, pthread_setcancelstate); 11bb535300SJeff Roberson __weak_reference(_pthread_setcanceltype, pthread_setcanceltype); 12bb535300SJeff Roberson __weak_reference(_pthread_testcancel, pthread_testcancel); 13bb535300SJeff Roberson 14bb535300SJeff Roberson int 15bb535300SJeff Roberson _pthread_cancel(pthread_t pthread) 16bb535300SJeff Roberson { 17bb535300SJeff Roberson int ret; 18bb535300SJeff Roberson pthread_t curthread; 19bb535300SJeff Roberson 20bb535300SJeff Roberson if ((ret = _find_thread(pthread)) != 0) { 21bb535300SJeff Roberson /* NOTHING */ 22bb535300SJeff Roberson } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK 23bb535300SJeff Roberson || (pthread->flags & PTHREAD_EXITING) != 0) { 24bb535300SJeff Roberson ret = 0; 25bb535300SJeff Roberson } else { 26bb535300SJeff Roberson curthread = _get_curthread(); 27bb535300SJeff Roberson GIANT_LOCK(curthread); 28bb535300SJeff Roberson 29bb535300SJeff Roberson if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) || 30bb535300SJeff Roberson (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) && 31bb535300SJeff Roberson ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0))) 32bb535300SJeff Roberson /* Just mark it for cancellation: */ 33bb535300SJeff Roberson pthread->cancelflags |= PTHREAD_CANCELLING; 34bb535300SJeff Roberson else { 35bb535300SJeff Roberson /* 36bb535300SJeff Roberson * Check if we need to kick it back into the 37bb535300SJeff Roberson * run queue: 38bb535300SJeff Roberson */ 39bb535300SJeff Roberson switch (pthread->state) { 40bb535300SJeff Roberson case PS_RUNNING: 41bb535300SJeff Roberson /* No need to resume: */ 42bb535300SJeff Roberson pthread->cancelflags |= PTHREAD_CANCELLING; 43bb535300SJeff Roberson break; 44bb535300SJeff Roberson 45bb535300SJeff Roberson case PS_SLEEP_WAIT: 46bb535300SJeff Roberson case PS_WAIT_WAIT: 47bb535300SJeff Roberson pthread->cancelflags |= PTHREAD_CANCELLING; 48bb535300SJeff Roberson PTHREAD_NEW_STATE(pthread, PS_RUNNING); 49bb535300SJeff Roberson break; 50bb535300SJeff Roberson 51bb535300SJeff Roberson case PS_JOIN: 52bb535300SJeff Roberson /* 53bb535300SJeff Roberson * Disconnect the thread from the joinee: 54bb535300SJeff Roberson */ 55bb535300SJeff Roberson if (pthread->join_status.thread != NULL) { 56bb535300SJeff Roberson pthread->join_status.thread->joiner 57bb535300SJeff Roberson = NULL; 58bb535300SJeff Roberson pthread->join_status.thread = NULL; 59bb535300SJeff Roberson } 60bb535300SJeff Roberson pthread->cancelflags |= PTHREAD_CANCELLING; 61bb535300SJeff Roberson PTHREAD_NEW_STATE(pthread, PS_RUNNING); 62bb535300SJeff Roberson break; 63bb535300SJeff Roberson 64bb535300SJeff Roberson case PS_MUTEX_WAIT: 65bb535300SJeff Roberson case PS_COND_WAIT: 66bb535300SJeff Roberson /* 67bb535300SJeff Roberson * Threads in these states may be in queues. 68bb535300SJeff Roberson * In order to preserve queue integrity, the 69bb535300SJeff Roberson * cancelled thread must remove itself from the 70bb535300SJeff Roberson * queue. When the thread resumes, it will 71bb535300SJeff Roberson * remove itself from the queue and call the 72bb535300SJeff Roberson * cancellation routine. 73bb535300SJeff Roberson */ 74bb535300SJeff Roberson pthread->cancelflags |= PTHREAD_CANCELLING; 75bb535300SJeff Roberson PTHREAD_NEW_STATE(pthread, PS_RUNNING); 76bb535300SJeff Roberson break; 77bb535300SJeff Roberson 78bb535300SJeff Roberson case PS_DEAD: 79bb535300SJeff Roberson case PS_DEADLOCK: 80bb535300SJeff Roberson case PS_STATE_MAX: 81bb535300SJeff Roberson /* Ignore - only here to silence -Wall: */ 82bb535300SJeff Roberson break; 83bb535300SJeff Roberson } 84bb535300SJeff Roberson } 85bb535300SJeff Roberson 86bb535300SJeff Roberson /* Unprotect the scheduling queues: */ 87bb535300SJeff Roberson GIANT_UNLOCK(curthread); 88bb535300SJeff Roberson 89bb535300SJeff Roberson ret = 0; 90bb535300SJeff Roberson } 91bb535300SJeff Roberson return (ret); 92bb535300SJeff Roberson } 93bb535300SJeff Roberson 94bb535300SJeff Roberson int 95bb535300SJeff Roberson _pthread_setcancelstate(int state, int *oldstate) 96bb535300SJeff Roberson { 97bb535300SJeff Roberson struct pthread *curthread = _get_curthread(); 98bb535300SJeff Roberson int ostate; 99bb535300SJeff Roberson 100bb535300SJeff Roberson GIANT_LOCK(curthread); 101bb535300SJeff Roberson ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE; 102bb535300SJeff Roberson 103bb535300SJeff Roberson switch (state) { 104bb535300SJeff Roberson case PTHREAD_CANCEL_ENABLE: 105bb535300SJeff Roberson if (oldstate != NULL) 106bb535300SJeff Roberson *oldstate = ostate; 107bb535300SJeff Roberson curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE; 108bb535300SJeff Roberson if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) 109bb535300SJeff Roberson break; 110bb535300SJeff Roberson GIANT_UNLOCK(curthread); 111bb535300SJeff Roberson pthread_testcancel(); 112bb535300SJeff Roberson break; 113bb535300SJeff Roberson case PTHREAD_CANCEL_DISABLE: 114bb535300SJeff Roberson if (oldstate != NULL) 115bb535300SJeff Roberson *oldstate = ostate; 116bb535300SJeff Roberson curthread->cancelflags |= PTHREAD_CANCEL_DISABLE; 117bb535300SJeff Roberson GIANT_UNLOCK(curthread); 118bb535300SJeff Roberson break; 119bb535300SJeff Roberson default: 120bb535300SJeff Roberson GIANT_UNLOCK(curthread); 121bb535300SJeff Roberson return (EINVAL); 122bb535300SJeff Roberson } 123bb535300SJeff Roberson 124bb535300SJeff Roberson return (0); 125bb535300SJeff Roberson } 126bb535300SJeff Roberson 127bb535300SJeff Roberson int 128bb535300SJeff Roberson _pthread_setcanceltype(int type, int *oldtype) 129bb535300SJeff Roberson { 130bb535300SJeff Roberson struct pthread *curthread = _get_curthread(); 131bb535300SJeff Roberson int otype; 132bb535300SJeff Roberson 133bb535300SJeff Roberson GIANT_LOCK(curthread); 134bb535300SJeff Roberson otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS; 135bb535300SJeff Roberson switch (type) { 136bb535300SJeff Roberson case PTHREAD_CANCEL_ASYNCHRONOUS: 137bb535300SJeff Roberson if (oldtype != NULL) 138bb535300SJeff Roberson *oldtype = otype; 139bb535300SJeff Roberson curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS; 140bb535300SJeff Roberson GIANT_UNLOCK(curthread); 141bb535300SJeff Roberson pthread_testcancel(); 142bb535300SJeff Roberson break; 143bb535300SJeff Roberson case PTHREAD_CANCEL_DEFERRED: 144bb535300SJeff Roberson if (oldtype != NULL) 145bb535300SJeff Roberson *oldtype = otype; 146bb535300SJeff Roberson curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS; 147bb535300SJeff Roberson GIANT_UNLOCK(curthread); 148bb535300SJeff Roberson break; 149bb535300SJeff Roberson default: 150bb535300SJeff Roberson GIANT_UNLOCK(curthread); 151bb535300SJeff Roberson return (EINVAL); 152bb535300SJeff Roberson } 153bb535300SJeff Roberson 154bb535300SJeff Roberson return (0); 155bb535300SJeff Roberson } 156bb535300SJeff Roberson 157bb535300SJeff Roberson /* 158bb535300SJeff Roberson * XXXTHR Make an internal locked version. 159bb535300SJeff Roberson */ 160bb535300SJeff Roberson void 161bb535300SJeff Roberson _pthread_testcancel(void) 162bb535300SJeff Roberson { 163bb535300SJeff Roberson struct pthread *curthread = _get_curthread(); 164bb535300SJeff Roberson 165bb535300SJeff Roberson GIANT_LOCK(curthread); 166bb535300SJeff Roberson if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) && 167bb535300SJeff Roberson ((curthread->cancelflags & PTHREAD_CANCELLING) != 0) && 168bb535300SJeff Roberson ((curthread->flags & PTHREAD_EXITING) == 0)) { 169bb535300SJeff Roberson /* 170bb535300SJeff Roberson * It is possible for this thread to be swapped out 171bb535300SJeff Roberson * while performing cancellation; do not allow it 172bb535300SJeff Roberson * to be cancelled again. 173bb535300SJeff Roberson */ 174bb535300SJeff Roberson curthread->cancelflags &= ~PTHREAD_CANCELLING; 175bb535300SJeff Roberson GIANT_UNLOCK(curthread); 176bb535300SJeff Roberson _thread_exit_cleanup(); 177bb535300SJeff Roberson pthread_exit(PTHREAD_CANCELED); 178bb535300SJeff Roberson PANIC("cancel"); 179bb535300SJeff Roberson } 180bb535300SJeff Roberson GIANT_UNLOCK(curthread); 181bb535300SJeff Roberson } 182bb535300SJeff Roberson 183bb535300SJeff Roberson void 184bb535300SJeff Roberson _thread_enter_cancellation_point(void) 185bb535300SJeff Roberson { 186bb535300SJeff Roberson struct pthread *curthread = _get_curthread(); 187bb535300SJeff Roberson 188bb535300SJeff Roberson pthread_testcancel(); 189bb535300SJeff Roberson 190bb535300SJeff Roberson GIANT_LOCK(curthread); 191bb535300SJeff Roberson curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT; 192bb535300SJeff Roberson GIANT_UNLOCK(curthread); 193bb535300SJeff Roberson } 194bb535300SJeff Roberson 195bb535300SJeff Roberson void 196bb535300SJeff Roberson _thread_leave_cancellation_point(void) 197bb535300SJeff Roberson { 198bb535300SJeff Roberson struct pthread *curthread = _get_curthread(); 199bb535300SJeff Roberson 200bb535300SJeff Roberson GIANT_LOCK(curthread); 201bb535300SJeff Roberson curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT; 202bb535300SJeff Roberson GIANT_UNLOCK(curthread); 203bb535300SJeff Roberson 204bb535300SJeff Roberson pthread_testcancel(); 205bb535300SJeff Roberson } 206