Beispiel #1
0
void vlc_control_cancel (int cmd, ...)
{
    /* NOTE: This function only modifies thread-specific data, so there is no
     * need to lock anything. */
    va_list ap;

    vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
    if (nfo == NULL)
        return; /* Main thread - cannot be cancelled anyway */

    va_start (ap, cmd);
    switch (cmd)
    {
        case VLC_DO_CANCEL:
            nfo->killed = true;
            break;

        case VLC_CLEANUP_PUSH:
        {
            /* cleaner is a pointer to the caller stack, no need to allocate
             * and copy anything. As a nice side effect, this cannot fail. */
            vlc_cleanup_t *cleaner = va_arg (ap, vlc_cleanup_t *);
            cleaner->next = nfo->cleaners;
            nfo->cleaners = cleaner;
            break;
        }

        case VLC_CLEANUP_POP:
        {
            nfo->cleaners = nfo->cleaners->next;
            break;
        }
    }
    va_end (ap);
}
Beispiel #2
0
int vlc_mwait_i11e(mtime_t deadline)
{
    vlc_interrupt_t *ctx = vlc_threadvar_get(vlc_interrupt_var);
    if (ctx == NULL)
        return mwait(deadline), 0;

    vlc_cond_t wait;
    vlc_cond_init(&wait);

    int ret = vlc_interrupt_prepare(ctx, vlc_mwait_i11e_wake, &wait);
    if (ret)
    {
        vlc_cond_destroy(&wait);
        vlc_testcancel();
        return ret;
    }

    vlc_mutex_lock(&ctx->lock);
    vlc_cleanup_push(vlc_mwait_i11e_cleanup, ctx);
    while (!ctx->interrupted
        && vlc_cond_timedwait(&wait, &ctx->lock, deadline) == 0);
    vlc_cleanup_pop();
    vlc_mutex_unlock(&ctx->lock);

    ret = vlc_interrupt_finish(ctx);
    vlc_cond_destroy(&wait);
    return ret;
}
Beispiel #3
0
static void vlc_thread_cleanup (struct vlc_thread *th)
{
    vlc_threadvar_t key;

retry:
    /* TODO: use RW lock or something similar */
    vlc_mutex_lock (&super_mutex);
    for (key = vlc_threadvar_last; key != NULL; key = key->prev)
    {
        void *value = vlc_threadvar_get (key);
        if (value != NULL && key->destroy != NULL)
        {
            vlc_mutex_unlock (&super_mutex);
            vlc_threadvar_set (key, NULL);
            key->destroy (value);
            goto retry;
        }
    }
    vlc_mutex_unlock (&super_mutex);

    if (th->detached)
    {
        CloseHandle (th->id);
        free (th);
    }
}
Beispiel #4
0
vlc_interrupt_t *vlc_interrupt_set(vlc_interrupt_t *newctx)
{
    vlc_interrupt_t *oldctx;

    /* This function is called to push or pop an interrupt context. Either way
     * either newctx or oldctx (or both) are non-NULL. Thus vlc_interrupt_refs
     * must be larger than zero and vlc_interrupt_var must be valid. And so the
     * read/write lock is not needed. */
    assert(vlc_interrupt_refs > 0);

    oldctx = vlc_threadvar_get(vlc_interrupt_var);
#ifndef NDEBUG
    if (oldctx != NULL)
    {
        assert(oldctx->attached);
        oldctx->attached = false;
    }
    if (newctx != NULL)
    {
        assert(!newctx->attached);
        newctx->attached = true;
    }
#endif
    vlc_threadvar_set(vlc_interrupt_var, newctx);

    return oldctx;
}
Beispiel #5
0
void vlc_control_cancel (int cmd, ...)
{
    /* NOTE: This function only modifies thread-specific data, so there is no
     * need to lock anything. */
    va_list ap;

    struct vlc_thread *th = (vlc_thread *)vlc_threadvar_get (thread_key);			// sunqueen modify
    if (th == NULL)
        return; /* Main thread - cannot be cancelled anyway */

    va_start (ap, cmd);
    switch (cmd)
    {
        case VLC_CLEANUP_PUSH:
        {
            /* cleaner is a pointer to the caller stack, no need to allocate
             * and copy anything. As a nice side effect, this cannot fail. */
            vlc_cleanup_t *cleaner = va_arg (ap, vlc_cleanup_t *);
            cleaner->next = th->cleaners;
            th->cleaners = cleaner;
            break;
        }

        case VLC_CLEANUP_POP:
        {
            th->cleaners = th->cleaners->next;
            break;
        }
    }
    va_end (ap);
}
Beispiel #6
0
static bool isCancelled(void)
{
    struct vlc_thread *th = vlc_threadvar_get (thread_key);
    if (th == NULL)
        return false; /* Main thread - cannot be cancelled anyway */

    return atomic_load(&th->killed);
}
Beispiel #7
0
static vlc_interrupt_t *vlc_interrupt_get(void)
{
    vlc_interrupt_t *ctx = NULL;

    vlc_rwlock_rdlock(&vlc_interrupt_lock);
    if (vlc_interrupt_refs > 0)
        ctx = vlc_threadvar_get(vlc_interrupt_var);
    vlc_rwlock_unlock(&vlc_interrupt_lock);
    return ctx;
}
Beispiel #8
0
int vlc_savecancel (void)
{
    struct vlc_thread *th = (vlc_thread *)vlc_threadvar_get (thread_key);			// sunqueen modify
    if (th == NULL)
        return false; /* Main thread - cannot be cancelled anyway */

    int state = th->killable;
    th->killable = false;
    return state;
}
Beispiel #9
0
static msg_context_t* GetContext(void)
{
    msg_context_t *p_ctx = vlc_threadvar_get( &msg_context_global_key );
    if( p_ctx == NULL )
    {
        MALLOC_NULL( p_ctx, msg_context_t );
        p_ctx->psz_message = NULL;
        vlc_threadvar_set( &msg_context_global_key, p_ctx );
    }
    return p_ctx;
}
Beispiel #10
0
void vlc_restorecancel (int state)
{
    struct vlc_thread *th = (vlc_thread *)vlc_threadvar_get (thread_key);			// sunqueen modify
    assert (state == false || state == true);

    if (th == NULL)
        return; /* Main thread - cannot be cancelled anyway */

    assert (!th->killable);
    th->killable = state != 0;
}
Beispiel #11
0
void vlc_restorecancel (int state)
{
    vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
    assert (state == false || state == true);

    if (nfo == NULL)
        return; /* Main thread - cannot be cancelled anyway */

    assert (!nfo->killable);
    nfo->killable = state != 0;
}
Beispiel #12
0
int vlc_savecancel (void)
{
    int state;

    vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
    if (nfo == NULL)
        return false; /* Main thread - cannot be cancelled anyway */

    state = nfo->killable;
    nfo->killable = false;
    return state;
}
Beispiel #13
0
int vlc_savecancel (void)
{
    int state;

    struct vlc_thread *th = vlc_threadvar_get (thread_key);
    if (th == NULL)
        return false; /* Main thread - cannot be cancelled anyway */

    state = th->killable;
    th->killable = false;
    return state;
}
Beispiel #14
0
static msg_context_t* GetContext(void)
{
    msg_context_t *p_ctx = vlc_threadvar_get( msg_context );
    if( p_ctx == NULL )
    {
        p_ctx = malloc( sizeof( msg_context_t ) );
        if( !p_ctx )
            return NULL;
        p_ctx->psz_message = NULL;
        vlc_threadvar_set( msg_context, p_ctx );
    }
    return p_ctx;
}
Beispiel #15
0
int vlc_interrupt_forward_start(vlc_interrupt_t *to, void *data[2])
{
    data[0] = data[1] = NULL;

    vlc_interrupt_t *from = vlc_threadvar_get(vlc_interrupt_var);
    if (from == NULL)
        return 0;

    assert(from != to);
    data[0] = to;
    data[1] = from;
    return vlc_interrupt_prepare(from, vlc_interrupt_forward_wake, data);
}
Beispiel #16
0
void vlc_testcancel (void)
{
    struct vlc_thread *th = (vlc_thread *)vlc_threadvar_get (thread_key);			// sunqueen modify
    if (th == NULL)
        return; /* Main thread - cannot be cancelled anyway */

    if (th->killable && th->killed)
    {
        for (vlc_cleanup_t *p = th->cleaners; p != NULL; p = p->next)
             p->proc (p->data);

        th->data = NULL; /* TODO: special value? */
        vlc_thread_cleanup (th);
        _endthreadex(0);
    }
}
Beispiel #17
0
void vlc_testcancel (void)
{
    vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
    if (nfo == NULL)
        return; /* Main thread - cannot be cancelled anyway */

    if (nfo->killable && nfo->killed)
    {
        for (vlc_cleanup_t *p = nfo->cleaners; p != NULL; p = p->next)
             p->proc (p->data);
#ifndef UNDER_CE
        _endthread ();
#else
        ExitThread(0);
#endif
    }
}
Beispiel #18
0
static DWORD vlc_WaitForMultipleObjects (DWORD count, const HANDLE *handles,
                                         DWORD delay)
{
    DWORD ret;
#ifdef UNDER_CE
    HANDLE buf[count + 1];

    struct vlc_thread *th = vlc_threadvar_get (thread_key);
    if (th != NULL)
    {
        memcpy (buf, handles, count * sizeof(HANDLE));
        buf[count++] = th->cancel_event;
        handles = buf;
    }

    if (count == 0)
    {
         Sleep (delay);
         ret = WAIT_TIMEOUT;
    }
    else
        ret = WaitForMultipleObjects (count, handles, FALSE, delay);

    if ((th != NULL) && (ret == WAIT_OBJECT_0 + count - 1))
    {
        vlc_cancel_self ((uintptr_t)th);
        ret = WAIT_IO_COMPLETION;
    }
#else
    if (count == 0)
    {
        ret = SleepEx (delay, TRUE);
        if (ret == 0)
            ret = WAIT_TIMEOUT;
    }
    else
        ret = WaitForMultipleObjectsEx (count, handles, FALSE, delay, TRUE);
#endif
    /* We do not abandon objects... this would be a bug */
    assert (ret < WAIT_ABANDONED_0 || WAIT_ABANDONED_0 + count - 1 < ret);

    if (unlikely(ret == WAIT_FAILED))
        abort (); /* We are screwed! */
    return ret;
}
Beispiel #19
0
static ULONG vlc_DosWaitEventSemEx( HEV hev, ULONG ulTimeout, BOOL fCancelable )
{
    HMUX      hmux;
    SEMRECORD asr[ 2 ];
    ULONG     ulUser;
    int       n;
    ULONG     rc;

    struct vlc_thread *th = vlc_threadvar_get( thread_key );
    if( th == NULL || !fCancelable )
    {
        /* Main thread - cannot be cancelled anyway
         * Alien thread - out of our control
         */
        if( hev != NULLHANDLE )
            return DosWaitEventSem( hev, ulTimeout );

        return DosSleep( ulTimeout );
    }

    n = 0;
    if( hev != NULLHANDLE )
    {
        asr[ n ].hsemCur = ( HSEM )hev;
        asr[ n ].ulUser  = 0;
        n++;
    }
    asr[ n ].hsemCur = ( HSEM )th->cancel_event;
    asr[ n ].ulUser  = 0xFFFF;
    n++;

    DosCreateMuxWaitSem( NULL, &hmux, n, asr, DCMW_WAIT_ANY );
    rc = DosWaitMuxWaitSem( hmux, ulTimeout, &ulUser );
    DosCloseMuxWaitSem( hmux );
    if( rc )
        return rc;

    if( ulUser == 0xFFFF )
    {
        vlc_cancel_self( th );
        return ERROR_INTERRUPT;
    }

    return NO_ERROR;
}
Beispiel #20
0
/**
 * Cleans up after an interruptible wait: waits for any pending invocations of
 * the callback previously registed with vlc_interrupt_prepare(), and rechecks
 * for any pending interruption.
 *
 * @warning As this function waits for ongoing callback invocation to complete,
 * the caller must not hold any resource necessary for the callback to run.
 * Otherwise a deadlock may occur.
 *
 * @return EINTR if an interruption occurred, zero otherwise
 */
