thr_cancel.c revision 81750
153812Salfred/* 253812Salfred * David Leonard <d@openbsd.org>, 1999. Public domain. 353812Salfred * $FreeBSD: head/lib/libkse/thread/thr_cancel.c 81750 2001-08-16 06:31:32Z jasone $ 453812Salfred */ 553812Salfred#include <sys/errno.h> 653812Salfred#include <pthread.h> 753812Salfred#include "pthread_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 */ 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 6676909Sjasone case PS_JOIN: 6781750Sjasone /* 6881750Sjasone * Disconnect the thread from the joinee and 6981750Sjasone * detach: 7081750Sjasone */ 7181750Sjasone if (pthread->data.thread != NULL) { 7281750Sjasone pthread->data.thread->joiner = NULL; 7381750Sjasone pthread_detach((pthread_t) 7481750Sjasone pthread->data.thread); 7581750Sjasone } 7681750Sjasone pthread->cancelflags |= PTHREAD_CANCELLING; 7781750Sjasone PTHREAD_NEW_STATE(pthread, PS_RUNNING); 7881750Sjasone break; 7981750Sjasone 8061681Sjasone case PS_SUSPENDED: 8161681Sjasone if (pthread->suspended == SUSP_NO || 8261681Sjasone pthread->suspended == SUSP_YES || 8381750Sjasone pthread->suspended == SUSP_JOIN || 8461681Sjasone pthread->suspended == SUSP_NOWAIT) { 8561681Sjasone /* 8661681Sjasone * This thread isn't in any scheduling 8761681Sjasone * queues; just change it's state: 8861681Sjasone */ 8961681Sjasone pthread->cancelflags |= 9061681Sjasone PTHREAD_CANCELLING; 9161681Sjasone PTHREAD_SET_STATE(pthread, PS_RUNNING); 9261681Sjasone break; 9361681Sjasone } 9461681Sjasone /* FALLTHROUGH */ 9553812Salfred case PS_MUTEX_WAIT: 9653812Salfred case PS_COND_WAIT: 9753812Salfred case PS_FDLR_WAIT: 9853812Salfred case PS_FDLW_WAIT: 9953812Salfred case PS_FILE_WAIT: 10053812Salfred /* 10153812Salfred * Threads in these states may be in queues. 10253812Salfred * In order to preserve queue integrity, the 10353812Salfred * cancelled thread must remove itself from the 10453812Salfred * queue. Mark the thread as interrupted and 10553812Salfred * needing cancellation, and set the state to 10653812Salfred * running. When the thread resumes, it will 10756277Sjasone * remove itself from the queue and call the 10856277Sjasone * cancellation completion routine. 10953812Salfred */ 11053812Salfred pthread->interrupted = 1; 11153812Salfred pthread->cancelflags |= PTHREAD_CANCEL_NEEDED; 11253812Salfred PTHREAD_NEW_STATE(pthread,PS_RUNNING); 11356277Sjasone pthread->continuation = finish_cancellation; 11453812Salfred break; 11553812Salfred 11653812Salfred case PS_DEAD: 11753812Salfred case PS_DEADLOCK: 11853812Salfred case PS_STATE_MAX: 11953812Salfred /* Ignore - only here to silence -Wall: */ 12053812Salfred break; 12154708Sdeischen } 12253812Salfred } 12354708Sdeischen 12453812Salfred /* Unprotect the scheduling queues: */ 12553812Salfred _thread_kern_sig_undefer(); 12653812Salfred 12753812Salfred ret = 0; 12853812Salfred } 12953812Salfred return (ret); 13053812Salfred} 13153812Salfred 13253812Salfredint 13371581Sdeischen_pthread_setcancelstate(int state, int *oldstate) 13453812Salfred{ 13571581Sdeischen struct pthread *curthread = _get_curthread(); 13653812Salfred int ostate; 13753812Salfred int ret; 13853812Salfred 13971581Sdeischen ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE; 14053812Salfred 14153812Salfred switch (state) { 14253812Salfred case PTHREAD_CANCEL_ENABLE: 14353812Salfred if (oldstate != NULL) 14453812Salfred *oldstate = ostate; 14571581Sdeischen curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE; 14671581Sdeischen if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0) 14753812Salfred pthread_testcancel(); 14853812Salfred ret = 0; 14953812Salfred break; 15053812Salfred case PTHREAD_CANCEL_DISABLE: 15153812Salfred if (oldstate != NULL) 15253812Salfred *oldstate = ostate; 15371581Sdeischen curthread->cancelflags |= PTHREAD_CANCEL_DISABLE; 15453812Salfred ret = 0; 15553812Salfred break; 15653812Salfred default: 15753812Salfred ret = EINVAL; 15853812Salfred } 15953812Salfred 16053812Salfred return (ret); 16153812Salfred} 16253812Salfred 16353812Salfredint 16471581Sdeischen_pthread_setcanceltype(int type, int *oldtype) 16553812Salfred{ 16671581Sdeischen struct pthread *curthread = _get_curthread(); 16753812Salfred int otype; 16853812Salfred int ret; 16953812Salfred 17071581Sdeischen otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS; 17153812Salfred switch (type) { 17253812Salfred case PTHREAD_CANCEL_ASYNCHRONOUS: 17353812Salfred if (oldtype != NULL) 17453812Salfred *oldtype = otype; 17571581Sdeischen curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS; 17653812Salfred pthread_testcancel(); 17753812Salfred ret = 0; 17853812Salfred break; 17953812Salfred case PTHREAD_CANCEL_DEFERRED: 18053812Salfred if (oldtype != NULL) 18153812Salfred *oldtype = otype; 18271581Sdeischen curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS; 18353812Salfred ret = 0; 18453812Salfred break; 18553812Salfred default: 18653812Salfred ret = EINVAL; 18753812Salfred } 18853812Salfred 18953812Salfred return (ret); 19053812Salfred} 19153812Salfred 19253812Salfredvoid 19371581Sdeischen_pthread_testcancel(void) 19453812Salfred{ 19571581Sdeischen struct pthread *curthread = _get_curthread(); 19671581Sdeischen 19771581Sdeischen if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) && 19871581Sdeischen ((curthread->cancelflags & PTHREAD_CANCELLING) != 0)) { 19953812Salfred /* 20053812Salfred * It is possible for this thread to be swapped out 20153812Salfred * while performing cancellation; do not allow it 20253812Salfred * to be cancelled again. 20353812Salfred */ 20471581Sdeischen curthread->cancelflags &= ~PTHREAD_CANCELLING; 20553812Salfred _thread_exit_cleanup(); 20653812Salfred pthread_exit(PTHREAD_CANCELED); 20753812Salfred PANIC("cancel"); 20853812Salfred } 20953812Salfred} 21053812Salfred 21153812Salfredvoid 21253812Salfred_thread_enter_cancellation_point(void) 21353812Salfred{ 21471581Sdeischen struct pthread *curthread = _get_curthread(); 21571581Sdeischen 21653812Salfred /* Look for a cancellation before we block: */ 21753812Salfred pthread_testcancel(); 21871581Sdeischen curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT; 21953812Salfred} 22053812Salfred 22153812Salfredvoid 22253812Salfred_thread_leave_cancellation_point(void) 22353812Salfred{ 22471581Sdeischen struct pthread *curthread = _get_curthread(); 22571581Sdeischen 22671581Sdeischen curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT; 22753812Salfred /* Look for a cancellation after we unblock: */ 22853812Salfred pthread_testcancel(); 22953812Salfred} 23056277Sjasone 23156277Sjasonestatic void 23256277Sjasonefinish_cancellation(void *arg) 23356277Sjasone{ 23471581Sdeischen struct pthread *curthread = _get_curthread(); 23556277Sjasone 23671581Sdeischen curthread->continuation = NULL; 23771581Sdeischen curthread->interrupted = 0; 23871581Sdeischen 23971581Sdeischen if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) { 24071581Sdeischen curthread->cancelflags &= ~PTHREAD_CANCEL_NEEDED; 24156277Sjasone _thread_exit_cleanup(); 24256277Sjasone pthread_exit(PTHREAD_CANCELED); 24356277Sjasone } 24456277Sjasone} 245