d3d11/tests: Move the is_warp_device() call out of the loop in check_format_support().
[wine.git] / dlls / ntoskrnl.exe / sync.c
blobb8239b0cd7dee176be6c6e668bad5437f9209843
1 /*
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
21 #include <limits.h>
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);
31 enum object_type
33 TYPE_MANUAL_EVENT = 0,
34 TYPE_AUTO_EVENT = 1,
35 TYPE_MUTEX = 2,
36 TYPE_SEMAPHORE = 5,
37 TYPE_MANUAL_TIMER = 8,
38 TYPE_AUTO_TIMER = 9,
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];
52 NTSTATUS ret;
53 ULONG i;
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] );
68 continue;
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 );
79 break;
80 case TYPE_AUTO_TIMER:
81 case TYPE_AUTO_EVENT:
82 objs[i]->WaitListHead.Blink = CreateEventW( NULL, FALSE, objs[i]->SignalState, NULL );
83 break;
84 case TYPE_MUTEX:
85 objs[i]->WaitListHead.Blink = CreateMutexW( NULL, FALSE, NULL );
86 break;
87 case TYPE_SEMAPHORE:
89 KSEMAPHORE *semaphore = CONTAINING_RECORD(objs[i], KSEMAPHORE, Header);
90 objs[i]->WaitListHead.Blink = CreateSemaphoreW( NULL,
91 semaphore->Header.SignalState, semaphore->Limit, NULL );
92 break;
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;
113 break;
114 case TYPE_MUTEX:
115 case TYPE_SEMAPHORE:
116 --objs[i]->SignalState;
117 break;
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:
133 case TYPE_SEMAPHORE:
134 CloseHandle(objs[i]->WaitListHead.Blink);
135 objs[i]->WaitListHead.Blink = NULL;
136 break;
137 case TYPE_MUTEX:
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;
145 break;
149 LeaveCriticalSection( &sync_cs );
151 return ret;
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;
189 KEVENT *event;
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 */
196 return event;
199 static const WCHAR event_type_name[] = {'E','v','e','n','t',0};
201 static struct _OBJECT_TYPE event_type = {
202 event_type_name,
203 create_event_object
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;
214 HANDLE handle;
215 KEVENT *event;
216 NTSTATUS ret;
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 ))
226 NtClose( handle);
227 return NULL;
230 *ret_handle = handle;
231 return event;
234 /***********************************************************************
235 * KeSetEvent (NTOSKRNL.EXE.@)
237 LONG WINAPI KeSetEvent( PRKEVENT event, KPRIORITY increment, BOOLEAN wait )
239 HANDLE handle;
240 LONG ret = 0;
242 TRACE("event %p, increment %ld, 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))
249 SetEvent( handle );
250 LeaveCriticalSection( &sync_cs );
252 else
254 if (!ObOpenObjectByPointer( event, OBJ_KERNEL_HANDLE, NULL, EVENT_MODIFY_STATE, NULL, KernelMode, &handle ))
256 NtSetEvent( handle, &ret );
257 NtClose( handle );
259 event->Header.SignalState = TRUE;
262 return ret;
265 /***********************************************************************
266 * KeResetEvent (NTOSKRNL.EXE.@)
268 LONG WINAPI KeResetEvent( PRKEVENT event )
270 HANDLE handle;
271 LONG ret = 0;
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 );
283 else
285 if (!ObOpenObjectByPointer( event, OBJ_KERNEL_HANDLE, NULL, EVENT_MODIFY_STATE, NULL, KernelMode, &handle ))
287 NtResetEvent( handle, &ret );
288 NtClose( handle );
290 event->Header.SignalState = FALSE;
293 return ret;
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 )
309 HANDLE handle;
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;
320 NtClose( handle );
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 %ld, limit %ld.\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 )
346 HANDLE handle;
347 LONG ret;
349 TRACE("semaphore %p, increment %ld, count %ld, 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 );
358 return ret;
361 static const WCHAR semaphore_type_name[] = {'S','e','m','a','p','h','o','r','e',0};
363 static struct _OBJECT_TYPE semaphore_type =
365 semaphore_type_name
368 POBJECT_TYPE ExSemaphoreObjectType = &semaphore_type;
370 /***********************************************************************
371 * KeInitializeMutex (NTOSKRNL.EXE.@)
373 void WINAPI KeInitializeMutex( PRKMUTEX mutex, ULONG level )
375 TRACE("mutex %p, level %lu.\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 )
388 LONG ret;
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 );
401 return ret;
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 )
451 BOOL ret;
453 TRACE("timer %p, duetime %s, period %ld, 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;
471 timer->Dpc = dpc;
473 SetThreadpoolTimer((TP_TIMER *)timer->TimerListEntry.Blink, (FILETIME *)&duetime, period, 0);
474 LeaveCriticalSection( &sync_cs );
476 return ret;
479 BOOLEAN WINAPI KeCancelTimer( KTIMER *timer )
481 BOOL ret;
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 );
511 return ret;
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);
529 *lock = 0;
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 ))
539 YieldProcessor();
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);
567 else
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))
575 YieldProcessor();
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)
597 return;
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))
602 YieldProcessor();
605 InterlockedExchangePointer( (void **)&next->Lock, (KSPIN_LOCK *)((ULONG_PTR)lock | QUEUED_SPINLOCK_OWNED) );
608 #ifndef __i386__
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 );
625 return 0;
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 );
645 #endif
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");
659 apc->Type = 18;
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;
672 else
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);
685 return TRUE;
688 /***********************************************************************
689 * KeAlertThread (NTOSKRNL.EXE.@)
691 BOOLEAN WINAPI KeAlertThread(PKTHREAD thread, KPROCESSOR_MODE mode)
693 FIXME("stub! %p mode %u\n", thread, mode);
694 return TRUE;
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 )
731 LIST_ENTRY *ret;
732 KIRQL irql;
734 TRACE("list %p, lock %p.\n", list, lock);
736 KeAcquireSpinLock( lock, &irql );
737 ret = RemoveHeadList( list );
738 KeReleaseSpinLock( lock, irql );
740 return ret;
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 )
800 LONG count;
802 TRACE("mutex %p.\n", mutex);
804 count = InterlockedDecrement( &mutex->Count );
805 if (count < 0)
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 )
815 LONG count;
817 TRACE("mutex %p.\n", mutex);
819 count = InterlockedIncrement( &mutex->Count );
820 if (count < 1)
821 KeSetEvent( &mutex->Event, IO_NO_INCREMENT, FALSE );
824 #ifndef __i386__
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 )
884 ULONG i, count;
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 )
905 KIRQL irql;
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 );
915 return TRUE;
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 );
926 return TRUE;
928 else if (!wait)
930 KeReleaseSpinLock( &resource->SpinLock, irql );
931 return FALSE;
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 );
954 return TRUE;
957 /***********************************************************************
958 * ExAcquireResourceSharedLite (NTOSKRNL.EXE.@)
960 BOOLEAN WINAPI ExAcquireResourceSharedLite( ERESOURCE *resource, BOOLEAN wait )
962 OWNER_ENTRY *entry;
963 KIRQL irql;
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 );
978 return TRUE;
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. */
985 entry->OwnerCount++;
986 resource->ActiveEntries++;
987 KeReleaseSpinLock( &resource->SpinLock, irql );
988 return TRUE;
991 if (!wait)
993 KeReleaseSpinLock( &resource->SpinLock, irql );
994 return FALSE;
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 );
1016 return TRUE;
1019 /***********************************************************************
1020 * ExAcquireSharedStarveExclusive (NTOSKRNL.EXE.@)
1022 BOOLEAN WINAPI ExAcquireSharedStarveExclusive( ERESOURCE *resource, BOOLEAN wait )
1024 OWNER_ENTRY *entry;
1025 KIRQL irql;
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 );
1039 return TRUE;
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 );
1052 return TRUE;
1055 if (!wait)
1057 KeReleaseSpinLock( &resource->SpinLock, irql );
1058 return FALSE;
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 );
1080 return TRUE;
1083 /***********************************************************************
1084 * ExAcquireSharedWaitForExclusive (NTOSKRNL.EXE.@)
1086 BOOLEAN WINAPI ExAcquireSharedWaitForExclusive( ERESOURCE *resource, BOOLEAN wait )
1088 OWNER_ENTRY *entry;
1089 KIRQL irql;
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 );
1104 return TRUE;
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 );
1114 return TRUE;
1117 if (!wait)
1119 KeReleaseSpinLock( &resource->SpinLock, irql );
1120 return FALSE;
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 );
1142 return TRUE;
1145 /***********************************************************************
1146 * ExReleaseResourceForThreadLite (NTOSKRNL.EXE.@)
1148 void WINAPI ExReleaseResourceForThreadLite( ERESOURCE *resource, ERESOURCE_THREAD thread )
1150 OWNER_ENTRY *entry;
1151 KIRQL irql;
1153 TRACE("resource %p, thread %#Ix.\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;
1167 else
1169 ERR("Trying to release %p for thread %#Ix, but resource is exclusively owned by %#Ix.\n",
1170 resource, thread, resource->OwnerEntry.OwnerThread);
1171 return;
1174 else
1176 entry = resource_get_shared_entry( resource, thread );
1177 if (entry->OwnerCount)
1179 entry->OwnerCount--;
1180 resource->ActiveEntries--;
1182 else
1184 ERR("Trying to release %p for thread %#Ix, but resource is not owned by that thread.\n", resource, thread);
1185 return;
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 )
1219 ULONG count;
1220 KIRQL irql;
1222 TRACE("resource %p.\n", resource);
1224 KeAcquireSpinLock( &resource->SpinLock, &irql );
1226 count = resource->NumberOfExclusiveWaiters;
1228 KeReleaseSpinLock( &resource->SpinLock, irql );
1230 return count;
1233 /***********************************************************************
1234 * ExGetSharedWaiterCount (NTOSKRNL.EXE.@)
1236 ULONG WINAPI ExGetSharedWaiterCount( ERESOURCE *resource )
1238 ULONG count;
1239 KIRQL irql;
1241 TRACE("resource %p.\n", resource);
1243 KeAcquireSpinLock( &resource->SpinLock, &irql );
1245 count = resource->NumberOfSharedWaiters;
1247 KeReleaseSpinLock( &resource->SpinLock, irql );
1249 return count;
1252 /***********************************************************************
1253 * ExIsResourceAcquiredExclusiveLite (NTOSKRNL.EXE.@)
1255 BOOLEAN WINAPI ExIsResourceAcquiredExclusiveLite( ERESOURCE *resource )
1257 BOOLEAN ret;
1258 KIRQL irql;
1260 TRACE("resource %p.\n", resource);
1262 KeAcquireSpinLock( &resource->SpinLock, &irql );
1264 ret = (resource->OwnerEntry.OwnerThread == (ERESOURCE_THREAD)KeGetCurrentThread());
1266 KeReleaseSpinLock( &resource->SpinLock, irql );
1268 return ret;
1271 /***********************************************************************
1272 * ExIsResourceAcquiredSharedLite (NTOSKRNL.EXE.@)
1274 ULONG WINAPI ExIsResourceAcquiredSharedLite( ERESOURCE *resource )
1276 ULONG ret;
1277 KIRQL irql;
1279 TRACE("resource %p.\n", resource);
1281 KeAcquireSpinLock( &resource->SpinLock, &irql );
1283 if (resource->OwnerEntry.OwnerThread == (ERESOURCE_THREAD)KeGetCurrentThread())
1284 ret = resource->ActiveEntries;
1285 else
1287 OWNER_ENTRY *entry = resource_get_shared_entry( resource, (ERESOURCE_THREAD)KeGetCurrentThread() );
1288 ret = entry->OwnerCount;
1291 KeReleaseSpinLock( &resource->SpinLock, irql );
1293 return ret;
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 %#lx, max_minutes %lu, max_count %lu, size %lu.\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 %lu, size %lu.\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 )
1330 LONG count;
1332 TRACE("lock %p, tag %p, size %lu.\n", lock, tag, size);
1334 if (!(count = InterlockedDecrement( &lock->Common.IoCount )) && lock->Common.Removed)
1335 KeSetEvent( &lock->Common.RemoveEvent, IO_NO_INCREMENT, FALSE );
1336 else if (count < 0)
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 )
1345 LONG count;
1347 TRACE("lock %p, tag %p, size %lu.\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 );
1353 else if (count < 0)
1354 ERR("Lock %p is not acquired!\n", lock);
1355 else if (count > 0)
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 )
1379 BOOL insert;
1380 KIRQL irql;
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 );
1387 queue->Busy = TRUE;
1388 KeReleaseSpinLock( &queue->Lock, irql );
1390 return insert;
1393 KDEVICE_QUEUE_ENTRY *WINAPI KeRemoveDeviceQueue( KDEVICE_QUEUE *queue )
1395 KDEVICE_QUEUE_ENTRY *entry = NULL;
1396 KIRQL irql;
1398 TRACE( "queue %p.\n", queue );
1400 KeAcquireSpinLock( &queue->Lock, &irql );
1401 if (IsListEmpty( &queue->DeviceListHead )) queue->Busy = FALSE;
1402 else
1404 entry = CONTAINING_RECORD( RemoveHeadList( &queue->DeviceListHead ),
1405 KDEVICE_QUEUE_ENTRY, DeviceListEntry );
1406 entry->Inserted = FALSE;
1408 KeReleaseSpinLock( &queue->Lock, irql );
1410 return entry;