wined3d: Support getdc with user memory.
[wine.git] / dlls / ntdll / sync.c
blobaf1dba92c401f8a4f83c253241c6fe1b938713a3
1 /*
2 * Process synchronisation
4 * Copyright 1996, 1997, 1998 Marcus Meissner
5 * Copyright 1997, 1999 Alexandre Julliard
6 * Copyright 1999, 2000 Juergen Schmied
7 * Copyright 2003 Eric Pouech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <assert.h>
28 #include <errno.h>
29 #include <signal.h>
30 #ifdef HAVE_SYS_TIME_H
31 # include <sys/time.h>
32 #endif
33 #ifdef HAVE_POLL_H
34 #include <poll.h>
35 #endif
36 #ifdef HAVE_SYS_POLL_H
37 # include <sys/poll.h>
38 #endif
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
42 #ifdef HAVE_SCHED_H
43 # include <sched.h>
44 #endif
45 #include <string.h>
46 #include <stdarg.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <time.h>
51 #define NONAMELESSUNION
52 #define NONAMELESSSTRUCT
54 #include "ntstatus.h"
55 #define WIN32_NO_STATUS
56 #include "windef.h"
57 #include "winternl.h"
58 #include "wine/server.h"
59 #include "wine/debug.h"
60 #include "ntdll_misc.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
64 HANDLE keyed_event = NULL;
66 /* creates a struct security_descriptor and contained information in one contiguous piece of memory */
67 NTSTATUS NTDLL_create_struct_sd(PSECURITY_DESCRIPTOR nt_sd, struct security_descriptor **server_sd,
68 data_size_t *server_sd_len)
70 unsigned int len;
71 PSID owner, group;
72 ACL *dacl, *sacl;
73 BOOLEAN owner_present, group_present, dacl_present, sacl_present;
74 BOOLEAN defaulted;
75 NTSTATUS status;
76 unsigned char *ptr;
78 if (!nt_sd)
80 *server_sd = NULL;
81 *server_sd_len = 0;
82 return STATUS_SUCCESS;
85 len = sizeof(struct security_descriptor);
87 status = RtlGetOwnerSecurityDescriptor(nt_sd, &owner, &owner_present);
88 if (status != STATUS_SUCCESS) return status;
89 status = RtlGetGroupSecurityDescriptor(nt_sd, &group, &group_present);
90 if (status != STATUS_SUCCESS) return status;
91 status = RtlGetSaclSecurityDescriptor(nt_sd, &sacl_present, &sacl, &defaulted);
92 if (status != STATUS_SUCCESS) return status;
93 status = RtlGetDaclSecurityDescriptor(nt_sd, &dacl_present, &dacl, &defaulted);
94 if (status != STATUS_SUCCESS) return status;
96 if (owner_present)
97 len += RtlLengthSid(owner);
98 if (group_present)
99 len += RtlLengthSid(group);
100 if (sacl_present && sacl)
101 len += sacl->AclSize;
102 if (dacl_present && dacl)
103 len += dacl->AclSize;
105 /* fix alignment for the Unicode name that follows the structure */
106 len = (len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
107 *server_sd = RtlAllocateHeap(GetProcessHeap(), 0, len);
108 if (!*server_sd) return STATUS_NO_MEMORY;
110 (*server_sd)->control = ((SECURITY_DESCRIPTOR *)nt_sd)->Control & ~SE_SELF_RELATIVE;
111 (*server_sd)->owner_len = owner_present ? RtlLengthSid(owner) : 0;
112 (*server_sd)->group_len = group_present ? RtlLengthSid(group) : 0;
113 (*server_sd)->sacl_len = (sacl_present && sacl) ? sacl->AclSize : 0;
114 (*server_sd)->dacl_len = (dacl_present && dacl) ? dacl->AclSize : 0;
116 ptr = (unsigned char *)(*server_sd + 1);
117 memcpy(ptr, owner, (*server_sd)->owner_len);
118 ptr += (*server_sd)->owner_len;
119 memcpy(ptr, group, (*server_sd)->group_len);
120 ptr += (*server_sd)->group_len;
121 memcpy(ptr, sacl, (*server_sd)->sacl_len);
122 ptr += (*server_sd)->sacl_len;
123 memcpy(ptr, dacl, (*server_sd)->dacl_len);
125 *server_sd_len = len;
127 return STATUS_SUCCESS;
130 /* frees a struct security_descriptor allocated by NTDLL_create_struct_sd */
131 void NTDLL_free_struct_sd(struct security_descriptor *server_sd)
133 RtlFreeHeap(GetProcessHeap(), 0, server_sd);
137 * Semaphores
140 /******************************************************************************
141 * NtCreateSemaphore (NTDLL.@)
143 NTSTATUS WINAPI NtCreateSemaphore( OUT PHANDLE SemaphoreHandle,
144 IN ACCESS_MASK access,
145 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
146 IN LONG InitialCount,
147 IN LONG MaximumCount )
149 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
150 NTSTATUS ret;
151 struct object_attributes objattr;
152 struct security_descriptor *sd = NULL;
154 if (MaximumCount <= 0 || InitialCount < 0 || InitialCount > MaximumCount)
155 return STATUS_INVALID_PARAMETER;
156 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
158 objattr.rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
159 objattr.sd_len = 0;
160 objattr.name_len = len;
161 if (attr)
163 ret = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
164 if (ret != STATUS_SUCCESS) return ret;
167 SERVER_START_REQ( create_semaphore )
169 req->access = access;
170 req->attributes = (attr) ? attr->Attributes : 0;
171 req->initial = InitialCount;
172 req->max = MaximumCount;
173 wine_server_add_data( req, &objattr, sizeof(objattr) );
174 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
175 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
176 ret = wine_server_call( req );
177 *SemaphoreHandle = wine_server_ptr_handle( reply->handle );
179 SERVER_END_REQ;
181 NTDLL_free_struct_sd( sd );
183 return ret;
186 /******************************************************************************
187 * NtOpenSemaphore (NTDLL.@)
189 NTSTATUS WINAPI NtOpenSemaphore( OUT PHANDLE SemaphoreHandle,
190 IN ACCESS_MASK access,
191 IN const OBJECT_ATTRIBUTES *attr )
193 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
194 NTSTATUS ret;
196 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
198 SERVER_START_REQ( open_semaphore )
200 req->access = access;
201 req->attributes = (attr) ? attr->Attributes : 0;
202 req->rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
203 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
204 ret = wine_server_call( req );
205 *SemaphoreHandle = wine_server_ptr_handle( reply->handle );
207 SERVER_END_REQ;
208 return ret;
211 /******************************************************************************
212 * NtQuerySemaphore (NTDLL.@)
214 NTSTATUS WINAPI NtQuerySemaphore(
215 HANDLE SemaphoreHandle,
216 SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass,
217 PVOID SemaphoreInformation,
218 ULONG Length,
219 PULONG ReturnLength)
221 FIXME("(%p,%d,%p,0x%08x,%p) stub!\n",
222 SemaphoreHandle, SemaphoreInformationClass, SemaphoreInformation, Length, ReturnLength);
223 return STATUS_SUCCESS;
226 /******************************************************************************
227 * NtReleaseSemaphore (NTDLL.@)
229 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
231 NTSTATUS ret;
232 SERVER_START_REQ( release_semaphore )
234 req->handle = wine_server_obj_handle( handle );
235 req->count = count;
236 if (!(ret = wine_server_call( req )))
238 if (previous) *previous = reply->prev_count;
241 SERVER_END_REQ;
242 return ret;
246 * Events
249 /**************************************************************************
250 * NtCreateEvent (NTDLL.@)
251 * ZwCreateEvent (NTDLL.@)
253 NTSTATUS WINAPI NtCreateEvent( PHANDLE EventHandle, ACCESS_MASK DesiredAccess,
254 const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN InitialState)
256 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
257 NTSTATUS ret;
258 struct security_descriptor *sd = NULL;
259 struct object_attributes objattr;
261 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
263 objattr.rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
264 objattr.sd_len = 0;
265 objattr.name_len = len;
266 if (attr)
268 ret = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
269 if (ret != STATUS_SUCCESS) return ret;
272 SERVER_START_REQ( create_event )
274 req->access = DesiredAccess;
275 req->attributes = (attr) ? attr->Attributes : 0;
276 req->manual_reset = (type == NotificationEvent);
277 req->initial_state = InitialState;
278 wine_server_add_data( req, &objattr, sizeof(objattr) );
279 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
280 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
281 ret = wine_server_call( req );
282 *EventHandle = wine_server_ptr_handle( reply->handle );
284 SERVER_END_REQ;
286 NTDLL_free_struct_sd( sd );
288 return ret;
291 /******************************************************************************
292 * NtOpenEvent (NTDLL.@)
293 * ZwOpenEvent (NTDLL.@)
295 NTSTATUS WINAPI NtOpenEvent(
296 OUT PHANDLE EventHandle,
297 IN ACCESS_MASK DesiredAccess,
298 IN const OBJECT_ATTRIBUTES *attr )
300 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
301 NTSTATUS ret;
303 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
305 SERVER_START_REQ( open_event )
307 req->access = DesiredAccess;
308 req->attributes = (attr) ? attr->Attributes : 0;
309 req->rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
310 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
311 ret = wine_server_call( req );
312 *EventHandle = wine_server_ptr_handle( reply->handle );
314 SERVER_END_REQ;
315 return ret;
319 /******************************************************************************
320 * NtSetEvent (NTDLL.@)
321 * ZwSetEvent (NTDLL.@)
323 NTSTATUS WINAPI NtSetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
325 NTSTATUS ret;
327 /* FIXME: set NumberOfThreadsReleased */
329 SERVER_START_REQ( event_op )
331 req->handle = wine_server_obj_handle( handle );
332 req->op = SET_EVENT;
333 ret = wine_server_call( req );
335 SERVER_END_REQ;
336 return ret;
339 /******************************************************************************
340 * NtResetEvent (NTDLL.@)
342 NTSTATUS WINAPI NtResetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
344 NTSTATUS ret;
346 /* resetting an event can't release any thread... */
347 if (NumberOfThreadsReleased) *NumberOfThreadsReleased = 0;
349 SERVER_START_REQ( event_op )
351 req->handle = wine_server_obj_handle( handle );
352 req->op = RESET_EVENT;
353 ret = wine_server_call( req );
355 SERVER_END_REQ;
356 return ret;
359 /******************************************************************************
360 * NtClearEvent (NTDLL.@)
362 * FIXME
363 * same as NtResetEvent ???
365 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
367 return NtResetEvent( handle, NULL );
370 /******************************************************************************
371 * NtPulseEvent (NTDLL.@)
373 * FIXME
374 * PulseCount
376 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, PULONG PulseCount )
378 NTSTATUS ret;
380 if (PulseCount)
381 FIXME("(%p,%d)\n", handle, *PulseCount);
383 SERVER_START_REQ( event_op )
385 req->handle = wine_server_obj_handle( handle );
386 req->op = PULSE_EVENT;
387 ret = wine_server_call( req );
389 SERVER_END_REQ;
390 return ret;
393 /******************************************************************************
394 * NtQueryEvent (NTDLL.@)
396 NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class,
397 void *info, ULONG len, ULONG *ret_len )
399 NTSTATUS ret;
400 EVENT_BASIC_INFORMATION *out = info;
402 if (class != EventBasicInformation)
404 FIXME("(%p, %d, %d) Unknown class\n",
405 handle, class, len);
406 return STATUS_INVALID_INFO_CLASS;
409 if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
411 SERVER_START_REQ( query_event )
413 req->handle = wine_server_obj_handle( handle );
414 if (!(ret = wine_server_call( req )))
416 out->EventType = reply->manual_reset ? NotificationEvent : SynchronizationEvent;
417 out->EventState = reply->state;
418 if (ret_len) *ret_len = sizeof(EVENT_BASIC_INFORMATION);
421 SERVER_END_REQ;
423 return ret;
427 * Mutants (known as Mutexes in Kernel32)
430 /******************************************************************************
431 * NtCreateMutant [NTDLL.@]
432 * ZwCreateMutant [NTDLL.@]
434 NTSTATUS WINAPI NtCreateMutant(OUT HANDLE* MutantHandle,
435 IN ACCESS_MASK access,
436 IN const OBJECT_ATTRIBUTES* attr OPTIONAL,
437 IN BOOLEAN InitialOwner)
439 NTSTATUS status;
440 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
441 struct security_descriptor *sd = NULL;
442 struct object_attributes objattr;
444 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
446 objattr.rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
447 objattr.sd_len = 0;
448 objattr.name_len = len;
449 if (attr)
451 status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
452 if (status != STATUS_SUCCESS) return status;
455 SERVER_START_REQ( create_mutex )
457 req->access = access;
458 req->attributes = (attr) ? attr->Attributes : 0;
459 req->owned = InitialOwner;
460 wine_server_add_data( req, &objattr, sizeof(objattr) );
461 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
462 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
463 status = wine_server_call( req );
464 *MutantHandle = wine_server_ptr_handle( reply->handle );
466 SERVER_END_REQ;
468 NTDLL_free_struct_sd( sd );
470 return status;
473 /**************************************************************************
474 * NtOpenMutant [NTDLL.@]
475 * ZwOpenMutant [NTDLL.@]
477 NTSTATUS WINAPI NtOpenMutant(OUT HANDLE* MutantHandle,
478 IN ACCESS_MASK access,
479 IN const OBJECT_ATTRIBUTES* attr )
481 NTSTATUS status;
482 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
484 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
486 SERVER_START_REQ( open_mutex )
488 req->access = access;
489 req->attributes = (attr) ? attr->Attributes : 0;
490 req->rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
491 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
492 status = wine_server_call( req );
493 *MutantHandle = wine_server_ptr_handle( reply->handle );
495 SERVER_END_REQ;
496 return status;
499 /**************************************************************************
500 * NtReleaseMutant [NTDLL.@]
501 * ZwReleaseMutant [NTDLL.@]
503 NTSTATUS WINAPI NtReleaseMutant( IN HANDLE handle, OUT PLONG prev_count OPTIONAL)
505 NTSTATUS status;
507 SERVER_START_REQ( release_mutex )
509 req->handle = wine_server_obj_handle( handle );
510 status = wine_server_call( req );
511 if (prev_count) *prev_count = reply->prev_count;
513 SERVER_END_REQ;
514 return status;
517 /******************************************************************
518 * NtQueryMutant [NTDLL.@]
519 * ZwQueryMutant [NTDLL.@]
521 NTSTATUS WINAPI NtQueryMutant(IN HANDLE handle,
522 IN MUTANT_INFORMATION_CLASS MutantInformationClass,
523 OUT PVOID MutantInformation,
524 IN ULONG MutantInformationLength,
525 OUT PULONG ResultLength OPTIONAL )
527 FIXME("(%p %u %p %u %p): stub!\n",
528 handle, MutantInformationClass, MutantInformation, MutantInformationLength, ResultLength);
529 return STATUS_NOT_IMPLEMENTED;
533 * Jobs
536 /******************************************************************************
537 * NtCreateJobObject [NTDLL.@]
538 * ZwCreateJobObject [NTDLL.@]
540 NTSTATUS WINAPI NtCreateJobObject( PHANDLE handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
542 FIXME( "stub: %p %x %s\n", handle, access, attr ? debugstr_us(attr->ObjectName) : "" );
543 *handle = (HANDLE)0xdead;
544 return STATUS_SUCCESS;
547 /******************************************************************************
548 * NtOpenJobObject [NTDLL.@]
549 * ZwOpenJobObject [NTDLL.@]
551 NTSTATUS WINAPI NtOpenJobObject( PHANDLE handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
553 FIXME( "stub: %p %x %s\n", handle, access, attr ? debugstr_us(attr->ObjectName) : "" );
554 return STATUS_NOT_IMPLEMENTED;
557 /******************************************************************************
558 * NtTerminateJobObject [NTDLL.@]
559 * ZwTerminateJobObject [NTDLL.@]
561 NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status )
563 FIXME( "stub: %p %x\n", handle, status );
564 return STATUS_SUCCESS;
567 /******************************************************************************
568 * NtQueryInformationJobObject [NTDLL.@]
569 * ZwQueryInformationJobObject [NTDLL.@]
571 NTSTATUS WINAPI NtQueryInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info,
572 ULONG len, PULONG ret_len )
574 FIXME( "stub: %p %u %p %u %p\n", handle, class, info, len, ret_len );
575 return STATUS_NOT_IMPLEMENTED;
578 /******************************************************************************
579 * NtSetInformationJobObject [NTDLL.@]
580 * ZwSetInformationJobObject [NTDLL.@]
582 NTSTATUS WINAPI NtSetInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info, ULONG len )
584 FIXME( "stub: %p %u %p %u\n", handle, class, info, len );
585 return STATUS_SUCCESS;
588 /******************************************************************************
589 * NtIsProcessInJob [NTDLL.@]
590 * ZwIsProcessInJob [NTDLL.@]
592 NTSTATUS WINAPI NtIsProcessInJob( HANDLE process, HANDLE job )
594 FIXME( "stub: %p %p\n", process, job );
595 return STATUS_PROCESS_NOT_IN_JOB;
598 /******************************************************************************
599 * NtAssignProcessToJobObject [NTDLL.@]
600 * ZwAssignProcessToJobObject [NTDLL.@]
602 NTSTATUS WINAPI NtAssignProcessToJobObject( HANDLE job, HANDLE process )
604 FIXME( "stub: %p %p\n", job, process );
605 return STATUS_SUCCESS;
609 * Timers
612 /**************************************************************************
613 * NtCreateTimer [NTDLL.@]
614 * ZwCreateTimer [NTDLL.@]
616 NTSTATUS WINAPI NtCreateTimer(OUT HANDLE *handle,
617 IN ACCESS_MASK access,
618 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
619 IN TIMER_TYPE timer_type)
621 DWORD len = (attr && attr->ObjectName) ? attr->ObjectName->Length : 0;
622 NTSTATUS status;
624 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
626 if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
627 return STATUS_INVALID_PARAMETER;
629 SERVER_START_REQ( create_timer )
631 req->access = access;
632 req->attributes = (attr) ? attr->Attributes : 0;
633 req->rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
634 req->manual = (timer_type == NotificationTimer) ? TRUE : FALSE;
635 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
636 status = wine_server_call( req );
637 *handle = wine_server_ptr_handle( reply->handle );
639 SERVER_END_REQ;
640 return status;
644 /**************************************************************************
645 * NtOpenTimer [NTDLL.@]
646 * ZwOpenTimer [NTDLL.@]
648 NTSTATUS WINAPI NtOpenTimer(OUT PHANDLE handle,
649 IN ACCESS_MASK access,
650 IN const OBJECT_ATTRIBUTES* attr )
652 DWORD len = (attr && attr->ObjectName) ? attr->ObjectName->Length : 0;
653 NTSTATUS status;
655 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
657 SERVER_START_REQ( open_timer )
659 req->access = access;
660 req->attributes = (attr) ? attr->Attributes : 0;
661 req->rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
662 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
663 status = wine_server_call( req );
664 *handle = wine_server_ptr_handle( reply->handle );
666 SERVER_END_REQ;
667 return status;
670 /**************************************************************************
671 * NtSetTimer [NTDLL.@]
672 * ZwSetTimer [NTDLL.@]
674 NTSTATUS WINAPI NtSetTimer(IN HANDLE handle,
675 IN const LARGE_INTEGER* when,
676 IN PTIMER_APC_ROUTINE callback,
677 IN PVOID callback_arg,
678 IN BOOLEAN resume,
679 IN ULONG period OPTIONAL,
680 OUT PBOOLEAN state OPTIONAL)
682 NTSTATUS status = STATUS_SUCCESS;
684 TRACE("(%p,%p,%p,%p,%08x,0x%08x,%p) stub\n",
685 handle, when, callback, callback_arg, resume, period, state);
687 SERVER_START_REQ( set_timer )
689 req->handle = wine_server_obj_handle( handle );
690 req->period = period;
691 req->expire = when->QuadPart;
692 req->callback = wine_server_client_ptr( callback );
693 req->arg = wine_server_client_ptr( callback_arg );
694 status = wine_server_call( req );
695 if (state) *state = reply->signaled;
697 SERVER_END_REQ;
699 /* set error but can still succeed */
700 if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
701 return status;
704 /**************************************************************************
705 * NtCancelTimer [NTDLL.@]
706 * ZwCancelTimer [NTDLL.@]
708 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
710 NTSTATUS status;
712 SERVER_START_REQ( cancel_timer )
714 req->handle = wine_server_obj_handle( handle );
715 status = wine_server_call( req );
716 if (state) *state = reply->signaled;
718 SERVER_END_REQ;
719 return status;
722 /******************************************************************************
723 * NtQueryTimer (NTDLL.@)
725 * Retrieves information about a timer.
727 * PARAMS
728 * TimerHandle [I] The timer to retrieve information about.
729 * TimerInformationClass [I] The type of information to retrieve.
730 * TimerInformation [O] Pointer to buffer to store information in.
731 * Length [I] The length of the buffer pointed to by TimerInformation.
732 * ReturnLength [O] Optional. The size of buffer actually used.
734 * RETURNS
735 * Success: STATUS_SUCCESS
736 * Failure: STATUS_INFO_LENGTH_MISMATCH, if Length doesn't match the required data
737 * size for the class specified.
738 * STATUS_INVALID_INFO_CLASS, if an invalid TimerInformationClass was specified.
739 * STATUS_ACCESS_DENIED, if TimerHandle does not have TIMER_QUERY_STATE access
740 * to the timer.
742 NTSTATUS WINAPI NtQueryTimer(
743 HANDLE TimerHandle,
744 TIMER_INFORMATION_CLASS TimerInformationClass,
745 PVOID TimerInformation,
746 ULONG Length,
747 PULONG ReturnLength)
749 TIMER_BASIC_INFORMATION * basic_info = TimerInformation;
750 NTSTATUS status;
751 LARGE_INTEGER now;
753 TRACE("(%p,%d,%p,0x%08x,%p)\n", TimerHandle, TimerInformationClass,
754 TimerInformation, Length, ReturnLength);
756 switch (TimerInformationClass)
758 case TimerBasicInformation:
759 if (Length < sizeof(TIMER_BASIC_INFORMATION))
760 return STATUS_INFO_LENGTH_MISMATCH;
762 SERVER_START_REQ(get_timer_info)
764 req->handle = wine_server_obj_handle( TimerHandle );
765 status = wine_server_call(req);
767 /* convert server time to absolute NTDLL time */
768 basic_info->RemainingTime.QuadPart = reply->when;
769 basic_info->TimerState = reply->signaled;
771 SERVER_END_REQ;
773 /* convert from absolute into relative time */
774 NtQuerySystemTime(&now);
775 if (now.QuadPart > basic_info->RemainingTime.QuadPart)
776 basic_info->RemainingTime.QuadPart = 0;
777 else
778 basic_info->RemainingTime.QuadPart -= now.QuadPart;
780 if (ReturnLength) *ReturnLength = sizeof(TIMER_BASIC_INFORMATION);
782 return status;
785 FIXME("Unhandled class %d\n", TimerInformationClass);
786 return STATUS_INVALID_INFO_CLASS;
790 /******************************************************************************
791 * NtQueryTimerResolution [NTDLL.@]
793 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
794 OUT ULONG* max_resolution,
795 OUT ULONG* current_resolution)
797 FIXME("(%p,%p,%p), stub!\n",
798 min_resolution, max_resolution, current_resolution);
800 return STATUS_NOT_IMPLEMENTED;
803 /******************************************************************************
804 * NtSetTimerResolution [NTDLL.@]
806 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
807 IN BOOLEAN set_resolution,
808 OUT ULONG* current_resolution )
810 FIXME("(%u,%u,%p), stub!\n",
811 resolution, set_resolution, current_resolution);
813 return STATUS_NOT_IMPLEMENTED;
818 /* wait operations */
820 /******************************************************************
821 * NtWaitForMultipleObjects (NTDLL.@)
823 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
824 BOOLEAN wait_all, BOOLEAN alertable,
825 const LARGE_INTEGER *timeout )
827 select_op_t select_op;
828 UINT i, flags = SELECT_INTERRUPTIBLE;
830 if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
832 if (alertable) flags |= SELECT_ALERTABLE;
833 select_op.wait.op = wait_all ? SELECT_WAIT_ALL : SELECT_WAIT;
834 for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] );
835 return server_select( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout );
839 /******************************************************************
840 * NtWaitForSingleObject (NTDLL.@)
842 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
844 return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );
848 /******************************************************************
849 * NtSignalAndWaitForSingleObject (NTDLL.@)
851 NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE hSignalObject, HANDLE hWaitObject,
852 BOOLEAN alertable, const LARGE_INTEGER *timeout )
854 select_op_t select_op;
855 UINT flags = SELECT_INTERRUPTIBLE;
857 if (!hSignalObject) return STATUS_INVALID_HANDLE;
859 if (alertable) flags |= SELECT_ALERTABLE;
860 select_op.signal_and_wait.op = SELECT_SIGNAL_AND_WAIT;
861 select_op.signal_and_wait.wait = wine_server_obj_handle( hWaitObject );
862 select_op.signal_and_wait.signal = wine_server_obj_handle( hSignalObject );
863 return server_select( &select_op, sizeof(select_op.signal_and_wait), flags, timeout );
867 /******************************************************************
868 * NtYieldExecution (NTDLL.@)
870 NTSTATUS WINAPI NtYieldExecution(void)
872 #ifdef HAVE_SCHED_YIELD
873 sched_yield();
874 return STATUS_SUCCESS;
875 #else
876 return STATUS_NO_YIELD_PERFORMED;
877 #endif
881 /******************************************************************
882 * NtDelayExecution (NTDLL.@)
884 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
886 /* if alertable, we need to query the server */
887 if (alertable)
888 return server_select( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout );
890 if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */
892 for (;;) select( 0, NULL, NULL, NULL, NULL );
894 else
896 LARGE_INTEGER now;
897 timeout_t when, diff;
899 if ((when = timeout->QuadPart) < 0)
901 NtQuerySystemTime( &now );
902 when = now.QuadPart - when;
905 /* Note that we yield after establishing the desired timeout */
906 NtYieldExecution();
907 if (!when) return STATUS_SUCCESS;
909 for (;;)
911 struct timeval tv;
912 NtQuerySystemTime( &now );
913 diff = (when - now.QuadPart + 9) / 10;
914 if (diff <= 0) break;
915 tv.tv_sec = diff / 1000000;
916 tv.tv_usec = diff % 1000000;
917 if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
920 return STATUS_SUCCESS;
924 /******************************************************************************
925 * NtCreateKeyedEvent (NTDLL.@)
927 NTSTATUS WINAPI NtCreateKeyedEvent( HANDLE *handle, ACCESS_MASK access,
928 const OBJECT_ATTRIBUTES *attr, ULONG flags )
930 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
931 NTSTATUS ret;
932 struct security_descriptor *sd = NULL;
933 struct object_attributes objattr;
935 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
937 objattr.rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
938 objattr.sd_len = 0;
939 objattr.name_len = len;
940 if (attr)
942 ret = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
943 if (ret != STATUS_SUCCESS) return ret;
946 SERVER_START_REQ( create_keyed_event )
948 req->access = access;
949 req->attributes = attr ? attr->Attributes : 0;
950 wine_server_add_data( req, &objattr, sizeof(objattr) );
951 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
952 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
953 ret = wine_server_call( req );
954 *handle = wine_server_ptr_handle( reply->handle );
956 SERVER_END_REQ;
958 NTDLL_free_struct_sd( sd );
959 return ret;
962 /******************************************************************************
963 * NtOpenKeyedEvent (NTDLL.@)
965 NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
967 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
968 NTSTATUS ret;
970 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
972 SERVER_START_REQ( open_keyed_event )
974 req->access = access;
975 req->attributes = attr ? attr->Attributes : 0;
976 req->rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
977 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
978 ret = wine_server_call( req );
979 *handle = wine_server_ptr_handle( reply->handle );
981 SERVER_END_REQ;
982 return ret;
985 /******************************************************************************
986 * NtWaitForKeyedEvent (NTDLL.@)
988 NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
989 BOOLEAN alertable, const LARGE_INTEGER *timeout )
991 select_op_t select_op;
992 UINT flags = SELECT_INTERRUPTIBLE;
994 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
995 if (alertable) flags |= SELECT_ALERTABLE;
996 select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT;
997 select_op.keyed_event.handle = wine_server_obj_handle( handle );
998 select_op.keyed_event.key = wine_server_client_ptr( key );
999 return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1002 /******************************************************************************
1003 * NtReleaseKeyedEvent (NTDLL.@)
1005 NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key,
1006 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1008 select_op_t select_op;
1009 UINT flags = SELECT_INTERRUPTIBLE;
1011 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1012 if (alertable) flags |= SELECT_ALERTABLE;
1013 select_op.keyed_event.op = SELECT_KEYED_EVENT_RELEASE;
1014 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1015 select_op.keyed_event.key = wine_server_client_ptr( key );
1016 return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1019 /******************************************************************
1020 * NtCreateIoCompletion (NTDLL.@)
1021 * ZwCreateIoCompletion (NTDLL.@)
1023 * Creates I/O completion object.
1025 * PARAMS
1026 * CompletionPort [O] created completion object handle will be placed there
1027 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1028 * ObjectAttributes [I] completion object attributes
1029 * NumberOfConcurrentThreads [I] desired number of concurrent active worker threads
1032 NTSTATUS WINAPI NtCreateIoCompletion( PHANDLE CompletionPort, ACCESS_MASK DesiredAccess,
1033 POBJECT_ATTRIBUTES ObjectAttributes, ULONG NumberOfConcurrentThreads )
1035 NTSTATUS status;
1037 TRACE("(%p, %x, %p, %d)\n", CompletionPort, DesiredAccess,
1038 ObjectAttributes, NumberOfConcurrentThreads);
1040 if (!CompletionPort)
1041 return STATUS_INVALID_PARAMETER;
1043 SERVER_START_REQ( create_completion )
1045 req->access = DesiredAccess;
1046 req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0;
1047 req->rootdir = wine_server_obj_handle( ObjectAttributes ? ObjectAttributes->RootDirectory : 0 );
1048 req->concurrent = NumberOfConcurrentThreads;
1049 if (ObjectAttributes && ObjectAttributes->ObjectName)
1050 wine_server_add_data( req, ObjectAttributes->ObjectName->Buffer,
1051 ObjectAttributes->ObjectName->Length );
1052 if (!(status = wine_server_call( req )))
1053 *CompletionPort = wine_server_ptr_handle( reply->handle );
1055 SERVER_END_REQ;
1056 return status;
1059 /******************************************************************
1060 * NtSetIoCompletion (NTDLL.@)
1061 * ZwSetIoCompletion (NTDLL.@)
1063 * Inserts completion message into queue
1065 * PARAMS
1066 * CompletionPort [I] HANDLE to completion object
1067 * CompletionKey [I] completion key
1068 * CompletionValue [I] completion value (usually pointer to OVERLAPPED)
1069 * Status [I] operation status
1070 * NumberOfBytesTransferred [I] number of bytes transferred
1072 NTSTATUS WINAPI NtSetIoCompletion( HANDLE CompletionPort, ULONG_PTR CompletionKey,
1073 ULONG_PTR CompletionValue, NTSTATUS Status,
1074 SIZE_T NumberOfBytesTransferred )
1076 NTSTATUS status;
1078 TRACE("(%p, %lx, %lx, %x, %lx)\n", CompletionPort, CompletionKey,
1079 CompletionValue, Status, NumberOfBytesTransferred);
1081 SERVER_START_REQ( add_completion )
1083 req->handle = wine_server_obj_handle( CompletionPort );
1084 req->ckey = CompletionKey;
1085 req->cvalue = CompletionValue;
1086 req->status = Status;
1087 req->information = NumberOfBytesTransferred;
1088 status = wine_server_call( req );
1090 SERVER_END_REQ;
1091 return status;
1094 /******************************************************************
1095 * NtRemoveIoCompletion (NTDLL.@)
1096 * ZwRemoveIoCompletion (NTDLL.@)
1098 * (Wait for and) retrieve first completion message from completion object's queue
1100 * PARAMS
1101 * CompletionPort [I] HANDLE to I/O completion object
1102 * CompletionKey [O] completion key
1103 * CompletionValue [O] Completion value given in NtSetIoCompletion or in async operation
1104 * iosb [O] IO_STATUS_BLOCK of completed asynchronous operation
1105 * WaitTime [I] optional wait time in NTDLL format
1108 NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE CompletionPort, PULONG_PTR CompletionKey,
1109 PULONG_PTR CompletionValue, PIO_STATUS_BLOCK iosb,
1110 PLARGE_INTEGER WaitTime )
1112 NTSTATUS status;
1114 TRACE("(%p, %p, %p, %p, %p)\n", CompletionPort, CompletionKey,
1115 CompletionValue, iosb, WaitTime);
1117 for(;;)
1119 SERVER_START_REQ( remove_completion )
1121 req->handle = wine_server_obj_handle( CompletionPort );
1122 if (!(status = wine_server_call( req )))
1124 *CompletionKey = reply->ckey;
1125 *CompletionValue = reply->cvalue;
1126 iosb->Information = reply->information;
1127 iosb->u.Status = reply->status;
1130 SERVER_END_REQ;
1131 if (status != STATUS_PENDING) break;
1133 status = NtWaitForSingleObject( CompletionPort, FALSE, WaitTime );
1134 if (status != WAIT_OBJECT_0) break;
1136 return status;
1139 /******************************************************************
1140 * NtOpenIoCompletion (NTDLL.@)
1141 * ZwOpenIoCompletion (NTDLL.@)
1143 * Opens I/O completion object
1145 * PARAMS
1146 * CompletionPort [O] completion object handle will be placed there
1147 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1148 * ObjectAttributes [I] completion object name
1151 NTSTATUS WINAPI NtOpenIoCompletion( PHANDLE CompletionPort, ACCESS_MASK DesiredAccess,
1152 POBJECT_ATTRIBUTES ObjectAttributes )
1154 NTSTATUS status;
1156 TRACE("(%p, 0x%x, %p)\n", CompletionPort, DesiredAccess, ObjectAttributes);
1158 if (!CompletionPort || !ObjectAttributes || !ObjectAttributes->ObjectName)
1159 return STATUS_INVALID_PARAMETER;
1161 SERVER_START_REQ( open_completion )
1163 req->access = DesiredAccess;
1164 req->rootdir = wine_server_obj_handle( ObjectAttributes->RootDirectory );
1165 wine_server_add_data( req, ObjectAttributes->ObjectName->Buffer,
1166 ObjectAttributes->ObjectName->Length );
1167 if (!(status = wine_server_call( req )))
1168 *CompletionPort = wine_server_ptr_handle( reply->handle );
1170 SERVER_END_REQ;
1171 return status;
1174 /******************************************************************
1175 * NtQueryIoCompletion (NTDLL.@)
1176 * ZwQueryIoCompletion (NTDLL.@)
1178 * Requests information about given I/O completion object
1180 * PARAMS
1181 * CompletionPort [I] HANDLE to completion port to request
1182 * InformationClass [I] information class
1183 * CompletionInformation [O] user-provided buffer for data
1184 * BufferLength [I] buffer length
1185 * RequiredLength [O] required buffer length
1188 NTSTATUS WINAPI NtQueryIoCompletion( HANDLE CompletionPort, IO_COMPLETION_INFORMATION_CLASS InformationClass,
1189 PVOID CompletionInformation, ULONG BufferLength, PULONG RequiredLength )
1191 NTSTATUS status;
1193 TRACE("(%p, %d, %p, 0x%x, %p)\n", CompletionPort, InformationClass, CompletionInformation,
1194 BufferLength, RequiredLength);
1196 if (!CompletionInformation) return STATUS_INVALID_PARAMETER;
1197 switch( InformationClass )
1199 case IoCompletionBasicInformation:
1201 ULONG *info = CompletionInformation;
1203 if (RequiredLength) *RequiredLength = sizeof(*info);
1204 if (BufferLength != sizeof(*info))
1205 status = STATUS_INFO_LENGTH_MISMATCH;
1206 else
1208 SERVER_START_REQ( query_completion )
1210 req->handle = wine_server_obj_handle( CompletionPort );
1211 if (!(status = wine_server_call( req )))
1212 *info = reply->depth;
1214 SERVER_END_REQ;
1217 break;
1218 default:
1219 status = STATUS_INVALID_PARAMETER;
1220 break;
1222 return status;
1225 NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue,
1226 NTSTATUS CompletionStatus, ULONG Information )
1228 NTSTATUS status;
1230 SERVER_START_REQ( add_fd_completion )
1232 req->handle = wine_server_obj_handle( hFile );
1233 req->cvalue = CompletionValue;
1234 req->status = CompletionStatus;
1235 req->information = Information;
1236 status = wine_server_call( req );
1238 SERVER_END_REQ;
1239 return status;
1242 /******************************************************************
1243 * RtlRunOnceInitialize (NTDLL.@)
1245 void WINAPI RtlRunOnceInitialize( RTL_RUN_ONCE *once )
1247 once->Ptr = NULL;
1250 /******************************************************************
1251 * RtlRunOnceBeginInitialize (NTDLL.@)
1253 DWORD WINAPI RtlRunOnceBeginInitialize( RTL_RUN_ONCE *once, ULONG flags, void **context )
1255 if (flags & RTL_RUN_ONCE_CHECK_ONLY)
1257 ULONG_PTR val = (ULONG_PTR)once->Ptr;
1259 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1260 if ((val & 3) != 2) return STATUS_UNSUCCESSFUL;
1261 if (context) *context = (void *)(val & ~3);
1262 return STATUS_SUCCESS;
1265 for (;;)
1267 ULONG_PTR next, val = (ULONG_PTR)once->Ptr;
1269 switch (val & 3)
1271 case 0: /* first time */
1272 if (!interlocked_cmpxchg_ptr( &once->Ptr,
1273 (flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0 ))
1274 return STATUS_PENDING;
1275 break;
1277 case 1: /* in progress, wait */
1278 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1279 next = val & ~3;
1280 if (interlocked_cmpxchg_ptr( &once->Ptr, (void *)((ULONG_PTR)&next | 1),
1281 (void *)val ) == (void *)val)
1282 NtWaitForKeyedEvent( keyed_event, &next, FALSE, NULL );
1283 break;
1285 case 2: /* done */
1286 if (context) *context = (void *)(val & ~3);
1287 return STATUS_SUCCESS;
1289 case 3: /* in progress, async */
1290 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
1291 return STATUS_PENDING;
1296 /******************************************************************
1297 * RtlRunOnceComplete (NTDLL.@)
1299 DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context )
1301 if ((ULONG_PTR)context & 3) return STATUS_INVALID_PARAMETER;
1303 if (flags & RTL_RUN_ONCE_INIT_FAILED)
1305 if (context) return STATUS_INVALID_PARAMETER;
1306 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1308 else context = (void *)((ULONG_PTR)context | 2);
1310 for (;;)
1312 ULONG_PTR val = (ULONG_PTR)once->Ptr;
1314 switch (val & 3)
1316 case 1: /* in progress */
1317 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break;
1318 val &= ~3;
1319 while (val)
1321 ULONG_PTR next = *(ULONG_PTR *)val;
1322 NtReleaseKeyedEvent( keyed_event, (void *)val, FALSE, NULL );
1323 val = next;
1325 return STATUS_SUCCESS;
1327 case 3: /* in progress, async */
1328 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
1329 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break;
1330 return STATUS_SUCCESS;
1332 default:
1333 return STATUS_UNSUCCESSFUL;
1338 /******************************************************************
1339 * RtlRunOnceExecuteOnce (NTDLL.@)
1341 DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN func,
1342 void *param, void **context )
1344 DWORD ret = RtlRunOnceBeginInitialize( once, 0, context );
1346 if (ret != STATUS_PENDING) return ret;
1348 if (!func( once, param, context ))
1350 RtlRunOnceComplete( once, RTL_RUN_ONCE_INIT_FAILED, NULL );
1351 return STATUS_UNSUCCESSFUL;
1354 return RtlRunOnceComplete( once, 0, context ? *context : NULL );
1357 /***********************************************************************
1358 * RtlInitializeSRWLock (NTDLL.@)
1360 void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock )
1362 lock->Ptr = NULL;
1365 /***********************************************************************
1366 * RtlAcquireSRWLockExclusive (NTDLL.@)
1368 void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
1370 FIXME( "%p stub\n", lock );
1373 /***********************************************************************
1374 * RtlAcquireSRWLockShared (NTDLL.@)
1376 void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
1378 FIXME( "%p stub\n", lock );
1381 /***********************************************************************
1382 * RtlReleaseSRWLockExclusive (NTDLL.@)
1384 void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
1386 FIXME( "%p stub\n", lock );
1389 /***********************************************************************
1390 * RtlReleaseSRWLockShared (NTDLL.@)
1392 void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
1394 FIXME( "%p stub\n", lock );