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 %lu, 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( "(%s %p)\n", debugstr_us(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 * IoCreateNotificationEvent (NTOSKRNL.EXE.@)
237 PKEVENT WINAPI
IoCreateNotificationEvent( UNICODE_STRING
*name
, HANDLE
*ret_handle
)
239 OBJECT_ATTRIBUTES attr
;
244 TRACE( "(%s %p)\n", debugstr_us(name
), ret_handle
);
246 InitializeObjectAttributes( &attr
, name
, 0, 0, NULL
);
247 ret
= NtCreateEvent( &handle
, EVENT_ALL_ACCESS
, &attr
, NotificationEvent
, TRUE
);
248 if (ret
) return NULL
;
250 if (kernel_object_from_handle( handle
, ExEventObjectType
, (void**)&event
))
256 *ret_handle
= handle
;
260 /***********************************************************************
261 * KeSetEvent (NTOSKRNL.EXE.@)
263 LONG WINAPI
KeSetEvent( PRKEVENT event
, KPRIORITY increment
, BOOLEAN wait
)
268 TRACE("event %p, increment %ld, wait %u.\n", event
, increment
, wait
);
270 if (event
->Header
.WaitListHead
.Blink
!= INVALID_HANDLE_VALUE
)
272 EnterCriticalSection( &sync_cs
);
273 ret
= InterlockedExchange( &event
->Header
.SignalState
, TRUE
);
274 if ((handle
= event
->Header
.WaitListHead
.Blink
))
276 LeaveCriticalSection( &sync_cs
);
280 if (!ObOpenObjectByPointer( event
, OBJ_KERNEL_HANDLE
, NULL
, EVENT_MODIFY_STATE
, NULL
, KernelMode
, &handle
))
282 NtSetEvent( handle
, &ret
);
285 event
->Header
.SignalState
= TRUE
;
291 /***********************************************************************
292 * KeResetEvent (NTOSKRNL.EXE.@)
294 LONG WINAPI
KeResetEvent( PRKEVENT event
)
299 TRACE("event %p.\n", event
);
301 if (event
->Header
.WaitListHead
.Blink
!= INVALID_HANDLE_VALUE
)
303 EnterCriticalSection( &sync_cs
);
304 ret
= InterlockedExchange( &event
->Header
.SignalState
, FALSE
);
305 if ((handle
= event
->Header
.WaitListHead
.Blink
))
306 ResetEvent( handle
);
307 LeaveCriticalSection( &sync_cs
);
311 if (!ObOpenObjectByPointer( event
, OBJ_KERNEL_HANDLE
, NULL
, EVENT_MODIFY_STATE
, NULL
, KernelMode
, &handle
))
313 NtResetEvent( handle
, &ret
);
316 event
->Header
.SignalState
= FALSE
;
322 /***********************************************************************
323 * KeClearEvent (NTOSKRNL.EXE.@)
325 void WINAPI
KeClearEvent( PRKEVENT event
)
327 KeResetEvent( event
);
330 /***********************************************************************
331 * KeReadStateEvent (NTOSKRNL.EXE.@)
333 LONG WINAPI
KeReadStateEvent( PRKEVENT event
)
337 TRACE("event %p.\n", event
);
339 if (event
->Header
.WaitListHead
.Blink
== INVALID_HANDLE_VALUE
)
341 if (!(ObOpenObjectByPointer( event
, OBJ_KERNEL_HANDLE
, NULL
, EVENT_QUERY_STATE
, NULL
, KernelMode
, &handle
)))
343 EVENT_BASIC_INFORMATION event_info
;
344 if (!(NtQueryEvent( handle
, EventBasicInformation
, &event_info
, sizeof(event_info
), NULL
)))
345 event
->Header
.SignalState
= event_info
.EventState
;
349 return event
->Header
.SignalState
;
352 /***********************************************************************
353 * KeInitializeSemaphore (NTOSKRNL.EXE.@)
355 void WINAPI
KeInitializeSemaphore( PRKSEMAPHORE semaphore
, LONG count
, LONG limit
)
357 TRACE("semaphore %p, count %ld, limit %ld.\n", semaphore
, count
, limit
);
359 semaphore
->Header
.Type
= TYPE_SEMAPHORE
;
360 semaphore
->Header
.SignalState
= count
;
361 semaphore
->Header
.WaitListHead
.Blink
= NULL
;
362 semaphore
->Header
.WaitListHead
.Flink
= NULL
;
363 semaphore
->Limit
= limit
;
366 /***********************************************************************
367 * KeReleaseSemaphore (NTOSKRNL.EXE.@)
369 LONG WINAPI
KeReleaseSemaphore( PRKSEMAPHORE semaphore
, KPRIORITY increment
,
370 LONG count
, BOOLEAN wait
)
375 TRACE("semaphore %p, increment %ld, count %ld, wait %u.\n",
376 semaphore
, increment
, count
, wait
);
378 EnterCriticalSection( &sync_cs
);
379 ret
= InterlockedExchangeAdd( &semaphore
->Header
.SignalState
, count
);
380 if ((handle
= semaphore
->Header
.WaitListHead
.Blink
))
381 ReleaseSemaphore( handle
, count
, NULL
);
382 LeaveCriticalSection( &sync_cs
);
387 static const WCHAR semaphore_type_name
[] = {'S','e','m','a','p','h','o','r','e',0};
389 static struct _OBJECT_TYPE semaphore_type
=
394 POBJECT_TYPE ExSemaphoreObjectType
= &semaphore_type
;
396 /***********************************************************************
397 * KeInitializeMutex (NTOSKRNL.EXE.@)
399 void WINAPI
KeInitializeMutex( PRKMUTEX mutex
, ULONG level
)
401 TRACE("mutex %p, level %lu.\n", mutex
, level
);
403 mutex
->Header
.Type
= TYPE_MUTEX
;
404 mutex
->Header
.SignalState
= 1;
405 mutex
->Header
.WaitListHead
.Blink
= NULL
;
406 mutex
->Header
.WaitListHead
.Flink
= NULL
;
409 /***********************************************************************
410 * KeReleaseMutex (NTOSKRNL.EXE.@)
412 LONG WINAPI
KeReleaseMutex( PRKMUTEX mutex
, BOOLEAN wait
)
416 TRACE("mutex %p, wait %u.\n", mutex
, wait
);
418 EnterCriticalSection( &sync_cs
);
419 ret
= mutex
->Header
.SignalState
++;
420 if (!ret
&& !mutex
->Header
.WaitListHead
.Flink
)
422 CloseHandle( mutex
->Header
.WaitListHead
.Blink
);
423 mutex
->Header
.WaitListHead
.Blink
= NULL
;
425 LeaveCriticalSection( &sync_cs
);
430 /***********************************************************************
431 * KeInitializeGuardedMutex (NTOSKRNL.EXE.@)
433 void WINAPI
KeInitializeGuardedMutex(PKGUARDED_MUTEX mutex
)
435 TRACE("mutex %p.\n", mutex
);
436 mutex
->Count
= FM_LOCK_BIT
;
438 mutex
->Contention
= 0;
439 KeInitializeEvent(&mutex
->Event
, SynchronizationEvent
, FALSE
);
442 static void CALLBACK
ke_timer_complete_proc(PTP_CALLBACK_INSTANCE instance
, void *timer_
, PTP_TIMER tp_timer
)
444 KTIMER
*timer
= timer_
;
445 KDPC
*dpc
= timer
->Dpc
;
447 TRACE("instance %p, timer %p, tp_timer %p.\n", instance
, timer
, tp_timer
);
449 if (dpc
&& dpc
->DeferredRoutine
)
451 TRACE("Calling dpc->DeferredRoutine %p, dpc->DeferredContext %p.\n", dpc
->DeferredRoutine
, dpc
->DeferredContext
);
452 dpc
->DeferredRoutine(dpc
, dpc
->DeferredContext
, dpc
->SystemArgument1
, dpc
->SystemArgument2
);
454 EnterCriticalSection( &sync_cs
);
455 timer
->Header
.SignalState
= TRUE
;
456 if (timer
->Header
.WaitListHead
.Blink
)
457 SetEvent(timer
->Header
.WaitListHead
.Blink
);
458 LeaveCriticalSection( &sync_cs
);
461 /***********************************************************************
462 * KeInitializeTimerEx (NTOSKRNL.EXE.@)
464 void WINAPI
KeInitializeTimerEx( KTIMER
*timer
, TIMER_TYPE type
)
466 TRACE("timer %p, type %u.\n", timer
, type
);
468 RtlZeroMemory(timer
, sizeof(KTIMER
));
469 timer
->Header
.Type
= (type
== NotificationTimer
) ? TYPE_MANUAL_TIMER
: TYPE_AUTO_TIMER
;
470 timer
->Header
.SignalState
= FALSE
;
471 timer
->Header
.Inserted
= FALSE
;
472 timer
->Header
.WaitListHead
.Blink
= NULL
;
473 timer
->Header
.WaitListHead
.Flink
= NULL
;
476 /***********************************************************************
477 * KeInitializeTimer (NTOSKRNL.EXE.@)
479 void WINAPI
KeInitializeTimer( KTIMER
*timer
)
481 KeInitializeTimerEx(timer
, NotificationTimer
);
484 /***********************************************************************
485 * KeSetTimerEx (NTOSKRNL.EXE.@)
487 BOOLEAN WINAPI
KeSetTimerEx( KTIMER
*timer
, LARGE_INTEGER duetime
, LONG period
, KDPC
*dpc
)
491 TRACE("timer %p, duetime %s, period %ld, dpc %p.\n",
492 timer
, wine_dbgstr_longlong(duetime
.QuadPart
), period
, dpc
);
494 EnterCriticalSection( &sync_cs
);
496 if ((ret
= timer
->Header
.Inserted
))
497 KeCancelTimer(timer
);
499 timer
->Header
.Inserted
= TRUE
;
501 if (!timer
->TimerListEntry
.Blink
)
502 timer
->TimerListEntry
.Blink
= (void *)CreateThreadpoolTimer(ke_timer_complete_proc
, timer
, NULL
);
504 if (!timer
->TimerListEntry
.Blink
)
505 ERR("Could not create thread pool timer.\n");
507 timer
->DueTime
.QuadPart
= duetime
.QuadPart
;
508 timer
->Period
= period
;
511 SetThreadpoolTimer((TP_TIMER
*)timer
->TimerListEntry
.Blink
, (FILETIME
*)&duetime
, period
, 0);
512 LeaveCriticalSection( &sync_cs
);
517 BOOLEAN WINAPI
KeCancelTimer( KTIMER
*timer
)
521 TRACE("timer %p.\n", timer
);
523 EnterCriticalSection( &sync_cs
);
524 if (timer
->TimerListEntry
.Blink
)
526 SetThreadpoolTimer((TP_TIMER
*)timer
->TimerListEntry
.Blink
, NULL
, 0, 0);
528 LeaveCriticalSection( &sync_cs
);
529 WaitForThreadpoolTimerCallbacks((TP_TIMER
*)timer
->TimerListEntry
.Blink
, TRUE
);
530 EnterCriticalSection( &sync_cs
);
532 if (timer
->TimerListEntry
.Blink
)
534 CloseThreadpoolTimer((TP_TIMER
*)timer
->TimerListEntry
.Blink
);
535 timer
->TimerListEntry
.Blink
= NULL
;
538 timer
->Header
.SignalState
= FALSE
;
539 if (timer
->Header
.WaitListHead
.Blink
&& !*((ULONG_PTR
*)&timer
->Header
.WaitListHead
.Flink
))
541 CloseHandle(timer
->Header
.WaitListHead
.Blink
);
542 timer
->Header
.WaitListHead
.Blink
= NULL
;
545 ret
= timer
->Header
.Inserted
;
546 timer
->Header
.Inserted
= FALSE
;
547 LeaveCriticalSection( &sync_cs
);
552 /***********************************************************************
553 * KeDelayExecutionThread (NTOSKRNL.EXE.@)
555 NTSTATUS WINAPI
KeDelayExecutionThread( KPROCESSOR_MODE mode
, BOOLEAN alertable
, LARGE_INTEGER
*timeout
)
557 TRACE("mode %d, alertable %u, timeout %p.\n", mode
, alertable
, timeout
);
558 return NtDelayExecution( alertable
, timeout
);
561 /***********************************************************************
562 * KeInitializeSpinLock (NTOSKRNL.EXE.@)
564 void WINAPI
NTOSKRNL_KeInitializeSpinLock( KSPIN_LOCK
*lock
)
566 TRACE("lock %p.\n", lock
);
570 /***********************************************************************
571 * KeAcquireSpinLockAtDpcLevel (NTOSKRNL.EXE.@)
573 void WINAPI
KeAcquireSpinLockAtDpcLevel( KSPIN_LOCK
*lock
)
575 TRACE("lock %p.\n", lock
);
576 while (InterlockedCompareExchangePointer( (void **)lock
, (void *)1, (void *)0 ))
580 /***********************************************************************
581 * KeReleaseSpinLockFromDpcLevel (NTOSKRNL.EXE.@)
583 void WINAPI
KeReleaseSpinLockFromDpcLevel( KSPIN_LOCK
*lock
)
585 TRACE("lock %p.\n", lock
);
586 InterlockedExchangePointer( (void **)lock
, 0 );
589 #define QUEUED_SPINLOCK_OWNED 0x2
591 /***********************************************************************
592 * KeAcquireInStackQueuedSpinLockAtDpcLevel (NTOSKRNL.EXE.@)
594 DEFINE_FASTCALL_WRAPPER( KeAcquireInStackQueuedSpinLockAtDpcLevel
, 8 )
595 void FASTCALL
KeAcquireInStackQueuedSpinLockAtDpcLevel( KSPIN_LOCK
*lock
, KLOCK_QUEUE_HANDLE
*queue
)
597 KSPIN_LOCK_QUEUE
*tail
;
599 TRACE("lock %p, queue %p.\n", lock
, queue
);
601 queue
->LockQueue
.Next
= NULL
;
603 if (!(tail
= InterlockedExchangePointer( (void **)lock
, &queue
->LockQueue
)))
604 queue
->LockQueue
.Lock
= (KSPIN_LOCK
*)((ULONG_PTR
)lock
| QUEUED_SPINLOCK_OWNED
);
607 queue
->LockQueue
.Lock
= lock
;
608 InterlockedExchangePointer( (void **)&tail
->Next
, &queue
->LockQueue
);
610 while (!((ULONG_PTR
)InterlockedCompareExchangePointer( (void **)&queue
->LockQueue
.Lock
, 0, 0 )
611 & QUEUED_SPINLOCK_OWNED
))
618 /***********************************************************************
619 * KeReleaseInStackQueuedSpinLockFromDpcLevel (NTOSKRNL.EXE.@)
621 DEFINE_FASTCALL1_WRAPPER( KeReleaseInStackQueuedSpinLockFromDpcLevel
)
622 void FASTCALL
KeReleaseInStackQueuedSpinLockFromDpcLevel( KLOCK_QUEUE_HANDLE
*queue
)
624 KSPIN_LOCK
*lock
= (KSPIN_LOCK
*)((ULONG_PTR
)queue
->LockQueue
.Lock
& ~QUEUED_SPINLOCK_OWNED
);
625 KSPIN_LOCK_QUEUE
*next
;
627 TRACE("lock %p, queue %p.\n", lock
, queue
);
629 queue
->LockQueue
.Lock
= NULL
;
631 if (!(next
= queue
->LockQueue
.Next
))
633 /* If we are truly the last in the queue, the lock will point to us. */
634 if (InterlockedCompareExchangePointer( (void **)lock
, NULL
, &queue
->LockQueue
) == queue
)
637 /* Otherwise, someone just queued themselves, but hasn't yet set
638 * themselves as successor. Spin waiting for them to do so. */
639 while (!(next
= queue
->LockQueue
.Next
))
643 InterlockedExchangePointer( (void **)&next
->Lock
, (KSPIN_LOCK
*)((ULONG_PTR
)lock
| QUEUED_SPINLOCK_OWNED
) );
647 /***********************************************************************
648 * KeReleaseSpinLock (NTOSKRNL.EXE.@)
650 void WINAPI
KeReleaseSpinLock( KSPIN_LOCK
*lock
, KIRQL irql
)
652 TRACE("lock %p, irql %u.\n", lock
, irql
);
653 KeReleaseSpinLockFromDpcLevel( lock
);
656 /***********************************************************************
657 * KeAcquireSpinLockRaiseToDpc (NTOSKRNL.EXE.@)
659 KIRQL WINAPI
KeAcquireSpinLockRaiseToDpc( KSPIN_LOCK
*lock
)
661 TRACE("lock %p.\n", lock
);
662 KeAcquireSpinLockAtDpcLevel( lock
);
666 /***********************************************************************
667 * KeAcquireInStackQueuedSpinLock (NTOSKRNL.EXE.@)
669 void WINAPI
KeAcquireInStackQueuedSpinLock( KSPIN_LOCK
*lock
, KLOCK_QUEUE_HANDLE
*queue
)
671 TRACE("lock %p, queue %p.\n", lock
, queue
);
672 KeAcquireInStackQueuedSpinLockAtDpcLevel( lock
, queue
);
675 /***********************************************************************
676 * KeReleaseInStackQueuedSpinLock (NTOSKRNL.EXE.@)
678 void WINAPI
KeReleaseInStackQueuedSpinLock( KLOCK_QUEUE_HANDLE
*queue
)
680 TRACE("queue %p.\n", queue
);
681 KeReleaseInStackQueuedSpinLockFromDpcLevel( queue
);
685 /***********************************************************************
686 * KeInitializeApc (NTOSKRNL.EXE.@)
688 void WINAPI
KeInitializeApc(PRKAPC apc
, PRKTHREAD thread
, KAPC_ENVIRONMENT env
, PKKERNEL_ROUTINE krnl_routine
,
689 PKRUNDOWN_ROUTINE rundown_routine
, PKNORMAL_ROUTINE normal_routine
, KPROCESSOR_MODE apc_mode
, PVOID ctx
)
691 TRACE("apc %p thread %p env %u krnl_routine %p rundown_routine %p normal_routine %p apc_mode %u ctx %p\n",
692 apc
, thread
, env
, krnl_routine
, rundown_routine
, normal_routine
, apc_mode
, ctx
);
694 if (env
!= OriginalApcEnvironment
)
695 FIXME("Unhandled APC_ENVIRONMENT\n");
698 apc
->Size
= sizeof(*apc
);
699 apc
->Thread
= thread
;
700 apc
->ApcStateIndex
= env
;
701 apc
->KernelRoutine
= krnl_routine
;
702 apc
->RundownRoutine
= rundown_routine
;
703 apc
->NormalRoutine
= normal_routine
;
704 apc
->Inserted
= FALSE
;
705 if (apc
->NormalRoutine
)
707 apc
->ApcMode
= apc_mode
;
708 apc
->NormalContext
= ctx
;
712 apc
->ApcMode
= KernelMode
;
713 apc
->NormalContext
= NULL
;
717 /***********************************************************************
718 * KeTestAlertThread (NTOSKRNL.EXE.@)
720 BOOLEAN WINAPI
KeTestAlertThread(KPROCESSOR_MODE mode
)
722 FIXME("stub! %u\n", mode
);
726 /***********************************************************************
727 * KeAlertThread (NTOSKRNL.EXE.@)
729 BOOLEAN WINAPI
KeAlertThread(PKTHREAD thread
, KPROCESSOR_MODE mode
)
731 FIXME("stub! %p mode %u\n", thread
, mode
);
735 static KSPIN_LOCK cancel_lock
;
737 /***********************************************************************
738 * IoAcquireCancelSpinLock (NTOSKRNL.EXE.@)
740 void WINAPI
IoAcquireCancelSpinLock( KIRQL
*irql
)
742 TRACE("irql %p.\n", irql
);
743 KeAcquireSpinLock( &cancel_lock
, irql
);
746 /***********************************************************************
747 * IoReleaseCancelSpinLock (NTOSKRNL.EXE.@)
749 void WINAPI
IoReleaseCancelSpinLock( KIRQL irql
)
751 TRACE("irql %u.\n", irql
);
752 KeReleaseSpinLock( &cancel_lock
, irql
);
755 /***********************************************************************
756 * ExfInterlockedRemoveHeadList (NTOSKRNL.EXE.@)
758 DEFINE_FASTCALL_WRAPPER( ExfInterlockedRemoveHeadList
, 8 )
759 PLIST_ENTRY FASTCALL
ExfInterlockedRemoveHeadList( LIST_ENTRY
*list
, KSPIN_LOCK
*lock
)
761 return ExInterlockedRemoveHeadList( list
, lock
);
764 /***********************************************************************
765 * ExInterlockedRemoveHeadList (NTOSKRNL.EXE.@)
767 LIST_ENTRY
* WINAPI
ExInterlockedRemoveHeadList( LIST_ENTRY
*list
, KSPIN_LOCK
*lock
)
772 TRACE("list %p, lock %p.\n", list
, lock
);
774 KeAcquireSpinLock( lock
, &irql
);
775 ret
= RemoveHeadList( list
);
776 KeReleaseSpinLock( lock
, irql
);
782 /***********************************************************************
783 * InterlockedPopEntrySList (NTOSKRNL.EXE.@)
785 DEFINE_FASTCALL1_WRAPPER( NTOSKRNL_InterlockedPopEntrySList
)
786 PSLIST_ENTRY FASTCALL
NTOSKRNL_InterlockedPopEntrySList( PSLIST_HEADER list
)
788 return RtlInterlockedPopEntrySList( list
);
792 /***********************************************************************
793 * InterlockedPushEntrySList (NTOSKRNL.EXE.@)
795 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_InterlockedPushEntrySList
, 8 )
796 PSLIST_ENTRY FASTCALL
NTOSKRNL_InterlockedPushEntrySList( PSLIST_HEADER list
, PSLIST_ENTRY entry
)
798 return RtlInterlockedPushEntrySList( list
, entry
);
802 /***********************************************************************
803 * ExInterlockedPopEntrySList (NTOSKRNL.EXE.@)
805 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_ExInterlockedPopEntrySList
, 8 )
806 PSLIST_ENTRY FASTCALL
NTOSKRNL_ExInterlockedPopEntrySList( PSLIST_HEADER list
, PKSPIN_LOCK lock
)
808 return RtlInterlockedPopEntrySList( list
);
812 /***********************************************************************
813 * ExInterlockedPushEntrySList (NTOSKRNL.EXE.@)
815 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_ExInterlockedPushEntrySList
, 12 )
816 PSLIST_ENTRY FASTCALL
NTOSKRNL_ExInterlockedPushEntrySList( PSLIST_HEADER list
, PSLIST_ENTRY entry
, PKSPIN_LOCK lock
)
818 return RtlInterlockedPushEntrySList( list
, entry
);
822 /***********************************************************************
823 * ExInterlockedFlushSList (NTOSKRNL.EXE.@)
825 DEFINE_FASTCALL1_WRAPPER( NTOSKRNL_ExInterlockedFlushSList
)
826 PSLIST_ENTRY FASTCALL
NTOSKRNL_ExInterlockedFlushSList( PSLIST_HEADER list
)
828 return RtlInterlockedFlushSList( list
);
832 /***********************************************************************
833 * ExAcquireFastMutexUnsafe (NTOSKRNL.EXE.@)
835 DEFINE_FASTCALL1_WRAPPER(ExAcquireFastMutexUnsafe
)
836 void FASTCALL
ExAcquireFastMutexUnsafe( FAST_MUTEX
*mutex
)
840 TRACE("mutex %p.\n", mutex
);
842 count
= InterlockedDecrement( &mutex
->Count
);
844 KeWaitForSingleObject( &mutex
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
847 /***********************************************************************
848 * ExReleaseFastMutexUnsafe (NTOSKRNL.EXE.@)
850 DEFINE_FASTCALL1_WRAPPER(ExReleaseFastMutexUnsafe
)
851 void FASTCALL
ExReleaseFastMutexUnsafe( FAST_MUTEX
*mutex
)
855 TRACE("mutex %p.\n", mutex
);
857 count
= InterlockedIncrement( &mutex
->Count
);
859 KeSetEvent( &mutex
->Event
, IO_NO_INCREMENT
, FALSE
);
864 /***********************************************************************
865 * ExAcquireFastMutex (NTOSKRNL.@)
867 void WINAPI
ExAcquireFastMutex( FAST_MUTEX
*mutex
)
869 /* FIXME: lower IRQL */
870 ExAcquireFastMutexUnsafe( mutex
);
873 /***********************************************************************
874 * ExReleaseFastMutex (NTOSKRNL.@)
876 void WINAPI
ExReleaseFastMutex( FAST_MUTEX
*mutex
)
878 ExReleaseFastMutexUnsafe( mutex
);
879 /* FIXME: restore IRQL */
882 #endif /* __i386__ */
884 /* Use of the fields of an ERESOURCE structure seems to vary wildly between
885 * Windows versions. The below implementation uses them as follows:
887 * OwnerTable - contains a list of shared owners, including threads which do
888 * not currently own the resource
889 * OwnerTable[i].OwnerThread - shared owner TID
890 * OwnerTable[i].OwnerCount - recursion count of this shared owner (may be 0)
891 * OwnerEntry.OwnerThread - the owner TID if exclusively owned
892 * OwnerEntry.TableSize - the number of entries in OwnerTable, including threads
893 * which do not currently own the resource
894 * ActiveEntries - total number of acquisitions (incl. recursive ones)
897 /***********************************************************************
898 * ExInitializeResourceLite (NTOSKRNL.EXE.@)
900 NTSTATUS WINAPI
ExInitializeResourceLite( ERESOURCE
*resource
)
902 TRACE("resource %p.\n", resource
);
903 memset(resource
, 0, sizeof(*resource
));
904 return STATUS_SUCCESS
;
907 /***********************************************************************
908 * ExDeleteResourceLite (NTOSKRNL.EXE.@)
910 NTSTATUS WINAPI
ExDeleteResourceLite( ERESOURCE
*resource
)
912 TRACE("resource %p.\n", resource
);
913 heap_free(resource
->OwnerTable
);
914 heap_free(resource
->ExclusiveWaiters
);
915 heap_free(resource
->SharedWaiters
);
916 return STATUS_SUCCESS
;
919 /* Find an existing entry in the shared owner list, or create a new one. */
920 static OWNER_ENTRY
*resource_get_shared_entry( ERESOURCE
*resource
, ERESOURCE_THREAD thread
)
924 for (i
= 0; i
< resource
->OwnerEntry
.TableSize
; ++i
)
926 if (resource
->OwnerTable
[i
].OwnerThread
== thread
)
927 return &resource
->OwnerTable
[i
];
930 count
= ++resource
->OwnerEntry
.TableSize
;
931 resource
->OwnerTable
= heap_realloc(resource
->OwnerTable
, count
* sizeof(*resource
->OwnerTable
));
932 resource
->OwnerTable
[count
- 1].OwnerThread
= thread
;
933 resource
->OwnerTable
[count
- 1].OwnerCount
= 0;
935 return &resource
->OwnerTable
[count
- 1];
938 /***********************************************************************
939 * ExAcquireResourceExclusiveLite (NTOSKRNL.EXE.@)
941 BOOLEAN WINAPI
ExAcquireResourceExclusiveLite( ERESOURCE
*resource
, BOOLEAN wait
)
945 TRACE("resource %p, wait %u.\n", resource
, wait
);
947 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
949 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
951 resource
->ActiveEntries
++;
952 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
955 /* In order to avoid a race between waiting for the ExclusiveWaiters event
956 * and grabbing the lock, do not grab the resource if it is unclaimed but
957 * has waiters; instead queue ourselves. */
958 else if (!resource
->ActiveEntries
&& !resource
->NumberOfExclusiveWaiters
&& !resource
->NumberOfSharedWaiters
)
960 resource
->Flag
|= ResourceOwnedExclusive
;
961 resource
->OwnerEntry
.OwnerThread
= (ERESOURCE_THREAD
)KeGetCurrentThread();
962 resource
->ActiveEntries
++;
963 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
968 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
972 if (!resource
->ExclusiveWaiters
)
974 resource
->ExclusiveWaiters
= heap_alloc( sizeof(*resource
->ExclusiveWaiters
) );
975 KeInitializeEvent( resource
->ExclusiveWaiters
, SynchronizationEvent
, FALSE
);
977 resource
->NumberOfExclusiveWaiters
++;
979 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
981 KeWaitForSingleObject( resource
->ExclusiveWaiters
, Executive
, KernelMode
, FALSE
, NULL
);
983 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
985 resource
->Flag
|= ResourceOwnedExclusive
;
986 resource
->OwnerEntry
.OwnerThread
= (ERESOURCE_THREAD
)KeGetCurrentThread();
987 resource
->ActiveEntries
++;
988 resource
->NumberOfExclusiveWaiters
--;
990 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
995 /***********************************************************************
996 * ExAcquireResourceSharedLite (NTOSKRNL.EXE.@)
998 BOOLEAN WINAPI
ExAcquireResourceSharedLite( ERESOURCE
*resource
, BOOLEAN wait
)
1003 TRACE("resource %p, wait %u.\n", resource
, wait
);
1005 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1007 entry
= resource_get_shared_entry( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
1009 if (resource
->Flag
& ResourceOwnedExclusive
)
1011 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
1013 /* We own the resource exclusively, so increase recursion. */
1014 resource
->ActiveEntries
++;
1015 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1019 else if (entry
->OwnerCount
|| !resource
->NumberOfExclusiveWaiters
)
1021 /* Either we already own the resource shared, or there are no exclusive
1022 * owners or waiters, so we can grab it shared. */
1023 entry
->OwnerCount
++;
1024 resource
->ActiveEntries
++;
1025 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1031 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1035 if (!resource
->SharedWaiters
)
1037 resource
->SharedWaiters
= heap_alloc( sizeof(*resource
->SharedWaiters
) );
1038 KeInitializeSemaphore( resource
->SharedWaiters
, 0, INT_MAX
);
1040 resource
->NumberOfSharedWaiters
++;
1042 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1044 KeWaitForSingleObject( resource
->SharedWaiters
, Executive
, KernelMode
, FALSE
, NULL
);
1046 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1048 entry
->OwnerCount
++;
1049 resource
->ActiveEntries
++;
1050 resource
->NumberOfSharedWaiters
--;
1052 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1057 /***********************************************************************
1058 * ExAcquireSharedStarveExclusive (NTOSKRNL.EXE.@)
1060 BOOLEAN WINAPI
ExAcquireSharedStarveExclusive( ERESOURCE
*resource
, BOOLEAN wait
)
1065 TRACE("resource %p, wait %u.\n", resource
, wait
);
1067 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1069 entry
= resource_get_shared_entry( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
1071 if (resource
->Flag
& ResourceOwnedExclusive
)
1073 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
1075 resource
->ActiveEntries
++;
1076 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1080 /* We are starving exclusive waiters, but we cannot steal the resource out
1081 * from under an exclusive waiter who is about to acquire it. (Because of
1082 * locking, and because exclusive waiters are always waked first, this is
1083 * guaranteed to be the case if the resource is unowned and there are
1084 * exclusive waiters.) */
1085 else if (!(!resource
->ActiveEntries
&& resource
->NumberOfExclusiveWaiters
))
1087 entry
->OwnerCount
++;
1088 resource
->ActiveEntries
++;
1089 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1095 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1099 if (!resource
->SharedWaiters
)
1101 resource
->SharedWaiters
= heap_alloc( sizeof(*resource
->SharedWaiters
) );
1102 KeInitializeSemaphore( resource
->SharedWaiters
, 0, INT_MAX
);
1104 resource
->NumberOfSharedWaiters
++;
1106 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1108 KeWaitForSingleObject( resource
->SharedWaiters
, Executive
, KernelMode
, FALSE
, NULL
);
1110 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1112 entry
->OwnerCount
++;
1113 resource
->ActiveEntries
++;
1114 resource
->NumberOfSharedWaiters
--;
1116 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1121 /***********************************************************************
1122 * ExAcquireSharedWaitForExclusive (NTOSKRNL.EXE.@)
1124 BOOLEAN WINAPI
ExAcquireSharedWaitForExclusive( ERESOURCE
*resource
, BOOLEAN wait
)
1129 TRACE("resource %p, wait %u.\n", resource
, wait
);
1131 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1133 entry
= resource_get_shared_entry( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
1135 if (resource
->Flag
& ResourceOwnedExclusive
)
1137 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
1139 /* We own the resource exclusively, so increase recursion. */
1140 resource
->ActiveEntries
++;
1141 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1145 /* We may only grab the resource if there are no exclusive waiters, even if
1146 * we already own it shared. */
1147 else if (!resource
->NumberOfExclusiveWaiters
)
1149 entry
->OwnerCount
++;
1150 resource
->ActiveEntries
++;
1151 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1157 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1161 if (!resource
->SharedWaiters
)
1163 resource
->SharedWaiters
= heap_alloc( sizeof(*resource
->SharedWaiters
) );
1164 KeInitializeSemaphore( resource
->SharedWaiters
, 0, INT_MAX
);
1166 resource
->NumberOfSharedWaiters
++;
1168 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1170 KeWaitForSingleObject( resource
->SharedWaiters
, Executive
, KernelMode
, FALSE
, NULL
);
1172 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1174 entry
->OwnerCount
++;
1175 resource
->ActiveEntries
++;
1176 resource
->NumberOfSharedWaiters
--;
1178 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1183 /***********************************************************************
1184 * ExReleaseResourceForThreadLite (NTOSKRNL.EXE.@)
1186 void WINAPI
ExReleaseResourceForThreadLite( ERESOURCE
*resource
, ERESOURCE_THREAD thread
)
1191 TRACE("resource %p, thread %#Ix.\n", resource
, thread
);
1193 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1195 if (resource
->Flag
& ResourceOwnedExclusive
)
1197 if (resource
->OwnerEntry
.OwnerThread
== thread
)
1199 if (!--resource
->ActiveEntries
)
1201 resource
->OwnerEntry
.OwnerThread
= 0;
1202 resource
->Flag
&= ~ResourceOwnedExclusive
;
1207 ERR("Trying to release %p for thread %#Ix, but resource is exclusively owned by %#Ix.\n",
1208 resource
, thread
, resource
->OwnerEntry
.OwnerThread
);
1214 entry
= resource_get_shared_entry( resource
, thread
);
1215 if (entry
->OwnerCount
)
1217 entry
->OwnerCount
--;
1218 resource
->ActiveEntries
--;
1222 ERR("Trying to release %p for thread %#Ix, but resource is not owned by that thread.\n", resource
, thread
);
1227 if (!resource
->ActiveEntries
)
1229 if (resource
->NumberOfExclusiveWaiters
)
1231 KeSetEvent( resource
->ExclusiveWaiters
, IO_NO_INCREMENT
, FALSE
);
1233 else if (resource
->NumberOfSharedWaiters
)
1235 KeReleaseSemaphore( resource
->SharedWaiters
, IO_NO_INCREMENT
,
1236 resource
->NumberOfSharedWaiters
, FALSE
);
1240 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1243 /***********************************************************************
1244 * ExReleaseResourceLite (NTOSKRNL.EXE.@)
1246 DEFINE_FASTCALL1_WRAPPER( ExReleaseResourceLite
)
1247 void FASTCALL
ExReleaseResourceLite( ERESOURCE
*resource
)
1249 ExReleaseResourceForThreadLite( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
1252 /***********************************************************************
1253 * ExGetExclusiveWaiterCount (NTOSKRNL.EXE.@)
1255 ULONG WINAPI
ExGetExclusiveWaiterCount( ERESOURCE
*resource
)
1260 TRACE("resource %p.\n", resource
);
1262 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1264 count
= resource
->NumberOfExclusiveWaiters
;
1266 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1271 /***********************************************************************
1272 * ExGetSharedWaiterCount (NTOSKRNL.EXE.@)
1274 ULONG WINAPI
ExGetSharedWaiterCount( ERESOURCE
*resource
)
1279 TRACE("resource %p.\n", resource
);
1281 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1283 count
= resource
->NumberOfSharedWaiters
;
1285 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1290 /***********************************************************************
1291 * ExIsResourceAcquiredExclusiveLite (NTOSKRNL.EXE.@)
1293 BOOLEAN WINAPI
ExIsResourceAcquiredExclusiveLite( ERESOURCE
*resource
)
1298 TRACE("resource %p.\n", resource
);
1300 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1302 ret
= (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread());
1304 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1309 /***********************************************************************
1310 * ExIsResourceAcquiredSharedLite (NTOSKRNL.EXE.@)
1312 ULONG WINAPI
ExIsResourceAcquiredSharedLite( ERESOURCE
*resource
)
1317 TRACE("resource %p.\n", resource
);
1319 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1321 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
1322 ret
= resource
->ActiveEntries
;
1325 OWNER_ENTRY
*entry
= resource_get_shared_entry( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
1326 ret
= entry
->OwnerCount
;
1329 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1334 /***********************************************************************
1335 * IoInitializeRemoveLockEx (NTOSKRNL.EXE.@)
1337 void WINAPI
IoInitializeRemoveLockEx( IO_REMOVE_LOCK
*lock
, ULONG tag
,
1338 ULONG max_minutes
, ULONG max_count
, ULONG size
)
1340 TRACE("lock %p, tag %#lx, max_minutes %lu, max_count %lu, size %lu.\n",
1341 lock
, tag
, max_minutes
, max_count
, size
);
1343 KeInitializeEvent( &lock
->Common
.RemoveEvent
, NotificationEvent
, FALSE
);
1344 lock
->Common
.Removed
= FALSE
;
1345 lock
->Common
.IoCount
= 0;
1348 /***********************************************************************
1349 * IoAcquireRemoveLockEx (NTOSKRNL.EXE.@)
1351 NTSTATUS WINAPI
IoAcquireRemoveLockEx( IO_REMOVE_LOCK
*lock
, void *tag
,
1352 const char *file
, ULONG line
, ULONG size
)
1354 TRACE("lock %p, tag %p, file %s, line %lu, size %lu.\n", lock
, tag
, debugstr_a(file
), line
, size
);
1356 if (lock
->Common
.Removed
)
1357 return STATUS_DELETE_PENDING
;
1359 InterlockedIncrement( &lock
->Common
.IoCount
);
1360 return STATUS_SUCCESS
;
1363 /***********************************************************************
1364 * IoReleaseRemoveLockEx (NTOSKRNL.EXE.@)
1366 void WINAPI
IoReleaseRemoveLockEx( IO_REMOVE_LOCK
*lock
, void *tag
, ULONG size
)
1370 TRACE("lock %p, tag %p, size %lu.\n", lock
, tag
, size
);
1372 if (!(count
= InterlockedDecrement( &lock
->Common
.IoCount
)) && lock
->Common
.Removed
)
1373 KeSetEvent( &lock
->Common
.RemoveEvent
, IO_NO_INCREMENT
, FALSE
);
1375 ERR("Lock %p is not acquired!\n", lock
);
1378 /***********************************************************************
1379 * IoReleaseRemoveLockAndWaitEx (NTOSKRNL.EXE.@)
1381 void WINAPI
IoReleaseRemoveLockAndWaitEx( IO_REMOVE_LOCK
*lock
, void *tag
, ULONG size
)
1385 TRACE("lock %p, tag %p, size %lu.\n", lock
, tag
, size
);
1387 lock
->Common
.Removed
= TRUE
;
1389 if (!(count
= InterlockedDecrement( &lock
->Common
.IoCount
)))
1390 KeSetEvent( &lock
->Common
.RemoveEvent
, IO_NO_INCREMENT
, FALSE
);
1392 ERR("Lock %p is not acquired!\n", lock
);
1394 KeWaitForSingleObject( &lock
->Common
.RemoveEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1397 BOOLEAN WINAPI
KeSetTimer(KTIMER
*timer
, LARGE_INTEGER duetime
, KDPC
*dpc
)
1399 TRACE("timer %p, duetime %I64x, dpc %p.\n", timer
, duetime
.QuadPart
, dpc
);
1401 return KeSetTimerEx(timer
, duetime
, 0, dpc
);
1404 void WINAPI
KeInitializeDeviceQueue( KDEVICE_QUEUE
*queue
)
1406 TRACE( "queue %p.\n", queue
);
1408 KeInitializeSpinLock( &queue
->Lock
);
1409 InitializeListHead( &queue
->DeviceListHead
);
1410 queue
->Busy
= FALSE
;
1411 queue
->Type
= IO_TYPE_DEVICE_QUEUE
;
1412 queue
->Size
= sizeof(*queue
);
1415 BOOLEAN WINAPI
KeInsertDeviceQueue( KDEVICE_QUEUE
*queue
, KDEVICE_QUEUE_ENTRY
*entry
)
1420 TRACE( "queue %p, entry %p.\n", queue
, entry
);
1422 KeAcquireSpinLock( &queue
->Lock
, &irql
);
1423 insert
= entry
->Inserted
= queue
->Busy
;
1424 if (insert
) InsertTailList( &queue
->DeviceListHead
, &entry
->DeviceListEntry
);
1426 KeReleaseSpinLock( &queue
->Lock
, irql
);
1431 KDEVICE_QUEUE_ENTRY
*WINAPI
KeRemoveDeviceQueue( KDEVICE_QUEUE
*queue
)
1433 KDEVICE_QUEUE_ENTRY
*entry
= NULL
;
1436 TRACE( "queue %p.\n", queue
);
1438 KeAcquireSpinLock( &queue
->Lock
, &irql
);
1439 if (IsListEmpty( &queue
->DeviceListHead
)) queue
->Busy
= FALSE
;
1442 entry
= CONTAINING_RECORD( RemoveHeadList( &queue
->DeviceListHead
),
1443 KDEVICE_QUEUE_ENTRY
, DeviceListEntry
);
1444 entry
->Inserted
= FALSE
;
1446 KeReleaseSpinLock( &queue
->Lock
, irql
);