xref: /reactos/win32ss/gdi/eng/semaphor.c (revision 40462c92)
1 #include <win32k.h>
2 
3 #define NDEBUG
4 #include <debug.h>
5 
6 /*
7  * @implemented
8  */
9 __drv_allocatesMem(Mem)
10 _Post_writable_byte_size_(sizeof(ERESOURCE))
11 HSEMAPHORE
12 APIENTRY
13 EngCreateSemaphore(
14     VOID)
15 {
16     // www.osr.com/ddk/graphics/gdifncs_95lz.htm
17     PERESOURCE psem = ExAllocatePoolWithTag(NonPagedPool,
18                                             sizeof(ERESOURCE),
19                                             GDITAG_SEMAPHORE);
20     if (!psem)
21         return NULL;
22 
23     if (!NT_SUCCESS(ExInitializeResourceLite(psem)))
24     {
25         ExFreePoolWithTag(psem, GDITAG_SEMAPHORE );
26         return NULL;
27     }
28 
29     return (HSEMAPHORE)psem;
30 }
31 
32 /*
33  * @implemented
34  */
35 _Requires_lock_not_held_(*hsem)
36 _Acquires_exclusive_lock_(*hsem)
37 _Acquires_lock_(_Global_critical_region_)
38 VOID
39 APIENTRY
40 EngAcquireSemaphore(
41     _Inout_ HSEMAPHORE hsem)
42 {
43     // www.osr.com/ddk/graphics/gdifncs_14br.htm
44     PTHREADINFO W32Thread;
45 
46     /* On Windows a NULL hsem is ignored */
47     if (hsem == NULL)
48     {
49         DPRINT1("EngAcquireSemaphore called with hsem == NULL!\n");
50         return;
51     }
52 
53     ExEnterCriticalRegionAndAcquireResourceExclusive((PERESOURCE)hsem);
54     W32Thread = PsGetThreadWin32Thread(PsGetCurrentThread());
55     if (W32Thread) W32Thread->dwEngAcquireCount++;
56 }
57 
58 /*
59  * @implemented
60  */
61 _Requires_lock_held_(*hsem)
62 _Releases_lock_(*hsem)
63 _Releases_lock_(_Global_critical_region_)
64 VOID
65 APIENTRY
66 EngReleaseSemaphore(
67     _Inout_ HSEMAPHORE hsem)
68 {
69     // www.osr.com/ddk/graphics/gdifncs_5u3r.htm
70     PTHREADINFO W32Thread;
71 
72     /* On Windows a NULL hsem is ignored */
73     if (hsem == NULL)
74     {
75         DPRINT1("EngReleaseSemaphore called with hsem == NULL!\n");
76         return;
77     }
78 
79     W32Thread = PsGetThreadWin32Thread(PsGetCurrentThread());
80     if (W32Thread) --W32Thread->dwEngAcquireCount;
81     ExReleaseResourceAndLeaveCriticalRegion((PERESOURCE)hsem);
82 }
83 
84 _Acquires_lock_(_Global_critical_region_)
85 _Requires_lock_not_held_(*hsem)
86 _Acquires_shared_lock_(*hsem)
87 VOID
88 NTAPI
89 EngAcquireSemaphoreShared(
90      _Inout_ HSEMAPHORE hsem)
91 {
92     PTHREADINFO pti;
93 
94     ASSERT(hsem);
95     ExEnterCriticalRegionAndAcquireResourceShared((PERESOURCE)hsem);
96     pti = PsGetThreadWin32Thread(PsGetCurrentThread());
97     if (pti) ++pti->dwEngAcquireCount;
98 }
99 
100 /*
101  * @implemented
102  */
103 _Requires_lock_not_held_(*hsem)
104 VOID
105 APIENTRY
106 EngDeleteSemaphore(
107     _Inout_ __drv_freesMem(Mem) HSEMAPHORE hsem)
108 {
109     // www.osr.com/ddk/graphics/gdifncs_13c7.htm
110     ASSERT(hsem);
111 
112     ExDeleteResourceLite((PERESOURCE)hsem);
113     ExFreePoolWithTag((PVOID)hsem, GDITAG_SEMAPHORE);
114 }
115 
116 /*
117  * @implemented
118  */
119 BOOL
120 APIENTRY
121 EngIsSemaphoreOwned(
122     _In_ HSEMAPHORE hsem)
123 {
124     // www.osr.com/ddk/graphics/gdifncs_6wmf.htm
125     ASSERT(hsem);
126     return (((PERESOURCE)hsem)->ActiveCount > 0);
127 }
128 
129 /*
130  * @implemented
131  */
132 BOOL
133 APIENTRY
134 EngIsSemaphoreOwnedByCurrentThread(
135     _In_ HSEMAPHORE hsem)
136 {
137     // www.osr.com/ddk/graphics/gdifncs_9yxz.htm
138     ASSERT(hsem);
139     return ExIsResourceAcquiredExclusiveLite((PERESOURCE)hsem);
140 }
141 
142 /*
143  * @implemented
144  */
145 BOOL
146 APIENTRY
147 EngInitializeSafeSemaphore(
148     _Out_ ENGSAFESEMAPHORE *Semaphore)
149 {
150     HSEMAPHORE hSem;
151 
152     if (InterlockedIncrement(&Semaphore->lCount) == 1)
153     {
154         /* Create the semaphore */
155         hSem = EngCreateSemaphore();
156         if (hSem == 0)
157         {
158             InterlockedDecrement(&Semaphore->lCount);
159             return FALSE;
160         }
161         /* FIXME: Not thread-safe! Check result of InterlockedCompareExchangePointer
162                   and delete semaphore if already initialized! */
163         (void)InterlockedExchangePointer((volatile PVOID *)&Semaphore->hsem, hSem);
164     }
165     else
166     {
167         /* Wait for the other thread to create the semaphore */
168         ASSERT(Semaphore->lCount > 1);
169         ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL);
170         while (Semaphore->hsem == NULL);
171     }
172 
173     return TRUE;
174 }
175 
176 /*
177  * @implemented
178  */
179 VOID
180 APIENTRY
181 EngDeleteSafeSemaphore(
182     _Inout_ _Post_invalid_ ENGSAFESEMAPHORE *pssem)
183 {
184     if (InterlockedDecrement(&pssem->lCount) == 0)
185     {
186         /* FIXME: Not thread-safe! Use result of InterlockedCompareExchangePointer! */
187         EngDeleteSemaphore(pssem->hsem);
188         (void)InterlockedExchangePointer((volatile PVOID *)&pssem->hsem, NULL);
189     }
190 }
191 
192 /* EOF */
193