static int vlc_interrupt_finish(vlc_interrupt_t *ctx)
{
    int ret = 0;

    assert(ctx != NULL);
    assert(ctx == vlc_threadvar_get(vlc_interrupt_var));

    /* Wait for pending callbacks to prevent access by other threads. */
    vlc_mutex_lock(&ctx->lock);
    ctx->callback = NULL;
    if (ctx->interrupted)
    {
        ret = EINTR;
        ctx->interrupted = false;
    }
    vlc_mutex_unlock(&ctx->lock);
    return ret;
}
Beispiel #21
0
int vlc_sem_wait_i11e(vlc_sem_t *sem)
{
    vlc_interrupt_t *ctx = vlc_threadvar_get(vlc_interrupt_var);
    if (ctx == NULL)
        return vlc_sem_wait(sem), 0;

    int ret = vlc_interrupt_prepare(ctx, vlc_interrupt_sem, sem);
    if (ret)
    {
        vlc_testcancel();
        return ret;
    }

    vlc_cleanup_push(vlc_interrupt_cleanup, ctx);
    vlc_sem_wait(sem);
    vlc_cleanup_pop();

    return vlc_interrupt_finish(ctx);
}
Beispiel #22
0
static void vlc_threadvars_cleanup(void)
{
    vlc_threadvar_t key;
retry:
    /* TODO: use RW lock or something similar */
    vlc_mutex_lock(&super_mutex);
    for (key = vlc_threadvar_last; key != NULL; key = key->prev)
    {
        void *value = vlc_threadvar_get(key);
        if (value != NULL && key->destroy != NULL)
        {
            vlc_mutex_unlock(&super_mutex);
            vlc_threadvar_set(key, NULL);
            key->destroy(value);
            goto retry;
        }
    }
    vlc_mutex_unlock(&super_mutex);
}
Beispiel #23
0
void vlc_testcancel (void)
{
    struct vlc_thread *th = vlc_threadvar_get (thread_key);
    if (th == NULL)
        return; /* Main thread - cannot be cancelled anyway */

    if (th->killable && th->killed)
    {
        for (vlc_cleanup_t *p = th->cleaners; p != NULL; p = p->next)
             p->proc (p->data);

        th->data = NULL; /* TODO: special value? */
        vlc_thread_cleanup (th);
#ifndef UNDER_CE
        _endthreadex(0);
#else
        ExitThread(0);
#endif
    }
}
Beispiel #24
0
vlc_interrupt_t *vlc_interrupt_set(vlc_interrupt_t *newctx)
{
    vlc_interrupt_t *oldctx;

    oldctx = vlc_threadvar_get(vlc_interrupt_var);
#ifndef NDEBUG
    if (oldctx != NULL)
    {
        assert(oldctx->attached);
        oldctx->attached = false;
    }
    if (newctx != NULL)
    {
        assert(!newctx->attached);
        newctx->attached = true;
    }
#endif
    vlc_threadvar_set(vlc_interrupt_var, newctx);

    return oldctx;
}
Beispiel #25
0
void vlc_testcancel (void)
{
    struct vlc_thread *th = vlc_threadvar_get (thread_key);
    if (th == NULL)
        return; /* Main thread - cannot be cancelled anyway */
    if (!th->killable)
        return;
#if !VLC_WINSTORE_APP
    if (likely(!th->killed))
        return;
#else
    if (!atomic_load(&th->killed))
        return;
#endif

    for (vlc_cleanup_t *p = th->cleaners; p != NULL; p = p->next)
        p->proc (p->data);

    th->data = NULL; /* TODO: special value? */
    vlc_thread_cleanup (th);
    _endthreadex(0);
}
Beispiel #26
0
void vlc_testcancel (void)
{
    struct vlc_thread *th = vlc_threadvar_get (thread_key);
    if (th == NULL)
        return; /* Main thread - cannot be cancelled anyway */

    /* This check is needed for the case that vlc_cancel() is followed by
     * vlc_testcancel() without any cancellation point */
    if( DosWaitEventSem( th->cancel_event, 0 ) == NO_ERROR )
        vlc_cancel_self( NULL );

    if (th->killable && th->killed)
    {
        for (vlc_cleanup_t *p = th->cleaners; p != NULL; p = p->next)
             p->proc (p->data);

        DosPostEventSem( th->done_event );
        th->data = NULL; /* TODO: special value? */
        vlc_thread_cleanup (th);
        _endthread();
    }
}
Beispiel #27
0
/**
 * Prepares to enter interruptible wait.
 * @param cb callback to interrupt the wait (i.e. wake up the thread)
 * @param data opaque data pointer for the callback
 * @return 0 on success or EINTR if an interruption is already pending
 * @note Any <b>succesful</b> call <b>must</b> be paired with a call to
 * vlc_interrupt_finish().
 */
