Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Open sidebar
Steve Lhomme
VLC
Commits
58191d7d
Commit
58191d7d
authored
May 26, 2016
by
Rémi Denis-Courmont
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
win32: run-time fallback for WaitOnAddress() and WakeByAddress()
parent
c47ade6b
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
134 additions
and
1 deletion
+134
-1
src/win32/thread.c
src/win32/thread.c
+134
-1
No files found.
src/win32/thread.c
View file @
58191d7d
...
...
@@ -440,9 +440,116 @@ retry:
vlc_mutex_unlock
(
&
super_mutex
);
}
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
/*** Futeces^WAddress waits ***/
#if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
static
BOOL
(
WINAPI
*
WaitOnAddress_
)(
VOID
volatile
*
,
PVOID
,
SIZE_T
,
DWORD
);
#define WaitOnAddress (*WaitOnAddress_)
static
VOID
(
WINAPI
*
WakeByAddressAll_
)(
PVOID
);
#define WakeByAddressAll (*WakeByAddressAll_)
static
VOID
(
WINAPI
*
WakeByAddressSingle_
)(
PVOID
);
#define WakeByAddressSingle (*WakeByAddressSingle_)
static
struct
wait_addr_bucket
{
CRITICAL_SECTION
lock
;
CONDITION_VARIABLE
wait
;
}
wait_addr_buckets
[
32
];
static
struct
wait_addr_bucket
*
wait_addr_get_bucket
(
void
volatile
*
addr
)
{
uintptr_t
u
=
(
uintptr_t
)
addr
;
return
wait_addr_buckets
+
((
u
>>
3
)
%
ARRAY_SIZE
(
wait_addr_buckets
));
}
static
void
vlc_wait_addr_init
(
void
)
{
for
(
size_t
i
=
0
;
i
<
ARRAY_SIZE
(
wait_addr_buckets
);
i
++
)
{
struct
wait_addr_bucket
*
bucket
=
wait_addr_buckets
+
i
;
InitializeCriticalSection
(
&
bucket
->
lock
);
InitializeConditionVariable
(
&
bucket
->
wait
);
}
}
static
void
vlc_wait_addr_deinit
(
void
)
{
for
(
size_t
i
=
0
;
i
<
ARRAY_SIZE
(
wait_addr_buckets
);
i
++
)
{
struct
wait_addr_bucket
*
bucket
=
wait_addr_buckets
+
i
;
DeleteCriticalSection
(
&
bucket
->
lock
);
}
}
static
BOOL
WINAPI
WaitOnAddressFallback
(
void
volatile
*
addr
,
void
*
value
,
SIZE_T
size
,
DWORD
ms
)
{
struct
wait_addr_bucket
*
bucket
=
wait_addr_get_bucket
(
addr
);
uint64_t
futex
,
val
=
0
;
BOOL
ret
=
0
;
EnterCriticalSection
(
&
bucket
->
lock
);
switch
(
size
)
{
case
1
:
futex
=
atomic_load_explicit
((
atomic_char
*
)
addr
,
memory_order_relaxed
);
val
=
*
(
const
char
*
)
value
;
break
;
case
2
:
futex
=
atomic_load_explicit
((
atomic_short
*
)
addr
,
memory_order_relaxed
);
val
=
*
(
const
short
*
)
value
;
break
;
case
4
:
futex
=
atomic_load_explicit
((
atomic_int
*
)
addr
,
memory_order_relaxed
);
val
=
*
(
const
int
*
)
value
;
break
;
case
8
:
futex
=
atomic_load_explicit
((
atomic_llong
*
)
addr
,
memory_order_relaxed
);
val
=
*
(
const
long
long
*
)
value
;
break
;
default:
vlc_assert_unreachable
();
}
if
(
futex
==
val
)
ret
=
SleepConditionVariableCS
(
&
bucket
->
wait
,
&
bucket
->
lock
,
ms
);
LeaveCriticalSection
(
&
bucket
->
lock
);
return
ret
;
}
static
void
WINAPI
WakeByAddressFallback
(
void
*
addr
)
{
struct
wait_addr_bucket
*
bucket
=
wait_addr_get_bucket
(
addr
);
/* Acquire the bucket critical section (only) to enforce proper sequencing.
* The critical section does not protect any actual memory object. */
EnterCriticalSection
(
&
bucket
->
lock
);
/* No other threads can hold the lock for this bucket while it is held
* here. Thus any other thread either:
* - is already sleeping in SleepConditionVariableCS(), and to be woken up
* by the following WakeAllConditionVariable(), or
* - has yet to retrieve the value at the wait address (with the
* 'switch (size)' block). */
LeaveCriticalSection
(
&
bucket
->
lock
);
/* At this point, other threads can retrieve the value at the wait address.
* But the value will have already been changed by our call site, thus
* (futex == val) will be false, and the threads will not go to sleep. */
/* Wake up any thread that was already sleeping. Since there are more than
* one wait address per bucket, all threads must be woken up :-/ */
WakeAllConditionVariable
(
&
bucket
->
wait
);
}
#endif
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
void
vlc_addr_wait
(
void
*
addr
,
int
val
)
{
WaitOnAddress
(
addr
,
&
val
,
sizeof
(
val
),
-
1
);
...
...
@@ -1041,6 +1148,8 @@ void vlc_threads_setup (libvlc_int_t *p_libvlc)
SelectClockSource
(
VLC_OBJECT
(
p_libvlc
));
}
#define LOOKUP(s) (((s##_) = (void *)GetProcAddress(h, #s)) != NULL)
extern
vlc_rwlock_t
config_lock
;
BOOL
WINAPI
DllMain
(
HINSTANCE
,
DWORD
,
LPVOID
);
...
...
@@ -1052,6 +1161,23 @@ BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
switch
(
fdwReason
)
{
case
DLL_PROCESS_ATTACH
:
{
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
#if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
HANDLE
h
=
GetModuleHandle
(
TEXT
(
"kernel32.dll"
));
if
(
unlikely
(
h
==
NULL
))
return
FALSE
;
if
(
!
LOOKUP
(
WaitOnAddress
)
||
!
LOOKUP
(
WakeByAddressAll
)
||
!
LOOKUP
(
WakeByAddressSingle
))
{
vlc_wait_addr_init
();
WaitOnAddress_
=
WaitOnAddressFallback
;
WakeByAddressAll_
=
WakeByAddressFallback
;
WakeByAddressSingle_
=
WakeByAddressFallback
;
}
#endif
#endif
thread_key
=
TlsAlloc
();
if
(
unlikely
(
thread_key
==
TLS_OUT_OF_INDEXES
))
return
FALSE
;
...
...
@@ -1061,6 +1187,7 @@ BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
vlc_rwlock_init
(
&
config_lock
);
vlc_CPU_init
();
break
;
}
case
DLL_PROCESS_DETACH
:
vlc_rwlock_destroy
(
&
config_lock
);
...
...
@@ -1068,6 +1195,12 @@ BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
vlc_mutex_destroy
(
&
super_mutex
);
DeleteCriticalSection
(
&
clock_lock
);
TlsFree
(
thread_key
);
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
#if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
if
(
WaitOnAddress_
==
WaitOnAddressFallback
)
vlc_wait_addr_deinit
();
#endif
#endif
break
;
case
DLL_THREAD_DETACH
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment