thr_cancel.c revision 111035
153812Salfred/* 253812Salfred * David Leonard <d@openbsd.org>, 1999. Public domain. 353812Salfred * $FreeBSD: head/lib/libkse/thread/thr_cancel.c 111035 2003-02-17 10:05:18Z mini $ 453812Salfred */ 553812Salfred#include <sys/errno.h> 653812Salfred#include <pthread.h> 7103388Smini#include "thr_private.h" 853812Salfred 956277Sjasonestatic void finish_cancellation(void *arg); 1056277Sjasone 1175369Sdeischen__weak_reference(_pthread_cancel, pthread_cancel); 1275369Sdeischen__weak_reference(_pthread_setcancelstate, pthread_setcancelstate); 1375369Sdeischen__weak_reference(_pthread_setcanceltype, pthread_setcanceltype); 1475369Sdeischen__weak_reference(_pthread_testcancel, pthread_testcancel); 1571581Sdeischen 1653812Salfredint 1771581Sdeischen_pthread_cancel(pthread_t pthread) 1853812Salfred{ 1953812Salfred int ret; 2053812Salfred 2153812Salfred if ((ret = _find_thread(pthread)) != 0) { 2253812Salfred /* NOTHING */ 2395947Sarchie } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK 2495947Sarchie || (pthread->flags & PTHREAD_EXITING) != 0) { 2553812Salfred ret = 0; 2653812Salfred } else { 2753812Salfred /* Protect the scheduling queues: */ 2853812Salfred _thread_kern_sig_defer(); 2953812Salfred 3054708Sdeischen if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) || 3154708Sdeischen (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) && 3254708Sdeischen ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0))) 3354708Sdeischen /* Just mark it for cancellation: */ 3454708Sdeischen pthread->cancelflags |= PTHREAD_CANCELLING; 3554708Sdeischen else { 3654708Sdeischen /* 3754708Sdeischen * Check if we need to kick it back into the 3854708Sdeischen * run queue: 3954708Sdeischen */ 4053812Salfred switch (pthread->state) { 4153812Salfred case PS_RUNNING: 4253812Salfred /* No need to resume: */ 4353812Salfred pthread->cancelflags |= PTHREAD_CANCELLING; 4453812Salfred break; 4553812Salfred 4653812Salfred case PS_SPINBLOCK: 4754708Sdeischen /* Remove these threads from the work queue: */ 4853812Salfred if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) 4953812Salfred != 0) 5053812Salfred PTHREAD_WORKQ_REMOVE(pthread); 5153812Salfred /* Fall through: */ 5253812Salfred case PS_SLEEP_WAIT: 5353812Salfred case PS_WAIT_WAIT: 54111035Smini case PS_SIGSUSPEND: 55111035Smini case PS_SIGWAIT: 5653812Salfred /* Interrupt and resume: */ 5753812Salfred pthread->interrupted = 1; 5853812Salfred pthread->cancelflags |= PTHREAD_CANCELLING; 5953812Salfred PTHREAD_NEW_STATE(pthread,PS_RUNNING); 6053812Salfred break; 6153812Salfred 6276909Sjasone case PS_JOIN: 6381750Sjasone /* 6488015Sdeischen * Disconnect the thread from the joinee: 6581750Sjasone */ 6687988Sdeischen if (pthread->join_status.thread != NULL) { 6787988Sdeischen pthread->join_status.thread->joiner 6887988Sdeischen = NULL; 6991762Sdeischen pthread->join_status.thread = NULL; 7081750Sjasone } 7181750Sjasone pthread->cancelflags |= PTHREAD_CANCELLING; 7281750Sjasone PTHREAD_NEW_STATE(pthread, PS_RUNNING); 7381750Sjasone break; 7481750Sjasone 7561681Sjasone case PS_SUSPENDED: 7653812Salfred case PS_MUTEX_WAIT: 7753812Salfred case PS_COND_WAIT: 7853812Salfred /* 7953812Salfred * Threads in these states may be in queues. 8053812Salfred * In order to preserve queue integrity, the 8153812Salfred * cancelled thread must remove itself from the 8253812Salfred * queue. Mark the thread as interrupted and 8353812Salfred * needing cancellation, and set the state to 8453812Salfred * running. When the thread resumes, it will 8556277Sjasone * remove itself from the queue and call the 8656277Sjasone * cancellation completion routine. 8753812Salfred */ 8853812Salfred pthread->interrupted = 1; 8953812Salfred pthread->cancelflags |= PTHREAD_CANCEL_NEEDED; 9097204Sdeischen PTHREAD_NEW_STATE(pthread, PS_RUNNING); 9156277Sjasone pthread->continuation = finish_cancellation; 9253812Salfred break; 9353812Salfred 9453812Salfred case PS_DEAD: 9553812Salfred case PS_DEADLOCK: 9653812Salfred case PS_STATE_MAX: 9753812Salfred /* Ignore - only here to silence -Wall: */ 9853812Salfred break; 9954708Sdeischen } 10053812Salfred } 10154708Sdeischen 10253812Salfred /* Unprotect the scheduling queues: */ 10353812Salfred _thread_kern_sig_undefer(); 10453812Salfred 10553812Salfred ret = 0; 10653812Salfred } 10753812Salfred return (ret); 10853812Salfred} 10953812Salfred 11053812Salfredint 11171581Sdeischen_pthread_setcancelstate(int state, int *oldstate) 11253812Salfred{ 11371581Sdeischen struct pthread *curthread = _get_curthread(); 11453812Salfred int ostate; 11553812Salfred int ret; 11653812Salfred 11771581Sdeischen ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE; 11853812Salfred 11953812Salfred switch (state) { 12053812Salfred case PTHREAD_CANCEL_ENABLE: 12153812Salfred if (oldstate != NULL) 12253812Salfred *oldstate = ostate; 12371581Sdeischen curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE; 12471581Sdeischen if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0) 12553812Salfred pthread_testcancel(); 12653812Salfred ret = 0; 12753812Salfred break; 12853812Salfred case PTHREAD_CANCEL_DISABLE: 12953812Salfred if (oldstate != NULL) 13053812Salfred *oldstate = ostate; 13171581Sdeischen curthread->cancelflags |= PTHREAD_CANCEL_DISABLE; 13253812Salfred ret = 0; 13353812Salfred break; 13453812Salfred default: 13553812Salfred ret = EINVAL; 13653812Salfred } 13753812Salfred 13853812Salfred return (ret); 13953812Salfred} 14053812Salfred 14153812Salfredint 14271581Sdeischen_pthread_setcanceltype(int type, int *oldtype) 14353812Salfred{ 14471581Sdeischen struct pthread *curthread = _get_curthread(); 14553812Salfred int otype; 14653812Salfred int ret; 14753812Salfred 14871581Sdeischen otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS; 14953812Salfred switch (type) { 15053812Salfred case PTHREAD_CANCEL_ASYNCHRONOUS: 15153812Salfred if (oldtype != NULL) 15253812Salfred *oldtype = otype; 15371581Sdeischen curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS; 15453812Salfred pthread_testcancel(); 15553812Salfred ret = 0; 15653812Salfred break; 15753812Salfred case PTHREAD_CANCEL_DEFERRED: 15853812Salfred if (oldtype != NULL) 15953812Salfred *oldtype = otype; 16071581Sdeischen curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS; 16153812Salfred ret = 0; 16253812Salfred break; 16353812Salfred default: 16453812Salfred ret = EINVAL; 16553812Salfred } 16653812Salfred 16753812Salfred return (ret); 16853812Salfred} 16953812Salfred 17053812Salfredvoid 17171581Sdeischen_pthread_testcancel(void) 17253812Salfred{ 17371581Sdeischen struct pthread *curthread = _get_curthread(); 17471581Sdeischen 17571581Sdeischen if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) && 17695947Sarchie ((curthread->cancelflags & PTHREAD_CANCELLING) != 0) && 17795947Sarchie ((curthread->flags & PTHREAD_EXITING) == 0)) { 17853812Salfred /* 17953812Salfred * It is possible for this thread to be swapped out 18053812Salfred * while performing cancellation; do not allow it 18153812Salfred * to be cancelled again. 18253812Salfred */ 18371581Sdeischen curthread->cancelflags &= ~PTHREAD_CANCELLING; 18453812Salfred _thread_exit_cleanup(); 18553812Salfred pthread_exit(PTHREAD_CANCELED); 18653812Salfred PANIC("cancel"); 18753812Salfred } 18853812Salfred} 18953812Salfred 19053812Salfredvoid 19153812Salfred_thread_enter_cancellation_point(void) 19253812Salfred{ 19371581Sdeischen struct pthread *curthread = _get_curthread(); 19471581Sdeischen 19553812Salfred /* Look for a cancellation before we block: */ 19653812Salfred pthread_testcancel(); 19771581Sdeischen curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT; 19853812Salfred} 19953812Salfred 20053812Salfredvoid 20153812Salfred_thread_leave_cancellation_point(void) 20253812Salfred{ 20371581Sdeischen struct pthread *curthread = _get_curthread(); 20471581Sdeischen 20571581Sdeischen curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT; 20653812Salfred /* Look for a cancellation after we unblock: */ 20753812Salfred pthread_testcancel(); 20853812Salfred} 20956277Sjasone 21056277Sjasonestatic void 21156277Sjasonefinish_cancellation(void *arg) 21256277Sjasone{ 21371581Sdeischen struct pthread *curthread = _get_curthread(); 21456277Sjasone 21571581Sdeischen curthread->continuation = NULL; 21671581Sdeischen curthread->interrupted = 0; 21771581Sdeischen 21871581Sdeischen if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) { 21971581Sdeischen curthread->cancelflags &= ~PTHREAD_CANCEL_NEEDED; 22056277Sjasone _thread_exit_cleanup(); 22156277Sjasone pthread_exit(PTHREAD_CANCELED); 22256277Sjasone } 22356277Sjasone} 224