static int vlc_interrupt_prepare(vlc_interrupt_t *ctx,
                                 void (*cb)(void *), void *data)
{
    int ret = 0;

    assert(ctx != NULL);
    assert(ctx == vlc_threadvar_get(vlc_interrupt_var));

    vlc_mutex_lock(&ctx->lock);
    assert(ctx->callback == NULL);
    if (ctx->interrupted)
    {
        ret = EINTR;
        ctx->interrupted = false;
    }
    else
    {
        ret = 0;
        ctx->callback = cb;
        ctx->data = data;
    }
    vlc_mutex_unlock(&ctx->lock);
    return ret;
}
Beispiel #28
0
static DWORD vlc_cancelable_wait (DWORD count, const HANDLE *handles,
                                  DWORD delay)
{
    vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
    if (nfo == NULL)
    {
        /* Main thread - cannot be cancelled anyway */
        return WaitForMultipleObjects (count, handles, FALSE, delay);
    }
    HANDLE new_handles[count + 1];
    memcpy(new_handles, handles, count * sizeof(HANDLE));
    new_handles[count] = nfo->cancel_event;
    DWORD result = WaitForMultipleObjects (count + 1, new_handles, FALSE,
                                           delay);
    if (result == WAIT_OBJECT_0 + count)
    {
        vlc_cancel_self (NULL);
        return WAIT_IO_COMPLETION;
    }
    else
    {
        return result;
    }
}
Beispiel #29
0
static char *get_error (void)
{
    return vlc_threadvar_get (context);
}
Beispiel #30
0
vlc_object_t *vlc_threadobj (void)
{
    return vlc_threadvar_get (&thread_object_key);
}