Пример #1
0
int pth_rwlock_acquire(pth_rwlock_t *rwlock, int op, int tryonly, pth_event_t ev_extra)
{
    /* consistency checks */
    if (rwlock == NULL)
        return pth_error(FALSE, EINVAL);
    if (!(rwlock->rw_state & PTH_RWLOCK_INITIALIZED))
        return pth_error(FALSE, EDEADLK);

    /* acquire lock */
    if (op == PTH_RWLOCK_RW) {
        /* read-write lock is simple */
        if (!pth_mutex_acquire(&(rwlock->rw_mutex_rw), tryonly, ev_extra))
            return FALSE;
        rwlock->rw_mode = PTH_RWLOCK_RW;
    }
    else {
        /* read-only lock is more complicated to get right */
        if (!pth_mutex_acquire(&(rwlock->rw_mutex_rd), tryonly, ev_extra))
            return FALSE;
        rwlock->rw_readers++;
        if (rwlock->rw_readers == 1) {
            if (!pth_mutex_acquire(&(rwlock->rw_mutex_rw), tryonly, ev_extra)) {
                rwlock->rw_readers--;
                pth_shield { pth_mutex_release(&(rwlock->rw_mutex_rd)); }
                return FALSE;
            }
        }
        rwlock->rw_mode = PTH_RWLOCK_RD;
        pth_mutex_release(&(rwlock->rw_mutex_rd));
    }
Пример #2
0
/* create user-space context structure */
int
pth_uctx_create(
    pth_uctx_t *puctx)
{
    pth_uctx_t uctx;

    /* argument sanity checking */
    if (puctx == NULL)
        return pth_error(FALSE, EINVAL);

    /* allocate the context structure */
    if ((uctx = (pth_uctx_t)malloc(sizeof(struct pth_uctx_st))) == NULL)
        return pth_error(FALSE, errno);

    /* initialize the context structure */
    uctx->uc_stack_own = FALSE;
    uctx->uc_stack_ptr = NULL;
    uctx->uc_stack_len = 0;
    uctx->uc_mctx_set  = FALSE;
    memset((void *)&uctx->uc_mctx, 0, sizeof(pth_mctx_t));

    /* pass result to caller */
    *puctx = uctx;

    return TRUE;
}
Пример #3
0
/* initialize the scheduler ingredients */
intern int pth_scheduler_init(void)
{
    /* create the internal signal pipe */
    if (pipe(pth_sigpipe) == -1)
        return pth_error(FALSE, errno);
    if (pth_fdmode(pth_sigpipe[0], PTH_FDMODE_NONBLOCK) == PTH_FDMODE_ERROR)
        return pth_error(FALSE, errno);
    if (pth_fdmode(pth_sigpipe[1], PTH_FDMODE_NONBLOCK) == PTH_FDMODE_ERROR)
        return pth_error(FALSE, errno);

    /* initialize the essential threads */
    pth_sched   = NULL;
    pth_current = NULL;

    /* initalize the thread queues */
    pth_pqueue_init(&pth_NQ);
    pth_pqueue_init(&pth_RQ);
    pth_pqueue_init(&pth_WQ);
    pth_pqueue_init(&pth_SQ);
    pth_pqueue_init(&pth_DQ);

    /* initialize scheduling hints */
    pth_favournew = 1; /* the default is the original behaviour */

    /* initialize load support */
    pth_loadval = 1.0;
    pth_time_set(&pth_loadticknext, PTH_TIME_NOW);

    return TRUE;
}
Пример #4
0
int pth_mutex_release(pth_mutex_t *mutex)
{
    /* consistency checks */
    if (mutex == NULL)
        return pth_error(FALSE, EINVAL);
    if (!(mutex->mx_state & PTH_MUTEX_INITIALIZED))
        return pth_error(FALSE, EDEADLK);
    if (!(mutex->mx_state & PTH_MUTEX_LOCKED))
        return pth_error(FALSE, EDEADLK);
#define DISABLE_SECURITY_CHECK
#ifndef DISABLE_SECURITY_CHECK
    if (mutex->mx_owner != pth_current)
        return pth_error(FALSE, EACCES);
#endif

    /* decrement recursion counter and release mutex */
    mutex->mx_count--;
    if (mutex->mx_count <= 0) {
        mutex->mx_state &= ~(PTH_MUTEX_LOCKED);
        mutex->mx_owner = NULL;
        mutex->mx_count = 0;
        pth_ring_delete(&(pth_current->mutexring), &(mutex->mx_node));
    }
    return TRUE;
}
Пример #5
0
int pth_mutex_acquire(pth_mutex_t *mutex, int tryonly, pth_event_t ev_extra)
{
    static pth_key_t ev_key = PTH_KEY_INIT;
    pth_event_t ev;

    pth_debug2("pth_mutex_acquire: called from thread \"%s\"", pth_current->name);

    /* consistency checks */
    if (mutex == NULL)
        return pth_error(FALSE, EINVAL);
    if (!(mutex->mx_state & PTH_MUTEX_INITIALIZED))
        return pth_error(FALSE, EDEADLK);

    /* still not locked, so simply acquire mutex? */
    if (!(mutex->mx_state & PTH_MUTEX_LOCKED)) {
        mutex->mx_state |= PTH_MUTEX_LOCKED;
        mutex->mx_owner = pth_current;
        mutex->mx_count = 1;
        pth_ring_append(&(pth_current->mutexring), &(mutex->mx_node));
        pth_debug1("pth_mutex_acquire: immediately locking mutex");
        return TRUE;
    }

    /* already locked by caller? */
    if (mutex->mx_count >= 1 && mutex->mx_owner == pth_current) {
        /* recursive lock */
        mutex->mx_count++;
        pth_debug1("pth_mutex_acquire: recursive locking");
        return TRUE;
    }

    /* should we just tryonly? */
    if (tryonly)
        return pth_error(FALSE, EBUSY);

    /* else wait for mutex to become unlocked.. */
    pth_debug1("pth_mutex_acquire: wait until mutex is unlocked");
    for (;;) {
        ev = pth_event(PTH_EVENT_MUTEX|PTH_MODE_STATIC, &ev_key, mutex);
        if (ev_extra != NULL)
            pth_event_concat(ev, ev_extra, NULL);
        pth_wait(ev);
        if (ev_extra != NULL) {
            pth_event_isolate(ev);
            if (pth_event_status(ev) == PTH_STATUS_PENDING)
                return pth_error(FALSE, EINTR);
        }
        if (!(mutex->mx_state & PTH_MUTEX_LOCKED))
            break;
    }

    /* now it's again unlocked, so acquire mutex */
    pth_debug1("pth_mutex_acquire: locking mutex");
    mutex->mx_state |= PTH_MUTEX_LOCKED;
    mutex->mx_owner = pth_current;
    mutex->mx_count = 1;
    pth_ring_append(&(pth_current->mutexring), &(mutex->mx_node));
    return TRUE;
}
Пример #6
0
/* make setup of user-space context structure */
int
pth_uctx_make(
    pth_uctx_t uctx,
    char *sk_addr, size_t sk_size,
    const sigset_t *sigmask,
    void (*start_func)(void *), void *start_arg,
    pth_uctx_t uctx_after)
{
    pth_mctx_t mctx_parent;
    sigset_t ss;

    /* argument sanity checking */
    if (uctx == NULL || start_func == NULL || sk_size < 16*1024)
        return pth_error(FALSE, EINVAL);

    /* configure run-time stack */
    if (sk_addr == NULL) {
        if ((sk_addr = (char *)malloc(sk_size)) == NULL)
            return pth_error(FALSE, errno);
        uctx->uc_stack_own = TRUE;
    }
    else
        uctx->uc_stack_own = FALSE;
    uctx->uc_stack_ptr = sk_addr;
    uctx->uc_stack_len = sk_size;

    /* configure the underlying machine context */
    if (!pth_mctx_set(&uctx->uc_mctx, pth_uctx_trampoline,
                      uctx->uc_stack_ptr, uctx->uc_stack_ptr+uctx->uc_stack_len))
        return pth_error(FALSE, errno);

    /* move context information into global storage for the trampoline jump */
    pth_gctx_get()->pth_uctx_trampoline_ctx.mctx_parent = &mctx_parent;
    pth_gctx_get()->pth_uctx_trampoline_ctx.uctx_this   = uctx;
    pth_gctx_get()->pth_uctx_trampoline_ctx.uctx_after  = uctx_after;
    pth_gctx_get()->pth_uctx_trampoline_ctx.start_func  = start_func;
    pth_gctx_get()->pth_uctx_trampoline_ctx.start_arg   = start_arg;

    /* optionally establish temporary signal mask */
    if (sigmask != NULL)
        sigprocmask(SIG_SETMASK, sigmask, &ss);

    /* perform the trampoline step */
    pth_mctx_switch(&mctx_parent, &(uctx->uc_mctx));

    /* optionally restore original signal mask */
    if (sigmask != NULL)
        sigprocmask(SIG_SETMASK, &ss, NULL);

    /* finally flag that the context is now configured */
    uctx->uc_mctx_set = TRUE;

    return TRUE;
}
Пример #7
0
/* cancel a thread (the friendly way) */
int pth_cancel(pth_t thread)
{
    pth_pqueue_t *q;

    if (thread == NULL)
        return pth_error(FALSE, EINVAL);

    /* the current thread cannot be cancelled */
    if (thread == pth_gctx_get()->pth_current)
        return pth_error(FALSE, EINVAL);

    /* the thread has to be at least still alive */
    if (thread->state == PTH_STATE_DEAD)
        return pth_error(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_gctx_get()->pth_NQ; break;
            case PTH_STATE_READY:   q = &pth_gctx_get()->pth_RQ; break;
            case PTH_STATE_WAITING: q = &pth_gctx_get()->pth_WQ; break;
            default:                q = NULL;
        }
        if (q == NULL)
            return pth_error(FALSE, ESRCH);
        if (!pth_pqueue_contains(q, thread))
            return pth_error(FALSE, ESRCH);
        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_pqueue_insert(&pth_gctx_get()->pth_DQ, PTH_PRIO_STD, thread);
        }
    }
    return TRUE;
}
Пример #8
0
int pth_cleanup_push(void (*func)(void *), void *arg)
{
    pth_cleanup_t *cleanup;

    if (func == NULL)
        return pth_error(FALSE, EINVAL);
    if ((cleanup = (pth_cleanup_t *)malloc(sizeof(pth_cleanup_t))) == NULL)
        return pth_error(FALSE, ENOMEM);
    cleanup->func = func;
    cleanup->arg  = arg;
    cleanup->next = pth_current->cleanups;
    pth_current->cleanups = cleanup;
    return TRUE;
}
Пример #9
0
/* switch from current to other user-space context */
int
pth_uctx_switch(
    pth_uctx_t uctx_from,
    pth_uctx_t uctx_to)
{
    /* argument sanity checking */
    if (uctx_from == NULL || uctx_to == NULL)
        return pth_error(FALSE, EINVAL);
    if (!(uctx_to->uc_mctx_set))
        return pth_error(FALSE, EPERM);

    /* switch underlying machine context */
    uctx_from->uc_mctx_set = TRUE;
    pth_mctx_switch(&(uctx_from->uc_mctx), &(uctx_to->uc_mctx));

    return TRUE;
}
Пример #10
0
int pth_mutex_init(pth_mutex_t *mutex)
{
    if (mutex == NULL)
        return pth_error(FALSE, EINVAL);
    mutex->mx_state = PTH_MUTEX_INITIALIZED;
    mutex->mx_owner = NULL;
    mutex->mx_count = 0;
    return TRUE;
}
Пример #11
0
int pth_rwlock_init(pth_rwlock_t *rwlock)
{
    if (rwlock == NULL)
        return pth_error(FALSE, EINVAL);
    rwlock->rw_state = PTH_RWLOCK_INITIALIZED;
    rwlock->rw_readers = 0;
    pth_mutex_init(&(rwlock->rw_mutex_rd));
    pth_mutex_init(&(rwlock->rw_mutex_rw));
    return TRUE;
}
Пример #12
0
int pth_atfork_push(void (*prepare)(void *), void (*parent)(void *),
                    void (*child)(void *), void *arg)
{
    if (pth_atfork_idx > PTH_ATFORK_MAX-1)
        return pth_error(FALSE, ENOMEM);
    pth_atfork_list[pth_atfork_idx].prepare = prepare;
    pth_atfork_list[pth_atfork_idx].parent  = parent;
    pth_atfork_list[pth_atfork_idx].child   = child;
    pth_atfork_list[pth_atfork_idx].arg     = arg;
    pth_atfork_idx++;
    return TRUE;
}
Пример #13
0
/* initialize the package */
int pth_init(void)
{
    pth_attr_t t_attr;

    /* support for implicit initialization calls
       and to prevent multiple explict initialization, too */
    if (pth_initialized)
        return pth_error(FALSE, EPERM);
    else
        pth_initialized = TRUE;

    pth_debug1("pth_init: enter");

    /* initialize syscall wrapping */
    pth_syscall_init();

    /* initialize the scheduler */
    if (!pth_scheduler_init()) {
        pth_shield { pth_syscall_kill(); }
        return pth_error(FALSE, EAGAIN);
    }
Пример #14
0
/* abort a thread (the cruel way) */
int pth_abort(pth_t thread)
{
    if (thread == NULL)
        return pth_error(FALSE, EINVAL);

    /* the current thread cannot be aborted */
    if (thread == pth_gctx_get()->pth_current)
        return pth_error(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;
}
Пример #15
0
/* destroy user-space context structure */
int
pth_uctx_destroy(
    pth_uctx_t uctx)
{
    /* argument sanity checking */
    if (uctx == NULL)
        return pth_error(FALSE, EINVAL);

    /* deallocate dynamically allocated stack */
    if (uctx->uc_stack_own && uctx->uc_stack_ptr != NULL)
        free(uctx->uc_stack_ptr);

    /* deallocate context structure */
    free(uctx);

    return TRUE;
}