thr_cancel.c revision 71581
153812Salfred/* 253812Salfred * David Leonard <d@openbsd.org>, 1999. Public domain. 353812Salfred * $FreeBSD: head/lib/libkse/thread/thr_cancel.c 71581 2001-01-24 13:03:38Z deischen $ 453812Salfred */ 553812Salfred#include <sys/errno.h> 653812Salfred#include <pthread.h> 753812Salfred#include "pthread_private.h" 853812Salfred 956277Sjasonestatic void finish_cancellation(void *arg); 1056277Sjasone 1171581Sdeischen#pragma weak pthread_cancel=_pthread_cancel 1271581Sdeischen#pragma weak pthread_setcancelstate=_pthread_setcancelstate 1371581Sdeischen#pragma weak pthread_setcanceltype=_pthread_setcanceltype 1471581Sdeischen#pragma weak 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 */ 2353812Salfred } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK) { 2453812Salfred ret = 0; 2553812Salfred } else { 2653812Salfred /* Protect the scheduling queues: */ 2753812Salfred _thread_kern_sig_defer(); 2853812Salfred 2954708Sdeischen if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) || 3054708Sdeischen (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) && 3154708Sdeischen ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0))) 3254708Sdeischen /* Just mark it for cancellation: */ 3354708Sdeischen pthread->cancelflags |= PTHREAD_CANCELLING; 3454708Sdeischen else { 3554708Sdeischen /* 3654708Sdeischen * Check if we need to kick it back into the 3754708Sdeischen * run queue: 3854708Sdeischen */ 3953812Salfred switch (pthread->state) { 4053812Salfred case PS_RUNNING: 4153812Salfred /* No need to resume: */ 4253812Salfred pthread->cancelflags |= PTHREAD_CANCELLING; 4353812Salfred break; 4453812Salfred 4553812Salfred case PS_SPINBLOCK: 4653812Salfred case PS_FDR_WAIT: 4753812Salfred case PS_FDW_WAIT: 4853812Salfred case PS_POLL_WAIT: 4953812Salfred case PS_SELECT_WAIT: 5054708Sdeischen /* Remove these threads from the work queue: */ 5153812Salfred if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) 5253812Salfred != 0) 5353812Salfred PTHREAD_WORKQ_REMOVE(pthread); 5453812Salfred /* Fall through: */ 5553812Salfred case PS_SIGTHREAD: 5653812Salfred case PS_SLEEP_WAIT: 5753812Salfred case PS_WAIT_WAIT: 5853812Salfred case PS_SIGSUSPEND: 5953812Salfred case PS_SIGWAIT: 6053812Salfred /* Interrupt and resume: */ 6153812Salfred pthread->interrupted = 1; 6253812Salfred pthread->cancelflags |= PTHREAD_CANCELLING; 6353812Salfred PTHREAD_NEW_STATE(pthread,PS_RUNNING); 6453812Salfred break; 6553812Salfred 6661681Sjasone case PS_SUSPENDED: 6761681Sjasone if (pthread->suspended == SUSP_NO || 6861681Sjasone pthread->suspended == SUSP_YES || 6961681Sjasone pthread->suspended == SUSP_NOWAIT) { 7061681Sjasone /* 7161681Sjasone * This thread isn't in any scheduling 7261681Sjasone * queues; just change it's state: 7361681Sjasone */ 7461681Sjasone pthread->cancelflags |= 7561681Sjasone PTHREAD_CANCELLING; 7661681Sjasone PTHREAD_SET_STATE(pthread, PS_RUNNING); 7761681Sjasone break; 7861681Sjasone } 7961681Sjasone /* FALLTHROUGH */ 8053812Salfred case PS_MUTEX_WAIT: 8153812Salfred case PS_COND_WAIT: 8253812Salfred case PS_FDLR_WAIT: 8353812Salfred case PS_FDLW_WAIT: 8453812Salfred case PS_FILE_WAIT: 8553812Salfred case PS_JOIN: 8653812Salfred /* 8753812Salfred * Threads in these states may be in queues. 8853812Salfred * In order to preserve queue integrity, the 8953812Salfred * cancelled thread must remove itself from the 9053812Salfred * queue. Mark the thread as interrupted and 9153812Salfred * needing cancellation, and set the state to 9253812Salfred * running. When the thread resumes, it will 9356277Sjasone * remove itself from the queue and call the 9456277Sjasone * cancellation completion routine. 9553812Salfred */ 9653812Salfred pthread->interrupted = 1; 9753812Salfred pthread->cancelflags |= PTHREAD_CANCEL_NEEDED; 9853812Salfred PTHREAD_NEW_STATE(pthread,PS_RUNNING); 9956277Sjasone pthread->continuation = finish_cancellation; 10053812Salfred break; 10153812Salfred 10253812Salfred case PS_DEAD: 10353812Salfred case PS_DEADLOCK: 10453812Salfred case PS_STATE_MAX: 10553812Salfred /* Ignore - only here to silence -Wall: */ 10653812Salfred break; 10754708Sdeischen } 10853812Salfred } 10954708Sdeischen 11053812Salfred /* Unprotect the scheduling queues: */ 11153812Salfred _thread_kern_sig_undefer(); 11253812Salfred 11353812Salfred ret = 0; 11453812Salfred } 11553812Salfred return (ret); 11653812Salfred} 11753812Salfred 11853812Salfredint 11971581Sdeischen_pthread_setcancelstate(int state, int *oldstate) 12053812Salfred{ 12171581Sdeischen struct pthread *curthread = _get_curthread(); 12253812Salfred int ostate; 12353812Salfred int ret; 12453812Salfred 12571581Sdeischen ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE; 12653812Salfred 12753812Salfred switch (state) { 12853812Salfred case PTHREAD_CANCEL_ENABLE: 12953812Salfred if (oldstate != NULL) 13053812Salfred *oldstate = ostate; 13171581Sdeischen curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE; 13271581Sdeischen if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0) 13353812Salfred pthread_testcancel(); 13453812Salfred ret = 0; 13553812Salfred break; 13653812Salfred case PTHREAD_CANCEL_DISABLE: 13753812Salfred if (oldstate != NULL) 13853812Salfred *oldstate = ostate; 13971581Sdeischen curthread->cancelflags |= PTHREAD_CANCEL_DISABLE; 14053812Salfred ret = 0; 14153812Salfred break; 14253812Salfred default: 14353812Salfred ret = EINVAL; 14453812Salfred } 14553812Salfred 14653812Salfred return (ret); 14753812Salfred} 14853812Salfred 14953812Salfredint 15071581Sdeischen_pthread_setcanceltype(int type, int *oldtype) 15153812Salfred{ 15271581Sdeischen struct pthread *curthread = _get_curthread(); 15353812Salfred int otype; 15453812Salfred int ret; 15553812Salfred 15671581Sdeischen otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS; 15753812Salfred switch (type) { 15853812Salfred case PTHREAD_CANCEL_ASYNCHRONOUS: 15953812Salfred if (oldtype != NULL) 16053812Salfred *oldtype = otype; 16171581Sdeischen curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS; 16253812Salfred pthread_testcancel(); 16353812Salfred ret = 0; 16453812Salfred break; 16553812Salfred case PTHREAD_CANCEL_DEFERRED: 16653812Salfred if (oldtype != NULL) 16753812Salfred *oldtype = otype; 16871581Sdeischen curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS; 16953812Salfred ret = 0; 17053812Salfred break; 17153812Salfred default: 17253812Salfred ret = EINVAL; 17353812Salfred } 17453812Salfred 17553812Salfred return (ret); 17653812Salfred} 17753812Salfred 17853812Salfredvoid 17971581Sdeischen_pthread_testcancel(void) 18053812Salfred{ 18171581Sdeischen struct pthread *curthread = _get_curthread(); 18271581Sdeischen 18371581Sdeischen if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) && 18471581Sdeischen ((curthread->cancelflags & PTHREAD_CANCELLING) != 0)) { 18553812Salfred /* 18653812Salfred * It is possible for this thread to be swapped out 18753812Salfred * while performing cancellation; do not allow it 18853812Salfred * to be cancelled again. 18953812Salfred */ 19071581Sdeischen curthread->cancelflags &= ~PTHREAD_CANCELLING; 19153812Salfred _thread_exit_cleanup(); 19253812Salfred pthread_exit(PTHREAD_CANCELED); 19353812Salfred PANIC("cancel"); 19453812Salfred } 19553812Salfred} 19653812Salfred 19753812Salfredvoid 19853812Salfred_thread_enter_cancellation_point(void) 19953812Salfred{ 20071581Sdeischen struct pthread *curthread = _get_curthread(); 20171581Sdeischen 20253812Salfred /* Look for a cancellation before we block: */ 20353812Salfred pthread_testcancel(); 20471581Sdeischen curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT; 20553812Salfred} 20653812Salfred 20753812Salfredvoid 20853812Salfred_thread_leave_cancellation_point(void) 20953812Salfred{ 21071581Sdeischen struct pthread *curthread = _get_curthread(); 21171581Sdeischen 21271581Sdeischen curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT; 21353812Salfred /* Look for a cancellation after we unblock: */ 21453812Salfred pthread_testcancel(); 21553812Salfred} 21656277Sjasone 21756277Sjasonestatic void 21856277Sjasonefinish_cancellation(void *arg) 21956277Sjasone{ 22071581Sdeischen struct pthread *curthread = _get_curthread(); 22156277Sjasone 22271581Sdeischen curthread->continuation = NULL; 22371581Sdeischen curthread->interrupted = 0; 22471581Sdeischen 22571581Sdeischen if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) { 22671581Sdeischen curthread->cancelflags &= ~PTHREAD_CANCEL_NEEDED; 22756277Sjasone _thread_exit_cleanup(); 22856277Sjasone pthread_exit(PTHREAD_CANCELED); 22956277Sjasone } 23056277Sjasone} 231