#include "pth_p.h"
void pth_cancel_state(int newstate, int *oldstate)
{
if (oldstate != NULL)
*oldstate = pth_current->cancelstate;
if (newstate != 0)
pth_current->cancelstate = newstate;
return;
}
void pth_cancel_point(void)
{
if ( pth_current->cancelreq == TRUE
&& pth_current->cancelstate & PTH_CANCEL_ENABLE) {
pth_current->cancelreq = FALSE;
pth_debug2("pth_cancel_point: terminating cancelled thread \"%s\"", pth_current->name);
pth_exit(PTH_CANCELED);
}
return;
}
int pth_cancel(pth_t thread)
{
pth_pqueue_t *q;
if (thread == NULL)
return_errno(FALSE, EINVAL);
if (thread == pth_current)
return_errno(FALSE, EINVAL);
if (thread->state == PTH_STATE_DEAD)
return_errno(FALSE, EPERM);
thread->cancelreq = TRUE;
if ( thread->cancelstate & PTH_CANCEL_ENABLE
&& thread->cancelstate & PTH_CANCEL_ASYNCHRONOUS) {
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_pqueue_delete(q, thread);
pth_thread_cleanup(thread);
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_pqueue_insert(&pth_DQ, PTH_PRIO_STD, thread);
}
}
return TRUE;
}
int pth_abort(pth_t thread)
{
if (thread == NULL)
return_errno(FALSE, EINVAL);
if (thread == pth_current)
return_errno(FALSE, EINVAL);
if (thread->state == PTH_STATE_DEAD && thread->joinable) {
if (!pth_join(thread, NULL))
return FALSE;
}
else {
thread->joinable = FALSE;
thread->cancelstate = (PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS);
if (!pth_cancel(thread))
return FALSE;
}
return TRUE;
}