[2/2] kernel32: Implement InitOnceExecuteOnce() for Linux platform (resend)

Nikolay Sivov nsivov at codeweavers.com
Tue Jul 24 04:51:25 CDT 2012


Implement InitOnceExecuteOnce() for Linux platform
-------------- next part --------------
>From 9ab5998256b69081e6d53e4b8ae4120d75b1554d Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov at codeweavers.com>
Date: Tue, 24 Jul 2012 13:40:02 +0400
Subject: [PATCH 2/2] Implement InitOnceExecuteOnce() for Linux platform

---
 dlls/kernel32/kernel32.spec |    1 +
 dlls/kernel32/tests/sync.c  |   16 ++++++++++----
 dlls/ntdll/critsection.c    |   45 +++++++++++++++++++++++++++++++++++++++++++
 dlls/ntdll/ntdll.spec       |    1 +
 dlls/ntdll/sync.c           |    5 ----
 include/winbase.h           |    1 +
 include/winnt.h             |    3 ++
 7 files changed, 62 insertions(+), 10 deletions(-)

diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index a916309..234d191 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -747,6 +747,7 @@
 @ stdcall InitializeCriticalSectionAndSpinCount(ptr long)
 @ stdcall InitializeCriticalSectionEx(ptr long long)
 @ stdcall InitializeSListHead(ptr) ntdll.RtlInitializeSListHead
+@ stdcall InitOnceExecuteOnce(ptr ptr ptr ptr) ntdll.RtlRunOnceExecuteOnce
 @ stdcall InitOnceInitialize(ptr) ntdll.RtlRunOnceInitialize
 @ stdcall -arch=i386 InterlockedCompareExchange (ptr long long)
 @ stdcall -arch=i386 -ret64 InterlockedCompareExchange64(ptr int64 int64) ntdll.RtlInterlockedCompareExchange64
diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c
index 2110711..5c4dbfb 100644
--- a/dlls/kernel32/tests/sync.c
+++ b/dlls/kernel32/tests/sync.c
@@ -1159,7 +1159,7 @@ static void test_initonce(void)
 
     if (!pInitOnceInitialize || !pInitOnceExecuteOnce)
     {
-        skip("one-time initialization API not supported\n");
+        win_skip("one-time initialization API not supported\n");
         return;
     }
 
@@ -1171,7 +1171,7 @@ static void test_initonce(void)
     /* initialisation completed successfully */
     g_initcallback_ret = TRUE;
     g_initctxt = NULL;
-    ret = pInitOnceExecuteOnce(&initonce, &initonce_callback, (void*)0xdeadbeef, &g_initctxt);
+    ret = pInitOnceExecuteOnce(&initonce, initonce_callback, (void*)0xdeadbeef, &g_initctxt);
     ok(ret, "got wrong ret value %d\n", ret);
     ok(initonce.Ptr == (void*)0x2, "got %p\n", initonce.Ptr);
     ok(g_initctxt == (void*)0x0, "got %p\n", g_initctxt);
@@ -1180,7 +1180,7 @@ static void test_initonce(void)
     /* so it's been called already so won't be called again */
     g_initctxt = NULL;
     g_initcallback_called = FALSE;
-    ret = pInitOnceExecuteOnce(&initonce, &initonce_callback, (void*)0xdeadbeef, &g_initctxt);
+    ret = pInitOnceExecuteOnce(&initonce, initonce_callback, (void*)0xdeadbeef, &g_initctxt);
     ok(ret, "got wrong ret value %d\n", ret);
     ok(initonce.Ptr == (void*)0x2, "got %p\n", initonce.Ptr);
     ok(g_initctxt == (void*)0, "got %p\n", g_initctxt);
@@ -1190,7 +1190,7 @@ static void test_initonce(void)
     g_initcallback_called = FALSE;
     /* 2 lower order bits should never be used, you'll get a crash in result */
     g_initctxt = (void*)0xFFFFFFF0;
-    ret = pInitOnceExecuteOnce(&initonce, &initonce_callback, (void*)0xdeadbeef, &g_initctxt);
+    ret = pInitOnceExecuteOnce(&initonce, initonce_callback, (void*)0xdeadbeef, &g_initctxt);
     ok(ret, "got wrong ret value %d\n", ret);
     ok(initonce.Ptr == (void*)0xFFFFFFF2, "got %p\n", initonce.Ptr);
     ok(g_initctxt == (void*)0xFFFFFFF0, "got %p\n", g_initctxt);
@@ -1201,12 +1201,18 @@ static void test_initonce(void)
     g_initcallback_called = FALSE;
     g_initctxt = NULL;
     pInitOnceInitialize(&initonce);
-    ret = pInitOnceExecuteOnce(&initonce, &initonce_callback, (void*)0xdeadbeef, &g_initctxt);
+    ret = pInitOnceExecuteOnce(&initonce, initonce_callback, (void*)0xdeadbeef, &g_initctxt);
     ok(!ret, "got wrong ret value %d\n", ret);
     ok(initonce.Ptr == NULL, "got %p\n", initonce.Ptr);
     ok(g_initctxt == NULL, "got %p\n", g_initctxt);
     ok(g_initcallback_called, "got %d\n", g_initcallback_called);
 
