Test commit. Not official branch release -- it will follow shortly in 15 minutes...
[reactos.git] / reactos / ntoskrnl / ke / sem.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/sem.c
6 * PURPOSE: Implements kernel semaphores
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* FUNCTIONS *****************************************************************/
18
19 /*
20 * @implemented
21 */
22 VOID
23 STDCALL
24 KeInitializeSemaphore(PKSEMAPHORE Semaphore,
25 LONG Count,
26 LONG Limit)
27 {
28
29 DPRINT("KeInitializeSemaphore Sem: %x\n", Semaphore);
30
31 /* Simply Initialize the Header */
32 KeInitializeDispatcherHeader(&Semaphore->Header,
33 SemaphoreObject,
34 sizeof(KSEMAPHORE)/sizeof(ULONG),
35 Count);
36
37 /* Set the Limit */
38 Semaphore->Limit = Limit;
39 }
40
41 /*
42 * @implemented
43 */
44 LONG
45 STDCALL
46 KeReadStateSemaphore(PKSEMAPHORE Semaphore)
47 {
48 /* Just return the Signal State */
49 return(Semaphore->Header.SignalState);
50 }
51
52 /*
53 * @implemented
54 *
55 * FUNCTION: KeReleaseSemaphore releases a given semaphore object. This
56 * routine supplies a runtime priority boost for waiting threads. If this
57 * call sets the semaphore to the Signaled state, the semaphore count is
58 * augmented by the given value. The caller can also specify whether it
59 * will call one of the KeWaitXXX routines as soon as KeReleaseSemaphore
60 * returns control.
61 * ARGUMENTS:
62 * Semaphore = Points to an initialized semaphore object for which the
63 * caller provides the storage.
64 * Increment = Specifies the priority increment to be applied if
65 * releasing the semaphore causes a wait to be
66 * satisfied.
67 * Adjustment = Specifies a value to be added to the current semaphore
68 * count. This value must be positive
69 * Wait = Specifies whether the call to KeReleaseSemaphore is to be
70 * followed immediately by a call to one of the KeWaitXXX.
71 * RETURNS: If the return value is zero, the previous state of the semaphore
72 * object is Not-Signaled.
73 */
74 LONG
75 STDCALL
76 KeReleaseSemaphore(PKSEMAPHORE Semaphore,
77 KPRIORITY Increment,
78 LONG Adjustment,
79 BOOLEAN Wait)
80
81 {
82 ULONG InitialState;
83 KIRQL OldIrql;
84 PKTHREAD CurrentThread;
85
86 DPRINT("KeReleaseSemaphore(Semaphore %x, Increment %d, Adjustment %d, Wait %d)\n",
87 Semaphore,
88 Increment,
89 Adjustment,
90 Wait);
91
92 /* Lock the Dispatcher Database */
93 OldIrql = KeAcquireDispatcherDatabaseLock();
94
95 /* Save the Old State */
96 InitialState = Semaphore->Header.SignalState;
97
98 /* Check if the Limit was exceeded */
99 if (Semaphore->Limit < (LONG) InitialState + Adjustment ||
100 InitialState > InitialState + Adjustment) {
101
102 /* Raise an error if it was exceeded */
103 KeReleaseDispatcherDatabaseLock(OldIrql);
104 ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED);
105 }
106
107 /* Now set the new state */
108 Semaphore->Header.SignalState += Adjustment;
109
110 /* Check if we should wake it */
111 if (InitialState == 0 && !IsListEmpty(&Semaphore->Header.WaitListHead)) {
112
113 /* Wake the Semaphore */
114 KiWaitTest(&Semaphore->Header, SEMAPHORE_INCREMENT);
115 }
116
117 /* If the Wait is true, then return with a Wait and don't unlock the Dispatcher Database */
118 if (Wait == FALSE) {
119
120 /* Release the Lock */
121 KeReleaseDispatcherDatabaseLock(OldIrql);
122
123 } else {
124
125 /* Set a wait */
126 CurrentThread = KeGetCurrentThread();
127 CurrentThread->WaitNext = TRUE;
128 CurrentThread->WaitIrql = OldIrql;
129 }
130
131 /* Return the previous state */
132 return InitialState;
133 }
134
135 /* EOF */