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
25 #define WIN32_NO_STATUS
29 #include "ddk/ntddk.h"
31 #include "ddk/ntifs.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
37 #include "ntoskrnl_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl
);
43 TYPE_MANUAL_EVENT
= 0,
47 TYPE_MANUAL_TIMER
= 8,
51 DECLARE_CRITICAL_SECTION(sync_cs
);
53 /***********************************************************************
54 * KeWaitForMultipleObjects (NTOSKRNL.EXE.@)
56 NTSTATUS WINAPI
KeWaitForMultipleObjects(ULONG count
, void *pobjs
[],
57 WAIT_TYPE wait_type
, KWAIT_REASON reason
, KPROCESSOR_MODE mode
,
58 BOOLEAN alertable
, LARGE_INTEGER
*timeout
, KWAIT_BLOCK
*wait_blocks
)
60 DISPATCHER_HEADER
**objs
= (DISPATCHER_HEADER
**)pobjs
;
61 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
65 TRACE("count %u, objs %p, wait_type %u, reason %u, mode %d, alertable %u, timeout %p, wait_blocks %p.\n",
66 count
, objs
, wait_type
, reason
, mode
, alertable
, timeout
, wait_blocks
);
68 /* We co-opt DISPATCHER_HEADER.WaitListHead:
69 * Blink stores a handle to the synchronization object,
70 * Flink stores the number of threads currently waiting on this object. */
72 EnterCriticalSection( &sync_cs
);
73 for (i
= 0; i
< count
; i
++)
75 if (objs
[i
]->WaitListHead
.Blink
== INVALID_HANDLE_VALUE
)
77 ObOpenObjectByPointer( objs
[i
], OBJ_KERNEL_HANDLE
, NULL
, SYNCHRONIZE
, NULL
, KernelMode
, &handles
[i
] );
81 ++*((ULONG_PTR
*)&objs
[i
]->WaitListHead
.Flink
);
82 if (!objs
[i
]->WaitListHead
.Blink
)
84 switch (objs
[i
]->Type
)
86 case TYPE_MANUAL_EVENT
:
87 objs
[i
]->WaitListHead
.Blink
= CreateEventW( NULL
, TRUE
, objs
[i
]->SignalState
, NULL
);
90 objs
[i
]->WaitListHead
.Blink
= CreateEventW( NULL
, FALSE
, objs
[i
]->SignalState
, NULL
);
93 objs
[i
]->WaitListHead
.Blink
= CreateMutexW( NULL
, FALSE
, NULL
);
97 KSEMAPHORE
*semaphore
= CONTAINING_RECORD(objs
[i
], KSEMAPHORE
, Header
);
98 objs
[i
]->WaitListHead
.Blink
= CreateSemaphoreW( NULL
,
99 semaphore
->Header
.SignalState
, semaphore
->Limit
, NULL
);
102 case TYPE_MANUAL_TIMER
:
103 case TYPE_AUTO_TIMER
:
108 handles
[i
] = objs
[i
]->WaitListHead
.Blink
;
110 LeaveCriticalSection( &sync_cs
);
112 ret
= NtWaitForMultipleObjects( count
, handles
, (wait_type
== WaitAny
), alertable
, timeout
);
114 EnterCriticalSection( &sync_cs
);
115 for (i
= 0; i
< count
; i
++)
117 if (ret
== i
|| (!ret
&& wait_type
== WaitAll
))
119 switch (objs
[i
]->Type
)
121 case TYPE_AUTO_EVENT
:
122 case TYPE_AUTO_TIMER
:
123 objs
[i
]->SignalState
= FALSE
;
127 --objs
[i
]->SignalState
;
132 if (objs
[i
]->WaitListHead
.Blink
== INVALID_HANDLE_VALUE
)
134 NtClose( handles
[i
] );
136 else if (!--*((ULONG_PTR
*)&objs
[i
]->WaitListHead
.Flink
))
138 switch (objs
[i
]->Type
)
140 case TYPE_MANUAL_EVENT
:
141 case TYPE_AUTO_EVENT
:
143 CloseHandle(objs
[i
]->WaitListHead
.Blink
);
144 objs
[i
]->WaitListHead
.Blink
= NULL
;
147 /* Native will panic if a mutex is destroyed while held, so we
148 * don't have to worry about leaking the handle here. */
149 if (objs
[i
]->SignalState
== 1)
151 CloseHandle(objs
[i
]->WaitListHead
.Blink
);
152 objs
[i
]->WaitListHead
.Blink
= NULL
;
158 LeaveCriticalSection( &sync_cs
);
163 /***********************************************************************
164 * KeWaitForSingleObject (NTOSKRNL.EXE.@)
166 NTSTATUS WINAPI
KeWaitForSingleObject( void *obj
, KWAIT_REASON reason
,
167 KPROCESSOR_MODE mode
, BOOLEAN alertable
, LARGE_INTEGER
*timeout
)
169 return KeWaitForMultipleObjects( 1, &obj
, WaitAny
, reason
, mode
, alertable
, timeout
, NULL
);
172 /***********************************************************************
173 * KeWaitForMutexObject (NTOSKRNL.EXE.@)
175 NTSTATUS WINAPI
KeWaitForMutexObject( PRKMUTEX mutex
, KWAIT_REASON reason
,
176 KPROCESSOR_MODE mode
, BOOLEAN alertable
, LARGE_INTEGER
*timeout
)
178 return KeWaitForSingleObject( mutex
, reason
, mode
, alertable
, timeout
);
182 /***********************************************************************
183 * KeInitializeEvent (NTOSKRNL.EXE.@)
185 void WINAPI
KeInitializeEvent( PRKEVENT event
, EVENT_TYPE type
, BOOLEAN state
)
187 TRACE("event %p, type %u, state %u.\n", event
, type
, state
);
189 event
->Header
.Type
= type
;
190 event
->Header
.SignalState
= state
;
191 event
->Header
.WaitListHead
.Blink
= NULL
;
192 event
->Header
.WaitListHead
.Flink
= NULL
;
195 static void *create_event_object( HANDLE handle
)
197 EVENT_BASIC_INFORMATION info
;
200 if (!(event
= alloc_kernel_object( ExEventObjectType
, handle
, sizeof(*event
), 0 ))) return NULL
;
202 if (!NtQueryEvent( handle
, EventBasicInformation
, &info
, sizeof(info
), NULL
))
203 KeInitializeEvent( event
, info
.EventType
, info
.EventState
);
204 event
->Header
.WaitListHead
.Blink
= INVALID_HANDLE_VALUE
; /* mark as kernel object */
208 static const WCHAR event_type_name
[] = {'E','v','e','n','t',0};
210 static struct _OBJECT_TYPE event_type
= {
215 POBJECT_TYPE ExEventObjectType
= &event_type
;
217 /***********************************************************************
218 * IoCreateSynchronizationEvent (NTOSKRNL.EXE.@)
220 PKEVENT WINAPI
IoCreateSynchronizationEvent( UNICODE_STRING
*name
, HANDLE
*ret_handle
)
222 OBJECT_ATTRIBUTES attr
;
227 TRACE( "(%p %p)\n", name
, ret_handle
);
229 InitializeObjectAttributes( &attr
, name
, 0, 0, NULL
);
230 ret
= NtCreateEvent( &handle
, EVENT_ALL_ACCESS
, &attr
, SynchronizationEvent
, TRUE
);
231 if (ret
) return NULL
;
233 if (kernel_object_from_handle( handle
, ExEventObjectType
, (void**)&event
))
239 *ret_handle
= handle
;
243 /***********************************************************************
244 * KeSetEvent (NTOSKRNL.EXE.@)
246 LONG WINAPI
KeSetEvent( PRKEVENT event
, KPRIORITY increment
, BOOLEAN wait
)
251 TRACE("event %p, increment %d, wait %u.\n", event
, increment
, wait
);
253 if (event
->Header
.WaitListHead
.Blink
!= INVALID_HANDLE_VALUE
)
255 EnterCriticalSection( &sync_cs
);
256 ret
= InterlockedExchange( &event
->Header
.SignalState
, TRUE
);
257 if ((handle
= event
->Header
.WaitListHead
.Blink
))
259 LeaveCriticalSection( &sync_cs
);
263 if (!ObOpenObjectByPointer( event
, OBJ_KERNEL_HANDLE
, NULL
, EVENT_MODIFY_STATE
, NULL
, KernelMode
, &handle
))
265 NtSetEvent( handle
, &ret
);
268 event
->Header
.SignalState
= TRUE
;
274 /***********************************************************************
275 * KeResetEvent (NTOSKRNL.EXE.@)
277 LONG WINAPI
KeResetEvent( PRKEVENT event
)
282 TRACE("event %p.\n", event
);
284 if (event
->Header
.WaitListHead
.Blink
!= INVALID_HANDLE_VALUE
)
286 EnterCriticalSection( &sync_cs
);
287 ret
= InterlockedExchange( &event
->Header
.SignalState
, FALSE
);
288 if ((handle
= event
->Header
.WaitListHead
.Blink
))
289 ResetEvent( handle
);
290 LeaveCriticalSection( &sync_cs
);
294 if (!ObOpenObjectByPointer( event
, OBJ_KERNEL_HANDLE
, NULL
, EVENT_MODIFY_STATE
, NULL
, KernelMode
, &handle
))
296 NtResetEvent( handle
, &ret
);
299 event
->Header
.SignalState
= FALSE
;
305 /***********************************************************************
306 * KeClearEvent (NTOSKRNL.EXE.@)
308 void WINAPI
KeClearEvent( PRKEVENT event
)
310 KeResetEvent( event
);
313 /***********************************************************************
314 * KeInitializeSemaphore (NTOSKRNL.EXE.@)
316 void WINAPI
KeInitializeSemaphore( PRKSEMAPHORE semaphore
, LONG count
, LONG limit
)
318 TRACE("semaphore %p, count %d, limit %d.\n", semaphore
, count
, limit
);
320 semaphore
->Header
.Type
= TYPE_SEMAPHORE
;
321 semaphore
->Header
.SignalState
= count
;
322 semaphore
->Header
.WaitListHead
.Blink
= NULL
;
323 semaphore
->Header
.WaitListHead
.Flink
= NULL
;
324 semaphore
->Limit
= limit
;
327 /***********************************************************************
328 * KeReleaseSemaphore (NTOSKRNL.EXE.@)
330 LONG WINAPI
KeReleaseSemaphore( PRKSEMAPHORE semaphore
, KPRIORITY increment
,
331 LONG count
, BOOLEAN wait
)
336 TRACE("semaphore %p, increment %d, count %d, wait %u.\n",
337 semaphore
, increment
, count
, wait
);
339 EnterCriticalSection( &sync_cs
);
340 ret
= InterlockedExchangeAdd( &semaphore
->Header
.SignalState
, count
);
341 if ((handle
= semaphore
->Header
.WaitListHead
.Blink
))
342 ReleaseSemaphore( handle
, count
, NULL
);
343 LeaveCriticalSection( &sync_cs
);
348 static const WCHAR semaphore_type_name
[] = {'S','e','m','a','p','h','o','r','e',0};
350 static struct _OBJECT_TYPE semaphore_type
=
355 POBJECT_TYPE ExSemaphoreObjectType
= &semaphore_type
;
357 /***********************************************************************
358 * KeInitializeMutex (NTOSKRNL.EXE.@)
360 void WINAPI
KeInitializeMutex( PRKMUTEX mutex
, ULONG level
)
362 TRACE("mutex %p, level %u.\n", mutex
, level
);
364 mutex
->Header
.Type
= TYPE_MUTEX
;
365 mutex
->Header
.SignalState
= 1;
366 mutex
->Header
.WaitListHead
.Blink
= NULL
;
367 mutex
->Header
.WaitListHead
.Flink
= NULL
;
370 /***********************************************************************
371 * KeReleaseMutex (NTOSKRNL.EXE.@)
373 LONG WINAPI
KeReleaseMutex( PRKMUTEX mutex
, BOOLEAN wait
)
377 TRACE("mutex %p, wait %u.\n", mutex
, wait
);
379 EnterCriticalSection( &sync_cs
);
380 ret
= mutex
->Header
.SignalState
++;
381 if (!ret
&& !mutex
->Header
.WaitListHead
.Flink
)
383 CloseHandle( mutex
->Header
.WaitListHead
.Blink
);
384 mutex
->Header
.WaitListHead
.Blink
= NULL
;
386 LeaveCriticalSection( &sync_cs
);
391 /***********************************************************************
392 * KeInitializeTimerEx (NTOSKRNL.EXE.@)
394 void WINAPI
KeInitializeTimerEx( KTIMER
*timer
, TIMER_TYPE type
)
396 TRACE("timer %p, type %u.\n", timer
, type
);
398 RtlZeroMemory(timer
, sizeof(KTIMER
));
399 timer
->Header
.Type
= (type
== NotificationTimer
) ? TYPE_MANUAL_TIMER
: TYPE_AUTO_TIMER
;
400 timer
->Header
.SignalState
= FALSE
;
401 timer
->Header
.Inserted
= FALSE
;
402 timer
->Header
.WaitListHead
.Blink
= NULL
;
403 timer
->Header
.WaitListHead
.Flink
= NULL
;
406 /***********************************************************************
407 * KeInitializeTimer (NTOSKRNL.EXE.@)
409 void WINAPI
KeInitializeTimer( KTIMER
*timer
)
411 KeInitializeTimerEx(timer
, NotificationTimer
);
414 /***********************************************************************
415 * KeSetTimerEx (NTOSKRNL.EXE.@)
417 BOOLEAN WINAPI
KeSetTimerEx( KTIMER
*timer
, LARGE_INTEGER duetime
, LONG period
, KDPC
*dpc
)
421 TRACE("timer %p, duetime %s, period %d, dpc %p.\n",
422 timer
, wine_dbgstr_longlong(duetime
.QuadPart
), period
, dpc
);
426 FIXME("Unhandled DPC %p.\n", dpc
);
430 EnterCriticalSection( &sync_cs
);
432 ret
= timer
->Header
.Inserted
;
433 timer
->Header
.Inserted
= TRUE
;
434 timer
->Header
.WaitListHead
.Blink
= CreateWaitableTimerW( NULL
, timer
->Header
.Type
== TYPE_MANUAL_TIMER
, NULL
);
435 SetWaitableTimer( timer
->Header
.WaitListHead
.Blink
, &duetime
, period
, NULL
, NULL
, FALSE
);
437 LeaveCriticalSection( &sync_cs
);
442 BOOLEAN WINAPI
KeCancelTimer( KTIMER
*timer
)
446 TRACE("timer %p.\n", timer
);
448 EnterCriticalSection( &sync_cs
);
449 ret
= timer
->Header
.Inserted
;
450 timer
->Header
.Inserted
= FALSE
;
451 CloseHandle(timer
->Header
.WaitListHead
.Blink
);
452 timer
->Header
.WaitListHead
.Blink
= NULL
;
453 LeaveCriticalSection( &sync_cs
);
458 /***********************************************************************
459 * KeDelayExecutionThread (NTOSKRNL.EXE.@)
461 NTSTATUS WINAPI
KeDelayExecutionThread( KPROCESSOR_MODE mode
, BOOLEAN alertable
, LARGE_INTEGER
*timeout
)
463 TRACE("mode %d, alertable %u, timeout %p.\n", mode
, alertable
, timeout
);
464 return NtDelayExecution( alertable
, timeout
);
467 /***********************************************************************
468 * KeInitializeSpinLock (NTOSKRNL.EXE.@)
470 void WINAPI
KeInitializeSpinLock( KSPIN_LOCK
*lock
)
472 TRACE("lock %p.\n", lock
);
476 static inline void small_pause(void)
479 __asm__
__volatile__( "rep;nop" : : : "memory" );
481 __asm__
__volatile__( "" : : : "memory" );
485 /***********************************************************************
486 * KeAcquireSpinLockAtDpcLevel (NTOSKRNL.EXE.@)
488 void WINAPI
KeAcquireSpinLockAtDpcLevel( KSPIN_LOCK
*lock
)
490 TRACE("lock %p.\n", lock
);
491 while (!InterlockedCompareExchangePointer( (void **)lock
, (void *)1, (void *)0 ))
495 /***********************************************************************
496 * KeReleaseSpinLockFromDpcLevel (NTOSKRNL.EXE.@)
498 void WINAPI
KeReleaseSpinLockFromDpcLevel( KSPIN_LOCK
*lock
)
500 TRACE("lock %p.\n", lock
);
501 InterlockedExchangePointer( (void **)lock
, 0 );
504 #define QUEUED_SPINLOCK_OWNED 0x2
506 /***********************************************************************
507 * KeAcquireInStackQueuedSpinLockAtDpcLevel (NTOSKRNL.EXE.@)
509 DEFINE_FASTCALL_WRAPPER( KeAcquireInStackQueuedSpinLockAtDpcLevel
, 8 )
510 void FASTCALL
KeAcquireInStackQueuedSpinLockAtDpcLevel( KSPIN_LOCK
*lock
, KLOCK_QUEUE_HANDLE
*queue
)
512 KSPIN_LOCK_QUEUE
*tail
;
514 TRACE("lock %p, queue %p.\n", lock
, queue
);
516 queue
->LockQueue
.Next
= NULL
;
518 if (!(tail
= InterlockedExchangePointer( (void **)lock
, &queue
->LockQueue
)))
519 queue
->LockQueue
.Lock
= (KSPIN_LOCK
*)((ULONG_PTR
)lock
| QUEUED_SPINLOCK_OWNED
);
522 queue
->LockQueue
.Lock
= lock
;
523 InterlockedExchangePointer( (void **)&tail
->Next
, &queue
->LockQueue
);
525 while (!((ULONG_PTR
)InterlockedCompareExchangePointer( (void **)&queue
->LockQueue
.Lock
, 0, 0 )
526 & QUEUED_SPINLOCK_OWNED
))
533 /***********************************************************************
534 * KeReleaseInStackQueuedSpinLockFromDpcLevel (NTOSKRNL.EXE.@)
536 DEFINE_FASTCALL1_WRAPPER( KeReleaseInStackQueuedSpinLockFromDpcLevel
)
537 void FASTCALL
KeReleaseInStackQueuedSpinLockFromDpcLevel( KLOCK_QUEUE_HANDLE
*queue
)
539 KSPIN_LOCK
*lock
= (KSPIN_LOCK
*)((ULONG_PTR
)queue
->LockQueue
.Lock
& ~QUEUED_SPINLOCK_OWNED
);
540 KSPIN_LOCK_QUEUE
*next
;
542 TRACE("lock %p, queue %p.\n", lock
, queue
);
544 queue
->LockQueue
.Lock
= NULL
;
546 if (!(next
= queue
->LockQueue
.Next
))
548 /* If we are truly the last in the queue, the lock will point to us. */
549 if (InterlockedCompareExchangePointer( (void **)lock
, NULL
, &queue
->LockQueue
) == queue
)
552 /* Otherwise, someone just queued themselves, but hasn't yet set
553 * themselves as successor. Spin waiting for them to do so. */
554 while (!(next
= queue
->LockQueue
.Next
))
558 InterlockedExchangePointer( (void **)&next
->Lock
, (KSPIN_LOCK
*)((ULONG_PTR
)lock
| QUEUED_SPINLOCK_OWNED
) );
562 /***********************************************************************
563 * KeReleaseSpinLock (NTOSKRNL.EXE.@)
565 void WINAPI
KeReleaseSpinLock( KSPIN_LOCK
*lock
, KIRQL irql
)
567 TRACE("lock %p, irql %u.\n", lock
, irql
);
568 KeReleaseSpinLockFromDpcLevel( lock
);
571 /***********************************************************************
572 * KeAcquireSpinLockRaiseToDpc (NTOSKRNL.EXE.@)
574 KIRQL WINAPI
KeAcquireSpinLockRaiseToDpc( KSPIN_LOCK
*lock
)
576 TRACE("lock %p.\n", lock
);
577 KeAcquireSpinLockAtDpcLevel( lock
);
581 /***********************************************************************
582 * KeAcquireInStackQueuedSpinLock (NTOSKRNL.EXE.@)
584 void WINAPI
KeAcquireInStackQueuedSpinLock( KSPIN_LOCK
*lock
, KLOCK_QUEUE_HANDLE
*queue
)
586 TRACE("lock %p, queue %p.\n", lock
, queue
);
587 KeAcquireInStackQueuedSpinLockAtDpcLevel( lock
, queue
);
590 /***********************************************************************
591 * KeReleaseInStackQueuedSpinLock (NTOSKRNL.EXE.@)
593 void WINAPI
KeReleaseInStackQueuedSpinLock( KLOCK_QUEUE_HANDLE
*queue
)
595 TRACE("queue %p.\n", queue
);
596 KeReleaseInStackQueuedSpinLockFromDpcLevel( queue
);
600 static KSPIN_LOCK cancel_lock
;
602 /***********************************************************************
603 * IoAcquireCancelSpinLock (NTOSKRNL.EXE.@)
605 void WINAPI
IoAcquireCancelSpinLock( KIRQL
*irql
)
607 TRACE("irql %p.\n", irql
);
608 KeAcquireSpinLock( &cancel_lock
, irql
);
611 /***********************************************************************
612 * IoReleaseCancelSpinLock (NTOSKRNL.EXE.@)
614 void WINAPI
IoReleaseCancelSpinLock( KIRQL irql
)
616 TRACE("irql %u.\n", irql
);
617 KeReleaseSpinLock( &cancel_lock
, irql
);
620 /***********************************************************************
621 * ExfInterlockedRemoveHeadList (NTOSKRNL.EXE.@)
623 DEFINE_FASTCALL_WRAPPER( ExfInterlockedRemoveHeadList
, 8 )
624 PLIST_ENTRY FASTCALL
ExfInterlockedRemoveHeadList( LIST_ENTRY
*list
, KSPIN_LOCK
*lock
)
626 return ExInterlockedRemoveHeadList( list
, lock
);
629 /***********************************************************************
630 * ExInterlockedRemoveHeadList (NTOSKRNL.EXE.@)
632 LIST_ENTRY
* WINAPI
ExInterlockedRemoveHeadList( LIST_ENTRY
*list
, KSPIN_LOCK
*lock
)
637 TRACE("list %p, lock %p.\n", list
, lock
);
639 KeAcquireSpinLock( lock
, &irql
);
640 ret
= RemoveHeadList( list
);
641 KeReleaseSpinLock( lock
, irql
);
647 /***********************************************************************
648 * InterlockedPopEntrySList (NTOSKRNL.EXE.@)
650 DEFINE_FASTCALL1_WRAPPER( NTOSKRNL_InterlockedPopEntrySList
)
651 PSLIST_ENTRY FASTCALL
NTOSKRNL_InterlockedPopEntrySList( PSLIST_HEADER list
)
653 return RtlInterlockedPopEntrySList( list
);
657 /***********************************************************************
658 * InterlockedPushEntrySList (NTOSKRNL.EXE.@)
660 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_InterlockedPushEntrySList
, 8 )
661 PSLIST_ENTRY FASTCALL
NTOSKRNL_InterlockedPushEntrySList( PSLIST_HEADER list
, PSLIST_ENTRY entry
)
663 return RtlInterlockedPushEntrySList( list
, entry
);
667 /***********************************************************************
668 * ExInterlockedPopEntrySList (NTOSKRNL.EXE.@)
670 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_ExInterlockedPopEntrySList
, 8 )
671 PSLIST_ENTRY FASTCALL
NTOSKRNL_ExInterlockedPopEntrySList( PSLIST_HEADER list
, PKSPIN_LOCK lock
)
673 return RtlInterlockedPopEntrySList( list
);
677 /***********************************************************************
678 * ExInterlockedPushEntrySList (NTOSKRNL.EXE.@)
680 DEFINE_FASTCALL_WRAPPER( NTOSKRNL_ExInterlockedPushEntrySList
, 12 )
681 PSLIST_ENTRY FASTCALL
NTOSKRNL_ExInterlockedPushEntrySList( PSLIST_HEADER list
, PSLIST_ENTRY entry
, PKSPIN_LOCK lock
)
683 return RtlInterlockedPushEntrySList( list
, entry
);
687 /***********************************************************************
688 * ExInterlockedFlushSList (NTOSKRNL.EXE.@)
690 DEFINE_FASTCALL1_WRAPPER( NTOSKRNL_ExInterlockedFlushSList
)
691 PSLIST_ENTRY FASTCALL
NTOSKRNL_ExInterlockedFlushSList( PSLIST_HEADER list
)
693 return RtlInterlockedFlushSList( list
);
697 /***********************************************************************
698 * ExAcquireFastMutexUnsafe (NTOSKRNL.EXE.@)
700 DEFINE_FASTCALL1_WRAPPER(ExAcquireFastMutexUnsafe
)
701 void FASTCALL
ExAcquireFastMutexUnsafe( FAST_MUTEX
*mutex
)
705 TRACE("mutex %p.\n", mutex
);
707 count
= InterlockedDecrement( &mutex
->Count
);
709 KeWaitForSingleObject( &mutex
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
712 /***********************************************************************
713 * ExReleaseFastMutexUnsafe (NTOSKRNL.EXE.@)
715 DEFINE_FASTCALL1_WRAPPER(ExReleaseFastMutexUnsafe
)
716 void FASTCALL
ExReleaseFastMutexUnsafe( FAST_MUTEX
*mutex
)
720 TRACE("mutex %p.\n", mutex
);
722 count
= InterlockedIncrement( &mutex
->Count
);
724 KeSetEvent( &mutex
->Event
, IO_NO_INCREMENT
, FALSE
);
729 /***********************************************************************
730 * ExAcquireFastMutex (NTOSKRNL.@)
732 void WINAPI
ExAcquireFastMutex( FAST_MUTEX
*mutex
)
734 /* FIXME: lower IRQL */
735 ExAcquireFastMutexUnsafe( mutex
);
738 /***********************************************************************
739 * ExReleaseFastMutex (NTOSKRNL.@)
741 void WINAPI
ExReleaseFastMutex( FAST_MUTEX
*mutex
)
743 ExReleaseFastMutexUnsafe( mutex
);
744 /* FIXME: restore IRQL */
747 #endif /* __i386__ */
749 /* Use of the fields of an ERESOURCE structure seems to vary wildly between
750 * Windows versions. The below implementation uses them as follows:
752 * OwnerTable - contains a list of shared owners, including threads which do
753 * not currently own the resource
754 * OwnerTable[i].OwnerThread - shared owner TID
755 * OwnerTable[i].OwnerCount - recursion count of this shared owner (may be 0)
756 * OwnerEntry.OwnerThread - the owner TID if exclusively owned
757 * OwnerEntry.TableSize - the number of entries in OwnerTable, including threads
758 * which do not currently own the resource
759 * ActiveEntries - total number of acquisitions (incl. recursive ones)
762 /***********************************************************************
763 * ExInitializeResourceLite (NTOSKRNL.EXE.@)
765 NTSTATUS WINAPI
ExInitializeResourceLite( ERESOURCE
*resource
)
767 TRACE("resource %p.\n", resource
);
768 memset(resource
, 0, sizeof(*resource
));
769 return STATUS_SUCCESS
;
772 /***********************************************************************
773 * ExDeleteResourceLite (NTOSKRNL.EXE.@)
775 NTSTATUS WINAPI
ExDeleteResourceLite( ERESOURCE
*resource
)
777 TRACE("resource %p.\n", resource
);
778 heap_free(resource
->OwnerTable
);
779 heap_free(resource
->ExclusiveWaiters
);
780 heap_free(resource
->SharedWaiters
);
781 return STATUS_SUCCESS
;
784 /* Find an existing entry in the shared owner list, or create a new one. */
785 static OWNER_ENTRY
*resource_get_shared_entry( ERESOURCE
*resource
, ERESOURCE_THREAD thread
)
789 for (i
= 0; i
< resource
->OwnerEntry
.TableSize
; ++i
)
791 if (resource
->OwnerTable
[i
].OwnerThread
== thread
)
792 return &resource
->OwnerTable
[i
];
795 count
= ++resource
->OwnerEntry
.TableSize
;
796 resource
->OwnerTable
= heap_realloc(resource
->OwnerTable
, count
* sizeof(*resource
->OwnerTable
));
797 resource
->OwnerTable
[count
- 1].OwnerThread
= thread
;
798 resource
->OwnerTable
[count
- 1].OwnerCount
= 0;
800 return &resource
->OwnerTable
[count
- 1];
803 /***********************************************************************
804 * ExAcquireResourceExclusiveLite (NTOSKRNL.EXE.@)
806 BOOLEAN WINAPI
ExAcquireResourceExclusiveLite( ERESOURCE
*resource
, BOOLEAN wait
)
810 TRACE("resource %p, wait %u.\n", resource
, wait
);
812 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
814 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
816 resource
->ActiveEntries
++;
817 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
820 /* In order to avoid a race between waiting for the ExclusiveWaiters event
821 * and grabbing the lock, do not grab the resource if it is unclaimed but
822 * has waiters; instead queue ourselves. */
823 else if (!resource
->ActiveEntries
&& !resource
->NumberOfExclusiveWaiters
&& !resource
->NumberOfSharedWaiters
)
825 resource
->Flag
|= ResourceOwnedExclusive
;
826 resource
->OwnerEntry
.OwnerThread
= (ERESOURCE_THREAD
)KeGetCurrentThread();
827 resource
->ActiveEntries
++;
828 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
833 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
837 if (!resource
->ExclusiveWaiters
)
839 resource
->ExclusiveWaiters
= heap_alloc( sizeof(*resource
->ExclusiveWaiters
) );
840 KeInitializeEvent( resource
->ExclusiveWaiters
, SynchronizationEvent
, FALSE
);
842 resource
->NumberOfExclusiveWaiters
++;
844 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
846 KeWaitForSingleObject( resource
->ExclusiveWaiters
, Executive
, KernelMode
, FALSE
, NULL
);
848 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
850 resource
->Flag
|= ResourceOwnedExclusive
;
851 resource
->OwnerEntry
.OwnerThread
= (ERESOURCE_THREAD
)KeGetCurrentThread();
852 resource
->ActiveEntries
++;
853 resource
->NumberOfExclusiveWaiters
--;
855 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
860 /***********************************************************************
861 * ExAcquireResourceSharedLite (NTOSKRNL.EXE.@)
863 BOOLEAN WINAPI
ExAcquireResourceSharedLite( ERESOURCE
*resource
, BOOLEAN wait
)
868 TRACE("resource %p, wait %u.\n", resource
, wait
);
870 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
872 entry
= resource_get_shared_entry( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
874 if (resource
->Flag
& ResourceOwnedExclusive
)
876 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
878 /* We own the resource exclusively, so increase recursion. */
879 resource
->ActiveEntries
++;
880 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
884 else if (entry
->OwnerCount
|| !resource
->NumberOfExclusiveWaiters
)
886 /* Either we already own the resource shared, or there are no exclusive
887 * owners or waiters, so we can grab it shared. */
889 resource
->ActiveEntries
++;
890 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
896 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
900 if (!resource
->SharedWaiters
)
902 resource
->SharedWaiters
= heap_alloc( sizeof(*resource
->SharedWaiters
) );
903 KeInitializeSemaphore( resource
->SharedWaiters
, 0, INT_MAX
);
905 resource
->NumberOfSharedWaiters
++;
907 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
909 KeWaitForSingleObject( resource
->SharedWaiters
, Executive
, KernelMode
, FALSE
, NULL
);
911 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
914 resource
->ActiveEntries
++;
915 resource
->NumberOfSharedWaiters
--;
917 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
922 /***********************************************************************
923 * ExAcquireSharedStarveExclusive (NTOSKRNL.EXE.@)
925 BOOLEAN WINAPI
ExAcquireSharedStarveExclusive( ERESOURCE
*resource
, BOOLEAN wait
)
930 TRACE("resource %p, wait %u.\n", resource
, wait
);
932 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
934 entry
= resource_get_shared_entry( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
936 if (resource
->Flag
& ResourceOwnedExclusive
)
938 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
940 resource
->ActiveEntries
++;
941 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
945 /* We are starving exclusive waiters, but we cannot steal the resource out
946 * from under an exclusive waiter who is about to acquire it. (Because of
947 * locking, and because exclusive waiters are always waked first, this is
948 * guaranteed to be the case if the resource is unowned and there are
949 * exclusive waiters.) */
950 else if (!(!resource
->ActiveEntries
&& resource
->NumberOfExclusiveWaiters
))
953 resource
->ActiveEntries
++;
954 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
960 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
964 if (!resource
->SharedWaiters
)
966 resource
->SharedWaiters
= heap_alloc( sizeof(*resource
->SharedWaiters
) );
967 KeInitializeSemaphore( resource
->SharedWaiters
, 0, INT_MAX
);
969 resource
->NumberOfSharedWaiters
++;
971 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
973 KeWaitForSingleObject( resource
->SharedWaiters
, Executive
, KernelMode
, FALSE
, NULL
);
975 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
978 resource
->ActiveEntries
++;
979 resource
->NumberOfSharedWaiters
--;
981 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
986 /***********************************************************************
987 * ExAcquireSharedWaitForExclusive (NTOSKRNL.EXE.@)
989 BOOLEAN WINAPI
ExAcquireSharedWaitForExclusive( ERESOURCE
*resource
, BOOLEAN wait
)
994 TRACE("resource %p, wait %u.\n", resource
, wait
);
996 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
998 entry
= resource_get_shared_entry( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
1000 if (resource
->Flag
& ResourceOwnedExclusive
)
1002 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
1004 /* We own the resource exclusively, so increase recursion. */
1005 resource
->ActiveEntries
++;
1006 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1010 /* We may only grab the resource if there are no exclusive waiters, even if
1011 * we already own it shared. */
1012 else if (!resource
->NumberOfExclusiveWaiters
)
1014 entry
->OwnerCount
++;
1015 resource
->ActiveEntries
++;
1016 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1022 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1026 if (!resource
->SharedWaiters
)
1028 resource
->SharedWaiters
= heap_alloc( sizeof(*resource
->SharedWaiters
) );
1029 KeInitializeSemaphore( resource
->SharedWaiters
, 0, INT_MAX
);
1031 resource
->NumberOfSharedWaiters
++;
1033 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1035 KeWaitForSingleObject( resource
->SharedWaiters
, Executive
, KernelMode
, FALSE
, NULL
);
1037 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1039 entry
->OwnerCount
++;
1040 resource
->ActiveEntries
++;
1041 resource
->NumberOfSharedWaiters
--;
1043 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1048 /***********************************************************************
1049 * ExReleaseResourceForThreadLite (NTOSKRNL.EXE.@)
1051 void WINAPI
ExReleaseResourceForThreadLite( ERESOURCE
*resource
, ERESOURCE_THREAD thread
)
1056 TRACE("resource %p, thread %#lx.\n", resource
, thread
);
1058 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1060 if (resource
->Flag
& ResourceOwnedExclusive
)
1062 if (resource
->OwnerEntry
.OwnerThread
== thread
)
1064 if (!--resource
->ActiveEntries
)
1066 resource
->OwnerEntry
.OwnerThread
= 0;
1067 resource
->Flag
&= ~ResourceOwnedExclusive
;
1072 ERR("Trying to release %p for thread %#lx, but resource is exclusively owned by %#lx.\n",
1073 resource
, thread
, resource
->OwnerEntry
.OwnerThread
);
1079 entry
= resource_get_shared_entry( resource
, thread
);
1080 if (entry
->OwnerCount
)
1082 entry
->OwnerCount
--;
1083 resource
->ActiveEntries
--;
1087 ERR("Trying to release %p for thread %#lx, but resource is not owned by that thread.\n", resource
, thread
);
1092 if (!resource
->ActiveEntries
)
1094 if (resource
->NumberOfExclusiveWaiters
)
1096 KeSetEvent( resource
->ExclusiveWaiters
, IO_NO_INCREMENT
, FALSE
);
1098 else if (resource
->NumberOfSharedWaiters
)
1100 KeReleaseSemaphore( resource
->SharedWaiters
, IO_NO_INCREMENT
,
1101 resource
->NumberOfSharedWaiters
, FALSE
);
1105 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1108 /***********************************************************************
1109 * ExReleaseResourceLite (NTOSKRNL.EXE.@)
1111 DEFINE_FASTCALL1_WRAPPER( ExReleaseResourceLite
)
1112 void FASTCALL
ExReleaseResourceLite( ERESOURCE
*resource
)
1114 ExReleaseResourceForThreadLite( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
1117 /***********************************************************************
1118 * ExGetExclusiveWaiterCount (NTOSKRNL.EXE.@)
1120 ULONG WINAPI
ExGetExclusiveWaiterCount( ERESOURCE
*resource
)
1125 TRACE("resource %p.\n", resource
);
1127 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1129 count
= resource
->NumberOfExclusiveWaiters
;
1131 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1136 /***********************************************************************
1137 * ExGetSharedWaiterCount (NTOSKRNL.EXE.@)
1139 ULONG WINAPI
ExGetSharedWaiterCount( ERESOURCE
*resource
)
1144 TRACE("resource %p.\n", resource
);
1146 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1148 count
= resource
->NumberOfSharedWaiters
;
1150 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1155 /***********************************************************************
1156 * ExIsResourceAcquiredExclusiveLite (NTOSKRNL.EXE.@)
1158 BOOLEAN WINAPI
ExIsResourceAcquiredExclusiveLite( ERESOURCE
*resource
)
1163 TRACE("resource %p.\n", resource
);
1165 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1167 ret
= (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread());
1169 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1174 /***********************************************************************
1175 * ExIsResourceAcquiredSharedLite (NTOSKRNL.EXE.@)
1177 ULONG WINAPI
ExIsResourceAcquiredSharedLite( ERESOURCE
*resource
)
1182 TRACE("resource %p.\n", resource
);
1184 KeAcquireSpinLock( &resource
->SpinLock
, &irql
);
1186 if (resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)KeGetCurrentThread())
1187 ret
= resource
->ActiveEntries
;
1190 OWNER_ENTRY
*entry
= resource_get_shared_entry( resource
, (ERESOURCE_THREAD
)KeGetCurrentThread() );
1191 ret
= entry
->OwnerCount
;
1194 KeReleaseSpinLock( &resource
->SpinLock
, irql
);
1199 /***********************************************************************
1200 * IoInitializeRemoveLockEx (NTOSKRNL.EXE.@)
1202 void WINAPI
IoInitializeRemoveLockEx( IO_REMOVE_LOCK
*lock
, ULONG tag
,
1203 ULONG max_minutes
, ULONG max_count
, ULONG size
)
1205 TRACE("lock %p, tag %#x, max_minutes %u, max_count %u, size %u.\n",
1206 lock
, tag
, max_minutes
, max_count
, size
);
1208 KeInitializeEvent( &lock
->Common
.RemoveEvent
, NotificationEvent
, FALSE
);
1209 lock
->Common
.Removed
= FALSE
;
1210 lock
->Common
.IoCount
= 0;
1213 /***********************************************************************
1214 * IoAcquireRemoveLockEx (NTOSKRNL.EXE.@)
1216 NTSTATUS WINAPI
IoAcquireRemoveLockEx( IO_REMOVE_LOCK
*lock
, void *tag
,
1217 const char *file
, ULONG line
, ULONG size
)
1219 TRACE("lock %p, tag %p, file %s, line %u, size %u.\n", lock
, tag
, debugstr_a(file
), line
, size
);
1221 if (lock
->Common
.Removed
)
1222 return STATUS_DELETE_PENDING
;
1224 InterlockedIncrement( &lock
->Common
.IoCount
);
1225 return STATUS_SUCCESS
;
1228 /***********************************************************************
1229 * IoReleaseRemoveLockEx (NTOSKRNL.EXE.@)
1231 void WINAPI
IoReleaseRemoveLockEx( IO_REMOVE_LOCK
*lock
, void *tag
, ULONG size
)
1235 TRACE("lock %p, tag %p, size %u.\n", lock
, tag
, size
);
1237 if (!(count
= InterlockedDecrement( &lock
->Common
.IoCount
)) && lock
->Common
.Removed
)
1238 KeSetEvent( &lock
->Common
.RemoveEvent
, IO_NO_INCREMENT
, FALSE
);
1240 ERR("Lock %p is not acquired!\n", lock
);
1243 /***********************************************************************
1244 * IoReleaseRemoveLockAndWaitEx (NTOSKRNL.EXE.@)
1246 void WINAPI
IoReleaseRemoveLockAndWaitEx( IO_REMOVE_LOCK
*lock
, void *tag
, ULONG size
)
1250 TRACE("lock %p, tag %p, size %u.\n", lock
, tag
, size
);
1252 lock
->Common
.Removed
= TRUE
;
1254 if (!(count
= InterlockedDecrement( &lock
->Common
.IoCount
)))
1255 KeSetEvent( &lock
->Common
.RemoveEvent
, IO_NO_INCREMENT
, FALSE
);
1257 ERR("Lock %p is not acquired!\n", lock
);
1259 KeWaitForSingleObject( &lock
->Common
.RemoveEvent
, Executive
, KernelMode
, FALSE
, NULL
);