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 */ 11 void WINAPI RtlRunOnceInitialize( RTL_RUN_ONCE *once ) 12 { 13 once->Ptr = NULL; 14 } 15 16 /****************************************************************** 17 * RtlRunOnceBeginInitialize (NTDLL.@) 18 */ 19 DWORD WINAPI RtlRunOnceBeginInitialize( RTL_RUN_ONCE *once, ULONG flags, void **context ) 20 { 21 if (flags & RTL_RUN_ONCE_CHECK_ONLY) 22 { 23 ULONG_PTR val = (ULONG_PTR)once->Ptr; 24 25 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER; 26 if ((val & 3) != 2) return STATUS_UNSUCCESSFUL; 27 if (context) *context = (void *)(val & ~3); 28 return STATUS_SUCCESS; 29 } 30 31 for (;;) 32 { 33 ULONG_PTR next, val = (ULONG_PTR)once->Ptr; 34 35 switch (val & 3) 36 { 37 case 0: /* first time */ 38 if (!interlocked_cmpxchg_ptr( &once->Ptr, 39 (flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0 )) 40 return STATUS_PENDING; 41 break; 42 43 case 1: /* in progress, wait */ 44 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER; 45 next = val & ~3; 46 if (interlocked_cmpxchg_ptr( &once->Ptr, (void *)((ULONG_PTR)&next | 1), 47 (void *)val ) == (void *)val) 48 NtWaitForKeyedEvent( 0, &next, FALSE, NULL ); 49 break; 50 51 case 2: /* done */ 52 if (context) *context = (void *)(val & ~3); 53 return STATUS_SUCCESS; 54 55 case 3: /* in progress, async */ 56 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER; 57 return STATUS_PENDING; 58 } 59 } 60 } 61 62 /****************************************************************** 63 * RtlRunOnceComplete (NTDLL.@) 64 */ 65 DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context ) 66 { 67 if ((ULONG_PTR)context & 3) return STATUS_INVALID_PARAMETER; 68 69 if (flags & RTL_RUN_ONCE_INIT_FAILED) 70 { 71 if (context) return STATUS_INVALID_PARAMETER; 72 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER; 73 } 74 else context = (void *)((ULONG_PTR)context | 2); 75 76 for (;;) 77 { 78 ULONG_PTR val = (ULONG_PTR)once->Ptr; 79 80 switch (val & 3) 81 { 82 case 1: /* in progress */ 83 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break; 84 val &= ~3; 85 while (val) 86 { 87 ULONG_PTR next = *(ULONG_PTR *)val; 88 NtReleaseKeyedEvent( 0, (void *)val, FALSE, NULL ); 89 val = next; 90 } 91 return STATUS_SUCCESS; 92 93 case 3: /* in progress, async */ 94 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER; 95 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break; 96 return STATUS_SUCCESS; 97 98 default: 99 return STATUS_UNSUCCESSFUL; 100 } 101 } 102 } 103 104 /****************************************************************** 105 * RtlRunOnceExecuteOnce (NTDLL.@) 106 */ 107 DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN func, 108 void *param, void **context ) 109 { 110 DWORD ret = RtlRunOnceBeginInitialize( once, 0, context ); 111 112 if (ret != STATUS_PENDING) return ret; 113 114 if (!func( once, param, context )) 115 { 116 RtlRunOnceComplete( once, RTL_RUN_ONCE_INIT_FAILED, NULL ); 117 return STATUS_UNSUCCESSFUL; 118 } 119 120 return RtlRunOnceComplete( once, 0, context ? *context : NULL ); 121 } 122