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