[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