Module: wine Branch: master Commit: fcb3e60332b153ce69b579aa33b1074b8cc5295a URL: http://source.winehq.org/git/wine.git/?a=commit;h=fcb3e60332b153ce69b579aa33...
Author: Alexandre Julliard julliard@winehq.org Date: Wed Aug 28 21:10:50 2013 +0200
ntdll: Implement the RunOnce functions.
---
dlls/ntdll/ntdll.spec | 3 + dlls/ntdll/ntdll_misc.h | 1 + dlls/ntdll/sync.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++- dlls/ntdll/thread.c | 2 + include/winnt.h | 2 +- 5 files changed, 122 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index e4ed913..dbef513 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -816,6 +816,9 @@ @ stub RtlRevertMemoryStream @ stub RtlRunDecodeUnicodeString @ stub RtlRunEncodeUnicodeString +@ stdcall RtlRunOnceBeginInitialize(ptr long ptr) +@ stdcall RtlRunOnceComplete(ptr long ptr) +@ stdcall RtlRunOnceExecuteOnce(ptr ptr ptr ptr) @ stdcall RtlRunOnceInitialize(ptr) @ stdcall RtlSecondsSince1970ToTime(long ptr) @ stdcall RtlSecondsSince1980ToTime(long ptr) diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 908b72f..3d9264d 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -241,6 +241,7 @@ static inline struct ntdll_thread_data *ntdll_get_thread_data(void) }
extern mode_t FILE_umask DECLSPEC_HIDDEN; +extern HANDLE keyed_event DECLSPEC_HIDDEN;
/* Register functions */
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 3198d96..f466dab 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -22,6 +22,7 @@ */
#include "config.h" +#include "wine/port.h"
#include <assert.h> #include <errno.h> @@ -60,6 +61,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
+HANDLE keyed_event = NULL; + /* creates a struct security_descriptor and contained information in one contiguous piece of memory */ NTSTATUS NTDLL_create_struct_sd(PSECURITY_DESCRIPTOR nt_sd, struct security_descriptor **server_sd, data_size_t *server_sd_len) @@ -1236,7 +1239,117 @@ NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue, return status; }
-VOID NTAPI RtlRunOnceInitialize(PRTL_RUN_ONCE initonce) +/****************************************************************** + * RtlRunOnceInitialize (NTDLL.@) + */ +void WINAPI RtlRunOnceInitialize( RTL_RUN_ONCE *once ) +{ + once->Ptr = NULL; +} + +/****************************************************************** + * RtlRunOnceBeginInitialize (NTDLL.@) + */ +DWORD WINAPI RtlRunOnceBeginInitialize( RTL_RUN_ONCE *once, ULONG flags, void **context ) +{ + if (flags & RTL_RUN_ONCE_CHECK_ONLY) + { + ULONG_PTR val = (ULONG_PTR)once->Ptr; + + if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER; + if ((val & 3) != 2) return STATUS_UNSUCCESSFUL; + if (context) *context = (void *)(val & ~3); + return STATUS_SUCCESS; + } + + for (;;) + { + ULONG_PTR next, val = (ULONG_PTR)once->Ptr; + + switch (val & 3) + { + case 0: /* first time */ + if (!interlocked_cmpxchg_ptr( &once->Ptr, + (flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0 )) + return STATUS_PENDING; + break; + + case 1: /* in progress, wait */ + if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER; + next = val & ~3; + if (interlocked_cmpxchg_ptr( &once->Ptr, (void *)((ULONG_PTR)&next | 1), + (void *)val ) == (void *)val) + NtWaitForKeyedEvent( keyed_event, &next, FALSE, NULL ); + break; + + case 2: /* done */ + if (context) *context = (void *)(val & ~3); + return STATUS_SUCCESS; + + case 3: /* in progress, async */ + if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER; + return STATUS_PENDING; + } + } +} + +/****************************************************************** + * RtlRunOnceComplete (NTDLL.@) + */ +DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context ) +{ + if ((ULONG_PTR)context & 3) return STATUS_INVALID_PARAMETER; + + if (flags & RTL_RUN_ONCE_INIT_FAILED) + { + if (context) return STATUS_INVALID_PARAMETER; + if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER; + } + else context = (void *)((ULONG_PTR)context | 2); + + for (;;) + { + ULONG_PTR val = (ULONG_PTR)once->Ptr; + + switch (val & 3) + { + case 1: /* in progress */ + if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break; + val &= ~3; + while (val) + { + ULONG_PTR next = *(ULONG_PTR *)val; + NtReleaseKeyedEvent( keyed_event, (void *)val, FALSE, NULL ); + val = next; + } + return STATUS_SUCCESS; + + case 3: /* in progress, async */ + if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER; + if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break; + return STATUS_SUCCESS; + + default: + return STATUS_UNSUCCESSFUL; + } + } +} + +/****************************************************************** + * RtlRunOnceExecuteOnce (NTDLL.@) + */ +DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN func, + void *param, void **context ) { - initonce->Ptr = NULL; + DWORD ret = RtlRunOnceBeginInitialize( once, 0, context ); + + if (ret != STATUS_PENDING) return ret; + + if (!func( once, param, context )) + { + RtlRunOnceComplete( once, RTL_RUN_ONCE_INIT_FAILED, NULL ); + return STATUS_UNSUCCESSFUL; + } + + return RtlRunOnceComplete( once, 0, context ? *context : NULL ); } diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index c93a0cd..703e83c 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -308,6 +308,8 @@ HANDLE thread_init(void)
fill_cpu_info();
+ NtCreateKeyedEvent( &keyed_event, GENERIC_READ | GENERIC_WRITE, NULL, 0 ); + return exe_file; }
diff --git a/include/winnt.h b/include/winnt.h index 171141e..1f71423 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -5163,7 +5163,7 @@ typedef DWORD WINAPI RTL_RUN_ONCE_INIT_FN(PRTL_RUN_ONCE, PVOID, PVOID*); typedef RTL_RUN_ONCE_INIT_FN *PRTL_RUN_ONCE_INIT_FN; NTSYSAPI VOID WINAPI RtlRunOnceInitialize(PRTL_RUN_ONCE); NTSYSAPI DWORD WINAPI RtlRunOnceExecuteOnce(PRTL_RUN_ONCE,PRTL_RUN_ONCE_INIT_FN,PVOID,PVOID*); -NTSYSAPI DWORD WINAPI RtlRunOnceBeginInitialize(PRTL_RUN_ONCE, DWORD, PBOOL, PVOID*); +NTSYSAPI DWORD WINAPI RtlRunOnceBeginInitialize(PRTL_RUN_ONCE, DWORD, PVOID*); NTSYSAPI DWORD WINAPI RtlRunOnceComplete(PRTL_RUN_ONCE, DWORD, PVOID);
#include <pshpack8.h>