/*****************************************************************************
* thread.c : Win32 back-end for LibVLC
*****************************************************************************
- * Copyright (C) 1999-2009 the VideoLAN team
+ * Copyright (C) 1999-2009 VLC authors and VideoLAN
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
* RĂ©mi Denis-Courmont
* Pierre Ynard
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
#include <assert.h>
#include <limits.h>
#include <errno.h>
-#ifdef UNDER_CE
-# include <mmsystem.h>
-#endif
-
-static vlc_threadvar_t thread_key;
-
-/**
- * Per-thread data
- */
-struct vlc_thread
-{
- HANDLE id;
-#ifdef UNDER_CE
- HANDLE cancel_event;
-#endif
-
- bool detached;
- bool killable;
- bool killed;
- vlc_cleanup_t *cleaners;
-
- void *(*entry) (void *);
- void *data;
-};
-
-#ifdef UNDER_CE
-static void CALLBACK vlc_cancel_self (ULONG_PTR dummy);
-
-DWORD WaitForMultipleObjectsEx (DWORD nCount, const HANDLE *lpHandles,
- BOOL bWaitAll, DWORD dwMilliseconds,
- BOOL bAlertable)
-{
- struct vlc_thread *th = vlc_threadvar_get (thread_key);
- HANDLE handles[nCount + 1];
- DWORD ret;
-
- memcpy(handles, lpHandles, nCount * sizeof(HANDLE));
- if (bAlertable)
- {
- if (th != NULL)
- {
- handles[nCount] = th->cancel_event;
- /* bWaitAll not implemented and not used by VLC... */
- assert (!bWaitAll);
- }
- else
- bAlertable = FALSE;
- }
-
- ret = WaitForMultipleObjects (nCount + bAlertable, handles, bWaitAll,
- dwMilliseconds);
- if (ret == WAIT_OBJECT_0 + nCount)
- {
- assert (bAlertable);
- vlc_cancel_self ((uintptr_t)th);
- ret = WAIT_IO_COMPLETION;
- }
- return ret;
-}
-#endif
+/*** Static mutex and condition variable ***/
static vlc_mutex_t super_mutex;
static vlc_cond_t super_variable;
-BOOL WINAPI DllMain (HINSTANCE, DWORD, LPVOID);
-
-BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
-{
- (void) hinstDll;
- (void) lpvReserved;
-
- switch (fdwReason)
- {
- case DLL_PROCESS_ATTACH:
- vlc_mutex_init (&super_mutex);
- vlc_cond_init (&super_variable);
- vlc_threadvar_create (&thread_key, NULL);
- break;
-
- case DLL_PROCESS_DETACH:
- vlc_threadvar_delete (&thread_key);
- vlc_cond_destroy (&super_variable);
- vlc_mutex_destroy (&super_mutex);
- break;
- }
- return TRUE;
-}
+/*** Common helpers ***/
static DWORD vlc_WaitForMultipleObjects (DWORD count, const HANDLE *handles,
DWORD delay)
{
- DWORD ret = WaitForMultipleObjectsEx (count, handles, FALSE, delay, TRUE);
-
- /* We do not abandon objects... this would be a bug */
- assert (ret < WAIT_ABANDONED_0 || WAIT_ABANDONED_0 + count - 1 < ret);
+ DWORD ret;
+ if (count == 0)
+ {
+ ret = SleepEx (delay, TRUE);
+ if (ret == 0)
+ ret = WAIT_TIMEOUT;
+ }
+ else
+ ret = WaitForMultipleObjectsEx (count, handles, FALSE, delay, TRUE);
- if (unlikely(ret == WAIT_FAILED))
- abort (); /* We are screwed! */
+ /* We do not abandon objects... this would be a bug */
+ assert (ret < WAIT_ABANDONED_0 || WAIT_ABANDONED_0 + count - 1 < ret);
- return ret;
+ if (unlikely(ret == WAIT_FAILED))
+ abort (); /* We are screwed! */
+ return ret;
}
static DWORD vlc_WaitForSingleObject (HANDLE handle, DWORD delay)
return vlc_WaitForMultipleObjects (1, &handle, delay);
}
-#if 0 // WaitForMultipleObjectsEx() cannot deal with zero handles
static DWORD vlc_Sleep (DWORD delay)
{
DWORD ret = vlc_WaitForMultipleObjects (0, NULL, delay);
- if (ret == WAIT_TIMEOUT)
- ret = 0;
- return ret;
+ return (ret != WAIT_TIMEOUT) ? ret : 0;
}
-#endif
/*** Mutexes ***/
/*** Condition variables ***/
enum
{
+ CLOCK_STATIC=0, /* must be zero for VLC_STATIC_COND */
CLOCK_MONOTONIC,
CLOCK_REALTIME,
};
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->clock)
+ return;
+
+ /* This is suboptimal but works. */
+ vlc_cond_broadcast (p_condvar);
}
void vlc_cond_broadcast (vlc_cond_t *p_condvar)
{
+ if (!p_condvar->clock)
+ 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->clock)
+ { /* FIXME FIXME FIXME */
+ msleep (50000);
+ return;
+ }
+
do
{
vlc_testcancel ();
- LeaveCriticalSection (&p_mutex->mutex);
+ vlc_mutex_unlock (p_mutex);
result = vlc_WaitForSingleObject (p_condvar->handle, INFINITE);
- EnterCriticalSection (&p_mutex->mutex);
+ vlc_mutex_lock (p_mutex);
}
while (result == WAIT_IO_COMPLETION);
{
DWORD result;
- assert (p_mutex->dynamic); /* TODO */
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 (p_condvar->clock == CLOCK_MONOTONIC);
- total = mdate();
- break;
+ assert (!p_condvar->clock);
+ /* FIXME FIXME FIXME */
+ msleep (50000);
+ return 0;
}
total = (deadline - total) / 1000;
if( total < 0 )
total = 0;
DWORD delay = (total > 0x7fffffff) ? 0x7fffffff : total;
- LeaveCriticalSection (&p_mutex->mutex);
+ vlc_mutex_unlock (p_mutex);
result = vlc_WaitForSingleObject (p_condvar->handle, delay);
- EnterCriticalSection (&p_mutex->mutex);
+ vlc_mutex_lock (p_mutex);
}
while (result == WAIT_IO_COMPLETION);
}
/*** Read/write locks */
+#if 0
/* SRW (Slim Read Write) locks are available in Vista+ only */
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);
- lock->readers = 0; /* active readers */
- lock->writers = 0; /* waiting writers */
- lock->writer = 0; /* ID of active writer */
}
void vlc_rwlock_destroy (vlc_rwlock_t *lock)
{
- vlc_cond_destroy (&lock->read_wait);
- vlc_cond_destroy (&lock->write_wait);
- vlc_mutex_destroy (&lock->mutex);
}
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)
- {
- assert (lock->readers == 0);
- vlc_cond_wait (&lock->read_wait, &lock->mutex);
- }
- if (unlikely(lock->readers == ULONG_MAX))
- abort ();
- lock->readers++;
- vlc_mutex_unlock (&lock->mutex);
-}
-
-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->write_wait);
- vlc_mutex_unlock (&lock->mutex);
}
void vlc_rwlock_wrlock (vlc_rwlock_t *lock)
{
- vlc_mutex_lock (&lock->mutex);
- 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);
- lock->writers--;
- assert (lock->writer == 0);
- lock->writer = GetCurrentThreadId ();
- vlc_mutex_unlock (&lock->mutex);
-}
-
-static void vlc_rwlock_wrunlock (vlc_rwlock_t *lock)
-{
- vlc_mutex_lock (&lock->mutex);
- assert (lock->writer == GetCurrentThreadId ());
- assert (lock->readers == 0);
- lock->writer = 0; /* Write unlock */
-
- /* Let reader and writer compete. Scheduler decides who wins. */
- if (lock->writers > 0)
- vlc_cond_signal (&lock->write_wait);
- vlc_cond_broadcast (&lock->read_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);
}
+#else
+# include "misc/rwlock.h"
+#endif
/*** Thread-specific variables (TLS) ***/
struct vlc_threadvar
vlc_mutex_lock (&super_mutex);
var->prev = vlc_threadvar_last;
+ if (var->prev)
+ var->prev->next = var;
+
vlc_threadvar_last = var;
vlc_mutex_unlock (&super_mutex);
return 0;
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;
+ else
+ vlc_threadvar_last = var->prev;
+
vlc_mutex_unlock (&super_mutex);
TlsFree (var->id);
}
/*** Threads ***/
-void vlc_threads_setup (libvlc_int_t *p_libvlc)
+static vlc_threadvar_t thread_key;
+
+/** Per-thread data */
+struct vlc_thread
{
- (void) p_libvlc;
-}
+ HANDLE id;
+
+ bool detached;
+ bool killable;
+ bool killed;
+ vlc_cleanup_t *cleaners;
+
+ void *(*entry) (void *);
+ void *data;
+};
static void vlc_thread_cleanup (struct vlc_thread *th)
{
if (th->detached)
{
CloseHandle (th->id);
-#ifdef UNDER_CE
- CloseHandle (th->cancel_event);
-#endif
free (th);
}
}
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
}
hThread = (HANDLE)h;
-#else
- th->cancel_event = CreateEvent (NULL, FALSE, FALSE, NULL);
- if (th->cancel_event == NULL)
- {
- free (th);
- return ENOMEM;
- }
-
- /* Not sure if CREATE_SUSPENDED + ResumeThread() is any useful on WinCE.
- * Thread handles act up, too. */
- hThread = CreateThread (NULL, 128*1024, vlc_entry, th,
- CREATE_SUSPENDED, NULL);
- if (hThread == NULL)
- {
- CloseHandle (th->cancel_event);
- free (th);
- return ENOMEM;
- }
-
-#endif
/* Thread is suspended, so we can safely set th->id */
th->id = hThread;
if (p_handle != NULL)
{
do
vlc_testcancel ();
- while (WaitForSingleObjectEx (th->id, INFINITE, TRUE)
- == WAIT_IO_COMPLETION);
+ while (vlc_WaitForSingleObject (th->id, INFINITE) == WAIT_IO_COMPLETION);
if (result != NULL)
*result = th->data;
CloseHandle (th->id);
-#ifdef UNDER_CE
- CloseHandle (th->cancel_event);
-#endif
free (th);
}
void vlc_cancel (vlc_thread_t th)
{
-#ifndef UNDER_CE
QueueUserAPC (vlc_cancel_self, th->id, (uintptr_t)th);
-#else
- SetEvent (th->cancel_event);
-#endif
}
int vlc_savecancel (void)
th->data = NULL; /* TODO: special value? */
vlc_thread_cleanup (th);
-#ifndef UNDER_CE
_endthreadex(0);
-#else
- ExitThread(0);
-#endif
}
}
va_end (ap);
}
-
/*** Clock ***/
+static CRITICAL_SECTION clock_lock;
+
+static mtime_t mdate_giveup (void)
+{
+ abort ();
+}
+
+static mtime_t (*mdate_selected) (void) = mdate_giveup;
+
mtime_t mdate (void)
+{
+ return mdate_selected ();
+}
+
+static union
+{
+ struct
+ {
+#if (_WIN32_WINNT < 0x0601)
+ BOOL (*query) (PULONGLONG);
+#endif
+ } interrupt;
+ struct
+ {
+#if (_WIN32_WINNT < 0x0600)
+ ULONGLONG (*get) (void);
+#endif
+ } tick;
+ struct
+ {
+ LARGE_INTEGER freq;
+ } perf;
+} clk;
+
+static mtime_t mdate_interrupt (void)
+{
+ ULONGLONG ts;
+ BOOL ret;
+
+#if (_WIN32_WINNT >= 0x0601)
+ ret = QueryUnbiasedInterruptTime (&ts);
+#else
+ ret = clk.interrupt.query (&ts);
+#endif
+ if (unlikely(!ret))
+ abort ();
+
+ /* hundreds of nanoseconds */
+ static_assert ((10000000 % CLOCK_FREQ) == 0, "Broken frequencies ratio");
+ return ts / (10000000 / CLOCK_FREQ);
+}
+
+static mtime_t mdate_tick (void)
+{
+#if (_WIN32_WINNT >= 0x0600)
+ ULONGLONG ts = GetTickCount64 ();
+#else
+ ULONGLONG ts = clk.tick.get ();
+#endif
+
+ /* milliseconds */
+ static_assert ((CLOCK_FREQ % 1000) == 0, "Broken frequencies ratio");
+ return ts * (CLOCK_FREQ / 1000);
+}
+#include <mmsystem.h>
+static mtime_t mdate_multimedia (void)
+{
+ DWORD ts = timeGetTime ();
+
+ /* milliseconds */
+ static_assert ((CLOCK_FREQ % 1000) == 0, "Broken frequencies ratio");
+ return ts * (CLOCK_FREQ / 1000);
+}
+
+static mtime_t mdate_perf (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();
+ LARGE_INTEGER counter;
+ if (!QueryPerformanceCounter (&counter))
+ 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);
+ lldiv_t d = lldiv (counter.QuadPart, clk.perf.freq.QuadPart);
- return (d.quot * 1000000) + ((d.rem * 1000000) / freq.QuadPart);
+ return (d.quot * 1000000) + ((d.rem * 1000000) / clk.perf.freq.QuadPart);
+}
+
+static mtime_t mdate_wall (void)
+{
+ FILETIME ts;
+ ULARGE_INTEGER s;
+
+#if (_WIN32_WINNT >= 0x0602)
+ GetSystemTimePreciseAsFileTime (&ts);
+#else
+ GetSystemTimeAsFileTime (&ts);
+#endif
+ s.LowPart = ts.dwLowDateTime;
+ s.HighPart = ts.dwHighDateTime;
+ /* hundreds of nanoseconds */
+ static_assert ((10000000 % CLOCK_FREQ) == 0, "Broken frequencies ratio");
+ return s.QuadPart / (10000000 / CLOCK_FREQ);
}
#undef mwait
delay /= 1000;
if (unlikely(delay > 0x7fffffff))
delay = 0x7fffffff;
- SleepEx (delay, TRUE);
+ vlc_Sleep (delay);
vlc_testcancel();
}
}
mwait (mdate () + delay);
}
+static void SelectClockSource (vlc_object_t *obj)
+{
+ EnterCriticalSection (&clock_lock);
+ if (mdate_selected != mdate_giveup)
+ {
+ LeaveCriticalSection (&clock_lock);
+ return;
+ }
+
+ const char *name = "perf";
+ char *str = var_InheritString (obj, "clock-source");
+ if (str != NULL)
+ name = str;
+ if (!strcmp (name, "interrupt"))
+ {
+ msg_Dbg (obj, "using interrupt time as clock source");
+#if (_WIN32_WINNT < 0x0601)
+ HANDLE h = GetModuleHandle (_T("kernel32.dll"));
+ if (unlikely(h == NULL))
+ abort ();
+ clk.interrupt.query = (void *)GetProcAddress (h,
+ _T("QueryUnbiasedInterruptTime"));
+ if (unlikely(clk.interrupt.query == NULL))
+ abort ();
+#endif
+ mdate_selected = mdate_interrupt;
+ }
+ else
+ if (!strcmp (name, "tick"))
+ {
+ msg_Dbg (obj, "using Windows time as clock source");
+#if (_WIN32_WINNT < 0x0601)
+ HANDLE h = GetModuleHandle (_T("kernel32.dll"));
+ if (unlikely(h == NULL))
+ abort ();
+ clk.tick.get = (void *)GetProcAddress (h, _T("GetTickCount64"));
+ if (unlikely(clk.tick.get == NULL))
+ abort ();
+#endif
+ mdate_selected = mdate_tick;
+ }
+ else
+ if (!strcmp (name, "multimedia"))
+ {
+ TIMECAPS caps;
+
+ msg_Dbg (obj, "using multimedia timers as clock source");
+ if (timeGetDevCaps (&caps, sizeof (caps)) != MMSYSERR_NOERROR)
+ abort ();
+ msg_Dbg (obj, " min period: %u ms, max period: %u ms",
+ caps.wPeriodMin, caps.wPeriodMax);
+ mdate_selected = mdate_multimedia;
+ }
+ else
+ if (!strcmp (name, "perf"))
+ {
+ msg_Dbg (obj, "using performance counters as clock source");
+ if (!QueryPerformanceFrequency (&clk.perf.freq))
+ abort ();
+ msg_Dbg (obj, " frequency: %llu Hz", clk.perf.freq.QuadPart);
+ mdate_selected = mdate_perf;
+ }
+ else
+ if (!strcmp (name, "wall"))
+ {
+ msg_Dbg (obj, "using system time as clock source");
+ mdate_selected = mdate_wall;
+ }
+ else
+ {
+ msg_Err (obj, "invalid clock source \"%s\"", name);
+ abort ();
+ }
+ LeaveCriticalSection (&clock_lock);
+ free (str);
+}
+
+#define xstrdup(str) (strdup(str) ?: (abort(), NULL))
+
+size_t EnumClockSource (vlc_object_t *obj, char ***vp, char ***np)
+{
+ const size_t max = 6;
+ char **values = xmalloc (sizeof (*values) * max);
+ char **names = xmalloc (sizeof (*names) * max);
+ size_t n = 0;
+
+#if (_WIN32_WINNT < 0x0601)
+ DWORD version = LOWORD(GetVersion());
+ version = (LOBYTE(version) << 8) | (HIBYTE(version) << 0);
+#endif
+
+ values[n] = xstrdup ("");
+ names[n] = xstrdup (_("Auto"));
+ n++;
+#if (_WIN32_WINNT < 0x0601)
+ if (version >= 0x0601)
+#endif
+ {
+ values[n] = xstrdup ("interrupt");
+ names[n] = xstrdup ("Interrupt time");
+ n++;
+ }
+#if (_WIN32_WINNT < 0x0600)
+ if (version >= 0x0600)
+#endif
+ {
+ values[n] = xstrdup ("tick");
+ names[n] = xstrdup ("Windows time");
+ n++;
+ }
+ values[n] = xstrdup ("multimedia");
+ names[n] = xstrdup ("Multimedia timers");
+ n++;
+ values[n] = xstrdup ("perf");
+ names[n] = xstrdup ("Performance counters");
+ n++;
+ values[n] = xstrdup ("wall");
+ names[n] = xstrdup ("System time (DANGEROUS!)");
+ n++;
+
+ *vp = values;
+ *np = names;
+ (void) obj;
+ return n;
+}
+
/*** Timers ***/
struct vlc_timer
{
-#ifndef UNDER_CE
HANDLE handle;
-#else
- unsigned id;
- unsigned interval;
-#endif
void (*func) (void *);
void *data;
};
-#ifndef UNDER_CE
static void CALLBACK vlc_timer_do (void *val, BOOLEAN timeout)
{
struct vlc_timer *timer = val;
assert (timeout);
timer->func (timer->data);
}
-#else
-static void CALLBACK vlc_timer_do (unsigned timer_id, unsigned msg,
- DWORD_PTR user, DWORD_PTR unused1,
- DWORD_PTR unused2)
-{
- struct vlc_timer *timer = (struct vlc_timer *) user;
- assert (timer_id == timer->id);
- (void) msg;
- (void) unused1;
- (void) unused2;
-
- timer->func (timer->data);
-
- if (timer->interval)
- {
- mtime_t interval = timer->interval * 1000;
- vlc_timer_schedule (timer, false, interval, interval);
- }
-}
-#endif
int vlc_timer_create (vlc_timer_t *id, void (*func) (void *), void *data)
{
return ENOMEM;
timer->func = func;
timer->data = data;
-#ifndef UNDER_CE
timer->handle = INVALID_HANDLE_VALUE;
-#else
- timer->id = 0;
- timer->interval = 0;
-#endif
*id = timer;
return 0;
}
void vlc_timer_destroy (vlc_timer_t timer)
{
-#ifndef UNDER_CE
if (timer->handle != INVALID_HANDLE_VALUE)
DeleteTimerQueueTimer (NULL, timer->handle, INVALID_HANDLE_VALUE);
-#else
- if (timer->id)
- timeKillEvent (timer->id);
- /* FIXME: timers that have not yet completed will trigger use-after-free */
-#endif
free (timer);
}
void vlc_timer_schedule (vlc_timer_t timer, bool absolute,
mtime_t value, mtime_t interval)
{
-#ifndef UNDER_CE
if (timer->handle != INVALID_HANDLE_VALUE)
{
DeleteTimerQueueTimer (NULL, timer->handle, NULL);
timer->handle = INVALID_HANDLE_VALUE;
}
-#else
- if (timer->id)
- {
- timeKillEvent (timer->id);
- timer->id = 0;
- timer->interval = 0;
- }
-#endif
if (value == 0)
return; /* Disarm */
value = (value + 999) / 1000;
interval = (interval + 999) / 1000;
-#ifndef UNDER_CE
if (!CreateTimerQueueTimer (&timer->handle, NULL, vlc_timer_do, timer,
value, interval, WT_EXECUTEDEFAULT))
-#else
- TIMECAPS caps;
- timeGetDevCaps (&caps, sizeof(caps));
-
- unsigned delay = value;
- delay = __MAX(delay, caps.wPeriodMin);
- delay = __MIN(delay, caps.wPeriodMax);
-
- unsigned event = TIME_ONESHOT;
-
- if (interval == delay)
- event = TIME_PERIODIC;
- else if (interval)
- timer->interval = interval;
-
- timer->id = timeSetEvent (delay, delay / 20, vlc_timer_do, (DWORD) timer,
- event);
- if (!timer->id)
-#endif
abort ();
}
/*** CPU ***/
unsigned vlc_GetCPUCount (void)
{
-#ifndef UNDER_CE
- DWORD process;
- DWORD system;
+ DWORD_PTR process;
+ DWORD_PTR system;
if (GetProcessAffinityMask (GetCurrentProcess(), &process, &system))
return popcount (system);
-#endif
return 1;
}
+
+
+/*** Initialization ***/
+void vlc_threads_setup (libvlc_int_t *p_libvlc)
+{
+ SelectClockSource (VLC_OBJECT(p_libvlc));
+}
+
+extern vlc_rwlock_t config_lock, msg_lock;
+BOOL WINAPI DllMain (HINSTANCE, DWORD, LPVOID);
+
+BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
+{
+ (void) hinstDll;
+ (void) lpvReserved;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ InitializeCriticalSection (&clock_lock);
+ 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);
+ DeleteCriticalSection (&clock_lock);
+ break;
+ }
+ return TRUE;
+}