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>
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 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_atomic.h>
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)
52 static DWORD thread_key
;
60 vlc_cleanup_t
*cleaners
;
62 void *(*entry
) (void *);
68 CRITICAL_SECTION lock
;
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
)
87 static BOOL WINAPI
SleepConditionVariableFallback(CONDITION_VARIABLE
*cv
,
92 LeaveCriticalSection(cs
);
93 SleepEx(ms
> 5 ? 5 : ms
, TRUE
);
94 EnterCriticalSection(cs
);
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
);
137 EnterCriticalSection (&p_mutex
->mutex
);
140 int vlc_mutex_trylock (vlc_mutex_t
*p_mutex
)
142 if (!p_mutex
->dynamic
)
143 { /* static mutexes */
146 EnterCriticalSection(&super_mutex
);
147 if (!p_mutex
->locked
)
149 p_mutex
->locked
= true;
152 LeaveCriticalSection(&super_mutex
);
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
);
172 LeaveCriticalSection (&p_mutex
->mutex
);
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
);
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
);
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
);
226 /*** Thread-specific variables (TLS) ***/
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
))
241 var
->id
= TlsAlloc();
242 if (var
->id
== TLS_OUT_OF_INDEXES
)
247 var
->destroy
= destr
;
251 EnterCriticalSection(&super_mutex
);
252 var
->prev
= vlc_threadvar_last
;
254 var
->prev
->next
= var
;
256 vlc_threadvar_last
= var
;
257 LeaveCriticalSection(&super_mutex
);
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
;
272 vlc_threadvar_last
= var
->prev
;
274 LeaveCriticalSection(&super_mutex
);
280 int vlc_threadvar_set (vlc_threadvar_t key
, void *value
)
282 int saved
= GetLastError ();
283 int val
= TlsSetValue (key
->id
, value
) ? ENOMEM
: 0;
290 void *vlc_threadvar_get (vlc_threadvar_t key
)
292 int saved
= GetLastError ();
293 void *value
= TlsGetValue (key
->id
);
299 static void vlc_threadvars_cleanup(void)
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
);
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;
369 EnterCriticalSection(&bucket
->lock
);
374 futex
= atomic_load_explicit((atomic_char
*)addr
,
375 memory_order_relaxed
);
376 val
= *(const char *)value
;
379 futex
= atomic_load_explicit((atomic_short
*)addr
,
380 memory_order_relaxed
);
381 val
= *(const short *)value
;
384 futex
= atomic_load_explicit((atomic_int
*)addr
,
385 memory_order_relaxed
);
386 val
= *(const int *)value
;
389 futex
= atomic_load_explicit((atomic_llong
*)addr
,
390 memory_order_relaxed
);
391 val
= *(const long long *)value
;
394 vlc_assert_unreachable();
398 ret
= SleepConditionVariableCS(&bucket
->wait
, &bucket
->lock
, ms
);
400 LeaveCriticalSection(&bucket
->lock
);
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
);
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
);
457 static void vlc_thread_destroy(vlc_thread_t th
)
459 DeleteCriticalSection(&th
->wait
.lock
);
463 static unsigned __stdcall
vlc_entry (void *p
)
465 struct vlc_thread
*th
= p
;
467 TlsSetValue(thread_key
, th
);
469 th
->data
= th
->entry (th
->data
);
470 TlsSetValue(thread_key
, NULL
);
472 if (th
->id
== NULL
) /* Detached thread */
473 vlc_thread_destroy(th
);
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
))
485 th
->killable
= false; /* not until vlc_entry() ! */
486 atomic_init(&th
->killed
, false);
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
);
505 CloseHandle((HANDLE
)h
);
511 if (p_handle
!= NULL
)
515 SetThreadPriority (th
->id
, priority
);
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
)
533 ret
= WaitForSingleObjectEx(th
->id
, INFINITE
, TRUE
);
534 assert(ret
!= WAIT_ABANDONED_0
);
536 while (ret
== WAIT_IO_COMPLETION
|| ret
== WAIT_FAILED
);
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
)
548 if (p_handle
== NULL
)
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
))
571 /*** Thread cancellation ***/
574 /* APC procedure for thread cancellation */
575 static void CALLBACK
vlc_cancel_self (ULONG_PTR self
)
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
);
594 QueueUserAPC (vlc_cancel_self
, th
->id
, (uintptr_t)th
);
598 int vlc_savecancel (void)
600 struct vlc_thread
*th
= vlc_thread_self();
602 return false; /* Main thread - cannot be cancelled anyway */
604 int state
= th
->killable
;
605 th
->killable
= false;
609 void vlc_restorecancel (int state
)
611 struct vlc_thread
*th
= vlc_thread_self();
612 assert (state
== false || state
== true);
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();
625 return; /* Main thread - cannot be cancelled anyway */
628 if (!atomic_load_explicit(&th
->killed
, memory_order_relaxed
))
631 th
->killable
= true; /* Do not re-enter cancellation cleanup */
633 for (vlc_cleanup_t
*p
= th
->cleaners
; p
!= NULL
; p
= p
->next
)
636 th
->data
= NULL
; /* TODO: special value? */
637 if (th
->id
== NULL
) /* Detached thread */
638 vlc_thread_destroy(th
);
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. */
648 struct vlc_thread
*th
= vlc_thread_self();
650 return; /* Main thread - cannot be cancelled anyway */
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
;
665 case VLC_CLEANUP_POP
:
667 th
->cleaners
= th
->cleaners
->next
;
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
);
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
);
699 #if (_WIN32_WINNT < _WIN32_WINNT_WIN7)
702 BOOL (*query
) (PULONGLONG
);
705 #if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
708 ULONGLONG (*get
) (void);
715 #if !VLC_WINSTORE_APP
718 MMRESULT (WINAPI
*timeGetDevCaps
)(LPTIMECAPS ptc
,UINT cbtc
);
719 DWORD (WINAPI
*timeGetTime
)(void);
724 static mtime_t
mdate_interrupt (void)
729 #if (_WIN32_WINNT >= _WIN32_WINNT_WIN7)
730 ret
= QueryUnbiasedInterruptTime (&ts
);
732 ret
= clk
.interrupt
.query (&ts
);
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 ();
747 ULONGLONG ts
= clk
.tick
.get ();
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 ();
760 static_assert ((CLOCK_FREQ
% 1000) == 0, "Broken frequencies ratio");
761 return ts
* (CLOCK_FREQ
/ 1000);
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
))
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)
784 #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) && !VLC_WINSTORE_APP
785 GetSystemTimePreciseAsFileTime (&ts
);
787 GetSystemTimeAsFileTime (&ts
);
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
);
802 static mtime_t (*mdate_selected
) (void) = mdate_default
;
806 return mdate_selected ();
809 #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
810 void (mwait
)(mtime_t deadline
)
815 while ((delay
= (deadline
- mdate())) > 0)
817 delay
= (delay
+ 999) / 1000;
818 if (unlikely(delay
> 0x7fffffff))
821 SleepEx(delay
, TRUE
);
826 void (msleep
)(mtime_t delay
)
828 mwait (mdate () + delay
);
832 static BOOL
SelectClockSource(void *data
)
834 vlc_object_t
*obj
= data
;
837 const char *name
= "perf";
839 const char *name
= "multimedia";
843 str
= var_InheritString(obj
, "clock-source");
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
))
853 clk
.interrupt
.query
= (void *)GetProcAddress (h
,
854 "QueryUnbiasedInterruptTime");
855 if (unlikely(clk
.interrupt
.query
== NULL
))
858 mdate_selected
= mdate_interrupt
;
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
))
868 clk
.tick
.get
= (void *)GetProcAddress (h
, "GetTickCount64");
869 if (unlikely(clk
.tick
.get
== NULL
))
872 mdate_selected
= mdate_tick
;
874 #if !VLC_WINSTORE_APP
876 if (!strcmp (name
, "multimedia"))
879 MMRESULT (WINAPI
* timeBeginPeriod
)(UINT
);
881 HMODULE hWinmm
= LoadLibrary(TEXT("winmm.dll"));
885 clk
.multimedia
.timeGetDevCaps
= (void*)GetProcAddress(hWinmm
, "timeGetDevCaps");
886 clk
.multimedia
.timeGetTime
= (void*)GetProcAddress(hWinmm
, "timeGetTime");
887 if (!clk
.multimedia
.timeGetDevCaps
|| !clk
.multimedia
.timeGetTime
)
890 msg_Dbg (obj
, "using multimedia timers as clock source");
891 if (clk
.multimedia
.timeGetDevCaps (&caps
, sizeof (caps
)) != MMSYSERR_NOERROR
)
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
)
903 if (!strcmp (name
, "perf"))
906 msg_Dbg (obj
, "using performance counters as clock source");
907 if (!QueryPerformanceFrequency (&clk
.perf
.freq
))
909 msg_Dbg (obj
, " frequency: %llu Hz", clk
.perf
.freq
.QuadPart
);
910 mdate_selected
= mdate_perf
;
913 if (!strcmp (name
, "wall"))
915 msg_Dbg (obj
, "using system time as clock source");
916 mdate_selected
= mdate_wall
;
920 msg_Err (obj
, "invalid clock source \"%s\"", name
);
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
);
935 #if (_WIN32_WINNT < _WIN32_WINNT_WIN7)
936 DWORD version
= LOWORD(GetVersion());
937 version
= (LOBYTE(version
) << 8) | (HIBYTE(version
) << 0);
940 values
[n
] = xstrdup ("");
941 names
[n
] = xstrdup (_("Auto"));
943 #if (_WIN32_WINNT < _WIN32_WINNT_WIN7)
944 if (version
>= 0x0601)
947 values
[n
] = xstrdup ("interrupt");
948 names
[n
] = xstrdup ("Interrupt time");
951 #if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
952 if (version
>= 0x0600)
955 values
[n
] = xstrdup ("tick");
956 names
[n
] = xstrdup ("Windows time");
959 #if !VLC_WINSTORE_APP
960 values
[n
] = xstrdup ("multimedia");
961 names
[n
] = xstrdup ("Multimedia timers");
964 values
[n
] = xstrdup ("perf");
965 names
[n
] = xstrdup ("Performance counters");
967 values
[n
] = xstrdup ("wall");
968 names
[n
] = xstrdup ("System time (DANGEROUS!)");
973 (void) obj
; (void) var
;
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
);
1001 if (!SelectClockSource((vlc
!= NULL
) ? VLC_OBJECT(vlc
) : NULL
))
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
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");
1016 msg_Dbg(vlc
, "could not raise process priority");
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
)
1034 case DLL_PROCESS_ATTACH
:
1036 #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
1037 HANDLE h
= GetModuleHandle(TEXT("kernel32.dll"));
1038 if (unlikely(h
== NULL
))
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
;
1054 vlc_wait_addr_init();
1055 WaitOnAddress_
= WaitOnAddressFallback
;
1056 WakeByAddressAll_
= WakeByAddressFallback
;
1057 WakeByAddressSingle_
= WakeByAddressFallback
;
1060 thread_key
= TlsAlloc();
1061 if (unlikely(thread_key
== TLS_OUT_OF_INDEXES
))
1063 InitializeCriticalSection(&setup_lock
);
1064 InitializeCriticalSection(&super_mutex
);
1065 InitializeConditionVariable(&super_variable
);
1066 vlc_rwlock_init (&config_lock
);
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();
1082 case DLL_THREAD_DETACH
:
1083 vlc_threadvars_cleanup();