Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
/* Taken from Wine ntdll/sync.c */
#include <rtl_vista.h>#include <wine/config.h>#include <wine/port.h>
/****************************************************************** * RtlRunOnceInitialize (NTDLL.@) */VOID NTAPI RtlRunOnceInitialize(_Out_ PRTL_RUN_ONCE RunOnce){ RunOnce->Ptr = NULL;}
/****************************************************************** * RtlRunOnceBeginInitialize (NTDLL.@) */_Must_inspect_result_NTSTATUSNTAPIRtlRunOnceBeginInitialize( _Inout_ PRTL_RUN_ONCE RunOnce, _In_ ULONG Flags, _Outptr_opt_result_maybenull_ PVOID *Context){ if (Flags & RTL_RUN_ONCE_CHECK_ONLY) { ULONG_PTR val = (ULONG_PTR)RunOnce->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)RunOnce->Ptr;
switch (val & 3) { case 0: /* first time */ if (!interlocked_cmpxchg_ptr( &RunOnce->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( &RunOnce->Ptr, (void *)((ULONG_PTR)&next | 1), (void *)val ) == (void *)val) NtWaitForKeyedEvent( 0, &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.@) */NTSTATUSNTAPIRtlRunOnceComplete( _Inout_ PRTL_RUN_ONCE RunOnce, _In_ ULONG Flags, _In_opt_ PVOID 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)RunOnce->Ptr;
switch (val & 3) { case 1: /* in progress */ if (interlocked_cmpxchg_ptr( &RunOnce->Ptr, Context, (void *)val ) != (void *)val) break; val &= ~3; while (val) { ULONG_PTR next = *(ULONG_PTR *)val; NtReleaseKeyedEvent( 0, (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( &RunOnce->Ptr, Context, (void *)val) != (void *)val) break; return STATUS_SUCCESS;
default: return STATUS_UNSUCCESSFUL; } }}
/****************************************************************** * RtlRunOnceExecuteOnce (NTDLL.@) */_Maybe_raises_SEH_exception_NTSTATUSNTAPIRtlRunOnceExecuteOnce( _Inout_ PRTL_RUN_ONCE RunOnce, _In_ __inner_callback PRTL_RUN_ONCE_INIT_FN InitFn, _Inout_opt_ PVOID Parameter, _Outptr_opt_result_maybenull_ PVOID *Context){ DWORD ret = RtlRunOnceBeginInitialize( RunOnce, 0, Context );
if (ret != STATUS_PENDING) return ret;
if (!InitFn( RunOnce, Parameter, Context )) { RtlRunOnceComplete( RunOnce, RTL_RUN_ONCE_INIT_FAILED, NULL ); return STATUS_UNSUCCESSFUL; }
return RtlRunOnceComplete( RunOnce, 0, Context ? *Context : NULL );}