2 * Kernel synchronization
4 * Copyright (C) 2018 Zebediah Figura
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "ntoskrnl_private.h"
24 #include "ddk/ntddk.h"
26 #include "wine/heap.h"
27 #include "wine/server.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl
);
33 TYPE_MANUAL_EVENT
= 0,
37 TYPE_MANUAL_TIMER
= 8,
41 DECLARE_CRITICAL_SECTION(sync_cs
);
43 /***********************************************************************
44 * KeWaitForMultipleObjects (NTOSKRNL.EXE.@)
46 NTSTATUS WINAPI
KeWaitForMultipleObjects(ULONG count
, void *pobjs
[],
47 WAIT_TYPE wait_type
, KWAIT_REASON reason
, KPROCESSOR_MODE mode
,
48 BOOLEAN alertable
, LARGE_INTEGER
*timeout
, KWAIT_BLOCK
*wait_blocks
)
50 DISPATCHER_HEADER
**objs
= (DISPATCHER_HEADER
**)pobjs
;
51 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
55 TRACE("count %u, objs %p, wait_type %u, reason %u, mode %d, alertable %u, timeout %p, wait_blocks %p.\n",
56 count
, objs
, wait_type
, reason
, mode
, alertable
, timeout
, wait_blocks
);
58 /* We co-opt DISPATCHER_HEADER.WaitListHead:
59 * Blink stores a handle to the synchronization object,
60 * Flink stores the number of threads currently waiting on this object. */
62 EnterCriticalSection( &sync_cs
);
63 for (i
= 0; i
< count
; i
++)
65 if (objs
[i
]->WaitListHead
.Blink
== INVALID_HANDLE_VALUE
)
67 ObOpenObjectByPointer( objs
[i
], OBJ_KERNEL_HANDLE
, NULL
, SYNCHRONIZE
, NULL
, KernelMode
, &handles
[i
] );
71 ++*((ULONG_PTR
*)&objs
[i
]->WaitListHead
.Flink
);
72 if (!objs
[i
]->WaitListHead
.Blink
)
74 switch (objs
[i
]->Type
)
76 case TYPE_MANUAL_TIMER
:
77 case TYPE_MANUAL_EVENT
:
78 objs
[i
]->WaitListHead
.Blink
= CreateEventW( NULL
, TRUE
, objs
[i
]->SignalState
, NULL
);
82 objs
[i
]->WaitListHead
.Blink
= CreateEventW( NULL
, FALSE
, objs
[i
]->SignalState
, NULL
);
85 objs
[i
]->WaitListHead
.Blink
= CreateMutexW( NULL
, FALSE
, NULL
);
89 KSEMAPHORE
*semaphore
= CONTAINING_RECORD(objs
[i
], KSEMAPHORE
, Header
);
90 objs
[i
]->WaitListHead
.Blink
= CreateSemaphoreW( NULL
,
91 semaphore
->Header
.SignalState
, semaphore
->Limit
, NULL
);
97 handles
[i
] = objs
[i
]->WaitListHead
.Blink
;
99 LeaveCriticalSection( &sync_cs
);
101 ret
= NtWaitForMultipleObjects( count
, handles
, (wait_type
== WaitAny
), alertable
, timeout
);
103 EnterCriticalSection( &sync_cs
);
104 for (i
= 0; i
< count
; i
++)
106 if (ret
== i
|| (!ret
&& wait_type
== WaitAll
))
108 switch (objs
[i
]->Type
)
110 case TYPE_AUTO_EVENT
:
111 case TYPE_AUTO_TIMER
:
112 objs
[i
]->SignalState
= FALSE
;
116 --objs
[i
]->SignalState
;
121 if (objs
[i
]->WaitListHead
.Blink
== INVALID_HANDLE_VALUE
)
123 NtClose( handles
[i
] );
125 else if (!--*((ULONG_PTR
*)&objs
[i
]->WaitListHead
.Flink
))
127 switch (objs
[i
]->Type
)
129 case TYPE_AUTO_TIMER
:
130 case TYPE_MANUAL_TIMER
:
131 case TYPE_MANUAL_EVENT
:
132 case TYPE_AUTO_EVENT
:
134 CloseHandle(objs
[i
]->WaitListHead
.Blink
);
135 objs
[i
]->WaitListHead
.Blink
= NULL
;
138 /* Native will panic if a mutex is destroyed while held, so we
139 * don't have to worry about leaking the handle here. */
140 if (objs
[i
]->SignalState
== 1)
142 CloseHandle(objs
[i
]->WaitListHead
.Blink
);
143 objs
[i
]->WaitListHead
.Blink
= NULL
;
149 LeaveCriticalSection( &sync_cs
);
154 /***********************************************************************
155 * KeWaitForSingleObject (NTOSKRNL.EXE.@)
157 NTSTATUS WINAPI
KeWaitForSingleObject( void *obj
, KWAIT_REASON reason
,
158 KPROCESSOR_MODE mode
, BOOLEAN alertable
, LARGE_INTEGER
*timeout
)
160 return KeWaitForMultipleObjects( 1, &obj
, WaitAny
, reason
, mode
, alertable
, timeout
, NULL
);
163 /***********************************************************************
164 * KeWaitForMutexObject (NTOSKRNL.EXE.@)
166 NTSTATUS WINAPI
KeWaitForMutexObject( PRKMUTEX mutex
, KWAIT_REASON reason
,
167 KPROCESSOR_MODE mode
, BOOLEAN alertable
, LARGE_INTEGER
*timeout
)
169 return KeWaitForSingleObject( mutex
, reason
, mode
, alertable
, timeout
);
173 /***********************************************************************
174 * KeInitializeEvent (NTOSKRNL.EXE.@)
176 void WINAPI
KeInitializeEvent( PRKEVENT event
, EVENT_TYPE type
, BOOLEAN state
)
178 TRACE("event %p, type %u, state %u.\n", event
, type
, state
);
180 event
->Header
.Type
= type
;
181 event
->Header
.SignalState
= state
;
182 event
->Header
.WaitListHead
.Blink
= NULL
;
183 event
->Header
.WaitListHead
.Flink
= NULL
;
186 static void *create_event_object( HANDLE handle
)
188 EVENT_BASIC_INFORMATION info
;
191 if (!(event
= alloc_kernel_object( ExEventObjectType
, handle
, sizeof(*event
), 0 ))) return NULL
;
193 if (!NtQueryEvent( handle
, EventBasicInformation
, &info
, sizeof(info
), NULL
))
194 KeInitializeEvent( event
, info
.EventType
, info
.EventState
);
195 event
->Header
.WaitListHead
.Blink
= INVALID_HANDLE_VALUE
; /* mark as kernel object */
199 static const WCHAR event_type_name
[] = {'E','v','e','n','t',0};
201 static struct _OBJECT_TYPE event_type
= {
206 POBJECT_TYPE ExEventObjectType
= &event_type
;
208 /***********************************************************************
209 * IoCreateSynchronizationEvent (NTOSKRNL.EXE.@)
211 PKEVENT WINAPI
IoCreateSynchronizationEvent( UNICODE_STRING
*name
, HANDLE
*ret_handle
)
213 OBJECT_ATTRIBUTES attr
;
218 TRACE( "(%p %p)\n", name
, ret_handle
);
220 InitializeObjectAttributes( &attr
, name
, 0, 0, NULL
);
221 ret
= NtCreateEvent( &handle
, EVENT_ALL_ACCESS
, &attr
, SynchronizationEvent
, TRUE
);
222 if (ret
) return NULL
;
224 if (kernel_object_from_handle( handle
, ExEventObjectType
, (void**)&event
))
230 *ret_handle
= handle
;
234 /***********************************************************************
235 * KeSetEvent (NTOSKRNL.EXE.@)
237 LONG WINAPI
KeSetEvent( PRKEVENT event
, KPRIORITY increment
, BOOLEAN wait
)
242 TRACE("event %p, increment %d, wait %u.\n", event
, increment
, wait
);
244 if (event
->Header
.WaitListHead
.Blink
!= INVALID_HANDLE_VALUE
)
246 EnterCriticalSection( &sync_cs
);
247 ret
= InterlockedExchange( &event
->Header
.SignalState
, TRUE
);
248 if ((handle
= event
->Header
.WaitListHead
.Blink
))
250 LeaveCriticalSection( &sync_cs
);
254 if (!ObOpenObjectByPointer( event
, OBJ_KERNEL_HANDLE
, NULL
, EVENT_MODIFY_STATE
, NULL
, KernelMode
, &handle
))
256 NtSetEvent( handle
, &ret
);
259 event
->Header
.SignalState
= TRUE
;
265 /***********************************************************************
266 * KeResetEvent (NTOSKRNL.EXE.@)
268 LONG WINAPI
KeResetEvent( PRKEVENT event
)
273 TRACE("event %p.\n", event
);
275 if (event
->Header
.WaitListHead
.Blink
!= INVALID_HANDLE_VALUE
)
277 EnterCriticalSection( &sync_cs
);
278 ret
= InterlockedExchange( &event
->Header
.SignalState
, FALSE
);
279 if ((handle
= event
->Header
.WaitListHead
.Blink
))
280 ResetEvent( handle
);
281 LeaveCriticalSection( &sync_cs
);
285 if (!ObOpenObjectByPointer( event
, OBJ_KERNEL_HANDLE
, NULL
, EVENT_MODIFY_STATE
, NULL
, KernelMode
, &handle
))
287 NtResetEvent( handle
, &ret
);
290 event
->Header
.SignalState
= FALSE
;
296 /***********************************************************************
297 * KeClearEvent (NTOSKRNL.EXE.@)
299 void WINAPI
KeClearEvent( PRKEVENT event
)
301 KeResetEvent( event
);
304 /***********************************************************************
305 * KeReadStateEvent (NTOSKRNL.EXE.@)
307 LONG WINAPI
KeReadStateEvent( PRKEVENT event
)
311 TRACE("event %p.\n", event
);
313 if (event
->Header
.WaitListHead
.Blink
== INVALID_HANDLE_VALUE
)
315 if (!(ObOpenObjectByPointer( event
, OBJ_KERNEL_HANDLE
, NULL
, EVENT_QUERY_STATE
, NULL
, KernelMode
, &handle
)))
317 EVENT_BASIC_INFORMATION event_info
;
318 if (!(NtQueryEvent( handle
, EventBasicInformation
, &event_info
, sizeof(event_info
), NULL
)))
319 event
->Header
.SignalState
= event_info
.EventState
;
323 return event
->Header
.SignalState
;
326 /***********************************************************************
327 * KeInitializeSemaphore (NTOSKRNL.EXE.@)
329 void WINAPI
KeInitializeSemaphore( PRKSEMAPHORE semaphore
, LONG count
, LONG limit
)
331 TRACE("semaphore %p, count %d, limit %d.\n", semaphore
, count
, limit
);
333 semaphore
->Header
.Type
= TYPE_SEMAPHORE
;
334 semaphore
->Header
.SignalState
= count
;
335 semaphore
->Header
.WaitListHead
.Blink
= NULL
;
336 semaphore
->Header
.WaitListHead
.Flink
= NULL
;
337 semaphore
->Limit
= limit
;
340 /***********************************************************************
341 * KeReleaseSemaphore (NTOSKRNL.EXE.@)
343 LONG WINAPI
KeReleaseSemaphore( PRKSEMAPHORE semaphore
, KPRIORITY increment
,
344 LONG count
, BOOLEAN wait
)
349 TRACE("semaphore %p, increment %d, count %d, wait %u.\n",
350 semaphore
, increment
, count
, wait
);
352 EnterCriticalSection( &sync_cs
);
353 ret
= InterlockedExchangeAdd( &semaphore
->Header
.SignalState
, count
);
354 if ((handle
= semaphore
->Header
.WaitListHead
.Blink
))
355 ReleaseSemaphore( handle
, count
, NULL
);
356 LeaveCriticalSection( &sync_cs
);
361 static const WCHAR semaphore_type_name
[] = {'S','e','m','a','p','h','o','r','e',0};
363 static struct _OBJECT_TYPE semaphore_type
=
368 POBJECT_TYPE ExSemaphoreObjectType
= &semaphore_type
;
370 /***********************************************************************
371 * KeInitializeMutex (NTOSKRNL.EXE.@)
373 void WINAPI
KeInitializeMutex( PRKMUTEX mutex
, ULONG level
)
375 TRACE("mutex %p, level %u.\n", mutex
, level
);
377 mutex
->Header
.Type
= TYPE_MUTEX
;
378 mutex
->Header
.SignalState
= 1;
379 mutex
->Header
.WaitListHead
.Blink
= NULL
;
380 mutex
->Header
.WaitListHead
.Flink
= NULL
;
383 /***********************************************************************
384 * KeReleaseMutex (NTOSKRNL.EXE.@)
386 LONG WINAPI
KeReleaseMutex( PRKMUTEX mutex
, BOOLEAN wait
)
390 TRACE("mutex %p, wait %u.\n", mutex
, wait
);
392 EnterCriticalSection( &sync_cs
);
393 ret
= mutex
->Header
.SignalState
++;
394 if (!ret
&& !mutex
->Header
.WaitListHead
.Flink
)
396 CloseHandle( mutex
->Header
.WaitListHead
.Blink
);
397 mutex
->Header
.WaitListHead
.Blink
= NULL
;
399 LeaveCriticalSection( &sync_cs
);
404 static void CALLBACK
ke_timer_complete_proc(PTP_CALLBACK_INSTANCE instance
, void *timer_
, PTP_TIMER tp_timer
)
406 KTIMER
*timer
= timer_
;
407 KDPC
*dpc
= timer
->Dpc
;
409 TRACE("instance %p, timer %p, tp_timer %p.\n", instance
, timer
, tp_timer
);
411 if (dpc
&& dpc
->DeferredRoutine
)
413 TRACE("Calling dpc->DeferredRoutine %p, dpc->DeferredContext %p.\n", dpc
->DeferredRoutine
, dpc
->DeferredContext
);
414 dpc
->DeferredRoutine(dpc
, dpc
->DeferredContext
, dpc
->SystemArgument1
, dpc
->SystemArgument2
);
416 EnterCriticalSection( &sync_cs
);
417 timer
->Header
.SignalState
= TRUE
;
418 if (timer
->Header
.WaitListHead
.Blink
)
419 SetEvent(timer
->Header
.WaitListHead
.Blink
);
420 LeaveCriticalSection( &sync_cs
);
423 /***********************************************************************
424 * KeInitializeTimerEx (NTOSKRNL.EXE.@)
426 void WINAPI
KeInitializeTimerEx( KTIMER
*timer
, TIMER_TYPE type
)
428 TRACE("timer %p, type %u.\n", timer
, type
);
430 RtlZeroMemory(timer
, sizeof(KTIMER
));
431 timer
->Header
.Type
= (type
== NotificationTimer
) ? TYPE_MANUAL_TIMER
: TYPE_AUTO_TIMER
;
432 timer
->Header
.SignalState
= FALSE
;
433 timer
->Header
.Inserted
= FALSE
;
434 timer
->Header
.WaitListHead
.Blink
= NULL
;
435 timer
->Header
.WaitListHead
.Flink
= NULL
;
438 /***********************************************************************
439 * KeInitializeTimer (NTOSKRNL.EXE.@)
441 void WINAPI
KeInitializeTimer( KTIMER
*timer
)
443 KeInitializeTimerEx(timer
, NotificationTimer
);
446 /***********************************************************************
447 * KeSetTimerEx (NTOSKRNL.EXE.@)
449 BOOLEAN WINAPI
KeSetTimerEx( KTIMER
*timer
, LARGE_INTEGER duetime
, LONG period
, KDPC
*dpc
)
453 TRACE("timer %p, duetime %s, period %d, dpc %p.\n",
454 timer
, wine_dbgstr_longlong(duetime
.QuadPart
), period
, dpc
);
456 EnterCriticalSection( &sync_cs
);
458 if ((ret
= timer
->Header
.Inserted
))
459 KeCancelTimer(timer
);
461 timer
->Header
.Inserted
= TRUE
;
463 if (!timer
->TimerListEntry
.Blink
)
464 timer
->TimerListEntry
.Blink
= (void *)CreateThreadpoolTimer(ke_timer_complete_proc
, timer
, NULL
);
466 if (!timer
->TimerListEntry
.Blink
)
467 ERR("Could not create thread pool timer.\n");
469 timer
->DueTime
.QuadPart
= duetime
.QuadPart
;
470 timer
->Period
= period
;
473 SetThreadpoolTimer((TP_TIMER
*)timer
->TimerListEntry
.Blink
, (FILETIME
*)&duetime
, period
, 0);
474 LeaveCriticalSection( &sync_cs
);
479 BOOLEAN WINAPI
KeCancelTimer( KTIMER
*timer
)
483 TRACE("timer %p.\n", timer
);
485 EnterCriticalSection( &sync_cs
);
486 if (timer
->TimerListEntry
.Blink
)
488 SetThreadpoolTimer((TP_TIMER
*)timer
->TimerListEntry
.Blink
, NULL
, 0, 0);
490 LeaveCriticalSection( &sync_cs
);
491 WaitForThreadpoolTimerCallbacks((TP_TIMER
*)timer
->TimerListEntry
.Blink
, TRUE
);
492 EnterCriticalSection( &sync_cs
);
494 if (timer
->TimerListEntry
.Blink
)
496 CloseThreadpoolTimer((TP_TIMER
*)timer
->TimerListEntry
.Blink
);
497 timer
->TimerListEntry
.Blink
= NULL
;
500 timer
->Header
.SignalState
= FALSE
;
501 if (timer
->Header
.WaitListHead
.Blink
&& !*((ULONG_PTR
*)&timer
->Header
.WaitListHead
.Flink
))
503 CloseHandle(timer
->Header
.WaitListHead
.Blink
);
504 timer
->Header
.WaitListHead
.Blink
= NULL
;
507 ret
= timer
->Header
.Inserted
;
508 timer
->Header
.Inserted
= FALSE
;
509 LeaveCriticalSection( &sync_cs
);
514 /***********************************************************************
515 * KeDelayExecutionThread (NTOSKRNL.EXE.@)
517 NTSTATUS WINAPI
KeDelayExecutionThread( KPROCESSOR_MODE mode
, BOOLEAN alertable
, LARGE_INTEGER
*timeout
)
519 TRACE("mode %d, alertable %u, timeout %p.\n", mode
, alertable
, timeout
);
520 return NtDelayExecution( alertable
, timeout
);
523 /***********************************************************************
524 * KeInitializeSpinLock (NTOSKRNL.EXE.@)
526 void WINAPI
NTOSKRNL_KeInitializeSpinLock( KSPIN_LOCK
*lock
)
528 TRACE("lock %p.\n", lock
);
532 /***********************************************************************
533 * KeAcquireSpinLockAtDpcLevel (NTOSKRNL.EXE.@)
535 void WINAPI
KeAcquireSpinLockAtDpcLevel( KSPIN_LOCK
*lock
)
537 TRACE("lock %p.\n", lock
);
538 while (InterlockedCompareExchangePointer( (void **)lock
, (void *)1, (void *)0 ))
542 /***********************************************************************
543 * KeReleaseSpinLockFromDpcLevel (NTOSKRNL.EXE.@)
545 void WINAPI
KeReleaseSpinLockFromDpcLevel( KSPIN_LOCK
*lock
)
547 TRACE("lock %p.\n", lock
);
548 InterlockedExchangePointer( (void **)lock
, 0 );
551 #define QUEUED_SPINLOCK_OWNED 0x2
553 /***********************************************************************
554 * KeAcquireInStackQueuedSpinLockAtDpcLevel (NTOSKRNL.EXE.@)
556 DEFINE_FASTCALL_WRAPPER( KeAcquireInStackQueuedSpinLockAtDpcLevel
, 8 )
557 void FASTCALL
KeAcquireInStackQueuedSpinLockAtDpcLevel( KSPIN_LOCK
*lock
, KLOCK_QUEUE_HANDLE
*queue
)
559 KSPIN_LOCK_QUEUE
*tail
;
561 TRACE("lock %p, queue %p.\n", lock
, queue
);
563 queue
->LockQueue
.Next
= NULL
;
565 if (!(tail
= InterlockedExchangePointer( (void **)lock
, &queue
->LockQueue
)))
566 queue
->LockQueue
.Lock
= (KSPIN_LOCK
*)((ULONG_PTR
)lock
| QUEUED_SPINLOCK_OWNED
);
569 queue
->LockQueue
.Lock
= lock
;
570 InterlockedExchangePointer( (void **)&tail
->Next
, &queue
->LockQueue
);
572 while (!((ULONG_PTR
)InterlockedCompareExchangePointer( (void **)&queue
->LockQueue
.Lock
, 0, 0 )
573 & QUEUED_SPINLOCK_OWNED
))
580 /***********************************************************************
581 * KeReleaseInStackQueuedSpinLockFromDpcLevel (NTOSKRNL.EXE.@)
583 DEFINE_FASTCALL1_WRAPPER( KeReleaseInStackQueuedSpinLockFromDpcLevel
)
584 void FASTCALL
KeReleaseInStackQueuedSpinLockFromDpcLevel( KLOCK_QUEUE_HANDLE
*queue
)
586 KSPIN_LOCK
*lock
= (KSPIN_LOCK
*)((ULONG_PTR
)queue
->LockQueue
.Lock
& ~QUEUED_SPINLOCK_OWNED
);
587 KSPIN_LOCK_QUEUE
*next
;
589 TRACE("lock %p, queue %p.\n", lock
, queue
);
591 queue
->LockQueue
.Lock
= NULL
;
593 if (!(next
= queue
->LockQueue
.Next
))
595 /* If we are truly the last in the queue, the lock will point to us. */
596 if (InterlockedCompareExchangePointer( (void **)lock
, NULL
, &queue
->LockQueue
) == queue
)
599 /* Otherwise, someone just queued themselves, but hasn't yet set
600 * themselves as successor. Spin waiting for them to do so. */
601 while (!(next
= queue
->LockQueue
.Next
))
605 InterlockedExchangePointer( (void **)&next
->Lock
, (KSPIN_LOCK
*)((ULONG_PTR
)lock
| QUEUED_SPINLOCK_OWNED
) );
609 /***********************************************************************
610 * KeReleaseSpinLock (NTOSKRNL.EXE.@)
612 void WINAPI
KeReleaseSpinLock( KSPIN_LOCK
*lock
, KIRQL irql
)
614 TRACE("lock %p, irql %u.\n", lock
, irql
);
615 KeReleaseSpinLockFromDpcLevel( lock
);
618 /***********************************************************************
619 * KeAcquireSpinLockRaiseToDpc (NTOSKRNL.EXE.@)
621 KIRQL WINAPI
KeAcquireSpinLockRaiseToDpc( KSPIN_LOCK
*lock
)
623 TRACE("lock %p.\n", lock
);
624 KeAcquireSpinLockAtDpcLevel( lock
);
628 /***********************************************************************
629 * KeAcquireInStackQueuedSpinLock (NTOSKRNL.EXE.@)
631 void WINAPI
KeAcquireInStackQueuedSpinLock( KSPIN_LOCK
*lock
, KLOCK_QUEUE_HANDLE
*queue
)
633 TRACE("lock %p, queue %p.\n", lock
, queue
);
634 KeAcquireInStackQueuedSpinLockAtDpcLevel( lock
, queue
);
637 /***********************************************************************
638 * KeReleaseInStackQueuedSpinLock (NTOSKRNL.EXE.@)
640 void WINAPI
KeReleaseInStackQueuedSpinLock( KLOCK_QUEUE_HANDLE
*queue
)
642 TRACE("queue %p.\n", queue
);
643 KeReleaseInStackQueuedSpinLockFromDpcLevel( queue
);
647 /***********************************************************************
648 * KeInitializeApc (NTOSKRNL.EXE.@)
650 void WINAPI
KeInitializeApc(PRKAPC apc
, PRKTHREAD thread
, KAPC_ENVIRONMENT env
, PKKERNEL_ROUTINE krnl_routine
,
651 PKRUNDOWN_ROUTINE rundown_routine
, PKNORMAL_ROUTINE normal_routine
, KPROCESSOR_MODE apc_mode
, PVOID ctx
)
653 TRACE("apc %p thread %p env %u krnl_routine %p rundown_routine %p normal_routine %p apc_mode %u ctx %p\n",
654 apc
, thread
, env
, krnl_routine
, rundown_routine
, normal_routine
, apc_mode
, ctx
);
656 if (env
!= OriginalApcEnvironment
)
657 FIXME("Unhandled APC_ENVIRONMENT\n");
660 apc
->Size
= sizeof(*apc
);
661 apc
->Thread
= thread
;
662 apc
->ApcStateIndex
= env
;
663 apc
->KernelRoutine
= krnl_routine
;
664 apc
->RundownRoutine
= rundown_routine
;
665 apc
->NormalRoutine
= normal_routine
;
666 apc
->Inserted
= FALSE
;
667 if (apc
->NormalRoutine
)
669 apc
->ApcMode
= apc_mode
;
670 apc
->NormalContext
= ctx
;
674 apc
->ApcMode
= KernelMode
;
675 apc
->NormalContext
= NULL
;
679 /***********************************************************************
680 * KeTestAlertThread (NTOSKRNL.EXE.@)
682 BOOLEAN WINAPI
KeTestAlertThread(KPROCESSOR_MODE mode
)
684 FIXME("stub! %u\n", mode
);
688 /***********************************************************************
689 * KeAlertThread (NTOSKRNL.EXE.@)
691 BOOLEAN WINAPI
KeAlertThread(PKTHREAD thread
, KPROCESSOR_MODE mode
)
693 FIXME("stub! %p mode %u\n", thread
, mode
);
697 static KSPIN_LOCK cancel_lock
;
699 /***********************************************************************
700 * IoAcquireCancelSpinLock (NTOSKRNL.EXE.@)
702 void WINAPI
IoAcquireCancelSpinLock( KIRQL
*irql
)
704 TRACE("irql %p.\n", irql
);
705 KeAcquireSpinLock( &cancel_lock
, irql
);
708 /***********************************************************************
709 * IoReleaseCancelSpinLock (NTOSKRNL.EXE.@)
711 void WINAPI
IoReleaseCancelSpinLock( KIRQL irql
)
713 TRACE("irql %u.\n", irql
);
714 KeReleaseSpinLock( &cancel_lock
, irql
);
717 /***********************************************************************
718 * ExfInterlockedRemoveHeadList (NTOSKRNL.EXE.@)
720 DEFINE_FASTCALL_WRAPPER( ExfInterlockedRemoveHeadList
, 8 )
721 PLIST_ENTRY FASTCALL
ExfInterlockedRemoveHeadList( LIST_ENTRY
*list
, KSPIN_LOCK
*lock
)
723 return ExInterlockedRemoveHeadList( list
, lock
);
726 /***********************************************************************
727 * ExInterlockedRemoveHeadList (NTOSKRNL.EXE.@)
729 LIST_ENTRY
* WINAPI
ExInterlockedRemoveHeadList( LIST_ENTRY
*list
, KSPIN_LOCK
*lock
)
734 TRACE("list %p, lock %p.\n", list
, lock
);
736 KeAcquireSpinLock( lock
, &irql
);
737 ret
= RemoveHeadList( list
);
738 KeReleaseSpinLock( lock
, irql
);
744 /***********************************************************************
745 * InterlockedPopEntrySList (NTOSKRNL.EXE.@)
747 DEFINE_FASTCALL1_WRAPPER( NTOSKRNL_InterlockedPopEntrySList
)
748 PSLIST_ENTRY FASTCALL
NTOSKRNL_InterlockedPopEntrySList( PSLIST_HEADER list
)
750 return RtlInterlockedPopEntrySList( list
);
754 /***********************************************************************
755 * InterlockedPushEntrySList (NTOSKRNL.EXE.@)
757 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_InterlockedPushEntrySList
, 8 )
758 PSLIST_ENTRY FASTCALL
NTOSKRNL_InterlockedPushEntrySList( PSLIST_HEADER list
, PSLIST_ENTRY entry
)
760 return RtlInterlockedPushEntrySList( list
, entry
);
764 /***********************************************************************
765 * ExInterlockedPopEntrySList (NTOSKRNL.EXE.@)
767 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_ExInterlockedPopEntrySList
, 8 )
768 PSLIST_ENTRY FASTCALL
NTOSKRNL_ExInterlockedPopEntrySList( PSLIST_HEADER list
, PKSPIN_LOCK lock
)
770 return RtlInterlockedPopEntrySList( list
);
774 /***********************************************************************
775 * ExInterlockedPushEntrySList (NTOSKRNL.EXE.@)
777 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_ExInterlockedPushEntrySList
, 12 )
778 PSLIST_ENTRY FASTCALL
NTOSKRNL_ExInterlockedPushEntrySList( PSLIST_HEADER list
, PSLIST_ENTRY entry
, PKSPIN_LOCK lock
)
780 return RtlInterlockedPushEntrySList( list
, entry
);
784 /***********************************************************************
785 * ExInterlockedFlushSList (NTOSKRNL.EXE.@)
787 DEFINE_FASTCALL1_WRAPPER( NTOSKRNL_ExInterlockedFlushSList
)
788 PSLIST_ENTRY FASTCALL
NTOSKRNL_ExInterlockedFlushSList( PSLIST_HEADER list
)
790 return RtlInterlockedFlushSList( list
);
794 /***********************************************************************
795 * ExAcquireFastMutexUnsafe (NTOSKRNL.EXE.@)
797 DEFINE_FASTCALL1_WRAPPER(ExAcquireFastMutexUnsafe
)
798 void FASTCALL
ExAcquireFastMutexUnsafe( FAST_MUTEX
*mutex
)
802 TRACE("mutex %p.\n", mutex
);
804 count
= InterlockedDecrement( &mutex
->Count
);
806 KeWaitForSingleObject( &mutex
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
809 /***********************************************************************
810 * ExReleaseFastMutexUnsafe (NTOSKRNL.EXE.@)
812 DEFINE_FASTCALL1_WRAPPER(ExReleaseFastMutexUnsafe
)
813 void FASTCALL
ExReleaseFastMutexUnsafe( FAST_MUTEX
*mutex
)
817 TRACE("mutex %p.\n", mutex
);
819 count
= InterlockedIncrement( &mutex
->Count
);
821 KeSetEvent( &mutex
->Event
, IO_NO_INCREMENT
, FALSE
);
826 /***********************************************************************
827 * ExAcquireFastMutex (NTOSKRNL.@)
829 void WINAPI
ExAcquireFastMutex( FAST_MUTEX
*mutex
)
831 /* FIXME: lower IRQL */
832 ExAcquireFastMutexUnsafe( mutex
);
835 /***********************************************************************
836 * ExReleaseFastMutex (NTOSKRNL.@)
838 void WINAPI
ExReleaseFastMutex( FAST_MUTEX
*mutex
)
840 ExReleaseFastMutexUnsafe( mutex
);
841 /* FIXME: restore IRQL */
844 #endif /* __i386__ */
846 /* Use of the fields of an ERESOURCE structure seems to vary wildly between
847 * Windows versions. The below implementation uses them as follows:
849 * OwnerTable - contains a list of shared owners, including threads which do
850 * not currently own the resource
851 * OwnerTable[i].OwnerThread - shared owner TID
852 * OwnerTable[i].OwnerCount - recursion count of this shared owner (may be 0)
853 * OwnerEntry.OwnerThread - the owner TID if exclusively owned
854 * OwnerEntry.TableSize - the number of entries in OwnerTable, including threads
855 * which do not currently own the resource
856 * ActiveEntries - total number of acquisitions (incl. recursive ones)
859 /***********************************************************************
860 * ExInitializeResourceLite (NTOSKRNL.EXE.@)
862 NTSTATUS WINAPI
ExInitializeResourceLite( ERESOURCE
*resource
)
864 TRACE("resource %p.\n", resource
);
865 memset(resource
, 0, sizeof(*resource
));
866 return STATUS_SUCCESS
;
869 /***********************************************************************
870 * ExDeleteResourceLite (NTOSKRNL.EXE.@)
872 NTSTATUS WINAPI
ExDeleteResourceLite( ERESOURCE
*resource
)
874 TRACE("resource %p.\n", resource
);
875 heap_free(resource
->OwnerTable
);
876 heap_free(resource
->ExclusiveWaiters
);
877 heap_free(resource
->SharedWaiters
);
878 return STATUS_SUCCESS
;
881 /* Find an existing entry in the shared owner list, or create a new one. */
882 static OWNER_ENTRY
*resource_get_shared_entry( ERESOURCE
*resource
, ERESOURCE_THREAD thread
)
886 for (i
= 0; i
< resource
->OwnerEntry
.TableSize
; ++i
)
888 if (resource
->OwnerTable
[i
].OwnerThread
== thread
)
889 return &resource
->OwnerTable
[i
];
892 count
= ++resource
->OwnerEntry
.TableSize
;
893 resource
->OwnerTable
= heap_realloc(resource
->OwnerTable
, count
* sizeof(*resource
->OwnerTable
));
894 resource
->OwnerTable
[count
- 1].OwnerThread
= thread
;
895 resource
->OwnerTable
[count
- 1].OwnerCount
= 0;
897 return &resource
->OwnerTable
[count
- 1];
900 /***********************************************************************
901 * ExAcquireResourceExclusiveLite (NTOSKRNL.EXE.@)
903 BOOLEAN WINAPI
ExAcquireResourceExclusiveLite( ERESOURCE
*resource
, BOOLEAN wait
)
907 TRACE("resource %p, wait %u.\n", resource
, wait
);
909 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
911 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
913 resource
->ActiveEntries
++;
914 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
917 /* In order to avoid a race between waiting for the ExclusiveWaiters event
918 * and grabbing the lock, do not grab the resource if it is unclaimed but
919 * has waiters; instead queue ourselves. */
920 else if (!resource
->ActiveEntries
&& !resource
->NumberOfExclusiveWaiters
&& !resource
->NumberOfSharedWaiters
)
922 resource
->Flag
|= ResourceOwnedExclusive
;
923 resource
->OwnerEntry
.OwnerThread
= (ERESOURCE_THREAD
)KeGetCurrentThread();
924 resource
->ActiveEntries
++;
925 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
930 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
934 if (!resource
->ExclusiveWaiters
)
936 resource
->ExclusiveWaiters
= heap_alloc( sizeof(*resource
->ExclusiveWaiters
) );
937 KeInitializeEvent( resource
->ExclusiveWaiters
, SynchronizationEvent
, FALSE
);
939 resource
->NumberOfExclusiveWaiters
++;
941 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
943 KeWaitForSingleObject( resource
->ExclusiveWaiters
, Executive
, KernelMode
, FALSE
, NULL
);
945 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
947 resource
->Flag
|= ResourceOwnedExclusive
;
948 resource
->OwnerEntry
.OwnerThread
= (ERESOURCE_THREAD
)KeGetCurrentThread();
949 resource
->ActiveEntries
++;
950 resource
->NumberOfExclusiveWaiters
--;
952 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
957 /***********************************************************************
958 * ExAcquireResourceSharedLite (NTOSKRNL.EXE.@)
960 BOOLEAN WINAPI
ExAcquireResourceSharedLite( ERESOURCE
*resource
, BOOLEAN wait
)
965 TRACE("resource %p, wait %u.\n", resource
, wait
);
967 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
969 entry
= resource_get_shared_entry( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
971 if (resource
->Flag
& ResourceOwnedExclusive
)
973 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
975 /* We own the resource exclusively, so increase recursion. */
976 resource
->ActiveEntries
++;
977 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
981 else if (entry
->OwnerCount
|| !resource
->NumberOfExclusiveWaiters
)
983 /* Either we already own the resource shared, or there are no exclusive
984 * owners or waiters, so we can grab it shared. */
986 resource
->ActiveEntries
++;
987 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
993 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
997 if (!resource
->SharedWaiters
)
999 resource
->SharedWaiters
= heap_alloc( sizeof(*resource
->SharedWaiters
) );
1000 KeInitializeSemaphore( resource
->SharedWaiters
, 0, INT_MAX
);
1002 resource
->NumberOfSharedWaiters
++;
1004 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1006 KeWaitForSingleObject( resource
->SharedWaiters
, Executive
, KernelMode
, FALSE
, NULL
);
1008 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1010 entry
->OwnerCount
++;
1011 resource
->ActiveEntries
++;
1012 resource
->NumberOfSharedWaiters
--;
1014 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1019 /***********************************************************************
1020 * ExAcquireSharedStarveExclusive (NTOSKRNL.EXE.@)
1022 BOOLEAN WINAPI
ExAcquireSharedStarveExclusive( ERESOURCE
*resource
, BOOLEAN wait
)
1027 TRACE("resource %p, wait %u.\n", resource
, wait
);
1029 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1031 entry
= resource_get_shared_entry( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
1033 if (resource
->Flag
& ResourceOwnedExclusive
)
1035 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
1037 resource
->ActiveEntries
++;
1038 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1042 /* We are starving exclusive waiters, but we cannot steal the resource out
1043 * from under an exclusive waiter who is about to acquire it. (Because of
1044 * locking, and because exclusive waiters are always waked first, this is
1045 * guaranteed to be the case if the resource is unowned and there are
1046 * exclusive waiters.) */
1047 else if (!(!resource
->ActiveEntries
&& resource
->NumberOfExclusiveWaiters
))
1049 entry
->OwnerCount
++;
1050 resource
->ActiveEntries
++;
1051 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1057 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1061 if (!resource
->SharedWaiters
)
1063 resource
->SharedWaiters
= heap_alloc( sizeof(*resource
->SharedWaiters
) );
1064 KeInitializeSemaphore( resource
->SharedWaiters
, 0, INT_MAX
);
1066 resource
->NumberOfSharedWaiters
++;
1068 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1070 KeWaitForSingleObject( resource
->SharedWaiters
, Executive
, KernelMode
, FALSE
, NULL
);
1072 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1074 entry
->OwnerCount
++;
1075 resource
->ActiveEntries
++;
1076 resource
->NumberOfSharedWaiters
--;
1078 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1083 /***********************************************************************
1084 * ExAcquireSharedWaitForExclusive (NTOSKRNL.EXE.@)
1086 BOOLEAN WINAPI
ExAcquireSharedWaitForExclusive( ERESOURCE
*resource
, BOOLEAN wait
)
1091 TRACE("resource %p, wait %u.\n", resource
, wait
);
1093 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1095 entry
= resource_get_shared_entry( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
1097 if (resource
->Flag
& ResourceOwnedExclusive
)
1099 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
1101 /* We own the resource exclusively, so increase recursion. */
1102 resource
->ActiveEntries
++;
1103 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1107 /* We may only grab the resource if there are no exclusive waiters, even if
1108 * we already own it shared. */
1109 else if (!resource
->NumberOfExclusiveWaiters
)
1111 entry
->OwnerCount
++;
1112 resource
->ActiveEntries
++;
1113 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1119 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1123 if (!resource
->SharedWaiters
)
1125 resource
->SharedWaiters
= heap_alloc( sizeof(*resource
->SharedWaiters
) );
1126 KeInitializeSemaphore( resource
->SharedWaiters
, 0, INT_MAX
);
1128 resource
->NumberOfSharedWaiters
++;
1130 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1132 KeWaitForSingleObject( resource
->SharedWaiters
, Executive
, KernelMode
, FALSE
, NULL
);
1134 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1136 entry
->OwnerCount
++;
1137 resource
->ActiveEntries
++;
1138 resource
->NumberOfSharedWaiters
--;
1140 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1145 /***********************************************************************
1146 * ExReleaseResourceForThreadLite (NTOSKRNL.EXE.@)
1148 void WINAPI
ExReleaseResourceForThreadLite( ERESOURCE
*resource
, ERESOURCE_THREAD thread
)
1153 TRACE("resource %p, thread %#lx.\n", resource
, thread
);
1155 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1157 if (resource
->Flag
& ResourceOwnedExclusive
)
1159 if (resource
->OwnerEntry
.OwnerThread
== thread
)
1161 if (!--resource
->ActiveEntries
)
1163 resource
->OwnerEntry
.OwnerThread
= 0;
1164 resource
->Flag
&= ~ResourceOwnedExclusive
;
1169 ERR("Trying to release %p for thread %#lx, but resource is exclusively owned by %#lx.\n",
1170 resource
, thread
, resource
->OwnerEntry
.OwnerThread
);
1176 entry
= resource_get_shared_entry( resource
, thread
);
1177 if (entry
->OwnerCount
)
1179 entry
->OwnerCount
--;
1180 resource
->ActiveEntries
--;
1184 ERR("Trying to release %p for thread %#lx, but resource is not owned by that thread.\n", resource
, thread
);
1189 if (!resource
->ActiveEntries
)
1191 if (resource
->NumberOfExclusiveWaiters
)
1193 KeSetEvent( resource
->ExclusiveWaiters
, IO_NO_INCREMENT
, FALSE
);
1195 else if (resource
->NumberOfSharedWaiters
)
1197 KeReleaseSemaphore( resource
->SharedWaiters
, IO_NO_INCREMENT
,
1198 resource
->NumberOfSharedWaiters
, FALSE
);
1202 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1205 /***********************************************************************
1206 * ExReleaseResourceLite (NTOSKRNL.EXE.@)
1208 DEFINE_FASTCALL1_WRAPPER( ExReleaseResourceLite
)
1209 void FASTCALL
ExReleaseResourceLite( ERESOURCE
*resource
)
1211 ExReleaseResourceForThreadLite( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
1214 /***********************************************************************
1215 * ExGetExclusiveWaiterCount (NTOSKRNL.EXE.@)
1217 ULONG WINAPI
ExGetExclusiveWaiterCount( ERESOURCE
*resource
)
1222 TRACE("resource %p.\n", resource
);
1224 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1226 count
= resource
->NumberOfExclusiveWaiters
;
1228 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1233 /***********************************************************************
1234 * ExGetSharedWaiterCount (NTOSKRNL.EXE.@)
1236 ULONG WINAPI
ExGetSharedWaiterCount( ERESOURCE
*resource
)
1241 TRACE("resource %p.\n", resource
);
1243 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1245 count
= resource
->NumberOfSharedWaiters
;
1247 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1252 /***********************************************************************
1253 * ExIsResourceAcquiredExclusiveLite (NTOSKRNL.EXE.@)
1255 BOOLEAN WINAPI
ExIsResourceAcquiredExclusiveLite( ERESOURCE
*resource
)
1260 TRACE("resource %p.\n", resource
);
1262 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1264 ret
= (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread());
1266 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1271 /***********************************************************************
1272 * ExIsResourceAcquiredSharedLite (NTOSKRNL.EXE.@)
1274 ULONG WINAPI
ExIsResourceAcquiredSharedLite( ERESOURCE
*resource
)
1279 TRACE("resource %p.\n", resource
);
1281 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1283 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
1284 ret
= resource
->ActiveEntries
;
1287 OWNER_ENTRY
*entry
= resource_get_shared_entry( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
1288 ret
= entry
->OwnerCount
;
1291 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1296 /***********************************************************************
1297 * IoInitializeRemoveLockEx (NTOSKRNL.EXE.@)
1299 void WINAPI
IoInitializeRemoveLockEx( IO_REMOVE_LOCK
*lock
, ULONG tag
,
1300 ULONG max_minutes
, ULONG max_count
, ULONG size
)
1302 TRACE("lock %p, tag %#x, max_minutes %u, max_count %u, size %u.\n",
1303 lock
, tag
, max_minutes
, max_count
, size
);
1305 KeInitializeEvent( &lock
->Common
.RemoveEvent
, NotificationEvent
, FALSE
);
1306 lock
->Common
.Removed
= FALSE
;
1307 lock
->Common
.IoCount
= 0;
1310 /***********************************************************************
1311 * IoAcquireRemoveLockEx (NTOSKRNL.EXE.@)
1313 NTSTATUS WINAPI
IoAcquireRemoveLockEx( IO_REMOVE_LOCK
*lock
, void *tag
,
1314 const char *file
, ULONG line
, ULONG size
)
1316 TRACE("lock %p, tag %p, file %s, line %u, size %u.\n", lock
, tag
, debugstr_a(file
), line
, size
);
1318 if (lock
->Common
.Removed
)
1319 return STATUS_DELETE_PENDING
;
1321 InterlockedIncrement( &lock
->Common
.IoCount
);
1322 return STATUS_SUCCESS
;
1325 /***********************************************************************
1326 * IoReleaseRemoveLockEx (NTOSKRNL.EXE.@)
1328 void WINAPI
IoReleaseRemoveLockEx( IO_REMOVE_LOCK
*lock
, void *tag
, ULONG size
)
1332 TRACE("lock %p, tag %p, size %u.\n", lock
, tag
, size
);
1334 if (!(count
= InterlockedDecrement( &lock
->Common
.IoCount
)) && lock
->Common
.Removed
)
1335 KeSetEvent( &lock
->Common
.RemoveEvent
, IO_NO_INCREMENT
, FALSE
);
1337 ERR("Lock %p is not acquired!\n", lock
);
1340 /***********************************************************************
1341 * IoReleaseRemoveLockAndWaitEx (NTOSKRNL.EXE.@)
1343 void WINAPI
IoReleaseRemoveLockAndWaitEx( IO_REMOVE_LOCK
*lock
, void *tag
, ULONG size
)
1347 TRACE("lock %p, tag %p, size %u.\n", lock
, tag
, size
);
1349 lock
->Common
.Removed
= TRUE
;
1351 if (!(count
= InterlockedDecrement( &lock
->Common
.IoCount
)))
1352 KeSetEvent( &lock
->Common
.RemoveEvent
, IO_NO_INCREMENT
, FALSE
);
1354 ERR("Lock %p is not acquired!\n", lock
);
1356 KeWaitForSingleObject( &lock
->Common
.RemoveEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1359 BOOLEAN WINAPI
KeSetTimer(KTIMER
*timer
, LARGE_INTEGER duetime
, KDPC
*dpc
)
1361 TRACE("timer %p, duetime %I64x, dpc %p.\n", timer
, duetime
.QuadPart
, dpc
);
1363 return KeSetTimerEx(timer
, duetime
, 0, dpc
);
1366 void WINAPI
KeInitializeDeviceQueue( KDEVICE_QUEUE
*queue
)
1368 TRACE( "queue %p.\n", queue
);
1370 KeInitializeSpinLock( &queue
->Lock
);
1371 InitializeListHead( &queue
->DeviceListHead
);
1372 queue
->Busy
= FALSE
;
1373 queue
->Type
= IO_TYPE_DEVICE_QUEUE
;
1374 queue
->Size
= sizeof(*queue
);
1377 BOOLEAN WINAPI
KeInsertDeviceQueue( KDEVICE_QUEUE
*queue
, KDEVICE_QUEUE_ENTRY
*entry
)
1382 TRACE( "queue %p, entry %p.\n", queue
, entry
);
1384 KeAcquireSpinLock( &queue
->Lock
, &irql
);
1385 insert
= entry
->Inserted
= queue
->Busy
;
1386 if (insert
) InsertTailList( &queue
->DeviceListHead
, &entry
->DeviceListEntry
);
1388 KeReleaseSpinLock( &queue
->Lock
, irql
);
1393 KDEVICE_QUEUE_ENTRY
*WINAPI
KeRemoveDeviceQueue( KDEVICE_QUEUE
*queue
)
1395 KDEVICE_QUEUE_ENTRY
*entry
= NULL
;
1398 TRACE( "queue %p.\n", queue
);
1400 KeAcquireSpinLock( &queue
->Lock
, &irql
);
1401 if (IsListEmpty( &queue
->DeviceListHead
)) queue
->Busy
= FALSE
;
1404 entry
= CONTAINING_RECORD( RemoveHeadList( &queue
->DeviceListHead
),
1405 KDEVICE_QUEUE_ENTRY
, DeviceListEntry
);
1406 entry
->Inserted
= FALSE
;
1408 KeReleaseSpinLock( &queue
->Lock
, irql
);