- Fix KiDispatchException to unmask KI_EXCEPTION_INTERNAL when setting the exception...
[reactos.git] / reactos / ntoskrnl / ke / sem.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/sem.c
5 * PURPOSE: Implements the Semaphore Dispatcher Object
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <internal/debug.h>
14
15 /* FUNCTIONS *****************************************************************/
16
17 /*
18 * @implemented
19 */
20 VOID
21 NTAPI
22 KeInitializeSemaphore(IN PKSEMAPHORE Semaphore,
23 IN LONG Count,
24 IN LONG Limit)
25 {
26 /* Simply Initialize the Header */
27 KeInitializeDispatcherHeader(&Semaphore->Header,
28 SemaphoreObject,
29 sizeof(KSEMAPHORE) / sizeof(ULONG),
30 Count);
31
32 /* Set the Limit */
33 Semaphore->Limit = Limit;
34 }
35
36 /*
37 * @implemented
38 */
39 LONG
40 NTAPI
41 KeReadStateSemaphore(IN PKSEMAPHORE Semaphore)
42 {
43 ASSERT_SEMAPHORE(Semaphore);
44
45 /* Just return the Signal State */
46 return Semaphore->Header.SignalState;
47 }
48
49 /*
50 * @implemented
51 */
52 LONG
53 NTAPI
54 KeReleaseSemaphore(IN PKSEMAPHORE Semaphore,
55 IN KPRIORITY Increment,
56 IN LONG Adjustment,
57 IN BOOLEAN Wait)
58 {
59 LONG InitialState, State;
60 KIRQL OldIrql;
61 PKTHREAD CurrentThread;
62 ASSERT_SEMAPHORE(Semaphore);
63 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
64
65 /* Lock the Dispatcher Database */
66 OldIrql = KiAcquireDispatcherLock();
67
68 /* Save the Old State and get new one */
69 InitialState = Semaphore->Header.SignalState;
70 State = InitialState + Adjustment;
71
72 /* Check if the Limit was exceeded */
73 if ((Semaphore->Limit < State) || (InitialState > State))
74 {
75 /* Raise an error if it was exceeded */
76 KiReleaseDispatcherLock(OldIrql);
77 ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED);
78 }
79
80 /* Now set the new state */
81 Semaphore->Header.SignalState = State;
82
83 /* Check if we should wake it */
84 if (!(InitialState) && !(IsListEmpty(&Semaphore->Header.WaitListHead)))
85 {
86 /* Wake the Semaphore */
87 KiWaitTest(&Semaphore->Header, Increment);
88 }
89
90 /* Check if the caller wants to wait after this release */
91 if (Wait == FALSE)
92 {
93 /* Release the Lock */
94 KiReleaseDispatcherLock(OldIrql);
95 }
96 else
97 {
98 /* Set a wait */
99 CurrentThread = KeGetCurrentThread();
100 CurrentThread->WaitNext = TRUE;
101 CurrentThread->WaitIrql = OldIrql;
102 }
103
104 /* Return the previous state */
105 return InitialState;
106 }
107
108 /* EOF */