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
29 #ifdef HAVE_SYS_TIME_H
30 # include <sys/time.h>
35 #ifdef HAVE_SYS_POLL_H
36 # include <sys/poll.h>
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
54 #define WIN32_NO_STATUS
57 #include "wine/server.h"
58 #include "wine/debug.h"
59 #include "ntdll_misc.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(ntdll
);
68 /******************************************************************************
69 * NtCreateSemaphore (NTDLL.@)
71 NTSTATUS WINAPI
NtCreateSemaphore( OUT PHANDLE SemaphoreHandle
,
72 IN ACCESS_MASK access
,
73 IN
const OBJECT_ATTRIBUTES
*attr OPTIONAL
,
75 IN LONG MaximumCount
)
77 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
80 if (MaximumCount
<= 0 || InitialCount
< 0 || InitialCount
> MaximumCount
)
81 return STATUS_INVALID_PARAMETER
;
82 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
84 SERVER_START_REQ( create_semaphore
)
87 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
88 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
89 req
->initial
= InitialCount
;
90 req
->max
= MaximumCount
;
91 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
92 ret
= wine_server_call( req
);
93 *SemaphoreHandle
= reply
->handle
;
99 /******************************************************************************
100 * NtOpenSemaphore (NTDLL.@)
102 NTSTATUS WINAPI
NtOpenSemaphore( OUT PHANDLE SemaphoreHandle
,
103 IN ACCESS_MASK access
,
104 IN
const OBJECT_ATTRIBUTES
*attr
)
106 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
109 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
111 SERVER_START_REQ( open_semaphore
)
113 req
->access
= access
;
114 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
115 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
116 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
117 ret
= wine_server_call( req
);
118 *SemaphoreHandle
= reply
->handle
;
124 /******************************************************************************
125 * NtQuerySemaphore (NTDLL.@)
127 NTSTATUS WINAPI
NtQuerySemaphore(
128 HANDLE SemaphoreHandle
,
129 SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass
,
130 PVOID SemaphoreInformation
,
134 FIXME("(%p,%d,%p,0x%08x,%p) stub!\n",
135 SemaphoreHandle
, SemaphoreInformationClass
, SemaphoreInformation
, Length
, ReturnLength
);
136 return STATUS_SUCCESS
;
139 /******************************************************************************
140 * NtReleaseSemaphore (NTDLL.@)
142 NTSTATUS WINAPI
NtReleaseSemaphore( HANDLE handle
, ULONG count
, PULONG previous
)
145 SERVER_START_REQ( release_semaphore
)
147 req
->handle
= handle
;
149 if (!(ret
= wine_server_call( req
)))
151 if (previous
) *previous
= reply
->prev_count
;
162 /**************************************************************************
163 * NtCreateEvent (NTDLL.@)
164 * ZwCreateEvent (NTDLL.@)
166 NTSTATUS WINAPI
NtCreateEvent(
167 OUT PHANDLE EventHandle
,
168 IN ACCESS_MASK DesiredAccess
,
169 IN
const OBJECT_ATTRIBUTES
*attr
,
170 IN BOOLEAN ManualReset
,
171 IN BOOLEAN InitialState
)
173 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
176 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
178 SERVER_START_REQ( create_event
)
180 req
->access
= DesiredAccess
;
181 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
182 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
183 req
->manual_reset
= ManualReset
;
184 req
->initial_state
= InitialState
;
185 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
186 ret
= wine_server_call( req
);
187 *EventHandle
= reply
->handle
;
193 /******************************************************************************
194 * NtOpenEvent (NTDLL.@)
195 * ZwOpenEvent (NTDLL.@)
197 NTSTATUS WINAPI
NtOpenEvent(
198 OUT PHANDLE EventHandle
,
199 IN ACCESS_MASK DesiredAccess
,
200 IN
const OBJECT_ATTRIBUTES
*attr
)
202 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
205 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
207 SERVER_START_REQ( open_event
)
209 req
->access
= DesiredAccess
;
210 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
211 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
212 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
213 ret
= wine_server_call( req
);
214 *EventHandle
= reply
->handle
;
221 /******************************************************************************
222 * NtSetEvent (NTDLL.@)
223 * ZwSetEvent (NTDLL.@)
225 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
229 /* FIXME: set NumberOfThreadsReleased */
231 SERVER_START_REQ( event_op
)
233 req
->handle
= handle
;
235 ret
= wine_server_call( req
);
241 /******************************************************************************
242 * NtResetEvent (NTDLL.@)
244 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
248 /* resetting an event can't release any thread... */
249 if (NumberOfThreadsReleased
) *NumberOfThreadsReleased
= 0;
251 SERVER_START_REQ( event_op
)
253 req
->handle
= handle
;
254 req
->op
= RESET_EVENT
;
255 ret
= wine_server_call( req
);
261 /******************************************************************************
262 * NtClearEvent (NTDLL.@)
265 * same as NtResetEvent ???
267 NTSTATUS WINAPI
NtClearEvent ( HANDLE handle
)
269 return NtResetEvent( handle
, NULL
);
272 /******************************************************************************
273 * NtPulseEvent (NTDLL.@)
278 NTSTATUS WINAPI
NtPulseEvent( HANDLE handle
, PULONG PulseCount
)
283 FIXME("(%p,%d)\n", handle
, *PulseCount
);
285 SERVER_START_REQ( event_op
)
287 req
->handle
= handle
;
288 req
->op
= PULSE_EVENT
;
289 ret
= wine_server_call( req
);
295 /******************************************************************************
296 * NtQueryEvent (NTDLL.@)
298 NTSTATUS WINAPI
NtQueryEvent (
299 IN HANDLE EventHandle
,
300 IN UINT EventInformationClass
,
301 OUT PVOID EventInformation
,
302 IN ULONG EventInformationLength
,
303 OUT PULONG ReturnLength
)
305 FIXME("(%p)\n", EventHandle
);
306 return STATUS_SUCCESS
;
310 * Mutants (known as Mutexes in Kernel32)
313 /******************************************************************************
314 * NtCreateMutant [NTDLL.@]
315 * ZwCreateMutant [NTDLL.@]
317 NTSTATUS WINAPI
NtCreateMutant(OUT HANDLE
* MutantHandle
,
318 IN ACCESS_MASK access
,
319 IN
const OBJECT_ATTRIBUTES
* attr OPTIONAL
,
320 IN BOOLEAN InitialOwner
)
323 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
325 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
327 SERVER_START_REQ( create_mutex
)
329 req
->access
= access
;
330 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
331 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
332 req
->owned
= InitialOwner
;
333 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
334 status
= wine_server_call( req
);
335 *MutantHandle
= reply
->handle
;
341 /**************************************************************************
342 * NtOpenMutant [NTDLL.@]
343 * ZwOpenMutant [NTDLL.@]
345 NTSTATUS WINAPI
NtOpenMutant(OUT HANDLE
* MutantHandle
,
346 IN ACCESS_MASK access
,
347 IN
const OBJECT_ATTRIBUTES
* attr
)
350 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
352 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
354 SERVER_START_REQ( open_mutex
)
356 req
->access
= access
;
357 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
358 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
359 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
360 status
= wine_server_call( req
);
361 *MutantHandle
= reply
->handle
;
367 /**************************************************************************
368 * NtReleaseMutant [NTDLL.@]
369 * ZwReleaseMutant [NTDLL.@]
371 NTSTATUS WINAPI
NtReleaseMutant( IN HANDLE handle
, OUT PLONG prev_count OPTIONAL
)
375 SERVER_START_REQ( release_mutex
)
377 req
->handle
= handle
;
378 status
= wine_server_call( req
);
379 if (prev_count
) *prev_count
= reply
->prev_count
;
385 /******************************************************************
386 * NtQueryMutant [NTDLL.@]
387 * ZwQueryMutant [NTDLL.@]
389 NTSTATUS WINAPI
NtQueryMutant(IN HANDLE handle
,
390 IN MUTANT_INFORMATION_CLASS MutantInformationClass
,
391 OUT PVOID MutantInformation
,
392 IN ULONG MutantInformationLength
,
393 OUT PULONG ResultLength OPTIONAL
)
395 FIXME("(%p %u %p %u %p): stub!\n",
396 handle
, MutantInformationClass
, MutantInformation
, MutantInformationLength
, ResultLength
);
397 return STATUS_NOT_IMPLEMENTED
;
404 /**************************************************************************
405 * NtCreateTimer [NTDLL.@]
406 * ZwCreateTimer [NTDLL.@]
408 NTSTATUS WINAPI
NtCreateTimer(OUT HANDLE
*handle
,
409 IN ACCESS_MASK access
,
410 IN
const OBJECT_ATTRIBUTES
*attr OPTIONAL
,
411 IN TIMER_TYPE timer_type
)
413 DWORD len
= (attr
&& attr
->ObjectName
) ? attr
->ObjectName
->Length
: 0;
416 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
418 if (timer_type
!= NotificationTimer
&& timer_type
!= SynchronizationTimer
)
419 return STATUS_INVALID_PARAMETER
;
421 SERVER_START_REQ( create_timer
)
423 req
->access
= access
;
424 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
425 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
426 req
->manual
= (timer_type
== NotificationTimer
) ? TRUE
: FALSE
;
427 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
428 status
= wine_server_call( req
);
429 *handle
= reply
->handle
;
436 /**************************************************************************
437 * NtOpenTimer [NTDLL.@]
438 * ZwOpenTimer [NTDLL.@]
440 NTSTATUS WINAPI
NtOpenTimer(OUT PHANDLE handle
,
441 IN ACCESS_MASK access
,
442 IN
const OBJECT_ATTRIBUTES
* attr
)
444 DWORD len
= (attr
&& attr
->ObjectName
) ? attr
->ObjectName
->Length
: 0;
447 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
449 SERVER_START_REQ( open_timer
)
451 req
->access
= access
;
452 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
453 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
454 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
455 status
= wine_server_call( req
);
456 *handle
= reply
->handle
;
462 /**************************************************************************
463 * NtSetTimer [NTDLL.@]
464 * ZwSetTimer [NTDLL.@]
466 NTSTATUS WINAPI
NtSetTimer(IN HANDLE handle
,
467 IN
const LARGE_INTEGER
* when
,
468 IN PTIMER_APC_ROUTINE callback
,
469 IN PVOID callback_arg
,
471 IN ULONG period OPTIONAL
,
472 OUT PBOOLEAN state OPTIONAL
)
474 NTSTATUS status
= STATUS_SUCCESS
;
476 TRACE("(%p,%p,%p,%p,%08x,0x%08x,%p) stub\n",
477 handle
, when
, callback
, callback_arg
, resume
, period
, state
);
479 SERVER_START_REQ( set_timer
)
481 req
->handle
= handle
;
482 req
->period
= period
;
483 req
->expire
= when
->QuadPart
;
484 req
->callback
= callback
;
485 req
->arg
= callback_arg
;
486 status
= wine_server_call( req
);
487 if (state
) *state
= reply
->signaled
;
491 /* set error but can still succeed */
492 if (resume
&& status
== STATUS_SUCCESS
) return STATUS_TIMER_RESUME_IGNORED
;
496 /**************************************************************************
497 * NtCancelTimer [NTDLL.@]
498 * ZwCancelTimer [NTDLL.@]
500 NTSTATUS WINAPI
NtCancelTimer(IN HANDLE handle
, OUT BOOLEAN
* state
)
504 SERVER_START_REQ( cancel_timer
)
506 req
->handle
= handle
;
507 status
= wine_server_call( req
);
508 if (state
) *state
= reply
->signaled
;
514 /******************************************************************************
515 * NtQueryTimer (NTDLL.@)
517 * Retrieves information about a timer.
520 * TimerHandle [I] The timer to retrieve information about.
521 * TimerInformationClass [I] The type of information to retrieve.
522 * TimerInformation [O] Pointer to buffer to store information in.
523 * Length [I] The length of the buffer pointed to by TimerInformation.
524 * ReturnLength [O] Optional. The size of buffer actually used.
527 * Success: STATUS_SUCCESS
528 * Failure: STATUS_INFO_LENGTH_MISMATCH, if Length doesn't match the required data
529 * size for the class specified.
530 * STATUS_INVALID_INFO_CLASS, if an invalid TimerInformationClass was specified.
531 * STATUS_ACCESS_DENIED, if TimerHandle does not have TIMER_QUERY_STATE access
534 NTSTATUS WINAPI
NtQueryTimer(
536 TIMER_INFORMATION_CLASS TimerInformationClass
,
537 PVOID TimerInformation
,
541 TIMER_BASIC_INFORMATION
* basic_info
= (TIMER_BASIC_INFORMATION
*)TimerInformation
;
545 TRACE("(%p,%d,%p,0x%08x,%p)\n", TimerHandle
, TimerInformationClass
,
546 TimerInformation
, Length
, ReturnLength
);
548 switch (TimerInformationClass
)
550 case TimerBasicInformation
:
551 if (Length
< sizeof(TIMER_BASIC_INFORMATION
))
552 return STATUS_INFO_LENGTH_MISMATCH
;
554 SERVER_START_REQ(get_timer_info
)
556 req
->handle
= TimerHandle
;
557 status
= wine_server_call(req
);
559 /* convert server time to absolute NTDLL time */
560 basic_info
->RemainingTime
.QuadPart
= reply
->when
;
561 basic_info
->TimerState
= reply
->signaled
;
565 /* convert from absolute into relative time */
566 NtQuerySystemTime(&now
);
567 if (now
.QuadPart
> basic_info
->RemainingTime
.QuadPart
)
568 basic_info
->RemainingTime
.QuadPart
= 0;
570 basic_info
->RemainingTime
.QuadPart
-= now
.QuadPart
;
572 if (ReturnLength
) *ReturnLength
= sizeof(TIMER_BASIC_INFORMATION
);
577 FIXME("Unhandled class %d\n", TimerInformationClass
);
578 return STATUS_INVALID_INFO_CLASS
;
582 /******************************************************************************
583 * NtQueryTimerResolution [NTDLL.@]
585 NTSTATUS WINAPI
NtQueryTimerResolution(OUT ULONG
* min_resolution
,
586 OUT ULONG
* max_resolution
,
587 OUT ULONG
* current_resolution
)
589 FIXME("(%p,%p,%p), stub!\n",
590 min_resolution
, max_resolution
, current_resolution
);
592 return STATUS_NOT_IMPLEMENTED
;
595 /******************************************************************************
596 * NtSetTimerResolution [NTDLL.@]
598 NTSTATUS WINAPI
NtSetTimerResolution(IN ULONG resolution
,
599 IN BOOLEAN set_resolution
,
600 OUT ULONG
* current_resolution
)
602 FIXME("(%u,%u,%p), stub!\n",
603 resolution
, set_resolution
, current_resolution
);
605 return STATUS_NOT_IMPLEMENTED
;
609 /***********************************************************************
612 * Wait for a reply on the waiting pipe of the current thread.
614 static int wait_reply( void *cookie
)
617 struct wake_up_reply reply
;
621 ret
= read( ntdll_get_thread_data()->wait_fd
[0], &reply
, sizeof(reply
) );
622 if (ret
== sizeof(reply
))
624 if (!reply
.cookie
) break; /* thread got killed */
625 if (reply
.cookie
== cookie
) return reply
.signaled
;
626 /* we stole another reply, wait for the real one */
627 signaled
= wait_reply( cookie
);
628 /* and now put the wrong one back in the pipe */
631 ret
= write( ntdll_get_thread_data()->wait_fd
[1], &reply
, sizeof(reply
) );
632 if (ret
== sizeof(reply
)) break;
633 if (ret
>= 0) server_protocol_error( "partial wakeup write %d\n", ret
);
634 if (errno
== EINTR
) continue;
635 server_protocol_perror("wakeup write");
639 if (ret
>= 0) server_protocol_error( "partial wakeup read %d\n", ret
);
640 if (errno
== EINTR
) continue;
641 server_protocol_perror("wakeup read");
643 /* the server closed the connection; time to die... */
644 server_abort_thread(0);
648 /***********************************************************************
651 * Invoke a single APC. Return TRUE if a user APC has been run.
653 static BOOL
invoke_apc( const apc_call_t
*call
, apc_result_t
*result
)
655 BOOL user_apc
= FALSE
;
657 memset( result
, 0, sizeof(*result
) );
662 call
->user
.func( call
->user
.args
[0], call
->user
.args
[1], call
->user
.args
[2] );
666 call
->timer
.func( call
->timer
.arg
, (DWORD
)call
->timer
.time
, (DWORD
)(call
->timer
.time
>> 32) );
670 result
->type
= call
->type
;
671 result
->async_io
.status
= call
->async_io
.func( call
->async_io
.user
,
673 call
->async_io
.status
);
674 if (result
->async_io
.status
!= STATUS_PENDING
)
675 NtCurrentTeb()->num_async_io
--;
677 case APC_VIRTUAL_ALLOC
:
678 result
->type
= call
->type
;
679 result
->virtual_alloc
.addr
= call
->virtual_alloc
.addr
;
680 result
->virtual_alloc
.size
= call
->virtual_alloc
.size
;
681 result
->virtual_alloc
.status
= NtAllocateVirtualMemory( NtCurrentProcess(),
682 &result
->virtual_alloc
.addr
,
683 call
->virtual_alloc
.zero_bits
,
684 &result
->virtual_alloc
.size
,
685 call
->virtual_alloc
.op_type
,
686 call
->virtual_alloc
.prot
);
688 case APC_VIRTUAL_FREE
:
689 result
->type
= call
->type
;
690 result
->virtual_free
.addr
= call
->virtual_free
.addr
;
691 result
->virtual_free
.size
= call
->virtual_free
.size
;
692 result
->virtual_free
.status
= NtFreeVirtualMemory( NtCurrentProcess(),
693 &result
->virtual_free
.addr
,
694 &result
->virtual_free
.size
,
695 call
->virtual_free
.op_type
);
697 case APC_VIRTUAL_QUERY
:
699 MEMORY_BASIC_INFORMATION info
;
700 result
->type
= call
->type
;
701 result
->virtual_query
.status
= NtQueryVirtualMemory( NtCurrentProcess(),
702 call
->virtual_query
.addr
,
703 MemoryBasicInformation
, &info
,
704 sizeof(info
), NULL
);
705 if (result
->virtual_query
.status
== STATUS_SUCCESS
)
707 result
->virtual_query
.base
= info
.BaseAddress
;
708 result
->virtual_query
.alloc_base
= info
.AllocationBase
;
709 result
->virtual_query
.size
= info
.RegionSize
;
710 result
->virtual_query
.state
= info
.State
;
711 result
->virtual_query
.prot
= info
.Protect
;
712 result
->virtual_query
.alloc_prot
= info
.AllocationProtect
;
713 result
->virtual_query
.alloc_type
= info
.Type
;
717 case APC_VIRTUAL_PROTECT
:
718 result
->type
= call
->type
;
719 result
->virtual_protect
.addr
= call
->virtual_protect
.addr
;
720 result
->virtual_protect
.size
= call
->virtual_protect
.size
;
721 result
->virtual_protect
.status
= NtProtectVirtualMemory( NtCurrentProcess(),
722 &result
->virtual_protect
.addr
,
723 &result
->virtual_protect
.size
,
724 call
->virtual_protect
.prot
,
725 &result
->virtual_protect
.prot
);
727 case APC_VIRTUAL_FLUSH
:
728 result
->type
= call
->type
;
729 result
->virtual_flush
.addr
= call
->virtual_flush
.addr
;
730 result
->virtual_flush
.size
= call
->virtual_flush
.size
;
731 result
->virtual_flush
.status
= NtFlushVirtualMemory( NtCurrentProcess(),
732 &result
->virtual_flush
.addr
,
733 &result
->virtual_flush
.size
, 0 );
735 case APC_VIRTUAL_LOCK
:
736 result
->type
= call
->type
;
737 result
->virtual_lock
.addr
= call
->virtual_lock
.addr
;
738 result
->virtual_lock
.size
= call
->virtual_lock
.size
;
739 result
->virtual_lock
.status
= NtLockVirtualMemory( NtCurrentProcess(),
740 &result
->virtual_lock
.addr
,
741 &result
->virtual_lock
.size
, 0 );
743 case APC_VIRTUAL_UNLOCK
:
744 result
->type
= call
->type
;
745 result
->virtual_unlock
.addr
= call
->virtual_unlock
.addr
;
746 result
->virtual_unlock
.size
= call
->virtual_unlock
.size
;
747 result
->virtual_unlock
.status
= NtUnlockVirtualMemory( NtCurrentProcess(),
748 &result
->virtual_unlock
.addr
,
749 &result
->virtual_unlock
.size
, 0 );
753 LARGE_INTEGER offset
;
754 result
->type
= call
->type
;
755 result
->map_view
.addr
= call
->map_view
.addr
;
756 result
->map_view
.size
= call
->map_view
.size
;
757 offset
.u
.LowPart
= call
->map_view
.offset_low
;
758 offset
.u
.HighPart
= call
->map_view
.offset_high
;
759 result
->map_view
.status
= NtMapViewOfSection( call
->map_view
.handle
, NtCurrentProcess(),
760 &result
->map_view
.addr
, call
->map_view
.zero_bits
,
761 0, &offset
, &result
->map_view
.size
, ViewShare
,
762 call
->map_view
.alloc_type
, call
->map_view
.prot
);
763 NtClose( call
->map_view
.handle
);
767 result
->type
= call
->type
;
768 result
->unmap_view
.status
= NtUnmapViewOfSection( NtCurrentProcess(), call
->unmap_view
.addr
);
770 case APC_CREATE_THREAD
:
773 result
->type
= call
->type
;
774 result
->create_thread
.status
= RtlCreateUserThread( NtCurrentProcess(), NULL
,
775 call
->create_thread
.suspend
, NULL
,
776 call
->create_thread
.reserve
,
777 call
->create_thread
.commit
,
778 call
->create_thread
.func
,
779 call
->create_thread
.arg
,
780 &result
->create_thread
.handle
, &id
);
781 result
->create_thread
.tid
= HandleToULong(id
.UniqueThread
);
785 server_protocol_error( "get_apc_request: bad type %d\n", call
->type
);
791 /***********************************************************************
794 * Call outstanding APCs. Return TRUE if a user APC has been run.
796 static BOOL
call_apcs( BOOL alertable
)
798 BOOL user_apc
= FALSE
;
804 memset( &result
, 0, sizeof(result
) );
808 SERVER_START_REQ( get_apc
)
810 req
->alertable
= alertable
;
812 req
->result
= result
;
813 if (!(ret
= wine_server_call( req
)))
815 handle
= reply
->handle
;
821 if (ret
) return user_apc
; /* no more APCs */
823 user_apc
= invoke_apc( &call
, &result
);
828 /***********************************************************************
829 * NTDLL_queue_process_apc
831 NTSTATUS
NTDLL_queue_process_apc( HANDLE process
, const apc_call_t
*call
, apc_result_t
*result
)
839 SERVER_START_REQ( queue_apc
)
841 req
->process
= process
;
843 if (!(ret
= wine_server_call( req
)))
845 handle
= reply
->handle
;
850 if (ret
!= STATUS_SUCCESS
) return ret
;
854 invoke_apc( call
, result
);
858 NtWaitForSingleObject( handle
, FALSE
, NULL
);
860 SERVER_START_REQ( get_apc_result
)
862 req
->handle
= handle
;
863 if (!(ret
= wine_server_call( req
))) *result
= reply
->result
;
867 if (!ret
&& result
->type
== APC_NONE
) continue; /* APC didn't run, try again */
868 if (ret
) NtClose( handle
);
875 /***********************************************************************
876 * NTDLL_wait_for_multiple_objects
878 * Implementation of NtWaitForMultipleObjects
880 NTSTATUS
NTDLL_wait_for_multiple_objects( UINT count
, const HANDLE
*handles
, UINT flags
,
881 const LARGE_INTEGER
*timeout
, HANDLE signal_object
)
885 timeout_t abs_timeout
= timeout
? timeout
->QuadPart
: TIMEOUT_INFINITE
;
889 SERVER_START_REQ( select
)
892 req
->cookie
= &cookie
;
893 req
->signal
= signal_object
;
894 req
->timeout
= abs_timeout
;
895 wine_server_add_data( req
, handles
, count
* sizeof(HANDLE
) );
896 ret
= wine_server_call( req
);
897 abs_timeout
= reply
->timeout
;
900 if (ret
== STATUS_PENDING
) ret
= wait_reply( &cookie
);
901 if (ret
!= STATUS_USER_APC
) break;
902 if (call_apcs( (flags
& SELECT_ALERTABLE
) != 0 )) break;
903 signal_object
= 0; /* don't signal it multiple times */
906 /* A test on Windows 2000 shows that Windows always yields during
907 a wait, but a wait that is hit by an event gets a priority
908 boost as well. This seems to model that behavior the closest. */
909 if (ret
== WAIT_TIMEOUT
) NtYieldExecution();
915 /* wait operations */
917 /******************************************************************
918 * NtWaitForMultipleObjects (NTDLL.@)
920 NTSTATUS WINAPI
NtWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
,
921 BOOLEAN wait_all
, BOOLEAN alertable
,
922 const LARGE_INTEGER
*timeout
)
924 UINT flags
= SELECT_INTERRUPTIBLE
;
926 if (!count
|| count
> MAXIMUM_WAIT_OBJECTS
) return STATUS_INVALID_PARAMETER_1
;
928 if (wait_all
) flags
|= SELECT_ALL
;
929 if (alertable
) flags
|= SELECT_ALERTABLE
;
930 return NTDLL_wait_for_multiple_objects( count
, handles
, flags
, timeout
, 0 );
934 /******************************************************************
935 * NtWaitForSingleObject (NTDLL.@)
937 NTSTATUS WINAPI
NtWaitForSingleObject(HANDLE handle
, BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
939 return NtWaitForMultipleObjects( 1, &handle
, FALSE
, alertable
, timeout
);
943 /******************************************************************
944 * NtSignalAndWaitForSingleObject (NTDLL.@)
946 NTSTATUS WINAPI
NtSignalAndWaitForSingleObject( HANDLE hSignalObject
, HANDLE hWaitObject
,
947 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
949 UINT flags
= SELECT_INTERRUPTIBLE
;
951 if (!hSignalObject
) return STATUS_INVALID_HANDLE
;
952 if (alertable
) flags
|= SELECT_ALERTABLE
;
953 return NTDLL_wait_for_multiple_objects( 1, &hWaitObject
, flags
, timeout
, hSignalObject
);
957 /******************************************************************
958 * NtYieldExecution (NTDLL.@)
960 NTSTATUS WINAPI
NtYieldExecution(void)
962 #ifdef HAVE_SCHED_YIELD
964 return STATUS_SUCCESS
;
966 return STATUS_NO_YIELD_PERFORMED
;
971 /******************************************************************
972 * NtDelayExecution (NTDLL.@)
974 NTSTATUS WINAPI
NtDelayExecution( BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
976 /* if alertable or async I/O in progress, we need to query the server */
977 if (alertable
|| NtCurrentTeb()->num_async_io
)
979 UINT flags
= SELECT_INTERRUPTIBLE
;
980 if (alertable
) flags
|= SELECT_ALERTABLE
;
981 return NTDLL_wait_for_multiple_objects( 0, NULL
, flags
, timeout
, 0 );
984 if (!timeout
|| timeout
->QuadPart
== TIMEOUT_INFINITE
) /* sleep forever */
986 for (;;) select( 0, NULL
, NULL
, NULL
, NULL
);
991 timeout_t when
, diff
;
993 if ((when
= timeout
->QuadPart
) < 0)
995 NtQuerySystemTime( &now
);
996 when
= now
.QuadPart
- when
;
999 /* Note that we yield after establishing the desired timeout */
1001 if (!when
) return STATUS_SUCCESS
;
1006 NtQuerySystemTime( &now
);
1007 diff
= (when
- now
.QuadPart
+ 9) / 10;
1008 if (diff
<= 0) break;
1009 tv
.tv_sec
= diff
/ 1000000;
1010 tv
.tv_usec
= diff
% 1000000;
1011 if (select( 0, NULL
, NULL
, NULL
, &tv
) != -1) break;
1014 return STATUS_SUCCESS
;
1017 /******************************************************************
1018 * NtCreateIoCompletion (NTDLL.@)
1020 NTSTATUS WINAPI
NtCreateIoCompletion( PHANDLE CompletionPort
, ACCESS_MASK DesiredAccess
,
1021 POBJECT_ATTRIBUTES ObjectAttributes
, ULONG NumberOfConcurrentThreads
)
1023 FIXME("(%p, %x, %p, %d)\n", CompletionPort
, DesiredAccess
,
1024 ObjectAttributes
, NumberOfConcurrentThreads
);
1025 return STATUS_NOT_IMPLEMENTED
;
1028 NTSTATUS WINAPI
NtSetIoCompletion( HANDLE CompletionPort
, ULONG_PTR CompletionKey
,
1029 PIO_STATUS_BLOCK iosb
, ULONG NumberOfBytesTransferred
,
1030 ULONG NumberOfBytesToTransfer
)
1032 FIXME("(%p, %lx, %p, %d, %d)\n", CompletionPort
, CompletionKey
,
1033 iosb
, NumberOfBytesTransferred
, NumberOfBytesToTransfer
);
1034 return STATUS_NOT_IMPLEMENTED
;
1037 NTSTATUS WINAPI
NtRemoveIoCompletion( HANDLE CompletionPort
, PULONG_PTR CompletionKey
,
1038 PIO_STATUS_BLOCK iosb
, PULONG OperationStatus
,
1039 PLARGE_INTEGER WaitTime
)
1041 FIXME("(%p, %p, %p, %p, %p)\n", CompletionPort
, CompletionKey
,
1042 iosb
, OperationStatus
, WaitTime
);
1043 return STATUS_NOT_IMPLEMENTED
;