Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
cc8f9b64
Commit
cc8f9b64
authored
Feb 05, 2019
by
Zebediah Figura
Committed by
Alexandre Julliard
Feb 06, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll: Add a futex-based implementation of WaitOnAddress().
Signed-off-by:
Zebediah Figura
<
z.figura12@gmail.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
749fe42d
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
139 additions
and
0 deletions
+139
-0
sync.c
dlls/ntdll/sync.c
+139
-0
No files found.
dlls/ntdll/sync.c
View file @
cc8f9b64
...
...
@@ -26,7 +26,11 @@
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>
#ifdef HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
...
...
@@ -63,6 +67,8 @@ HANDLE keyed_event = NULL;
static
const
LARGE_INTEGER
zero_timeout
;
#define TICKSPERSEC 10000000
static
inline
int
interlocked_dec_if_nonzero
(
int
*
dest
)
{
int
val
,
tmp
;
...
...
@@ -74,6 +80,41 @@ static inline int interlocked_dec_if_nonzero( int *dest )
return
val
;
}
#ifdef __linux__
static
int
wait_op
=
128
;
/*FUTEX_WAIT|FUTEX_PRIVATE_FLAG*/
static
int
wake_op
=
129
;
/*FUTEX_WAKE|FUTEX_PRIVATE_FLAG*/
static
inline
int
futex_wait
(
const
int
*
addr
,
int
val
,
struct
timespec
*
timeout
)
{
return
syscall
(
__NR_futex
,
addr
,
wait_op
,
val
,
timeout
,
0
,
0
);
}
static
inline
int
futex_wake
(
const
int
*
addr
,
int
val
)
{
return
syscall
(
__NR_futex
,
addr
,
wake_op
,
val
,
NULL
,
0
,
0
);
}
static
inline
int
use_futexes
(
void
)
{
static
int
supported
=
-
1
;
if
(
supported
==
-
1
)
{
futex_wait
(
&
supported
,
10
,
NULL
);
if
(
errno
==
ENOSYS
)
{
wait_op
=
0
;
/*FUTEX_WAIT*/
wake_op
=
1
;
/*FUTEX_WAKE*/
futex_wait
(
&
supported
,
10
,
NULL
);
}
supported
=
(
errno
!=
ENOSYS
);
}
return
supported
;
}
#endif
/* creates a struct security_descriptor and contained information in one contiguous piece of memory */
NTSTATUS
alloc_object_attributes
(
const
OBJECT_ATTRIBUTES
*
attr
,
struct
object_attributes
**
ret
,
data_size_t
*
ret_len
)
...
...
@@ -1987,6 +2028,95 @@ static BOOL compare_addr( const void *addr, const void *cmp, SIZE_T size )
return
FALSE
;
}
#ifdef __linux__
/* We can't map addresses to futex directly, because an application can wait on
* 8 bytes, and we can't pass all 8 as the compare value to futex(). Instead we
* map all addresses to a small fixed table of futexes. This may result in
* spurious wakes, but the application is already expected to handle those. */
static
int
addr_futex_table
[
256
];
static
inline
int
*
hash_addr
(
const
void
*
addr
)
{
ULONG_PTR
val
=
(
ULONG_PTR
)
addr
;
return
&
addr_futex_table
[(
val
>>
2
)
&
255
];
}
static
inline
NTSTATUS
fast_wait_addr
(
const
void
*
addr
,
const
void
*
cmp
,
SIZE_T
size
,
const
LARGE_INTEGER
*
timeout
)
{
int
*
futex
;
int
val
;
LARGE_INTEGER
now
;
timeout_t
diff
;
struct
timespec
timespec
;
int
ret
;
if
(
!
use_futexes
())
return
STATUS_NOT_IMPLEMENTED
;
futex
=
hash_addr
(
addr
);
/* We must read the previous value of the futex before checking the value
* of the address being waited on. That way, if we receive a wake between
* now and waiting on the futex, we know that val will have changed.
* Use an atomic load so that memory accesses are ordered between this read
* and the increment below. */
val
=
interlocked_cmpxchg
(
futex
,
0
,
0
);
if
(
!
compare_addr
(
addr
,
cmp
,
size
))
return
STATUS_SUCCESS
;
if
(
timeout
)
{
if
(
timeout
->
QuadPart
>
0
)
{
NtQuerySystemTime
(
&
now
);
diff
=
timeout
->
QuadPart
-
now
.
QuadPart
;
}
else
diff
=
-
timeout
->
QuadPart
;
timespec
.
tv_sec
=
diff
/
TICKSPERSEC
;
timespec
.
tv_nsec
=
(
diff
%
TICKSPERSEC
)
*
100
;
ret
=
futex_wait
(
futex
,
val
,
&
timespec
);
}
else
ret
=
futex_wait
(
futex
,
val
,
NULL
);
if
(
ret
==
-
1
&&
errno
==
ETIMEDOUT
)
return
STATUS_TIMEOUT
;
return
STATUS_SUCCESS
;
}
static
inline
NTSTATUS
fast_wake_addr
(
const
void
*
addr
)
{
int
*
futex
;
if
(
!
use_futexes
())
return
STATUS_NOT_IMPLEMENTED
;
futex
=
hash_addr
(
addr
);
interlocked_xchg_add
(
futex
,
1
);
futex_wake
(
futex
,
INT_MAX
);
return
STATUS_SUCCESS
;
}
#else
static
inline
NTSTATUS
fast_wait_addr
(
const
void
*
addr
,
const
void
*
cmp
,
SIZE_T
size
,
const
LARGE_INTEGER
*
timeout
)
{
return
STATUS_NOT_IMPLEMENTED
;
}
static
inline
NTSTATUS
fast_wake_addr
(
const
void
*
addr
)
{
return
STATUS_NOT_IMPLEMENTED
;
}
#endif
/***********************************************************************
* RtlWaitOnAddress (NTDLL.@)
*/
...
...
@@ -2005,6 +2135,9 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
if
(
size
!=
1
&&
size
!=
2
&&
size
!=
4
&&
size
!=
8
)
return
STATUS_INVALID_PARAMETER
;
if
((
ret
=
fast_wait_addr
(
addr
,
cmp
,
size
,
timeout
))
!=
STATUS_NOT_IMPLEMENTED
)
return
ret
;
select_op
.
keyed_event
.
op
=
SELECT_KEYED_EVENT_WAIT
;
select_op
.
keyed_event
.
handle
=
wine_server_obj_handle
(
keyed_event
);
select_op
.
keyed_event
.
key
=
wine_server_client_ptr
(
addr
);
...
...
@@ -2059,6 +2192,9 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
*/
void
WINAPI
RtlWakeAddressAll
(
const
void
*
addr
)
{
if
(
fast_wake_addr
(
addr
)
!=
STATUS_NOT_IMPLEMENTED
)
return
;
RtlEnterCriticalSection
(
&
addr_section
);
while
(
NtReleaseKeyedEvent
(
0
,
addr
,
0
,
&
zero_timeout
)
==
STATUS_SUCCESS
)
{}
RtlLeaveCriticalSection
(
&
addr_section
);
...
...
@@ -2069,6 +2205,9 @@ void WINAPI RtlWakeAddressAll( const void *addr )
*/
void
WINAPI
RtlWakeAddressSingle
(
const
void
*
addr
)
{
if
(
fast_wake_addr
(
addr
)
!=
STATUS_NOT_IMPLEMENTED
)
return
;
RtlEnterCriticalSection
(
&
addr_section
);
NtReleaseKeyedEvent
(
0
,
addr
,
0
,
&
zero_timeout
);
RtlLeaveCriticalSection
(
&
addr_section
);
...
...
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