1
2 /* Taken from Wine ntdll/sync.c */
3
4 #include <rtl_vista.h>
5 #include <wine/config.h>
6 #include <wine/port.h>
7
8 /******************************************************************
9 * RtlRunOnceInitialize (NTDLL.@)
10 */
RtlRunOnceInitialize(_Out_ PRTL_RUN_ONCE RunOnce)11 VOID NTAPI RtlRunOnceInitialize(_Out_ PRTL_RUN_ONCE RunOnce)
12 {
13 RunOnce->Ptr = NULL;
14 }
15
16 /******************************************************************
17 * RtlRunOnceBeginInitialize (NTDLL.@)
18 */
19 _Must_inspect_result_
20 NTSTATUS
21 NTAPI
RtlRunOnceBeginInitialize(_Inout_ PRTL_RUN_ONCE RunOnce,_In_ ULONG Flags,_Outptr_opt_result_maybenull_ PVOID * Context)22 RtlRunOnceBeginInitialize(
23 _Inout_ PRTL_RUN_ONCE RunOnce,
24 _In_ ULONG Flags,
25 _Outptr_opt_result_maybenull_ PVOID *Context)
26 {
27 if (Flags & RTL_RUN_ONCE_CHECK_ONLY)
28 {
29 ULONG_PTR val = (ULONG_PTR)RunOnce->Ptr;
30
31 if (Flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
32 if ((val & 3) != 2) return STATUS_UNSUCCESSFUL;
33 if (Context) *Context = (void *)(val & ~3);
34 return STATUS_SUCCESS;
35 }
36
37 for (;;)
38 {
39 ULONG_PTR next, val = (ULONG_PTR)RunOnce->Ptr;
40
41 switch (val & 3)
42 {
43 case 0: /* first time */
44 if (!interlocked_cmpxchg_ptr( &RunOnce->Ptr,
45 (Flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0))
46 return STATUS_PENDING;
47 break;
48
49 case 1: /* in progress, wait */
50 if (Flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
51 next = val & ~3;
52 if (interlocked_cmpxchg_ptr( &RunOnce->Ptr, (void *)((ULONG_PTR)&next | 1),
53 (void *)val ) == (void *)val)
54 NtWaitForKeyedEvent( 0, &next, FALSE, NULL );
55 break;
56
57 case 2: /* done */
58 if (Context) *Context = (void *)(val & ~3);
59 return STATUS_SUCCESS;
60
61 case 3: /* in progress, async */
62 if (!(Flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
63 return STATUS_PENDING;
64 }
65 }
66 }
67
68 /******************************************************************
69 * RtlRunOnceComplete (NTDLL.@)
70 */
71 NTSTATUS
72 NTAPI
RtlRunOnceComplete(_Inout_ PRTL_RUN_ONCE RunOnce,_In_ ULONG Flags,_In_opt_ PVOID Context)73 RtlRunOnceComplete(
74 _Inout_ PRTL_RUN_ONCE RunOnce,
75 _In_ ULONG Flags,
76 _In_opt_ PVOID Context)
77 {
78 if ((ULONG_PTR)Context & 3) return STATUS_INVALID_PARAMETER;
79
80 if (Flags & RTL_RUN_ONCE_INIT_FAILED)
81 {
82 if (Context) return STATUS_INVALID_PARAMETER;
83 if (Flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
84 }
85 else Context = (void *)((ULONG_PTR)Context | 2);
86
87 for (;;)
88 {
89 ULONG_PTR val = (ULONG_PTR)RunOnce->Ptr;
90
91 switch (val & 3)
92 {
93 case 1: /* in progress */
94 if (interlocked_cmpxchg_ptr( &RunOnce->Ptr, Context, (void *)val ) != (void *)val) break;
95 val &= ~3;
96 while (val)
97 {
98 ULONG_PTR next = *(ULONG_PTR *)val;
99 NtReleaseKeyedEvent( 0, (void *)val, FALSE, NULL );
100 val = next;
101 }
102 return STATUS_SUCCESS;
103
104 case 3: /* in progress, async */
105 if (!(Flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
106 if (interlocked_cmpxchg_ptr( &RunOnce->Ptr, Context, (void *)val) != (void *)val) break;
107 return STATUS_SUCCESS;
108
109 default:
110 return STATUS_UNSUCCESSFUL;
111 }
112 }
113 }
114
115 /******************************************************************
116 * RtlRunOnceExecuteOnce (NTDLL.@)
117 */
118 _Maybe_raises_SEH_exception_
119 NTSTATUS
120 NTAPI
RtlRunOnceExecuteOnce(_Inout_ PRTL_RUN_ONCE RunOnce,_In_ __inner_callback PRTL_RUN_ONCE_INIT_FN InitFn,_Inout_opt_ PVOID Parameter,_Outptr_opt_result_maybenull_ PVOID * Context)121 RtlRunOnceExecuteOnce(
122 _Inout_ PRTL_RUN_ONCE RunOnce,
123 _In_ __inner_callback PRTL_RUN_ONCE_INIT_FN InitFn,
124 _Inout_opt_ PVOID Parameter,
125 _Outptr_opt_result_maybenull_ PVOID *Context)
126 {
127 DWORD ret = RtlRunOnceBeginInitialize( RunOnce, 0, Context );
128
129 if (ret != STATUS_PENDING) return ret;
130
131 if (!InitFn( RunOnce, Parameter, Context ))
132 {
133 RtlRunOnceComplete( RunOnce, RTL_RUN_ONCE_INIT_FAILED, NULL );
134 return STATUS_UNSUCCESSFUL;
135 }
136
137 return RtlRunOnceComplete( RunOnce, 0, Context ? *Context : NULL );
138 }
139