Alexandre Julliard : ntdll: Implement the RunOnce functions.
Alexandre Julliard
julliard at winehq.org
Thu Aug 29 13:18:14 CDT 2013
Module: wine
Branch: master
Commit: fcb3e60332b153ce69b579aa33b1074b8cc5295a
URL: http://source.winehq.org/git/wine.git/?a=commit;h=fcb3e60332b153ce69b579aa33b1074b8cc5295a
Author: Alexandre Julliard <julliard at 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>
More information about the wine-cvs
mailing list