demux: adaptive: missing es_format_Init
[vlc.git] / src / win32 / thread.c
blob40c294dd5289eed178b88a383261de7438851ebc
1 /*****************************************************************************
2 * thread.c : Win32 back-end for LibVLC
3 *****************************************************************************
4 * Copyright (C) 1999-2016 VLC authors and VideoLAN
6 * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
7 * Samuel Hocevar <sam@zoy.org>
8 * Gildas Bazin <gbazin@netcourrier.com>
9 * Clément Sténac
10 * Rémi Denis-Courmont
11 * Pierre Ynard
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation; either version 2.1 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this program; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <vlc_common.h>
33 #include <vlc_atomic.h>
35 #include "libvlc.h"
36 #include <stdarg.h>
37 #include <assert.h>
38 #include <limits.h>
39 #include <errno.h>
40 #include <time.h>
41 #if !VLC_WINSTORE_APP
42 #include <mmsystem.h>
43 #endif
45 /*** Static mutex and condition variable ***/
46 static CRITICAL_SECTION super_mutex;
47 static CONDITION_VARIABLE super_variable;
49 #define IS_INTERRUPTIBLE (!VLC_WINSTORE_APP || _WIN32_WINNT >= 0x0A00)
51 /*** Threads ***/
52 static DWORD thread_key;
54 struct vlc_thread
56 HANDLE id;
58 bool killable;
59 atomic_bool killed;
60 vlc_cleanup_t *cleaners;
62 void *(*entry) (void *);
63 void *data;
65 struct
67 atomic_int *addr;
68 CRITICAL_SECTION lock;
69 } wait;
72 /*** Condition variables (low-level) ***/
73 #if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
74 static VOID (WINAPI *InitializeConditionVariable_)(PCONDITION_VARIABLE);
75 #define InitializeConditionVariable InitializeConditionVariable_
76 static BOOL (WINAPI *SleepConditionVariableCS_)(PCONDITION_VARIABLE,
77 PCRITICAL_SECTION, DWORD);
78 #define SleepConditionVariableCS SleepConditionVariableCS_
79 static VOID (WINAPI *WakeAllConditionVariable_)(PCONDITION_VARIABLE);
80 #define WakeAllConditionVariable WakeAllConditionVariable_
82 static void WINAPI DummyConditionVariable(CONDITION_VARIABLE *cv)
84 (void) cv;
87 static BOOL WINAPI SleepConditionVariableFallback(CONDITION_VARIABLE *cv,
88 CRITICAL_SECTION *cs,
89 DWORD ms)
91 (void) cv;
92 LeaveCriticalSection(cs);
93 SleepEx(ms > 5 ? 5 : ms, TRUE);
94 EnterCriticalSection(cs);
95 return ms != 0;
97 #endif
99 /*** Mutexes ***/
100 void vlc_mutex_init( vlc_mutex_t *p_mutex )
102 /* This creates a recursive mutex. This is OK as fast mutexes have
103 * no defined behavior in case of recursive locking. */
104 InitializeCriticalSection (&p_mutex->mutex);
105 p_mutex->dynamic = true;
108 void vlc_mutex_init_recursive( vlc_mutex_t *p_mutex )
110 InitializeCriticalSection( &p_mutex->mutex );
111 p_mutex->dynamic = true;
115 void vlc_mutex_destroy (vlc_mutex_t *p_mutex)
117 assert (p_mutex->dynamic);
118 DeleteCriticalSection (&p_mutex->mutex);
121 void vlc_mutex_lock (vlc_mutex_t *p_mutex)
123 if (!p_mutex->dynamic)
124 { /* static mutexes */
125 EnterCriticalSection(&super_mutex);
126 while (p_mutex->locked)
128 p_mutex->contention++;
129 SleepConditionVariableCS(&super_variable, &super_mutex, INFINITE);
130 p_mutex->contention--;
132 p_mutex->locked = true;
133 LeaveCriticalSection(&super_mutex);
134 return;
137 EnterCriticalSection (&p_mutex->mutex);
140 int vlc_mutex_trylock (vlc_mutex_t *p_mutex)
142 if (!p_mutex->dynamic)
143 { /* static mutexes */
144 int ret = EBUSY;
146 EnterCriticalSection(&super_mutex);
147 if (!p_mutex->locked)
149 p_mutex->locked = true;
150 ret = 0;
152 LeaveCriticalSection(&super_mutex);
153 return ret;
156 return TryEnterCriticalSection (&p_mutex->mutex) ? 0 : EBUSY;
159 void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
161 if (!p_mutex->dynamic)
162 { /* static mutexes */
163 EnterCriticalSection(&super_mutex);
164 assert (p_mutex->locked);
165 p_mutex->locked = false;
166 if (p_mutex->contention)
167 WakeAllConditionVariable(&super_variable);
168 LeaveCriticalSection(&super_mutex);
169 return;
172 LeaveCriticalSection (&p_mutex->mutex);
175 /*** Semaphore ***/
176 #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
177 # include <stdalign.h>
179 static inline HANDLE *vlc_sem_handle_p(vlc_sem_t *sem)
181 /* NOTE: vlc_sem_t layout cannot easily depend on Windows version */
182 static_assert (sizeof (HANDLE) <= sizeof (vlc_sem_t), "Size mismatch!");
183 static_assert ((alignof (HANDLE) % alignof (vlc_sem_t)) == 0,
184 "Alignment mismatch");
185 return (HANDLE *)sem;
187 #define vlc_sem_handle(sem) (*vlc_sem_handle_p(sem))
189 void vlc_sem_init (vlc_sem_t *sem, unsigned value)
191 HANDLE handle = CreateSemaphore(NULL, value, 0x7fffffff, NULL);
192 if (handle == NULL)
193 abort ();
195 vlc_sem_handle(sem) = handle;
198 void vlc_sem_destroy (vlc_sem_t *sem)
200 CloseHandle(vlc_sem_handle(sem));
203 int vlc_sem_post (vlc_sem_t *sem)
205 ReleaseSemaphore(vlc_sem_handle(sem), 1, NULL);
206 return 0; /* FIXME */
209 void vlc_sem_wait (vlc_sem_t *sem)
211 HANDLE handle = vlc_sem_handle(sem);
212 DWORD result;
216 vlc_testcancel ();
217 result = WaitForSingleObjectEx(handle, INFINITE, TRUE);
219 /* Semaphore abandoned would be a bug. */
220 assert(result != WAIT_ABANDONED_0);
222 while (result == WAIT_IO_COMPLETION || result == WAIT_FAILED);
224 #endif
226 /*** Thread-specific variables (TLS) ***/
227 struct vlc_threadvar
229 DWORD id;
230 void (*destroy) (void *);
231 struct vlc_threadvar *prev;
232 struct vlc_threadvar *next;
233 } *vlc_threadvar_last = NULL;
235 int vlc_threadvar_create (vlc_threadvar_t *p_tls, void (*destr) (void *))
237 struct vlc_threadvar *var = malloc (sizeof (*var));
238 if (unlikely(var == NULL))
239 return errno;
241 var->id = TlsAlloc();
242 if (var->id == TLS_OUT_OF_INDEXES)
244 free (var);
245 return EAGAIN;
247 var->destroy = destr;
248 var->next = NULL;
249 *p_tls = var;
251 EnterCriticalSection(&super_mutex);
252 var->prev = vlc_threadvar_last;
253 if (var->prev)
254 var->prev->next = var;
256 vlc_threadvar_last = var;
257 LeaveCriticalSection(&super_mutex);
258 return 0;
261 void vlc_threadvar_delete (vlc_threadvar_t *p_tls)
263 struct vlc_threadvar *var = *p_tls;
265 EnterCriticalSection(&super_mutex);
266 if (var->prev != NULL)
267 var->prev->next = var->next;
269 if (var->next != NULL)
270 var->next->prev = var->prev;
271 else
272 vlc_threadvar_last = var->prev;
274 LeaveCriticalSection(&super_mutex);
276 TlsFree (var->id);
277 free (var);
280 int vlc_threadvar_set (vlc_threadvar_t key, void *value)
282 int saved = GetLastError ();
283 int val = TlsSetValue (key->id, value) ? ENOMEM : 0;
285 if (val == 0)
286 SetLastError(saved);
287 return val;
290 void *vlc_threadvar_get (vlc_threadvar_t key)
292 int saved = GetLastError ();
293 void *value = TlsGetValue (key->id);
295 SetLastError(saved);
296 return value;
299 static void vlc_threadvars_cleanup(void)
301 vlc_threadvar_t key;
302 retry:
303 /* TODO: use RW lock or something similar */
304 EnterCriticalSection(&super_mutex);
305 for (key = vlc_threadvar_last; key != NULL; key = key->prev)
307 void *value = vlc_threadvar_get(key);
308 if (value != NULL && key->destroy != NULL)
310 LeaveCriticalSection(&super_mutex);
311 vlc_threadvar_set(key, NULL);
312 key->destroy(value);
313 goto retry;
316 LeaveCriticalSection(&super_mutex);
319 /*** Futeces^WAddress waits ***/
320 #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
321 static BOOL (WINAPI *WaitOnAddress_)(VOID volatile *, PVOID, SIZE_T, DWORD);
322 #define WaitOnAddress (*WaitOnAddress_)
323 static VOID (WINAPI *WakeByAddressAll_)(PVOID);
324 #define WakeByAddressAll (*WakeByAddressAll_)
325 static VOID (WINAPI *WakeByAddressSingle_)(PVOID);
326 #define WakeByAddressSingle (*WakeByAddressSingle_)
328 static struct wait_addr_bucket
330 CRITICAL_SECTION lock;
331 CONDITION_VARIABLE wait;
332 } wait_addr_buckets[32];
334 static struct wait_addr_bucket *wait_addr_get_bucket(void volatile *addr)
336 uintptr_t u = (uintptr_t)addr;
338 return wait_addr_buckets + ((u >> 3) % ARRAY_SIZE(wait_addr_buckets));
341 static void vlc_wait_addr_init(void)
343 for (size_t i = 0; i < ARRAY_SIZE(wait_addr_buckets); i++)
345 struct wait_addr_bucket *bucket = wait_addr_buckets + i;
347 InitializeCriticalSection(&bucket->lock);
348 InitializeConditionVariable(&bucket->wait);
352 static void vlc_wait_addr_deinit(void)
354 for (size_t i = 0; i < ARRAY_SIZE(wait_addr_buckets); i++)
356 struct wait_addr_bucket *bucket = wait_addr_buckets + i;
358 DeleteCriticalSection(&bucket->lock);
362 static BOOL WINAPI WaitOnAddressFallback(void volatile *addr, void *value,
363 SIZE_T size, DWORD ms)
365 struct wait_addr_bucket *bucket = wait_addr_get_bucket(addr);
366 uint64_t futex, val = 0;
367 BOOL ret = 0;
369 EnterCriticalSection(&bucket->lock);
371 switch (size)
373 case 1:
374 futex = atomic_load_explicit((atomic_char *)addr,
375 memory_order_relaxed);
376 val = *(const char *)value;
377 break;
378 case 2:
379 futex = atomic_load_explicit((atomic_short *)addr,
380 memory_order_relaxed);
381 val = *(const short *)value;
382 break;
383 case 4:
384 futex = atomic_load_explicit((atomic_int *)addr,
385 memory_order_relaxed);
386 val = *(const int *)value;
387 break;
388 case 8:
389 futex = atomic_load_explicit((atomic_llong *)addr,
390 memory_order_relaxed);
391 val = *(const long long *)value;
392 break;
393 default:
394 vlc_assert_unreachable();
397 if (futex == val)
398 ret = SleepConditionVariableCS(&bucket->wait, &bucket->lock, ms);
400 LeaveCriticalSection(&bucket->lock);
401 return ret;
404 static void WINAPI WakeByAddressFallback(void *addr)
406 struct wait_addr_bucket *bucket = wait_addr_get_bucket(addr);
408 /* Acquire the bucket critical section (only) to enforce proper sequencing.
409 * The critical section does not protect any actual memory object. */
410 EnterCriticalSection(&bucket->lock);
411 /* No other threads can hold the lock for this bucket while it is held
412 * here. Thus any other thread either:
413 * - is already sleeping in SleepConditionVariableCS(), and to be woken up
414 * by the following WakeAllConditionVariable(), or
415 * - has yet to retrieve the value at the wait address (with the
416 * 'switch (size)' block). */
417 LeaveCriticalSection(&bucket->lock);
418 /* At this point, other threads can retrieve the value at the wait address.
419 * But the value will have already been changed by our call site, thus
420 * (futex == val) will be false, and the threads will not go to sleep. */
422 /* Wake up any thread that was already sleeping. Since there are more than
423 * one wait address per bucket, all threads must be woken up :-/ */
424 WakeAllConditionVariable(&bucket->wait);
426 #endif
428 void vlc_addr_wait(void *addr, unsigned val)
430 WaitOnAddress(addr, &val, sizeof (val), -1);
433 bool vlc_addr_timedwait(void *addr, unsigned val, mtime_t delay)
435 delay = (delay + 999) / 1000;
437 if (delay > 0x7fffffff)
439 WaitOnAddress(addr, &val, sizeof (val), 0x7fffffff);
440 return true; /* woke up early, claim spurious wake-up */
443 return WaitOnAddress(addr, &val, sizeof (val), delay);
446 void vlc_addr_signal(void *addr)
448 WakeByAddressSingle(addr);
451 void vlc_addr_broadcast(void *addr)
453 WakeByAddressAll(addr);
456 /*** Threads ***/
457 static void vlc_thread_destroy(vlc_thread_t th)
459 DeleteCriticalSection(&th->wait.lock);
460 free(th);
463 static unsigned __stdcall vlc_entry (void *p)
465 struct vlc_thread *th = p;
467 TlsSetValue(thread_key, th);
468 th->killable = true;
469 th->data = th->entry (th->data);
470 TlsSetValue(thread_key, NULL);
472 if (th->id == NULL) /* Detached thread */
473 vlc_thread_destroy(th);
474 return 0;
477 static int vlc_clone_attr (vlc_thread_t *p_handle, bool detached,
478 void *(*entry) (void *), void *data, int priority)
480 struct vlc_thread *th = malloc (sizeof (*th));
481 if (unlikely(th == NULL))
482 return ENOMEM;
483 th->entry = entry;
484 th->data = data;
485 th->killable = false; /* not until vlc_entry() ! */
486 atomic_init(&th->killed, false);
487 th->cleaners = NULL;
488 th->wait.addr = NULL;
489 InitializeCriticalSection(&th->wait.lock);
491 /* When using the MSVCRT C library you have to use the _beginthreadex
492 * function instead of CreateThread, otherwise you'll end up with
493 * memory leaks and the signal functions not working (see Microsoft
494 * Knowledge Base, article 104641) */
495 uintptr_t h = _beginthreadex (NULL, 0, vlc_entry, th, 0, NULL);
496 if (h == 0)
498 int err = errno;
499 free (th);
500 return err;
503 if (detached)
505 CloseHandle((HANDLE)h);
506 th->id = NULL;
508 else
509 th->id = (HANDLE)h;
511 if (p_handle != NULL)
512 *p_handle = th;
514 if (priority)
515 SetThreadPriority (th->id, priority);
517 return 0;
520 int vlc_clone (vlc_thread_t *p_handle, void *(*entry) (void *),
521 void *data, int priority)
523 return vlc_clone_attr (p_handle, false, entry, data, priority);
526 void vlc_join (vlc_thread_t th, void **result)
528 DWORD ret;
532 vlc_testcancel ();
533 ret = WaitForSingleObjectEx(th->id, INFINITE, TRUE);
534 assert(ret != WAIT_ABANDONED_0);
536 while (ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED);
538 if (result != NULL)
539 *result = th->data;
540 CloseHandle (th->id);
541 vlc_thread_destroy(th);
544 int vlc_clone_detach (vlc_thread_t *p_handle, void *(*entry) (void *),
545 void *data, int priority)
547 vlc_thread_t th;
548 if (p_handle == NULL)
549 p_handle = &th;
551 return vlc_clone_attr (p_handle, true, entry, data, priority);
554 vlc_thread_t vlc_thread_self (void)
556 return TlsGetValue(thread_key);
559 unsigned long vlc_thread_id (void)
561 return GetCurrentThreadId ();
564 int vlc_set_priority (vlc_thread_t th, int priority)
566 if (!SetThreadPriority (th->id, priority))
567 return VLC_EGENERIC;
568 return VLC_SUCCESS;
571 /*** Thread cancellation ***/
573 #if IS_INTERRUPTIBLE
574 /* APC procedure for thread cancellation */
575 static void CALLBACK vlc_cancel_self (ULONG_PTR self)
577 (void) self;
579 #endif
581 void vlc_cancel (vlc_thread_t th)
583 atomic_store_explicit(&th->killed, true, memory_order_relaxed);
585 EnterCriticalSection(&th->wait.lock);
586 if (th->wait.addr != NULL)
588 atomic_fetch_or_explicit(th->wait.addr, 1, memory_order_relaxed);
589 vlc_addr_broadcast(th->wait.addr);
591 LeaveCriticalSection(&th->wait.lock);
593 #if IS_INTERRUPTIBLE
594 QueueUserAPC (vlc_cancel_self, th->id, (uintptr_t)th);
595 #endif
598 int vlc_savecancel (void)
600 struct vlc_thread *th = vlc_thread_self();
601 if (th == NULL)
602 return false; /* Main thread - cannot be cancelled anyway */
604 int state = th->killable;
605 th->killable = false;
606 return state;
609 void vlc_restorecancel (int state)
611 struct vlc_thread *th = vlc_thread_self();
612 assert (state == false || state == true);
614 if (th == NULL)
615 return; /* Main thread - cannot be cancelled anyway */
617 assert (!th->killable);
618 th->killable = state != 0;
621 void vlc_testcancel (void)
623 struct vlc_thread *th = vlc_thread_self();
624 if (th == NULL)
625 return; /* Main thread - cannot be cancelled anyway */
626 if (!th->killable)
627 return;
628 if (!atomic_load_explicit(&th->killed, memory_order_relaxed))
629 return;
631 th->killable = true; /* Do not re-enter cancellation cleanup */
633 for (vlc_cleanup_t *p = th->cleaners; p != NULL; p = p->next)
634 p->proc (p->data);
636 th->data = NULL; /* TODO: special value? */
637 if (th->id == NULL) /* Detached thread */
638 vlc_thread_destroy(th);
639 _endthreadex(0);
642 void vlc_control_cancel (int cmd, ...)
644 /* NOTE: This function only modifies thread-specific data, so there is no
645 * need to lock anything. */
646 va_list ap;
648 struct vlc_thread *th = vlc_thread_self();
649 if (th == NULL)
650 return; /* Main thread - cannot be cancelled anyway */
652 va_start (ap, cmd);
653 switch (cmd)
655 case VLC_CLEANUP_PUSH:
657 /* cleaner is a pointer to the caller stack, no need to allocate
658 * and copy anything. As a nice side effect, this cannot fail. */
659 vlc_cleanup_t *cleaner = va_arg (ap, vlc_cleanup_t *);
660 cleaner->next = th->cleaners;
661 th->cleaners = cleaner;
662 break;
665 case VLC_CLEANUP_POP:
667 th->cleaners = th->cleaners->next;
668 break;
671 case VLC_CANCEL_ADDR_SET:
673 void *addr = va_arg(ap, void *);
675 EnterCriticalSection(&th->wait.lock);
676 assert(th->wait.addr == NULL);
677 th->wait.addr = addr;
678 LeaveCriticalSection(&th->wait.lock);
679 break;
682 case VLC_CANCEL_ADDR_CLEAR:
684 void *addr = va_arg(ap, void *);
686 EnterCriticalSection(&th->wait.lock);
687 assert(th->wait.addr == addr);
688 th->wait.addr = NULL;
689 LeaveCriticalSection(&th->wait.lock);
690 break;
693 va_end (ap);
696 /*** Clock ***/
697 static union
699 #if (_WIN32_WINNT < _WIN32_WINNT_WIN7)
700 struct
702 BOOL (*query) (PULONGLONG);
703 } interrupt;
704 #endif
705 #if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
706 struct
708 ULONGLONG (*get) (void);
709 } tick;
710 #endif
711 struct
713 LARGE_INTEGER freq;
714 } perf;
715 #if !VLC_WINSTORE_APP
716 struct
718 MMRESULT (WINAPI *timeGetDevCaps)(LPTIMECAPS ptc,UINT cbtc);
719 DWORD (WINAPI *timeGetTime)(void);
720 } multimedia;
721 #endif
722 } clk;
724 static mtime_t mdate_interrupt (void)
726 ULONGLONG ts;
727 BOOL ret;
729 #if (_WIN32_WINNT >= _WIN32_WINNT_WIN7)
730 ret = QueryUnbiasedInterruptTime (&ts);
731 #else
732 ret = clk.interrupt.query (&ts);
733 #endif
734 if (unlikely(!ret))
735 abort ();
737 /* hundreds of nanoseconds */
738 static_assert ((10000000 % CLOCK_FREQ) == 0, "Broken frequencies ratio");
739 return ts / (10000000 / CLOCK_FREQ);
742 static mtime_t mdate_tick (void)
744 #if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
745 ULONGLONG ts = GetTickCount64 ();
746 #else
747 ULONGLONG ts = clk.tick.get ();
748 #endif
750 /* milliseconds */
751 static_assert ((CLOCK_FREQ % 1000) == 0, "Broken frequencies ratio");
752 return ts * (CLOCK_FREQ / 1000);
754 #if !VLC_WINSTORE_APP
755 static mtime_t mdate_multimedia (void)
757 DWORD ts = clk.multimedia.timeGetTime ();
759 /* milliseconds */
760 static_assert ((CLOCK_FREQ % 1000) == 0, "Broken frequencies ratio");
761 return ts * (CLOCK_FREQ / 1000);
763 #endif
765 static mtime_t mdate_perf (void)
767 /* We don't need the real date, just the value of a high precision timer */
768 LARGE_INTEGER counter;
769 if (!QueryPerformanceCounter (&counter))
770 abort ();
772 /* Convert to from (1/freq) to microsecond resolution */
773 /* We need to split the division to avoid 63-bits overflow */
774 lldiv_t d = lldiv (counter.QuadPart, clk.perf.freq.QuadPart);
776 return (d.quot * 1000000) + ((d.rem * 1000000) / clk.perf.freq.QuadPart);
779 static mtime_t mdate_wall (void)
781 FILETIME ts;
782 ULARGE_INTEGER s;
784 #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) && !VLC_WINSTORE_APP
785 GetSystemTimePreciseAsFileTime (&ts);
786 #else
787 GetSystemTimeAsFileTime (&ts);
788 #endif
789 s.LowPart = ts.dwLowDateTime;
790 s.HighPart = ts.dwHighDateTime;
791 /* hundreds of nanoseconds */
792 static_assert ((10000000 % CLOCK_FREQ) == 0, "Broken frequencies ratio");
793 return s.QuadPart / (10000000 / CLOCK_FREQ);
796 static mtime_t mdate_default(void)
798 vlc_threads_setup(NULL);
799 return mdate_perf();
802 static mtime_t (*mdate_selected) (void) = mdate_default;
804 mtime_t mdate (void)
806 return mdate_selected ();
809 #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
810 void (mwait)(mtime_t deadline)
812 mtime_t delay;
814 vlc_testcancel();
815 while ((delay = (deadline - mdate())) > 0)
817 delay = (delay + 999) / 1000;
818 if (unlikely(delay > 0x7fffffff))
819 delay = 0x7fffffff;
821 SleepEx(delay, TRUE);
822 vlc_testcancel();
826 void (msleep)(mtime_t delay)
828 mwait (mdate () + delay);
830 #endif
832 static BOOL SelectClockSource(void *data)
834 vlc_object_t *obj = data;
836 #if VLC_WINSTORE_APP
837 const char *name = "perf";
838 #else
839 const char *name = "multimedia";
840 #endif
841 char *str = NULL;
842 if (obj != NULL)
843 str = var_InheritString(obj, "clock-source");
844 if (str != NULL)
845 name = str;
846 if (!strcmp (name, "interrupt"))
848 msg_Dbg (obj, "using interrupt time as clock source");
849 #if (_WIN32_WINNT < _WIN32_WINNT_WIN7)
850 HANDLE h = GetModuleHandle (_T("kernel32.dll"));
851 if (unlikely(h == NULL))
852 return FALSE;
853 clk.interrupt.query = (void *)GetProcAddress (h,
854 "QueryUnbiasedInterruptTime");
855 if (unlikely(clk.interrupt.query == NULL))
856 abort ();
857 #endif
858 mdate_selected = mdate_interrupt;
860 else
861 if (!strcmp (name, "tick"))
863 msg_Dbg (obj, "using Windows time as clock source");
864 #if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
865 HANDLE h = GetModuleHandle (_T("kernel32.dll"));
866 if (unlikely(h == NULL))
867 return FALSE;
868 clk.tick.get = (void *)GetProcAddress (h, "GetTickCount64");
869 if (unlikely(clk.tick.get == NULL))
870 return FALSE;
871 #endif
872 mdate_selected = mdate_tick;
874 #if !VLC_WINSTORE_APP
875 else
876 if (!strcmp (name, "multimedia"))
878 TIMECAPS caps;
879 MMRESULT (WINAPI * timeBeginPeriod)(UINT);
881 HMODULE hWinmm = LoadLibrary(TEXT("winmm.dll"));
882 if (!hWinmm)
883 goto perf;
885 clk.multimedia.timeGetDevCaps = (void*)GetProcAddress(hWinmm, "timeGetDevCaps");
886 clk.multimedia.timeGetTime = (void*)GetProcAddress(hWinmm, "timeGetTime");
887 if (!clk.multimedia.timeGetDevCaps || !clk.multimedia.timeGetTime)
888 goto perf;
890 msg_Dbg (obj, "using multimedia timers as clock source");
891 if (clk.multimedia.timeGetDevCaps (&caps, sizeof (caps)) != MMSYSERR_NOERROR)
892 goto perf;
893 msg_Dbg (obj, " min period: %u ms, max period: %u ms",
894 caps.wPeriodMin, caps.wPeriodMax);
895 mdate_selected = mdate_multimedia;
897 timeBeginPeriod = (void*)GetProcAddress(hWinmm, "timeBeginPeriod");
898 if (timeBeginPeriod != NULL)
899 timeBeginPeriod(5);
901 #endif
902 else
903 if (!strcmp (name, "perf"))
905 perf:
906 msg_Dbg (obj, "using performance counters as clock source");
907 if (!QueryPerformanceFrequency (&clk.perf.freq))
908 abort ();
909 msg_Dbg (obj, " frequency: %llu Hz", clk.perf.freq.QuadPart);
910 mdate_selected = mdate_perf;
912 else
913 if (!strcmp (name, "wall"))
915 msg_Dbg (obj, "using system time as clock source");
916 mdate_selected = mdate_wall;
918 else
920 msg_Err (obj, "invalid clock source \"%s\"", name);
921 abort ();
923 free (str);
924 return TRUE;
927 size_t EnumClockSource (vlc_object_t *obj, const char *var,
928 char ***vp, char ***np)
930 const size_t max = 6;
931 char **values = xmalloc (sizeof (*values) * max);
932 char **names = xmalloc (sizeof (*names) * max);
933 size_t n = 0;
935 #if (_WIN32_WINNT < _WIN32_WINNT_WIN7)
936 DWORD version = LOWORD(GetVersion());
937 version = (LOBYTE(version) << 8) | (HIBYTE(version) << 0);
938 #endif
940 values[n] = xstrdup ("");
941 names[n] = xstrdup (_("Auto"));
942 n++;
943 #if (_WIN32_WINNT < _WIN32_WINNT_WIN7)
944 if (version >= 0x0601)
945 #endif
947 values[n] = xstrdup ("interrupt");
948 names[n] = xstrdup ("Interrupt time");
949 n++;
951 #if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
952 if (version >= 0x0600)
953 #endif
955 values[n] = xstrdup ("tick");
956 names[n] = xstrdup ("Windows time");
957 n++;
959 #if !VLC_WINSTORE_APP
960 values[n] = xstrdup ("multimedia");
961 names[n] = xstrdup ("Multimedia timers");
962 n++;
963 #endif
964 values[n] = xstrdup ("perf");
965 names[n] = xstrdup ("Performance counters");
966 n++;
967 values[n] = xstrdup ("wall");
968 names[n] = xstrdup ("System time (DANGEROUS!)");
969 n++;
971 *vp = values;
972 *np = names;
973 (void) obj; (void) var;
974 return n;
978 /*** CPU ***/
979 unsigned vlc_GetCPUCount (void)
981 SYSTEM_INFO systemInfo;
983 GetNativeSystemInfo(&systemInfo);
985 return systemInfo.dwNumberOfProcessors;
989 /*** Initialization ***/
990 static CRITICAL_SECTION setup_lock; /* FIXME: use INIT_ONCE */
992 void vlc_threads_setup(libvlc_int_t *vlc)
994 EnterCriticalSection(&setup_lock);
995 if (mdate_selected != mdate_default)
997 LeaveCriticalSection(&setup_lock);
998 return;
1001 if (!SelectClockSource((vlc != NULL) ? VLC_OBJECT(vlc) : NULL))
1002 abort();
1003 assert(mdate_selected != mdate_default);
1005 #if !VLC_WINSTORE_APP
1006 /* Raise default priority of the current process */
1007 #ifndef ABOVE_NORMAL_PRIORITY_CLASS
1008 # define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
1009 #endif
1010 if (var_InheritBool(vlc, "high-priority"))
1012 if (SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS)
1013 || SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
1014 msg_Dbg(vlc, "raised process priority");
1015 else
1016 msg_Dbg(vlc, "could not raise process priority");
1018 #endif
1019 LeaveCriticalSection(&setup_lock);
1022 #define LOOKUP(s) (((s##_) = (void *)GetProcAddress(h, #s)) != NULL)
1024 extern vlc_rwlock_t config_lock;
1025 BOOL WINAPI DllMain (HINSTANCE, DWORD, LPVOID);
1027 BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
1029 (void) hinstDll;
1030 (void) lpvReserved;
1032 switch (fdwReason)
1034 case DLL_PROCESS_ATTACH:
1036 #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
1037 HANDLE h = GetModuleHandle(TEXT("kernel32.dll"));
1038 if (unlikely(h == NULL))
1039 return FALSE;
1041 if (!LOOKUP(WaitOnAddress)
1042 || !LOOKUP(WakeByAddressAll) || !LOOKUP(WakeByAddressSingle))
1044 # if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
1045 if (!LOOKUP(InitializeConditionVariable)
1046 || !LOOKUP(SleepConditionVariableCS)
1047 || !LOOKUP(WakeAllConditionVariable))
1049 InitializeConditionVariable_ = DummyConditionVariable;
1050 SleepConditionVariableCS_ = SleepConditionVariableFallback;
1051 WakeAllConditionVariable_ = DummyConditionVariable;
1053 # endif
1054 vlc_wait_addr_init();
1055 WaitOnAddress_ = WaitOnAddressFallback;
1056 WakeByAddressAll_ = WakeByAddressFallback;
1057 WakeByAddressSingle_ = WakeByAddressFallback;
1059 #endif
1060 thread_key = TlsAlloc();
1061 if (unlikely(thread_key == TLS_OUT_OF_INDEXES))
1062 return FALSE;
1063 InitializeCriticalSection(&setup_lock);
1064 InitializeCriticalSection(&super_mutex);
1065 InitializeConditionVariable(&super_variable);
1066 vlc_rwlock_init (&config_lock);
1067 vlc_CPU_init ();
1068 break;
1071 case DLL_PROCESS_DETACH:
1072 vlc_rwlock_destroy (&config_lock);
1073 DeleteCriticalSection(&super_mutex);
1074 DeleteCriticalSection(&setup_lock);
1075 TlsFree(thread_key);
1076 #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
1077 if (WaitOnAddress_ == WaitOnAddressFallback)
1078 vlc_wait_addr_deinit();
1079 #endif
1080 break;
1082 case DLL_THREAD_DETACH:
1083 vlc_threadvars_cleanup();
1084 break;
1086 return TRUE;