# include <mmsystem.h>
#endif
-static vlc_threadvar_t cancel_key;
+static vlc_threadvar_t thread_key;
/**
- * Per-thread cancellation data
+ * Per-thread data
*/
-typedef struct vlc_cancel_t
+struct vlc_thread
{
- vlc_cleanup_t *cleaners;
+ HANDLE id;
#ifdef UNDER_CE
HANDLE cancel_event;
#endif
+
+ bool detached;
bool killable;
bool killed;
-} vlc_cancel_t;
+ vlc_cleanup_t *cleaners;
-#ifndef UNDER_CE
-# define VLC_CANCEL_INIT { NULL, true, false }
-#else
-# define VLC_CANCEL_INIT { NULL, NULL, true, false }
-#endif
+ void *(*entry) (void *);
+ void *data;
+};
-#ifdef UNDER_CE
-static void CALLBACK vlc_cancel_self (ULONG_PTR dummy);
+static vlc_mutex_t super_mutex;
+static vlc_cond_t super_variable;
+extern vlc_rwlock_t config_lock, msg_lock;
+
+BOOL WINAPI DllMain (HINSTANCE, DWORD, LPVOID);
-static DWORD vlc_cancelable_wait (DWORD count, const HANDLE *handles,
- DWORD delay)
+BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
{
- 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
+ (void) hinstDll;
+ (void) lpvReserved;
+
+ switch (fdwReason)
{
- return result;
+ case DLL_PROCESS_ATTACH:
+ vlc_mutex_init (&super_mutex);
+ vlc_cond_init (&super_variable);
+ vlc_threadvar_create (&thread_key, NULL);
+ vlc_rwlock_init (&config_lock);
+ vlc_rwlock_init (&msg_lock);
+ vlc_CPU_init ();
+ break;
+
+ case DLL_PROCESS_DETACH:
+ vlc_rwlock_destroy (&msg_lock);
+ vlc_rwlock_destroy (&config_lock);
+ vlc_threadvar_delete (&thread_key);
+ vlc_cond_destroy (&super_variable);
+ vlc_mutex_destroy (&super_mutex);
+ break;
}
+ return TRUE;
}
-DWORD SleepEx (DWORD dwMilliseconds, BOOL bAlertable)
+static void CALLBACK vlc_cancel_self (ULONG_PTR);
+
+static DWORD vlc_WaitForMultipleObjects (DWORD count, const HANDLE *handles,
+ DWORD delay)
{
- if (bAlertable)
- {
- DWORD result = vlc_cancelable_wait (0, NULL, dwMilliseconds);
- return (result == WAIT_TIMEOUT) ? 0 : WAIT_IO_COMPLETION;
- }
- else
+ DWORD ret;
+#ifdef UNDER_CE
+ HANDLE buf[count + 1];
+
+ struct vlc_thread *th = vlc_threadvar_get (thread_key);
+ if (th != NULL)
{
- Sleep(dwMilliseconds);
- return 0;
+ memcpy (buf, handles, count * sizeof(HANDLE));
+ buf[count++] = th->cancel_event;
+ handles = buf;
}
-}
-DWORD WaitForSingleObjectEx (HANDLE hHandle, DWORD dwMilliseconds,
- BOOL bAlertable)
-{
- if (bAlertable)
+ if (count == 0)
{
- /* The MSDN documentation specifies different return codes,
- * but in practice they are the same. We just check that it
- * remains so. */
-#if WAIT_ABANDONED != WAIT_ABANDONED_0
-# error Windows headers changed, code needs to be rewritten!
-#endif
- return vlc_cancelable_wait (1, &hHandle, dwMilliseconds);
+ Sleep (delay);
+ ret = WAIT_TIMEOUT;
}
else
- {
- return WaitForSingleObject (hHandle, dwMilliseconds);
- }
-}
+ ret = WaitForMultipleObjects (count, handles, FALSE, delay);
-DWORD WaitForMultipleObjectsEx (DWORD nCount, const HANDLE *lpHandles,
- BOOL bWaitAll, DWORD dwMilliseconds,
- BOOL bAlertable)
-{
- if (bAlertable)
+ if ((th != NULL) && (ret == WAIT_OBJECT_0 + count - 1))
{
- /* We do not support the bWaitAll case */
- assert (! bWaitAll);
- return vlc_cancelable_wait (nCount, lpHandles, dwMilliseconds);
+ vlc_cancel_self ((uintptr_t)th);
+ ret = WAIT_IO_COMPLETION;
}
- else
+#else
+ if (count == 0)
{
- return WaitForMultipleObjects (nCount, lpHandles, bWaitAll,
- dwMilliseconds);
+ 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);
-vlc_mutex_t super_mutex;
-vlc_cond_t super_variable;
+ if (unlikely(ret == WAIT_FAILED))
+ abort (); /* We are screwed! */
+ return ret;
+}
-BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
+static DWORD vlc_WaitForSingleObject (HANDLE handle, DWORD delay)
{
- (void) hinstDll;
- (void) lpvReserved;
-
- switch (fdwReason)
- {
- case DLL_PROCESS_ATTACH:
- vlc_mutex_init (&super_mutex);
- vlc_cond_init (&super_variable);
- vlc_threadvar_create (&cancel_key, free);
- break;
+ return vlc_WaitForMultipleObjects (1, &handle, delay);
+}
- case DLL_PROCESS_DETACH:
- vlc_threadvar_delete( &cancel_key );
- vlc_cond_destroy (&super_variable);
- vlc_mutex_destroy (&super_mutex);
- break;
- }
- return TRUE;
+static DWORD vlc_Sleep (DWORD delay)
+{
+ DWORD ret = vlc_WaitForMultipleObjects (0, NULL, delay);
+ return (ret != WAIT_TIMEOUT) ? ret : 0;
}
+
/*** Mutexes ***/
void vlc_mutex_init( vlc_mutex_t *p_mutex )
{
/*** Condition variables ***/
enum
{
+ CLOCK_REALTIME=0, /* must be zero for VLC_STATIC_COND */
CLOCK_MONOTONIC,
- CLOCK_REALTIME,
};
static void vlc_cond_init_common (vlc_cond_t *p_condvar, unsigned clock)
void vlc_cond_signal (vlc_cond_t *p_condvar)
{
- /* NOTE: This will cause a broadcast, that is wrong.
- * This will also wake up the next waiting thread if no threads are yet
- * waiting, which is also wrong. However both of these issues are allowed
- * by the provision for spurious wakeups. Better have too many wakeups
- * than too few (= deadlocks). */
- SetEvent (p_condvar->handle);
+ if (!p_condvar->handle)
+ return;
+
+ /* This is suboptimal but works. */
+ vlc_cond_broadcast (p_condvar);
}
void vlc_cond_broadcast (vlc_cond_t *p_condvar)
{
+ if (!p_condvar->handle)
+ return;
+
+ /* Wake all threads up (as the event HANDLE has manual reset) */
SetEvent (p_condvar->handle);
}
{
DWORD result;
- assert (p_mutex->dynamic); /* TODO */
+ if (!p_condvar->handle)
+ { /* FIXME FIXME FIXME */
+ msleep (50000);
+ return;
+ }
+
do
{
vlc_testcancel ();
- LeaveCriticalSection (&p_mutex->mutex);
- result = WaitForSingleObjectEx (p_condvar->handle, INFINITE, TRUE);
- EnterCriticalSection (&p_mutex->mutex);
+ vlc_mutex_unlock (p_mutex);
+ result = vlc_WaitForSingleObject (p_condvar->handle, INFINITE);
+ vlc_mutex_lock (p_mutex);
}
while (result == WAIT_IO_COMPLETION);
- assert (result != WAIT_ABANDONED); /* another thread failed to cleanup! */
- assert (result != WAIT_FAILED);
ResetEvent (p_condvar->handle);
}
{
DWORD result;
- assert (p_mutex->dynamic); /* TODO */
+ if (!p_condvar->handle)
+ { /* FIXME FIXME FIXME */
+ msleep (50000);
+ return 0;
+ }
+
do
{
vlc_testcancel ();
mtime_t total;
switch (p_condvar->clock)
{
- case CLOCK_MONOTONIC:
- total = mdate();
- break;
case CLOCK_REALTIME: /* FIXME? sub-second precision */
total = CLOCK_FREQ * time (NULL);
break;
default:
- assert (0);
+ assert (p_condvar->clock == CLOCK_MONOTONIC);
+ total = mdate();
+ break;
}
total = (deadline - total) / 1000;
if( total < 0 )
total = 0;
DWORD delay = (total > 0x7fffffff) ? 0x7fffffff : total;
- LeaveCriticalSection (&p_mutex->mutex);
- result = WaitForSingleObjectEx (p_condvar->handle, delay, TRUE);
- EnterCriticalSection (&p_mutex->mutex);
+ vlc_mutex_unlock (p_mutex);
+ result = vlc_WaitForSingleObject (p_condvar->handle, delay);
+ vlc_mutex_lock (p_mutex);
}
while (result == WAIT_IO_COMPLETION);
- assert (result != WAIT_ABANDONED);
- assert (result != WAIT_FAILED);
ResetEvent (p_condvar->handle);
return (result == WAIT_OBJECT_0) ? 0 : ETIMEDOUT;
do
{
vlc_testcancel ();
- result = WaitForSingleObjectEx (*sem, INFINITE, TRUE);
+ result = vlc_WaitForSingleObject (*sem, INFINITE);
}
while (result == WAIT_IO_COMPLETION);
}
void vlc_rwlock_init (vlc_rwlock_t *lock)
{
vlc_mutex_init (&lock->mutex);
- vlc_cond_init (&lock->read_wait);
- vlc_cond_init (&lock->write_wait);
+ vlc_cond_init (&lock->wait);
lock->readers = 0; /* active readers */
- lock->writers = 0; /* waiting or active writers */
+ lock->writers = 0; /* waiting writers */
lock->writer = 0; /* ID of active writer */
}
-/**
- * Destroys an initialized unused read/write lock.
- */
void vlc_rwlock_destroy (vlc_rwlock_t *lock)
{
- vlc_cond_destroy (&lock->read_wait);
- vlc_cond_destroy (&lock->write_wait);
+ vlc_cond_destroy (&lock->wait);
vlc_mutex_destroy (&lock->mutex);
}
-/**
- * Acquires a read/write lock for reading. Recursion is allowed.
- */
void vlc_rwlock_rdlock (vlc_rwlock_t *lock)
{
vlc_mutex_lock (&lock->mutex);
+ /* Recursive read-locking is allowed. With the infos available:
+ * - the loosest possible condition (no active writer) is:
+ * (lock->writer != 0)
+ * - the strictest possible condition is:
+ * (lock->writer != 0 || (lock->readers == 0 && lock->writers > 0))
+ * or (lock->readers == 0 && (lock->writer != 0 || lock->writers > 0))
+ */
while (lock->writer != 0)
- vlc_cond_wait (&lock->read_wait, &lock->mutex);
- if (lock->readers == ULONG_MAX)
+ {
+ assert (lock->readers == 0);
+ vlc_cond_wait (&lock->wait, &lock->mutex);
+ }
+ if (unlikely(lock->readers == ULONG_MAX))
abort ();
lock->readers++;
vlc_mutex_unlock (&lock->mutex);
}
-/**
- * Acquires a read/write lock for writing. Recursion is not allowed.
- */
+static void vlc_rwlock_rdunlock (vlc_rwlock_t *lock)
+{
+ vlc_mutex_lock (&lock->mutex);
+ assert (lock->readers > 0);
+
+ /* If there are no readers left, wake up a writer. */
+ if (--lock->readers == 0 && lock->writers > 0)
+ vlc_cond_signal (&lock->wait);
+ vlc_mutex_unlock (&lock->mutex);
+}
+
void vlc_rwlock_wrlock (vlc_rwlock_t *lock)
{
vlc_mutex_lock (&lock->mutex);
- if (lock->writers == ULONG_MAX)
+ if (unlikely(lock->writers == ULONG_MAX))
abort ();
lock->writers++;
+ /* Wait until nobody owns the lock in either way. */
while ((lock->readers > 0) || (lock->writer != 0))
- vlc_cond_wait (&lock->write_wait, &lock->mutex);
+ vlc_cond_wait (&lock->wait, &lock->mutex);
lock->writers--;
+ assert (lock->writer == 0);
lock->writer = GetCurrentThreadId ();
vlc_mutex_unlock (&lock->mutex);
}
-/**
- * Releases a read/write lock.
- */
-void vlc_rwlock_unlock (vlc_rwlock_t *lock)
+static void vlc_rwlock_wrunlock (vlc_rwlock_t *lock)
{
vlc_mutex_lock (&lock->mutex);
- if (lock->readers > 0)
- lock->readers--; /* Read unlock */
- else
- lock->writer = 0; /* Write unlock */
+ assert (lock->writer == GetCurrentThreadId ());
+ assert (lock->readers == 0);
+ lock->writer = 0; /* Write unlock */
- if (lock->writers > 0)
- {
- if (lock->readers == 0)
- vlc_cond_signal (&lock->write_wait);
- }
- else
- vlc_cond_broadcast (&lock->read_wait);
+ /* Let reader and writer compete. Scheduler decides who wins. */
+ vlc_cond_broadcast (&lock->wait);
vlc_mutex_unlock (&lock->mutex);
}
+void vlc_rwlock_unlock (vlc_rwlock_t *lock)
+{
+ /* Note: If the lock is held for reading, lock->writer is nul.
+ * If the lock is held for writing, only this thread can store a value to
+ * lock->writer. Either way, lock->writer is safe to fetch here. */
+ if (lock->writer != 0)
+ vlc_rwlock_wrunlock (lock);
+ else
+ vlc_rwlock_rdunlock (lock);
+}
+
/*** Thread-specific variables (TLS) ***/
+struct vlc_threadvar
+{
+ DWORD id;
+ void (*destroy) (void *);
+ struct vlc_threadvar *prev;
+ struct vlc_threadvar *next;
+} *vlc_threadvar_last = NULL;
+
int vlc_threadvar_create (vlc_threadvar_t *p_tls, void (*destr) (void *))
{
-#warning FIXME: use destr() callback and stop leaking!
- VLC_UNUSED( destr );
+ struct vlc_threadvar *var = malloc (sizeof (*var));
+ if (unlikely(var == NULL))
+ return errno;
- *p_tls = TlsAlloc();
- return (*p_tls == TLS_OUT_OF_INDEXES) ? EAGAIN : 0;
+ var->id = TlsAlloc();
+ if (var->id == TLS_OUT_OF_INDEXES)
+ {
+ free (var);
+ return EAGAIN;
+ }
+ var->destroy = destr;
+ var->next = NULL;
+ *p_tls = var;
+
+ vlc_mutex_lock (&super_mutex);
+ var->prev = vlc_threadvar_last;
+ vlc_threadvar_last = var;
+ vlc_mutex_unlock (&super_mutex);
+ return 0;
}
void vlc_threadvar_delete (vlc_threadvar_t *p_tls)
{
- TlsFree (*p_tls);
+ struct vlc_threadvar *var = *p_tls;
+
+ vlc_mutex_lock (&super_mutex);
+ if (var->prev != NULL)
+ var->prev->next = var->next;
+ else
+ vlc_threadvar_last = var->next;
+ if (var->next != NULL)
+ var->next->prev = var->prev;
+ vlc_mutex_unlock (&super_mutex);
+
+ TlsFree (var->id);
+ free (var);
}
-/**
- * Sets a thread-local variable.
- * @param key thread-local variable key (created with vlc_threadvar_create())
- * @param value new value for the variable for the calling thread
- * @return 0 on success, a system error code otherwise.
- */
int vlc_threadvar_set (vlc_threadvar_t key, void *value)
{
- return TlsSetValue (key, value) ? ENOMEM : 0;
+ return TlsSetValue (key->id, value) ? ENOMEM : 0;
}
-/**
- * Gets the value of a thread-local variable for the calling thread.
- * This function cannot fail.
- * @return the value associated with the given variable for the calling
- * or NULL if there is no value.
- */
void *vlc_threadvar_get (vlc_threadvar_t key)
{
- return TlsGetValue (key);
+ return TlsGetValue (key->id);
}
-
/*** Threads ***/
void vlc_threads_setup (libvlc_int_t *p_libvlc)
{
(void) p_libvlc;
}
-struct vlc_entry_data
+static void vlc_thread_cleanup (struct vlc_thread *th)
{
- void * (*func) (void *);
- void * data;
+ 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);
#ifdef UNDER_CE
- HANDLE cancel_event;
+ CloseHandle (th->cancel_event);
#endif
-};
+ free (th);
+ }
+}
static unsigned __stdcall vlc_entry (void *p)
{
- vlc_cancel_t cancel_data = VLC_CANCEL_INIT;
- struct vlc_entry_data data;
-
- memcpy (&data, p, sizeof (data));
- free (p);
-
-#ifdef UNDER_CE
- cancel_data.cancel_event = data.cancel_event;
-#endif
+ struct vlc_thread *th = p;
- vlc_threadvar_set (cancel_key, &cancel_data);
- data.func (data.data);
+ vlc_threadvar_set (thread_key, th);
+ th->killable = true;
+ th->data = th->entry (th->data);
+ vlc_thread_cleanup (th);
return 0;
}
-int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
- int priority)
+static int vlc_clone_attr (vlc_thread_t *p_handle, bool detached,
+ void *(*entry) (void *), void *data, int priority)
{
- int err = ENOMEM;
- HANDLE hThread;
-
- struct vlc_entry_data *entry_data = malloc (sizeof (*entry_data));
- if (entry_data == NULL)
+ struct vlc_thread *th = malloc (sizeof (*th));
+ if (unlikely(th == NULL))
return ENOMEM;
- entry_data->func = entry;
- entry_data->data = data;
+ th->entry = entry;
+ th->data = data;
+ th->detached = detached;
+ th->killable = false; /* not until vlc_entry() ! */
+ th->killed = false;
+ th->cleaners = NULL;
+ HANDLE hThread;
#ifndef UNDER_CE
/* When using the MSVCRT C library you have to use the _beginthreadex
* function instead of CreateThread, otherwise you'll end up with
* memory leaks and the signal functions not working (see Microsoft
* Knowledge Base, article 104641) */
- hThread = (HANDLE)(uintptr_t)
- _beginthreadex (NULL, 0, vlc_entry, entry_data, CREATE_SUSPENDED, NULL);
- if (! hThread)
- {
- err = errno;
- goto error;
- }
+ uintptr_t h;
- /* Thread closes the handle when exiting, duplicate it here
- * to be on the safe side when joining. */
- if (!DuplicateHandle (GetCurrentProcess (), hThread,
- GetCurrentProcess (), p_handle, 0, FALSE,
- DUPLICATE_SAME_ACCESS))
+ h = _beginthreadex (NULL, 0, vlc_entry, th, CREATE_SUSPENDED, NULL);
+ if (h == 0)
{
- CloseHandle (hThread);
- goto error;
+ int err = errno;
+ free (th);
+ return err;
}
+ hThread = (HANDLE)h;
#else
- vlc_thread_t th = malloc (sizeof (*th));
- if (th == NULL)
- goto error;
th->cancel_event = CreateEvent (NULL, FALSE, FALSE, NULL);
if (th->cancel_event == NULL)
{
free (th);
- goto error;
+ return ENOMEM;
}
- entry_data->cancel_event = th->cancel_event;
/* Not sure if CREATE_SUSPENDED + ResumeThread() is any useful on WinCE.
* Thread handles act up, too. */
- th->handle = CreateThread (NULL, 128*1024, vlc_entry, entry_data,
- CREATE_SUSPENDED, NULL);
- if (th->handle == NULL)
+ hThread = CreateThread (NULL, 128*1024, vlc_entry, th,
+ CREATE_SUSPENDED, NULL);
+ if (hThread == NULL)
{
CloseHandle (th->cancel_event);
free (th);
- goto error;
+ return ENOMEM;
}
- *p_handle = th;
- hThread = th->handle;
-
#endif
+ /* Thread is suspended, so we can safely set th->id */
+ th->id = hThread;
+ if (p_handle != NULL)
+ *p_handle = th;
- ResumeThread (hThread);
if (priority)
SetThreadPriority (hThread, priority);
+ ResumeThread (hThread);
+
return 0;
+}
-error:
- free (entry_data);
- return err;
+int vlc_clone (vlc_thread_t *p_handle, void *(*entry) (void *),
+ void *data, int priority)
+{
+ return vlc_clone_attr (p_handle, false, entry, data, priority);
}
-void vlc_join (vlc_thread_t handle, void **result)
+void vlc_join (vlc_thread_t th, void **result)
{
-#ifdef UNDER_CE
-# define handle handle->handle
-#endif
do
vlc_testcancel ();
- while (WaitForSingleObjectEx (handle, INFINITE, TRUE)
+ while (vlc_WaitForSingleObject (th->id, INFINITE)
== WAIT_IO_COMPLETION);
- CloseHandle (handle);
- assert (result == NULL); /* <- FIXME if ever needed */
+ if (result != NULL)
+ *result = th->data;
+ CloseHandle (th->id);
#ifdef UNDER_CE
-# undef handle
- CloseHandle (handle->cancel_event);
- free (handle);
+ CloseHandle (th->cancel_event);
#endif
+ free (th);
}
-void vlc_detach (vlc_thread_t handle)
+int vlc_clone_detach (vlc_thread_t *p_handle, void *(*entry) (void *),
+ void *data, int priority)
{
-#ifndef UNDER_CE
- CloseHandle (handle);
-#else
- /* FIXME: handle->cancel_event leak */
- CloseHandle (handle->handle);
- free (handle);
-#endif
+ vlc_thread_t th;
+ if (p_handle == NULL)
+ p_handle = &th;
+
+ return vlc_clone_attr (p_handle, true, entry, data, priority);
+}
+
+int vlc_set_priority (vlc_thread_t th, int priority)
+{
+ if (!SetThreadPriority (th->id, priority))
+ return VLC_EGENERIC;
+ return VLC_SUCCESS;
}
/*** Thread cancellation ***/
/* APC procedure for thread cancellation */
-static void CALLBACK vlc_cancel_self (ULONG_PTR dummy)
+static void CALLBACK vlc_cancel_self (ULONG_PTR self)
{
- vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
+ struct vlc_thread *th = (void *)self;
- if (likely(nfo != NULL))
- nfo->killed = true;
-
- (void)dummy;
+ if (likely(th != NULL))
+ th->killed = true;
}
-void vlc_cancel (vlc_thread_t thread_id)
+void vlc_cancel (vlc_thread_t th)
{
#ifndef UNDER_CE
- QueueUserAPC (vlc_cancel_self, thread_id, 0);
+ QueueUserAPC (vlc_cancel_self, th->id, (uintptr_t)th);
#else
- SetEvent (thread_id->cancel_event);
+ SetEvent (th->cancel_event);
#endif
}
int vlc_savecancel (void)
{
- int state;
-
- vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
- if (nfo == NULL)
+ struct vlc_thread *th = vlc_threadvar_get (thread_key);
+ if (th == NULL)
return false; /* Main thread - cannot be cancelled anyway */
- state = nfo->killable;
- nfo->killable = false;
+ int state = th->killable;
+ th->killable = false;
return state;
}
void vlc_restorecancel (int state)
{
- vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
+ struct vlc_thread *th = vlc_threadvar_get (thread_key);
assert (state == false || state == true);
- if (nfo == NULL)
+ if (th == NULL)
return; /* Main thread - cannot be cancelled anyway */
- assert (!nfo->killable);
- nfo->killable = state != 0;
+ assert (!th->killable);
+ th->killable = state != 0;
}
void vlc_testcancel (void)
{
- vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
- if (nfo == NULL)
+ struct vlc_thread *th = vlc_threadvar_get (thread_key);
+ if (th == NULL)
return; /* Main thread - cannot be cancelled anyway */
- if (nfo->killable && nfo->killed)
+ if (th->killable && th->killed)
{
- for (vlc_cleanup_t *p = nfo->cleaners; p != NULL; p = p->next)
+ 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
- _endthread ();
+ _endthreadex(0);
#else
ExitThread(0);
#endif
* need to lock anything. */
va_list ap;
- vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
- if (nfo == NULL)
+ struct vlc_thread *th = vlc_threadvar_get (thread_key);
+ if (th == NULL)
return; /* Main thread - cannot be cancelled anyway */
va_start (ap, cmd);
/* 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;
+ cleaner->next = th->cleaners;
+ th->cleaners = cleaner;
break;
}
case VLC_CLEANUP_POP:
{
- nfo->cleaners = nfo->cleaners->next;
+ th->cleaners = th->cleaners->next;
break;
}
}
}
+/*** Clock ***/
+mtime_t mdate (void)
+{
+ /* We don't need the real date, just the value of a high precision timer */
+ LARGE_INTEGER counter, freq;
+ if (!QueryPerformanceCounter (&counter)
+ || !QueryPerformanceFrequency (&freq))
+ abort();
+
+ /* Convert to from (1/freq) to microsecond resolution */
+ /* We need to split the division to avoid 63-bits overflow */
+ lldiv_t d = lldiv (counter.QuadPart, freq.QuadPart);
+
+ return (d.quot * 1000000) + ((d.rem * 1000000) / freq.QuadPart);
+}
+
+#undef mwait
+void mwait (mtime_t deadline)
+{
+ mtime_t delay;
+
+ vlc_testcancel();
+ while ((delay = (deadline - mdate())) > 0)
+ {
+ delay /= 1000;
+ if (unlikely(delay > 0x7fffffff))
+ delay = 0x7fffffff;
+ vlc_Sleep (delay);
+ vlc_testcancel();
+ }
+}
+
+#undef msleep
+void msleep (mtime_t delay)
+{
+ mwait (mdate () + delay);
+}
+
+
/*** Timers ***/
struct vlc_timer
{
(void)timer;
return 0;
}
+
+
+/*** CPU ***/
+unsigned vlc_GetCPUCount (void)
+{
+#ifndef UNDER_CE
+ DWORD process;
+ DWORD system;
+
+ if (GetProcessAffinityMask (GetCurrentProcess(), &process, &system))
+ return popcount (system);
+#endif
+ return 1;
+}