win32u: Use the dummy surface for empty layered window surfaces.
[wine.git] / dlls / ntoskrnl.exe / sync.c
blobd9b5726b9206e6d7a6e61a4cf96dd32b586171b5
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( "(%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 ))
226 NtClose( handle );
227 return NULL;
230 *ret_handle = handle;
231 return event;
234 /***********************************************************************
235 * IoCreateNotificationEvent (NTOSKRNL.EXE.@)
237 PKEVENT WINAPI IoCreateNotificationEvent( UNICODE_STRING *name, HANDLE *ret_handle )
239 OBJECT_ATTRIBUTES attr;
240 HANDLE handle;
241 KEVENT *event;
242 NTSTATUS ret;
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 ))
252 NtClose(handle);
253 return NULL;
256 *ret_handle = handle;
257 return event;
260 /***********************************************************************
261 * KeSetEvent (NTOSKRNL.EXE.@)
263 LONG WINAPI KeSetEvent( PRKEVENT event, KPRIORITY increment, BOOLEAN wait )
265 HANDLE handle;
266 LONG ret = 0;
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))
275 SetEvent( handle );
276 LeaveCriticalSection( &sync_cs );
278 else
280 if (!ObOpenObjectByPointer( event, OBJ_KERNEL_HANDLE, NULL, EVENT_MODIFY_STATE, NULL, KernelMode, &handle ))
282 NtSetEvent( handle, &ret );
283 NtClose( handle );
285 event->Header.SignalState = TRUE;
288 return ret;
291 /***********************************************************************
292 * KeResetEvent (NTOSKRNL.EXE.@)
294 LONG WINAPI KeResetEvent( PRKEVENT event )
296 HANDLE handle;
297 LONG ret = 0;
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 );
309 else
311 if (!ObOpenObjectByPointer( event, OBJ_KERNEL_HANDLE, NULL, EVENT_MODIFY_STATE, NULL, KernelMode, &handle ))
313 NtResetEvent( handle, &ret );
314 NtClose( handle );
316 event->Header.SignalState = FALSE;
319 return ret;
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 )
335 HANDLE handle;
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;
346 NtClose( handle );
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 )
372 HANDLE handle;
373 LONG ret;
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 );
384 return ret;
387 static const WCHAR semaphore_type_name[] = {'S','e','m','a','p','h','o','r','e',0};
389 static struct _OBJECT_TYPE semaphore_type =
391 semaphore_type_name
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 )
414 LONG ret;
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 );
427 return ret;
430 /***********************************************************************
431 * KeInitializeGuardedMutex (NTOSKRNL.EXE.@)
433 void WINAPI KeInitializeGuardedMutex(PKGUARDED_MUTEX mutex)
435 TRACE("mutex %p.\n", mutex);
436 mutex->Count = FM_LOCK_BIT;
437 mutex->Owner = NULL;
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 )
489 BOOL ret;
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;
509 timer->Dpc = dpc;
511 SetThreadpoolTimer((TP_TIMER *)timer->TimerListEntry.Blink, (FILETIME *)&duetime, period, 0);
512 LeaveCriticalSection( &sync_cs );
514 return ret;
517 BOOLEAN WINAPI KeCancelTimer( KTIMER *timer )
519 BOOL ret;
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 );
549 return ret;
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);
567 *lock = 0;
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 ))
577 YieldProcessor();
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);
605 else
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))
613 YieldProcessor();
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)
635 return;
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))
640 YieldProcessor();
643 InterlockedExchangePointer( (void **)&next->Lock, (KSPIN_LOCK *)((ULONG_PTR)lock | QUEUED_SPINLOCK_OWNED) );
646 #ifndef __i386__
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 );
663 return 0;
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 );
683 #endif
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");
697 apc->Type = 18;
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;
710 else
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);
723 return TRUE;
726 /***********************************************************************
727 * KeAlertThread (NTOSKRNL.EXE.@)
729 BOOLEAN WINAPI KeAlertThread(PKTHREAD thread, KPROCESSOR_MODE mode)
731 FIXME("stub! %p mode %u\n", thread, mode);
732 return TRUE;
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 )
769 LIST_ENTRY *ret;
770 KIRQL irql;
772 TRACE("list %p, lock %p.\n", list, lock);
774 KeAcquireSpinLock( lock, &irql );
775 ret = RemoveHeadList( list );
776 KeReleaseSpinLock( lock, irql );
778 return ret;
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 )
838 LONG count;
840 TRACE("mutex %p.\n", mutex);
842 count = InterlockedDecrement( &mutex->Count );
843 if (count < 0)
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 )
853 LONG count;
855 TRACE("mutex %p.\n", mutex);
857 count = InterlockedIncrement( &mutex->Count );
858 if (count < 1)
859 KeSetEvent( &mutex->Event, IO_NO_INCREMENT, FALSE );
862 #ifndef __i386__
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 )
922 ULONG i, count;
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 )
943 KIRQL irql;
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 );
953 return TRUE;
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 );
964 return TRUE;
966 else if (!wait)
968 KeReleaseSpinLock( &resource->SpinLock, irql );
969 return FALSE;
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 );
992 return TRUE;
995 /***********************************************************************
996 * ExAcquireResourceSharedLite (NTOSKRNL.EXE.@)
998 BOOLEAN WINAPI ExAcquireResourceSharedLite( ERESOURCE *resource, BOOLEAN wait )
1000 OWNER_ENTRY *entry;
1001 KIRQL irql;
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 );
1016 return TRUE;
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 );
1026 return TRUE;
1029 if (!wait)
1031 KeReleaseSpinLock( &resource->SpinLock, irql );
1032 return FALSE;
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 );
1054 return TRUE;
1057 /***********************************************************************
1058 * ExAcquireSharedStarveExclusive (NTOSKRNL.EXE.@)
1060 BOOLEAN WINAPI ExAcquireSharedStarveExclusive( ERESOURCE *resource, BOOLEAN wait )
1062 OWNER_ENTRY *entry;
1063 KIRQL irql;
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 );
1077 return TRUE;
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 );
1090 return TRUE;
1093 if (!wait)
1095 KeReleaseSpinLock( &resource->SpinLock, irql );
1096 return FALSE;
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 );
1118 return TRUE;
1121 /***********************************************************************
1122 * ExAcquireSharedWaitForExclusive (NTOSKRNL.EXE.@)
1124 BOOLEAN WINAPI ExAcquireSharedWaitForExclusive( ERESOURCE *resource, BOOLEAN wait )
1126 OWNER_ENTRY *entry;
1127 KIRQL irql;
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 );
1142 return TRUE;
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 );
1152 return TRUE;
1155 if (!wait)
1157 KeReleaseSpinLock( &resource->SpinLock, irql );
1158 return FALSE;
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 );
1180 return TRUE;
1183 /***********************************************************************
1184 * ExReleaseResourceForThreadLite (NTOSKRNL.EXE.@)
1186 void WINAPI ExReleaseResourceForThreadLite( ERESOURCE *resource, ERESOURCE_THREAD thread )
1188 OWNER_ENTRY *entry;
1189 KIRQL irql;
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;
1205 else
1207 ERR("Trying to release %p for thread %#Ix, but resource is exclusively owned by %#Ix.\n",
1208 resource, thread, resource->OwnerEntry.OwnerThread);
1209 return;
1212 else
1214 entry = resource_get_shared_entry( resource, thread );
1215 if (entry->OwnerCount)
1217 entry->OwnerCount--;
1218 resource->ActiveEntries--;
1220 else
1222 ERR("Trying to release %p for thread %#Ix, but resource is not owned by that thread.\n", resource, thread);
1223 return;
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 )
1257 ULONG count;
1258 KIRQL irql;
1260 TRACE("resource %p.\n", resource);
1262 KeAcquireSpinLock( &resource->SpinLock, &irql );
1264 count = resource->NumberOfExclusiveWaiters;
1266 KeReleaseSpinLock( &resource->SpinLock, irql );
1268 return count;
1271 /***********************************************************************
1272 * ExGetSharedWaiterCount (NTOSKRNL.EXE.@)
1274 ULONG WINAPI ExGetSharedWaiterCount( ERESOURCE *resource )
1276 ULONG count;
1277 KIRQL irql;
1279 TRACE("resource %p.\n", resource);
1281 KeAcquireSpinLock( &resource->SpinLock, &irql );
1283 count = resource->NumberOfSharedWaiters;
1285 KeReleaseSpinLock( &resource->SpinLock, irql );
1287 return count;
1290 /***********************************************************************
1291 * ExIsResourceAcquiredExclusiveLite (NTOSKRNL.EXE.@)
1293 BOOLEAN WINAPI ExIsResourceAcquiredExclusiveLite( ERESOURCE *resource )
1295 BOOLEAN ret;
1296 KIRQL irql;
1298 TRACE("resource %p.\n", resource);
1300 KeAcquireSpinLock( &resource->SpinLock, &irql );
1302 ret = (resource->OwnerEntry.OwnerThread == (ERESOURCE_THREAD)KeGetCurrentThread());
1304 KeReleaseSpinLock( &resource->SpinLock, irql );
1306 return ret;
1309 /***********************************************************************
1310 * ExIsResourceAcquiredSharedLite (NTOSKRNL.EXE.@)
1312 ULONG WINAPI ExIsResourceAcquiredSharedLite( ERESOURCE *resource )
1314 ULONG ret;
1315 KIRQL irql;
1317 TRACE("resource %p.\n", resource);
1319 KeAcquireSpinLock( &resource->SpinLock, &irql );
1321 if (resource->OwnerEntry.OwnerThread == (ERESOURCE_THREAD)KeGetCurrentThread())
1322 ret = resource->ActiveEntries;
1323 else
1325 OWNER_ENTRY *entry = resource_get_shared_entry( resource, (ERESOURCE_THREAD)KeGetCurrentThread() );
1326 ret = entry->OwnerCount;
1329 KeReleaseSpinLock( &resource->SpinLock, irql );
1331 return ret;
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 )
1368 LONG count;
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 );
1374 else if (count < 0)
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 )
1383 LONG count;
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 );
1391 else if (count < 0)
1392 ERR("Lock %p is not acquired!\n", lock);
1393 else if (count > 0)
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 )
1417 BOOL insert;
1418 KIRQL irql;
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 );
1425 queue->Busy = TRUE;
1426 KeReleaseSpinLock( &queue->Lock, irql );
1428 return insert;
1431 KDEVICE_QUEUE_ENTRY *WINAPI KeRemoveDeviceQueue( KDEVICE_QUEUE *queue )
1433 KDEVICE_QUEUE_ENTRY *entry = NULL;
1434 KIRQL irql;
1436 TRACE( "queue %p.\n", queue );
1438 KeAcquireSpinLock( &queue->Lock, &irql );
1439 if (IsListEmpty( &queue->DeviceListHead )) queue->Busy = FALSE;
1440 else
1442 entry = CONTAINING_RECORD( RemoveHeadList( &queue->DeviceListHead ),
1443 KDEVICE_QUEUE_ENTRY, DeviceListEntry );
1444 entry->Inserted = FALSE;
1446 KeReleaseSpinLock( &queue->Lock, irql );
1448 return entry;