X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fwin32%2Fthread.c;h=848c5a3c68c0ee31d22998748e5737594c126fae;hb=fba184a0ca0b28376a22f6daf5dac96b50f8e669;hp=96cd777116ba7247f8d0518fadc0c8db5a19b0dc;hpb=588ce05760940696ab64acf1ba52fd5871e8bc64;p=vlc diff --git a/src/win32/thread.c b/src/win32/thread.c index 96cd777116..848c5a3c68 100644 --- a/src/win32/thread.c +++ b/src/win32/thread.c @@ -1,7 +1,7 @@ /***************************************************************************** * 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 * Samuel Hocevar @@ -10,19 +10,19 @@ * 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 @@ -36,135 +36,46 @@ #include #include #include -#ifdef UNDER_CE -# include -#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; -}; +/*** Static mutex and condition variable ***/ +static vlc_mutex_t super_mutex; +static vlc_cond_t super_variable; -#ifdef UNDER_CE -static void CALLBACK vlc_cancel_self (ULONG_PTR dummy); -static DWORD vlc_cancelable_wait (DWORD count, const HANDLE *handles, - DWORD delay) +/*** Common helpers ***/ +static DWORD vlc_WaitForMultipleObjects (DWORD count, const HANDLE *handles, + DWORD delay) { - struct vlc_thread *th = vlc_threadvar_get (thread_key); - if (th == NULL) + DWORD ret; + if (count == 0) { - /* 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] = th->cancel_event; - DWORD result = WaitForMultipleObjects (count + 1, new_handles, FALSE, - delay); - if (result == WAIT_OBJECT_0 + count) - { - vlc_cancel_self ((uintptr_t)th); - return WAIT_IO_COMPLETION; + ret = SleepEx (delay, TRUE); + if (ret == 0) + ret = WAIT_TIMEOUT; } else - { - return result; - } -} + ret = WaitForMultipleObjectsEx (count, handles, FALSE, delay, TRUE); -DWORD SleepEx (DWORD dwMilliseconds, BOOL bAlertable) -{ - if (bAlertable) - { - DWORD result = vlc_cancelable_wait (0, NULL, dwMilliseconds); - return (result == WAIT_TIMEOUT) ? 0 : WAIT_IO_COMPLETION; - } - else - { - Sleep(dwMilliseconds); - return 0; - } -} + /* We do not abandon objects... this would be a bug */ + assert (ret < WAIT_ABANDONED_0 || WAIT_ABANDONED_0 + count - 1 < ret); -DWORD WaitForSingleObjectEx (HANDLE hHandle, DWORD dwMilliseconds, - BOOL bAlertable) -{ - if (bAlertable) - { - /* 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); - } - else - { - return WaitForSingleObject (hHandle, dwMilliseconds); - } + if (unlikely(ret == WAIT_FAILED)) + abort (); /* We are screwed! */ + return ret; } -DWORD WaitForMultipleObjectsEx (DWORD nCount, const HANDLE *lpHandles, - BOOL bWaitAll, DWORD dwMilliseconds, - BOOL bAlertable) +static DWORD vlc_WaitForSingleObject (HANDLE handle, DWORD delay) { - if (bAlertable) - { - /* We do not support the bWaitAll case */ - assert (! bWaitAll); - return vlc_cancelable_wait (nCount, lpHandles, dwMilliseconds); - } - else - { - return WaitForMultipleObjects (nCount, lpHandles, bWaitAll, - dwMilliseconds); - } + return vlc_WaitForMultipleObjects (1, &handle, delay); } -#endif - -vlc_mutex_t super_mutex; -vlc_cond_t super_variable; -BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved) +static DWORD vlc_Sleep (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 (&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; + DWORD ret = vlc_WaitForMultipleObjects (0, NULL, delay); + return (ret != WAIT_TIMEOUT) ? ret : 0; } + /*** Mutexes ***/ void vlc_mutex_init( vlc_mutex_t *p_mutex ) { @@ -251,6 +162,7 @@ void vlc_mutex_unlock (vlc_mutex_t *p_mutex) /*** Condition variables ***/ enum { + CLOCK_STATIC=0, /* must be zero for VLC_STATIC_COND */ CLOCK_MONOTONIC, CLOCK_REALTIME, }; @@ -281,16 +193,19 @@ void vlc_cond_destroy (vlc_cond_t *p_condvar) 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); } @@ -298,18 +213,21 @@ void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex) { DWORD result; - assert (p_mutex->dynamic); /* TODO */ + if (!p_condvar->clock) + { /* 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); } @@ -318,7 +236,6 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex, { DWORD result; - assert (p_mutex->dynamic); /* TODO */ do { vlc_testcancel (); @@ -333,21 +250,22 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex, total = CLOCK_FREQ * time (NULL); break; default: - assert (0); + 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); - 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; @@ -379,83 +297,36 @@ void vlc_sem_wait (vlc_sem_t *sem) do { vlc_testcancel (); - result = WaitForSingleObjectEx (*sem, INFINITE, TRUE); + result = vlc_WaitForSingleObject (*sem, INFINITE); } 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 or active 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_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); - while (lock->writer != 0) - vlc_cond_wait (&lock->read_wait, &lock->mutex); - if (lock->readers == ULONG_MAX) - abort (); - lock->readers++; - vlc_mutex_unlock (&lock->mutex); } -/** - * Acquires a read/write lock for writing. Recursion is not allowed. - */ void vlc_rwlock_wrlock (vlc_rwlock_t *lock) { - vlc_mutex_lock (&lock->mutex); - if (lock->writers == ULONG_MAX) - abort (); - lock->writers++; - while ((lock->readers > 0) || (lock->writer != 0)) - vlc_cond_wait (&lock->write_wait, &lock->mutex); - lock->writers--; - lock->writer = GetCurrentThreadId (); - vlc_mutex_unlock (&lock->mutex); } -/** - * Releases a read/write lock. - */ void vlc_rwlock_unlock (vlc_rwlock_t *lock) { - vlc_mutex_lock (&lock->mutex); - if (lock->readers > 0) - lock->readers--; /* Read unlock */ - else - 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); - vlc_mutex_unlock (&lock->mutex); } +#else +# include "misc/rwlock.h" +#endif /*** Thread-specific variables (TLS) ***/ struct vlc_threadvar @@ -484,6 +355,9 @@ int vlc_threadvar_create (vlc_threadvar_t *p_tls, void (*destr) (void *)) 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; @@ -496,10 +370,12 @@ void vlc_threadvar_delete (vlc_threadvar_t *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; + else + vlc_threadvar_last = var->prev; + vlc_mutex_unlock (&super_mutex); TlsFree (var->id); @@ -517,10 +393,21 @@ void *vlc_threadvar_get (vlc_threadvar_t key) } /*** 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) { @@ -545,9 +432,6 @@ retry: if (th->detached) { CloseHandle (th->id); -#ifdef UNDER_CE - CloseHandle (th->cancel_event); -#endif free (th); } } @@ -577,71 +461,49 @@ static int vlc_clone_attr (vlc_thread_t *p_handle, bool detached, 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, th, CREATE_SUSPENDED, NULL); - if (hThread == NULL) + uintptr_t h; + + h = _beginthreadex (NULL, 0, vlc_entry, th, CREATE_SUSPENDED, NULL); + if (h == 0) { int err = errno; free (th); return err; } + 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) *p_handle = th; - ResumeThread (hThread); if (priority) SetThreadPriority (hThread, priority); + ResumeThread (hThread); + return 0; } int vlc_clone (vlc_thread_t *p_handle, void *(*entry) (void *), void *data, int priority) { - return vlc_clone_attr (p_handle, false, entry, data, prioity); + return vlc_clone_attr (p_handle, false, entry, data, priority); } void vlc_join (vlc_thread_t th, void **result) { 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); } @@ -655,6 +517,13 @@ int vlc_clone_detach (vlc_thread_t *p_handle, void *(*entry) (void *), 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 */ @@ -668,11 +537,7 @@ static void CALLBACK vlc_cancel_self (ULONG_PTR self) 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) @@ -711,11 +576,7 @@ void vlc_testcancel (void) th->data = NULL; /* TODO: special value? */ vlc_thread_cleanup (th); -#ifndef UNDER_CE _endthreadex(0); -#else - ExitThread(0); -#endif } } @@ -751,49 +612,277 @@ void vlc_control_cancel (int cmd, ...) va_end (ap); } +/*** Clock ***/ +static CRITICAL_SECTION clock_lock; -/*** Timers ***/ -struct vlc_timer +static mtime_t mdate_giveup (void) { -#ifndef UNDER_CE - HANDLE handle; + 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 - unsigned id; - unsigned interval; + ret = clk.interrupt.query (&ts); #endif - void (*func) (void *); - void *data; -}; + if (unlikely(!ret)) + abort (); -#ifndef UNDER_CE -static void CALLBACK vlc_timer_do (void *val, BOOLEAN timeout) + /* hundreds of nanoseconds */ + static_assert ((10000000 % CLOCK_FREQ) == 0, "Broken frequencies ratio"); + return ts / (10000000 / CLOCK_FREQ); +} + +static mtime_t mdate_tick (void) { - struct vlc_timer *timer = val; +#if (_WIN32_WINNT >= 0x0600) + ULONGLONG ts = GetTickCount64 (); +#else + ULONGLONG ts = clk.tick.get (); +#endif - assert (timeout); - timer->func (timer->data); + /* milliseconds */ + static_assert ((CLOCK_FREQ % 1000) == 0, "Broken frequencies ratio"); + return ts * (CLOCK_FREQ / 1000); } +#include +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; + 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, clk.perf.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 -static void CALLBACK vlc_timer_do (unsigned timer_id, unsigned msg, - DWORD_PTR user, DWORD_PTR unused1, - DWORD_PTR unused2) + 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 +void mwait (mtime_t deadline) { - struct vlc_timer *timer = (struct vlc_timer *) user; - assert (timer_id == timer->id); - (void) msg; - (void) unused1; - (void) unused2; + mtime_t delay; - timer->func (timer->data); + 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); +} + +static void SelectClockSource (vlc_object_t *obj) +{ + EnterCriticalSection (&clock_lock); + if (mdate_selected != mdate_giveup) + { + LeaveCriticalSection (&clock_lock); + return; + } - if (timer->interval) + const char *name = "perf"; + char *str = var_InheritString (obj, "clock-source"); + if (str != NULL) + name = str; + if (!strcmp (name, "interrupt")) { - mtime_t interval = timer->interval * 1000; - vlc_timer_schedule (timer, false, interval, interval); + 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 +{ + HANDLE handle; + void (*func) (void *); + void *data; +}; + +static void CALLBACK vlc_timer_do (void *val, BOOLEAN timeout) +{ + struct vlc_timer *timer = val; + + assert (timeout); + timer->func (timer->data); +} + int vlc_timer_create (vlc_timer_t *id, void (*func) (void *), void *data) { struct vlc_timer *timer = malloc (sizeof (*timer)); @@ -802,46 +891,26 @@ 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 */ @@ -850,28 +919,8 @@ void vlc_timer_schedule (vlc_timer_t timer, bool absolute, 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 (); } @@ -880,3 +929,54 @@ unsigned vlc_timer_getoverrun (vlc_timer_t timer) (void)timer; return 0; } + + +/*** CPU ***/ +unsigned vlc_GetCPUCount (void) +{ + DWORD_PTR process; + DWORD_PTR system; + + if (GetProcessAffinityMask (GetCurrentProcess(), &process, &system)) + return popcount (system); + 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; +}