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); }
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; }
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); } }
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; }
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); }
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); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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); }
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); } }
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 } }
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; }
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; }
/** * 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; }
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); }
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); }
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 } }
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; }
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); }
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(); } }
/** * 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; }
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; } }
static char *get_error (void) { return vlc_threadvar_get (context); }
vlc_object_t *vlc_threadobj (void) { return vlc_threadvar_get (&thread_object_key); }