+    if (!pInitOnceBeginInitialize)
+    {
+        skip("one-time initialization without callback not supported\n");
+        return;
+    }
+
     /* blocking initialzation without a callback */
     pInitOnceInitialize(&initonce);
     g_initctxt = NULL;
diff --git a/dlls/ntdll/critsection.c b/dlls/ntdll/critsection.c
index fb69b31..0dfc855 100644
--- a/dlls/ntdll/critsection.c
+++ b/dlls/ntdll/critsection.c
@@ -629,3 +629,48 @@ NTSTATUS WINAPI RtlLeaveCriticalSection( RTL_CRITICAL_SECTION *crit )
     }
     return STATUS_SUCCESS;
 }
+
+/* Once-time initialization API */
+VOID NTAPI RtlRunOnceInitialize(PRTL_RUN_ONCE initonce)
+{
+    initonce->Ptr = NULL;
+}
+
+DWORD NTAPI RtlRunOnceExecuteOnce(PRTL_RUN_ONCE initonce, PRTL_RUN_ONCE_INIT_FN callback, void *parameter, void **ctxt)
+{
+#ifdef __linux__
+    if (!use_futexes()) return FALSE;
+
+    for (;;)
+    {
+        DWORD_PTR val = (DWORD_PTR)interlocked_cmpxchg_ptr( &initonce->Ptr, (void*)1, NULL );
+        switch (val & 0x3)
+        {
+            case 0:
+            {
+                DWORD ret = callback(initonce, parameter, ctxt);
+                if (ret)
+                {
+                    DWORD_PTR context = ctxt ? (DWORD_PTR)*ctxt : 0;
+                    context = (context & ~0x3) | 0x2;
+                    interlocked_cmpxchg_ptr( &initonce->Ptr, (void*)context, (void*)1 );
+                }
+                else
+                    interlocked_cmpxchg_ptr( &initonce->Ptr, NULL, (void*)1 );
+                futex_wake( (int *)&initonce->Ptr, 1 );
+                return ret;
+            }
+            case 1:
+                /* blocked by another thread */
+                futex_wait( (int *)&initonce->Ptr, 1, NULL );
+                break;
+            case 2:
+                /* already initialized */
+                return TRUE;
+        }
+    }
+#else
+    FIXME("unimplemented for this platform\n");
+    return 0;
+#endif
+}
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 4ace865..755e698 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -815,6 +815,7 @@
 @ stub RtlRevertMemoryStream
 @ stub RtlRunDecodeUnicodeString
 @ stub RtlRunEncodeUnicodeString
+@ stdcall RtlRunOnceExecuteOnce(ptr ptr ptr ptr)
 @ stdcall RtlRunOnceInitialize(ptr)
 @ stdcall RtlSecondsSince1970ToTime(long ptr)
 @ stdcall RtlSecondsSince1980ToTime(long ptr)
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 09151a9..f759ce6 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -1463,8 +1463,3 @@ NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue,
     SERVER_END_REQ;
     return status;
 }
-
-VOID NTAPI RtlRunOnceInitialize(PRTL_RUN_ONCE initonce)
-{
-    initonce->Ptr = NULL;
-}
diff --git a/include/winbase.h b/include/winbase.h
index a6ca4b6..bc765f1 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -1887,6 +1887,7 @@ WINADVAPI  BOOL        WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR,
 WINADVAPI  BOOL        WINAPI InitializeSid(PSID,PSID_IDENTIFIER_AUTHORITY,BYTE);
 WINBASEAPI VOID        WINAPI InitializeSListHead(PSLIST_HEADER);
 WINBASEAPI VOID        WINAPI InitializeSRWLock(PSRWLOCK);
+WINBASEAPI BOOL        WINAPI InitOnceExecuteOnce(PINIT_ONCE,PINIT_ONCE_FN,PVOID,PVOID*);
 WINBASEAPI VOID        WINAPI InitOnceInitialize(PINIT_ONCE);
 WINBASEAPI PSLIST_ENTRY WINAPI InterlockedFlushSList(PSLIST_HEADER);
 WINBASEAPI PSLIST_ENTRY WINAPI InterlockedPopEntrySList(PSLIST_HEADER);
diff --git a/include/winnt.h b/include/winnt.h
index 121b83c..b843517 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -5096,7 +5096,10 @@ typedef union _RTL_RUN_ONCE {
 #define RTL_RUN_ONCE_ASYNC          0x00000002
 #define RTL_RUN_ONCE_INIT_FAILED    0x00000004
 
+typedef DWORD NTAPI RTL_RUN_ONCE_INIT_FN(PRTL_RUN_ONCE, PVOID, PVOID*);
+typedef RTL_RUN_ONCE_INIT_FN *PRTL_RUN_ONCE_INIT_FN;
 NTSYSAPI VOID NTAPI RtlRunOnceInitialize(PRTL_RUN_ONCE);
+NTSYSAPI DWORD NTAPI RtlRunOnceExecuteOnce(PRTL_RUN_ONCE,PRTL_RUN_ONCE_INIT_FN,PVOID,PVOID*);
 
 #include <pshpack8.h>
 typedef struct _IO_COUNTERS {
-- 
1.5.6.5




More information about the wine-patches mailing list