chromecast: Hide some private variable from settings
[vlc.git] / src / win32 / thread.c
blobcf3c13eb496c62c06ddc1806aa138cfd3af689b7
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>
34 #include "libvlc.h"
35 #include <stdarg.h>
36 #include <stdatomic.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 /*** Mutexes ***/
73 void vlc_mutex_init( vlc_mutex_t *p_mutex )
75 /* This creates a recursive mutex. This is OK as fast mutexes have
76 * no defined behavior in case of recursive locking. */
77 InitializeCriticalSection (&p_mutex->mutex);
78 p_mutex->dynamic = true;
81 void vlc_mutex_init_recursive( vlc_mutex_t *p_mutex )
83 InitializeCriticalSection( &p_mutex->mutex );
84 p_mutex->dynamic = true;
88 void vlc_mutex_destroy (vlc_mutex_t *p_mutex)
90 assert (p_mutex->dynamic);
91 DeleteCriticalSection (&p_mutex->mutex);
94 void vlc_mutex_lock (vlc_mutex_t *p_mutex)
96 if (!p_mutex->dynamic)
97 { /* static mutexes */
98 EnterCriticalSection(&super_mutex);
99 while (p_mutex->locked)
101 p_mutex->contention++;
102 SleepConditionVariableCS(&super_variable, &super_mutex, INFINITE);
103 p_mutex->contention--;
105 p_mutex->locked = true;
106 LeaveCriticalSection(&super_mutex);
107 return;
110 EnterCriticalSection (&p_mutex->mutex);
113 int vlc_mutex_trylock (vlc_mutex_t *p_mutex)
115 if (!p_mutex->dynamic)
116 { /* static mutexes */
117 int ret = EBUSY;
119 EnterCriticalSection(&super_mutex);
120 if (!p_mutex->locked)
122 p_mutex->locked = true;
123 ret = 0;
125 LeaveCriticalSection(&super_mutex);
126 return ret;
129 return TryEnterCriticalSection (&p_mutex->mutex) ? 0 : EBUSY;
132 void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
134 if (!p_mutex->dynamic)
135 { /* static mutexes */
136 EnterCriticalSection(&super_mutex);
137 assert (p_mutex->locked);
138 p_mutex->locked = false;
139 if (p_mutex->contention)
140 WakeAllConditionVariable(&super_variable);
141 LeaveCriticalSection(&super_mutex);
142 return;
145 LeaveCriticalSection (&p_mutex->mutex);
148 /*** Semaphore ***/
149 #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
150 # include <stdalign.h>
152 static inline HANDLE *vlc_sem_handle_p(vlc_sem_t *sem)
154 /* NOTE: vlc_sem_t layout cannot easily depend on Windows version */
155 static_assert (sizeof (HANDLE) <= sizeof (vlc_sem_t), "Size mismatch!");
156 static_assert ((alignof (HANDLE) % alignof (vlc_sem_t)) == 0,
157 "Alignment mismatch");
158 return (HANDLE *)sem;
160 #define vlc_sem_handle(sem) (*vlc_sem_handle_p(sem))
162 void vlc_sem_init (vlc_sem_t *sem, unsigned value)
164 HANDLE handle = CreateSemaphore(NULL, value, 0x7fffffff, NULL);
165 if (handle == NULL)
166 abort ();
168 vlc_sem_handle(sem) = handle;
171 void vlc_sem_destroy (vlc_sem_t *sem)
173 CloseHandle(vlc_sem_handle(sem));
176 int vlc_sem_post (vlc_sem_t *sem)
178 ReleaseSemaphore(vlc_sem_handle(sem), 1, NULL);
179 return 0; /* FIXME */
182 void vlc_sem_wait (vlc_sem_t *sem)
184 HANDLE handle = vlc_sem_handle(sem);
185 DWORD result;
189 vlc_testcancel ();
190 result = WaitForSingleObjectEx(handle, INFINITE, TRUE);
192 /* Semaphore abandoned would be a bug. */
193 assert(result != WAIT_ABANDONED_0);
195 while (result == WAIT_IO_COMPLETION || result == WAIT_FAILED);
197 #endif
199 /*** Thread-specific variables (TLS) ***/
200 struct vlc_threadvar
202 DWORD id;
203 void (*destroy) (void *);
204 struct vlc_threadvar *prev;
205 struct vlc_threadvar *next;
206 } *vlc_threadvar_last = NULL;
208 int vlc_threadvar_create (vlc_threadvar_t *p_tls, void (*destr) (void *))
210 struct vlc_threadvar *var = malloc (sizeof (*var));
211 if (unlikely(var == NULL))
212 return errno;
214 var->id = TlsAlloc();
215 if (var->id == TLS_OUT_OF_INDEXES)
217 free (var);
218 return EAGAIN;
220 var->destroy = destr;
221 var->next = NULL;
222 *p_tls = var;
224 EnterCriticalSection(&super_mutex);
225 var->prev = vlc_threadvar_last;
226 if (var->prev)
227 var->prev->next = var;
229 vlc_threadvar_last = var;
230 LeaveCriticalSection(&super_mutex);
231 return 0;
234 void vlc_threadvar_delete (vlc_threadvar_t *p_tls)
236 struct vlc_threadvar *var = *p_tls;
238 EnterCriticalSection(&super_mutex);
239 if (var->prev != NULL)
240 var->prev->next = var->next;
242 if (var->next != NULL)
243 var->next->prev = var->prev;
244 else
245 vlc_threadvar_last = var->prev;
247 LeaveCriticalSection(&super_mutex);
249 TlsFree (var->id);
250 free (var);
253 int vlc_threadvar_set (vlc_threadvar_t key, void *value)
255 int saved = GetLastError ();
257 if (!TlsSetValue(key->id, value))
258 return ENOMEM;
260 SetLastError(saved);
261 return 0;
264 void *vlc_threadvar_get (vlc_threadvar_t key)
266 int saved = GetLastError ();
267 void *value = TlsGetValue (key->id);
269 SetLastError(saved);
270 return value;
273 static void vlc_threadvars_cleanup(void)
275 vlc_threadvar_t key;
276 retry:
277 /* TODO: use RW lock or something similar */
278 EnterCriticalSection(&super_mutex);
279 for (key = vlc_threadvar_last; key != NULL; key = key->prev)
281 void *value = vlc_threadvar_get(key);
282 if (value != NULL && key->destroy != NULL)
284 LeaveCriticalSection(&super_mutex);
285 vlc_threadvar_set(key, NULL);
286 key->destroy(value);
287 goto retry;
290 LeaveCriticalSection(&super_mutex);
293 /*** Futeces^WAddress waits ***/
294 #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
295 static BOOL (WINAPI *WaitOnAddress_)(VOID volatile *, PVOID, SIZE_T, DWORD);
296 #define WaitOnAddress (*WaitOnAddress_)
297 static VOID (WINAPI *WakeByAddressAll_)(PVOID);
298 #define WakeByAddressAll (*WakeByAddressAll_)
299 static VOID (WINAPI *WakeByAddressSingle_)(PVOID);
300 #define WakeByAddressSingle (*WakeByAddressSingle_)
302 static struct wait_addr_bucket
304 CRITICAL_SECTION lock;
305 CONDITION_VARIABLE wait;
306 } wait_addr_buckets[32];
308 static struct wait_addr_bucket *wait_addr_get_bucket(void volatile *addr)
310 uintptr_t u = (uintptr_t)addr;
312 return wait_addr_buckets + ((u >> 3) % ARRAY_SIZE(wait_addr_buckets));
315 static void vlc_wait_addr_init(void)
317 for (size_t i = 0; i < ARRAY_SIZE(wait_addr_buckets); i++)
319 struct wait_addr_bucket *bucket = wait_addr_buckets + i;
321 InitializeCriticalSection(&bucket->lock);
322 InitializeConditionVariable(&bucket->wait);
326 static void vlc_wait_addr_deinit(void)
328 for (size_t i = 0; i < ARRAY_SIZE(wait_addr_buckets); i++)
330 struct wait_addr_bucket *bucket = wait_addr_buckets + i;
332 DeleteCriticalSection(&bucket->lock);
336 static BOOL WINAPI WaitOnAddressFallback(void volatile *addr, void *value,
337 SIZE_T size, DWORD ms)
339 struct wait_addr_bucket *bucket = wait_addr_get_bucket(addr);
340 uint64_t futex, val = 0;
341 BOOL ret = 0;
343 EnterCriticalSection(&bucket->lock);
345 switch (size)
347 case 1:
348 futex = atomic_load_explicit((atomic_char *)addr,
349 memory_order_relaxed);
350 val = *(const char *)value;
351 break;
352 case 2:
353 futex = atomic_load_explicit((atomic_short *)addr,
354 memory_order_relaxed);
355 val = *(const short *)value;
356 break;
357 case 4:
358 futex = atomic_load_explicit((atomic_int *)addr,
359 memory_order_relaxed);
360 val = *(const int *)value;
361 break;
362 case 8:
363 futex = atomic_load_explicit((atomic_llong *)addr,
364 memory_order_relaxed);
365 val = *(const long long *)value;
366 break;
367 default:
368 vlc_assert_unreachable();
371 if (futex == val)
372 ret = SleepConditionVariableCS(&bucket->wait, &bucket->lock, ms);
374 LeaveCriticalSection(&bucket->lock);
375 return ret;
378 static void WINAPI WakeByAddressFallback(void *addr)
380 struct wait_addr_bucket *bucket = wait_addr_get_bucket(addr);
382 /* Acquire the bucket critical section (only) to enforce proper sequencing.
383 * The critical section does not protect any actual memory object. */
384 EnterCriticalSection(&bucket->lock);
385 /* No other threads can hold the lock for this bucket while it is held
386 * here. Thus any other thread either:
387 * - is already sleeping in SleepConditionVariableCS(), and to be woken up
388 * by the following WakeAllConditionVariable(), or
389 * - has yet to retrieve the value at the wait address (with the
390 * 'switch (size)' block). */
391 LeaveCriticalSection(&bucket->lock);
392 /* At this point, other threads can retrieve the value at the wait address.
393 * But the value will have already been changed by our call site, thus
394 * (futex == val) will be false, and the threads will not go to sleep. */
396 /* Wake up any thread that was already sleeping. Since there are more than
397 * one wait address per bucket, all threads must be woken up :-/ */
398 WakeAllConditionVariable(&bucket->wait);
400 #endif
402 void vlc_addr_wait(void *addr, unsigned val)
404 WaitOnAddress(addr, &val, sizeof (val), -1);
407 bool vlc_addr_timedwait(void *addr, unsigned val, mtime_t delay)
409 delay = (delay + 999) / 1000;
411 if (delay > 0x7fffffff)
413 WaitOnAddress(addr, &val, sizeof (val), 0x7fffffff);
414 return true; /* woke up early, claim spurious wake-up */
417 return WaitOnAddress(addr, &val, sizeof (val), delay);
420 void vlc_addr_signal(void *addr)
422 WakeByAddressSingle(addr);
425 void vlc_addr_broadcast(void *addr)
427 WakeByAddressAll(addr);
430 /*** Threads ***/
431 static void vlc_thread_destroy(vlc_thread_t th)
433 DeleteCriticalSection(&th->wait.lock);
434 free(th);
437 static unsigned __stdcall vlc_entry (void *p)
439 struct vlc_thread *th = p;
441 TlsSetValue(thread_key, th);
442 th->killable = true;
443 th->data = th->entry (th->data);
444 TlsSetValue(thread_key, NULL);
446 if (th->id == NULL) /* Detached thread */
447 vlc_thread_destroy(th);
448 return 0;
451 static int vlc_clone_attr (vlc_thread_t *p_handle, bool detached,
452 void *(*entry) (void *), void *data, int priority)
454 struct vlc_thread *th = malloc (sizeof (*th));
455 if (unlikely(th == NULL))
456 return ENOMEM;
457 th->entry = entry;
458 th->data = data;
459 th->killable = false; /* not until vlc_entry() ! */
460 atomic_init(&th->killed, false);
461 th->cleaners = NULL;
462 th->wait.addr = NULL;
463 InitializeCriticalSection(&th->wait.lock);
465 /* When using the MSVCRT C library you have to use the _beginthreadex
466 * function instead of CreateThread, otherwise you'll end up with
467 * memory leaks and the signal functions not working (see Microsoft
468 * Knowledge Base, article 104641) */
469 uintptr_t h = _beginthreadex (NULL, 0, vlc_entry, th, 0, NULL);
470 if (h == 0)
472 int err = errno;
473 free (th);
474 return err;
477 if (detached)
479 CloseHandle((HANDLE)h);
480 th->id = NULL;
482 else
483 th->id = (HANDLE)h;
485 if (p_handle != NULL)
486 *p_handle = th;
488 if (priority)
489 SetThreadPriority (th->id, priority);
491 return 0;
494 int vlc_clone (vlc_thread_t *p_handle, void *(*entry) (void *),
495 void *data, int priority)
497 return vlc_clone_attr (p_handle, false, entry, data, priority);
500 void vlc_join (vlc_thread_t th, void **result)
502 DWORD ret;
506 vlc_testcancel ();
507 ret = WaitForSingleObjectEx(th->id, INFINITE, TRUE);
508 assert(ret != WAIT_ABANDONED_0);
510 while (ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED);
512 if (result != NULL)
513 *result = th->data;
514 CloseHandle (th->id);
515 vlc_thread_destroy(th);
518 int vlc_clone_detach (vlc_thread_t *p_handle, void *(*entry) (void *),
519 void *data, int priority)
521 vlc_thread_t th;
522 if (p_handle == NULL)
523 p_handle = &th;
525 return vlc_clone_attr (p_handle, true, entry, data, priority);
528 vlc_thread_t vlc_thread_self (void)
530 return TlsGetValue(thread_key);
533 unsigned long vlc_thread_id (void)
535 return GetCurrentThreadId ();
538 int vlc_set_priority (vlc_thread_t th, int priority)
540 if (!SetThreadPriority (th->id, priority))
541 return VLC_EGENERIC;
542 return VLC_SUCCESS;
545 /*** Thread cancellation ***/
547 #if IS_INTERRUPTIBLE
548 /* APC procedure for thread cancellation */
549 static void CALLBACK vlc_cancel_self (ULONG_PTR self)
551 (void) self;
553 #endif
555 void vlc_cancel (vlc_thread_t th)
557 atomic_store_explicit(&th->killed, true, memory_order_relaxed);
559 EnterCriticalSection(&th->wait.lock);
560 if (th->wait.addr != NULL)
562 atomic_fetch_or_explicit(th->wait.addr, 1, memory_order_relaxed);
563 vlc_addr_broadcast(th->wait.addr);
565 LeaveCriticalSection(&th->wait.lock);
567 #if IS_INTERRUPTIBLE
568 QueueUserAPC (vlc_cancel_self, th->id, (uintptr_t)th);
569 #endif
572 int vlc_savecancel (void)
574 struct vlc_thread *th = vlc_thread_self();
575 if (th == NULL)
576 return false; /* Main thread - cannot be cancelled anyway */
578 int state = th->killable;
579 th->killable = false;
580 return state;
583 void vlc_restorecancel (int state)
585 struct vlc_thread *th = vlc_thread_self();
586 assert (state == false || state == true);
588 if (th == NULL)
589 return; /* Main thread - cannot be cancelled anyway */
591 assert (!th->killable);
592 th->killable = state != 0;
595 void vlc_testcancel (void)
597 struct vlc_thread *th = vlc_thread_self();
598 if (th == NULL)
599 return; /* Main thread - cannot be cancelled anyway */
600 if (!th->killable)
601 return;
602 if (!atomic_load_explicit(&th->killed, memory_order_relaxed))
603 return;
605 th->killable = true; /* Do not re-enter cancellation cleanup */
607 for (vlc_cleanup_t *p = th->cleaners; p != NULL; p = p->next)
608 p->proc (p->data);
610 th->data = NULL; /* TODO: special value? */
611 if (th->id == NULL) /* Detached thread */
612 vlc_thread_destroy(th);
613 _endthreadex(0);
616 void vlc_control_cancel (int cmd, ...)
618 /* NOTE: This function only modifies thread-specific data, so there is no
619 * need to lock anything. */
620 va_list ap;
622 struct vlc_thread *th = vlc_thread_self();
623 if (th == NULL)
624 return; /* Main thread - cannot be cancelled anyway */
626 va_start (ap, cmd);
627 switch (cmd)
629 case VLC_CLEANUP_PUSH:
631 /* cleaner is a pointer to the caller stack, no need to allocate
632 * and copy anything. As a nice side effect, this cannot fail. */
633 vlc_cleanup_t *cleaner = va_arg (ap, vlc_cleanup_t *);
634 cleaner->next = th->cleaners;
635 th->cleaners = cleaner;
636 break;
639 case VLC_CLEANUP_POP:
641 th->cleaners = th->cleaners->next;
642 break;
645 case VLC_CANCEL_ADDR_SET:
647 void *addr = va_arg(ap, void *);
649 EnterCriticalSection(&th->wait.lock);
650 assert(th->wait.addr == NULL);
651 th->wait.addr = addr;
652 LeaveCriticalSection(&th->wait.lock);
653 break;
656 case VLC_CANCEL_ADDR_CLEAR:
658 void *addr = va_arg(ap, void *);
660 EnterCriticalSection(&th->wait.lock);
661 assert(th->wait.addr == addr);
662 th->wait.addr = NULL;
663 LeaveCriticalSection(&th->wait.lock);
664 break;
667 va_end (ap);
670 /*** Clock ***/
671 static union
673 struct
675 LARGE_INTEGER freq;
676 } perf;
677 #if !VLC_WINSTORE_APP
678 struct
680 MMRESULT (WINAPI *timeGetDevCaps)(LPTIMECAPS ptc,UINT cbtc);
681 DWORD (WINAPI *timeGetTime)(void);
682 } multimedia;
683 #endif
684 } clk;
686 static mtime_t mdate_interrupt (void)
688 ULONGLONG ts;
689 BOOL ret;
691 ret = QueryUnbiasedInterruptTime (&ts);
692 if (unlikely(!ret))
693 abort ();
695 /* hundreds of nanoseconds */
696 static_assert ((10000000 % CLOCK_FREQ) == 0, "Broken frequencies ratio");
697 return ts / (10000000 / CLOCK_FREQ);
700 static mtime_t mdate_tick (void)
702 ULONGLONG ts = GetTickCount64 ();
704 /* milliseconds */
705 static_assert ((CLOCK_FREQ % 1000) == 0, "Broken frequencies ratio");
706 return ts * (CLOCK_FREQ / 1000);
708 #if !VLC_WINSTORE_APP
709 static mtime_t mdate_multimedia (void)
711 DWORD ts = clk.multimedia.timeGetTime ();
713 /* milliseconds */
714 static_assert ((CLOCK_FREQ % 1000) == 0, "Broken frequencies ratio");
715 return ts * (CLOCK_FREQ / 1000);
717 #endif
719 static mtime_t mdate_perf (void)
721 /* We don't need the real date, just the value of a high precision timer */
722 LARGE_INTEGER counter;
723 if (!QueryPerformanceCounter (&counter))
724 abort ();
726 /* Convert to from (1/freq) to microsecond resolution */
727 /* We need to split the division to avoid 63-bits overflow */
728 lldiv_t d = lldiv (counter.QuadPart, clk.perf.freq.QuadPart);
730 return (d.quot * 1000000) + ((d.rem * 1000000) / clk.perf.freq.QuadPart);
733 static mtime_t mdate_wall (void)
735 FILETIME ts;
736 ULARGE_INTEGER s;
738 #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) && !VLC_WINSTORE_APP
739 GetSystemTimePreciseAsFileTime (&ts);
740 #else
741 GetSystemTimeAsFileTime (&ts);
742 #endif
743 s.LowPart = ts.dwLowDateTime;
744 s.HighPart = ts.dwHighDateTime;
745 /* hundreds of nanoseconds */
746 static_assert ((10000000 % CLOCK_FREQ) == 0, "Broken frequencies ratio");
747 return s.QuadPart / (10000000 / CLOCK_FREQ);
750 static mtime_t mdate_default(void)
752 vlc_threads_setup(NULL);
753 return mdate_perf();
756 static mtime_t (*mdate_selected) (void) = mdate_default;
758 mtime_t mdate (void)
760 return mdate_selected ();
763 #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
764 void (mwait)(mtime_t deadline)
766 mtime_t delay;
768 vlc_testcancel();
769 while ((delay = (deadline - mdate())) > 0)
771 delay = (delay + 999) / 1000;
772 if (unlikely(delay > 0x7fffffff))
773 delay = 0x7fffffff;
775 SleepEx(delay, TRUE);
776 vlc_testcancel();
780 void (msleep)(mtime_t delay)
782 mwait (mdate () + delay);
784 #endif
786 static BOOL SelectClockSource(void *data)
788 vlc_object_t *obj = data;
790 #if VLC_WINSTORE_APP
791 const char *name = "perf";
792 #else
793 const char *name = "multimedia";
794 #endif
795 char *str = NULL;
796 if (obj != NULL)
797 str = var_InheritString(obj, "clock-source");
798 if (str != NULL)
799 name = str;
800 if (!strcmp (name, "interrupt"))
802 msg_Dbg (obj, "using interrupt time as clock source");
803 mdate_selected = mdate_interrupt;
805 else
806 if (!strcmp (name, "tick"))
808 msg_Dbg (obj, "using Windows time as clock source");
809 mdate_selected = mdate_tick;
811 #if !VLC_WINSTORE_APP
812 else
813 if (!strcmp (name, "multimedia"))
815 TIMECAPS caps;
816 MMRESULT (WINAPI * timeBeginPeriod)(UINT);
818 HMODULE hWinmm = LoadLibrary(TEXT("winmm.dll"));
819 if (!hWinmm)
820 goto perf;
822 clk.multimedia.timeGetDevCaps = (void*)GetProcAddress(hWinmm, "timeGetDevCaps");
823 clk.multimedia.timeGetTime = (void*)GetProcAddress(hWinmm, "timeGetTime");
824 if (!clk.multimedia.timeGetDevCaps || !clk.multimedia.timeGetTime)
825 goto perf;
827 msg_Dbg (obj, "using multimedia timers as clock source");
828 if (clk.multimedia.timeGetDevCaps (&caps, sizeof (caps)) != MMSYSERR_NOERROR)
829 goto perf;
830 msg_Dbg (obj, " min period: %u ms, max period: %u ms",
831 caps.wPeriodMin, caps.wPeriodMax);
832 mdate_selected = mdate_multimedia;
834 timeBeginPeriod = (void*)GetProcAddress(hWinmm, "timeBeginPeriod");
835 if (timeBeginPeriod != NULL)
836 timeBeginPeriod(5);
838 #endif
839 else
840 if (!strcmp (name, "perf"))
842 perf:
843 msg_Dbg (obj, "using performance counters as clock source");
844 if (!QueryPerformanceFrequency (&clk.perf.freq))
845 abort ();
846 msg_Dbg (obj, " frequency: %llu Hz", clk.perf.freq.QuadPart);
847 mdate_selected = mdate_perf;
849 else
850 if (!strcmp (name, "wall"))
852 msg_Dbg (obj, "using system time as clock source");
853 mdate_selected = mdate_wall;
855 else
857 msg_Err (obj, "invalid clock source \"%s\"", name);
858 abort ();
860 free (str);
861 return TRUE;
864 size_t EnumClockSource (vlc_object_t *obj, const char *var,
865 char ***vp, char ***np)
867 const size_t max = 6;
868 char **values = xmalloc (sizeof (*values) * max);
869 char **names = xmalloc (sizeof (*names) * max);
870 size_t n = 0;
872 values[n] = xstrdup ("");
873 names[n] = xstrdup (_("Auto"));
874 n++;
875 values[n] = xstrdup ("interrupt");
876 names[n] = xstrdup ("Interrupt time");
877 n++;
878 values[n] = xstrdup ("tick");
879 names[n] = xstrdup ("Windows time");
880 n++;
881 #if !VLC_WINSTORE_APP
882 values[n] = xstrdup ("multimedia");
883 names[n] = xstrdup ("Multimedia timers");
884 n++;
885 #endif
886 values[n] = xstrdup ("perf");
887 names[n] = xstrdup ("Performance counters");
888 n++;
889 values[n] = xstrdup ("wall");
890 names[n] = xstrdup ("System time (DANGEROUS!)");
891 n++;
893 *vp = values;
894 *np = names;
895 (void) obj; (void) var;
896 return n;
900 /*** CPU ***/
901 unsigned vlc_GetCPUCount (void)
903 SYSTEM_INFO systemInfo;
905 GetNativeSystemInfo(&systemInfo);
907 return systemInfo.dwNumberOfProcessors;
911 /*** Initialization ***/
912 static CRITICAL_SECTION setup_lock; /* FIXME: use INIT_ONCE */
914 void vlc_threads_setup(libvlc_int_t *vlc)
916 EnterCriticalSection(&setup_lock);
917 if (mdate_selected != mdate_default)
919 LeaveCriticalSection(&setup_lock);
920 return;
923 if (!SelectClockSource((vlc != NULL) ? VLC_OBJECT(vlc) : NULL))
924 abort();
925 assert(mdate_selected != mdate_default);
927 #if !VLC_WINSTORE_APP
928 /* Raise default priority of the current process */
929 #ifndef ABOVE_NORMAL_PRIORITY_CLASS
930 # define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
931 #endif
932 if (var_InheritBool(vlc, "high-priority"))
934 if (SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS)
935 || SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
936 msg_Dbg(vlc, "raised process priority");
937 else
938 msg_Dbg(vlc, "could not raise process priority");
940 #endif
941 LeaveCriticalSection(&setup_lock);
944 #define LOOKUP(s) (((s##_) = (void *)GetProcAddress(h, #s)) != NULL)
946 extern vlc_rwlock_t config_lock;
947 BOOL WINAPI DllMain (HINSTANCE, DWORD, LPVOID);
949 BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
951 (void) hinstDll;
952 (void) lpvReserved;
954 switch (fdwReason)
956 case DLL_PROCESS_ATTACH:
958 #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
959 HANDLE h = GetModuleHandle(TEXT("kernel32.dll"));
960 if (unlikely(h == NULL))
961 return FALSE;
963 if (!LOOKUP(WaitOnAddress)
964 || !LOOKUP(WakeByAddressAll) || !LOOKUP(WakeByAddressSingle))
966 vlc_wait_addr_init();
967 WaitOnAddress_ = WaitOnAddressFallback;
968 WakeByAddressAll_ = WakeByAddressFallback;
969 WakeByAddressSingle_ = WakeByAddressFallback;
971 #endif
972 thread_key = TlsAlloc();
973 if (unlikely(thread_key == TLS_OUT_OF_INDEXES))
974 return FALSE;
975 InitializeCriticalSection(&setup_lock);
976 InitializeCriticalSection(&super_mutex);
977 InitializeConditionVariable(&super_variable);
978 vlc_rwlock_init (&config_lock);
979 vlc_CPU_init ();
980 break;
983 case DLL_PROCESS_DETACH:
984 vlc_rwlock_destroy (&config_lock);
985 DeleteCriticalSection(&super_mutex);
986 DeleteCriticalSection(&setup_lock);
987 TlsFree(thread_key);
988 #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
989 if (WaitOnAddress_ == WaitOnAddressFallback)
990 vlc_wait_addr_deinit();
991 #endif
992 break;
994 case DLL_THREAD_DETACH:
995 vlc_threadvars_cleanup();
996 break;
998 return TRUE;