From fcb3e60332b153ce69b579aa33b1074b8cc5295a Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 28 Aug 2013 21:10:50 +0200 Subject: [PATCH] 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 e4ed9133595..dbef5132969 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 908b72f0769..3d9264d9f0c 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 3198d960ba0..f466dababba 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -22,6 +22,7 @@ */ #include "config.h" +#include "wine/port.h" #include #include @@ -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 ) { - initonce->Ptr = NULL; + 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 ) +{ + 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 c93a0cd04ab..703e83cf1be 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 171141e25e6..1f7142326d4 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