/* ** NGPT - Next Generation POSIX Threading ** Copyright (c) 2001 IBM Corporation ** Portions Copyright (c) 1999-2000 Ralf S. Engelschall ** ** This file is part of NGPT, a non-preemptive thread scheduling ** library which can be found at http://www.ibm.com/developer. ** ** This library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public ** License as published by the Free Software Foundation; either ** version 2.1 of the License, or (at your option) any later version. ** ** This library is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser General Public ** License along with this library; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ** USA. ** ** pth_cancel.c: Pth thread cancellation */ /* ``Study it forever and you'll still wonder. Fly it once and you'll know.'' -- Henry Spencer */ #include "pth_p.h" /* set cancellation state */ void pth_cancel_state(int newstate, int *oldstate) { pth_t current = pth_get_current(); if (oldstate != NULL) *oldstate = current->cancelstate; if (newstate != 0) current->cancelstate = newstate; if (current->cancelstate & PTH_CANCEL_ASYNCHRONOUS) pth_yield(NULL); return; } /* enter a cancellation point */ void pth_cancel_point(void) { pth_t current = pth_get_current(); if ( current->cancelreq == TRUE && current->cancelstate & PTH_CANCEL_ENABLE) { /* avoid looping if cleanup handlers contain cancellation points */ current->cancelreq = FALSE; pth_debug2("pth_cancel_point: terminating cancelled thread \"%s\"", current->name); pth_exit(PTH_CANCELED); } else pth_yield(NULL); return; } /* cancel a thread (the friendly way) */ int pth_cancel(pth_t thread) { pth_pqueue_t *q; if (thread == NULL) return_errno(FALSE, EINVAL); /* the current thread cannot be cancelled */ if (thread == pth_get_current()) return_errno(FALSE, EINVAL); /* the thread has to be at least still alive */ if (thread->state == PTH_STATE_DEAD) return_errno(FALSE, EPERM); /* now mark the thread as cancelled */ thread->cancelreq = TRUE; /* when cancellation is enabled in async mode we cancel the thread immediately */ if ( thread->cancelstate & PTH_CANCEL_ENABLE && thread->cancelstate & PTH_CANCEL_ASYNCHRONOUS) { /* remove thread from its queue */ switch (thread->state) { case PTH_STATE_NEW: q = &pth_NQ; break; case PTH_STATE_READY: q = &pth_RQ; break; case PTH_STATE_WAITING: q = &pth_WQ; break; default: q = NULL; } if (q == NULL) return_errno(FALSE, ESRCH); if (!pth_pqueue_contains(q, thread)) return_errno(FALSE, ESRCH); pth_acquire_lock(&(q->q_lock)); pth_pqueue_delete(q, thread); /* execute cleanups */ pth_thread_cleanup(thread); /* and now either kick it out or move it to dead queue */ if (!thread->joinable) { pth_debug2("pth_cancel: kicking out cancelled thread \"%s\" immediately", thread->name); pth_tcb_free(thread); } else { pth_debug2("pth_cancel: moving cancelled thread \"%s\" to dead queue", thread->name); thread->join_arg = PTH_CANCELED; thread->state = PTH_STATE_DEAD; pth_acquire_lock(&(pth_DQ.q_lock)); pth_pqueue_insert(&pth_DQ, PTH_PRIO_STD, thread); pth_release_lock(&(pth_DQ.q_lock)); } pth_release_lock(&(q->q_lock)); } return TRUE; } /* abort a thread (the cruel way) */ int pth_abort(pth_t thread) { if (thread == NULL) return_errno(FALSE, EINVAL); /* the current thread cannot be aborted */ if (thread == pth_get_current()) return_errno(FALSE, EINVAL); if (thread->state == PTH_STATE_DEAD && thread->joinable) { /* if thread is already terminated, just join it */ if (!pth_join(thread, NULL)) return FALSE; } else { /* else force it to be detached and cancel it asynchronously */ thread->joinable = FALSE; thread->cancelstate = (PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS); if (!pth_cancel(thread)) return FALSE; } return TRUE; }