1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*++
6
7
8
9Module Name:
10
11 semaphore.cpp
12
13Abstract:
14
15 Implementation of the sempahore synchroniztion object as described in
16 the WIN32 API
17
18Revision History:
19
20
21
22--*/
23
24#include "pal/semaphore.hpp"
25#include "pal/thread.hpp"
26#include "pal/dbgmsg.h"
27
28using namespace CorUnix;
29
30/* ------------------- Definitions ------------------------------*/
31SET_DEFAULT_DEBUG_CHANNEL(SYNC);
32
33CObjectType CorUnix::otSemaphore(
34 otiSemaphore,
35 NULL, // No cleanup routine
36 NULL, // No initialization routine
37 sizeof(SemaphoreImmutableData),
38 NULL, // No immutable data copy routine
39 NULL, // No immutable data cleanup routine
40 0, // No process local data
41 NULL, // No process local data cleanup routine
42 0, // No shared data
43 0, // Should be SEMAPHORE_ALL_ACCESS; currently ignored (no Win32 security)
44 CObjectType::SecuritySupported,
45 CObjectType::SecurityInfoNotPersisted,
46 CObjectType::UnnamedObject,
47 CObjectType::LocalDuplicationOnly,
48 CObjectType::WaitableObject,
49 CObjectType::ObjectCanBeUnsignaled,
50 CObjectType::ThreadReleaseAltersSignalCount,
51 CObjectType::NoOwner
52 );
53
54CAllowedObjectTypes aotSempahore(otiSemaphore);
55
56/*++
57Function:
58CreateSemaphoreExA
59
60Note:
61lpSemaphoreAttributes currently ignored:
62-- Win32 object security not supported
63-- handles to semaphore objects are not inheritable
64
65Parameters:
66See MSDN doc.
67--*/
68
69HANDLE
70PALAPI
71CreateSemaphoreExA(
72 IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
73 IN LONG lInitialCount,
74 IN LONG lMaximumCount,
75 IN LPCSTR lpName,
76 IN /*_Reserved_*/ DWORD dwFlags,
77 IN DWORD dwDesiredAccess)
78{
79 // dwFlags is reserved and unused, and dwDesiredAccess is currently
80 // only ever used as SEMAPHORE_ALL_ACCESS. The other parameters
81 // all map to CreateSemaphoreA.
82 _ASSERTE(SEMAPHORE_ALL_ACCESS == dwDesiredAccess);
83
84 return CreateSemaphoreA(
85 lpSemaphoreAttributes,
86 lInitialCount,
87 lMaximumCount,
88 lpName);
89}
90
91/*++
92Function:
93 CreateSemaphoreA
94
95Note:
96 lpSemaphoreAttributes currently ignored:
97 -- Win32 object security not supported
98 -- handles to semaphore objects are not inheritable
99
100Parameters:
101 See MSDN doc.
102--*/
103
104HANDLE
105PALAPI
106CreateSemaphoreA(
107 IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
108 IN LONG lInitialCount,
109 IN LONG lMaximumCount,
110 IN LPCSTR lpName)
111{
112 HANDLE hSemaphore = NULL;
113 CPalThread *pthr = NULL;
114 PAL_ERROR palError;
115
116 PERF_ENTRY(CreateSemaphoreA);
117 ENTRY("CreateSemaphoreA(lpSemaphoreAttributes=%p, lInitialCount=%d, "
118 "lMaximumCount=%d, lpName=%p (%s))\n",
119 lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName, lpName?lpName:"NULL");
120
121 pthr = InternalGetCurrentThread();
122
123 if (lpName != nullptr)
124 {
125 ASSERT("lpName: Cross-process named objects are not supported in PAL");
126 palError = ERROR_NOT_SUPPORTED;
127 }
128 else
129 {
130 palError = InternalCreateSemaphore(
131 pthr,
132 lpSemaphoreAttributes,
133 lInitialCount,
134 lMaximumCount,
135 NULL,
136 &hSemaphore
137 );
138 }
139
140 //
141 // We always need to set last error, even on success:
142 // we need to protect ourselves from the situation
143 // where last error is set to ERROR_ALREADY_EXISTS on
144 // entry to the function
145 //
146
147 pthr->SetLastError(palError);
148
149 LOGEXIT("CreateSemaphoreA returns HANDLE %p\n", hSemaphore);
150 PERF_EXIT(CreateSemaphoreA);
151 return hSemaphore;
152}
153
154/*++
155Function:
156CreateSemaphoreExW
157
158Note:
159lpSemaphoreAttributes currentely ignored:
160-- Win32 object security not supported
161-- handles to semaphore objects are not inheritable
162
163Parameters:
164See MSDN doc.
165--*/
166
167HANDLE
168PALAPI
169CreateSemaphoreExW(
170 IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
171 IN LONG lInitialCount,
172 IN LONG lMaximumCount,
173 IN LPCWSTR lpName,
174 IN /*_Reserved_*/ DWORD dwFlags,
175 IN DWORD dwDesiredAccess)
176{
177 // dwFlags is reserved and unused
178
179 return CreateSemaphoreW(
180 lpSemaphoreAttributes,
181 lInitialCount,
182 lMaximumCount,
183 lpName);
184}
185
186/*++
187Function:
188 CreateSemaphoreW
189
190Note:
191 lpSemaphoreAttributes currentely ignored:
192 -- Win32 object security not supported
193 -- handles to semaphore objects are not inheritable
194
195Parameters:
196 See MSDN doc.
197--*/
198
199HANDLE
200PALAPI
201CreateSemaphoreW(
202 IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
203 IN LONG lInitialCount,
204 IN LONG lMaximumCount,
205 IN LPCWSTR lpName)
206{
207 HANDLE hSemaphore = NULL;
208 PAL_ERROR palError;
209 CPalThread *pthr = NULL;
210
211 PERF_ENTRY(CreateSemaphoreW);
212 ENTRY("CreateSemaphoreW(lpSemaphoreAttributes=%p, lInitialCount=%d, "
213 "lMaximumCount=%d, lpName=%p (%S))\n",
214 lpSemaphoreAttributes, lInitialCount, lMaximumCount,
215 lpName, lpName?lpName:W16_NULLSTRING);
216
217 pthr = InternalGetCurrentThread();
218
219 palError = InternalCreateSemaphore(
220 pthr,
221 lpSemaphoreAttributes,
222 lInitialCount,
223 lMaximumCount,
224 lpName,
225 &hSemaphore
226 );
227
228 //
229 // We always need to set last error, even on success:
230 // we need to protect ourselves from the situation
231 // where last error is set to ERROR_ALREADY_EXISTS on
232 // entry to the function
233 //
234
235 pthr->SetLastError(palError);
236
237 LOGEXIT("CreateSemaphoreW returns HANDLE %p\n", hSemaphore);
238 PERF_EXIT(CreateSemaphoreW);
239 return hSemaphore;
240}
241
242/*++
243Function:
244 InternalCreateSemaphore
245
246Note:
247 lpSemaphoreAttributes currentely ignored:
248 -- Win32 object security not supported
249 -- handles to semaphore objects are not inheritable
250
251Parameters
252 pthr -- thread data for calling thread
253 phEvent -- on success, receives the allocated semaphore handle
254
255 See MSDN docs on CreateSemaphore for all other parameters.
256--*/
257
258PAL_ERROR
259CorUnix::InternalCreateSemaphore(
260 CPalThread *pthr,
261 LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
262 LONG lInitialCount,
263 LONG lMaximumCount,
264 LPCWSTR lpName,
265 HANDLE *phSemaphore
266 )
267{
268 CObjectAttributes oa(lpName, lpSemaphoreAttributes);
269 PAL_ERROR palError = NO_ERROR;
270 IPalObject *pobjSemaphore = NULL;
271 IPalObject *pobjRegisteredSemaphore = NULL;
272 SemaphoreImmutableData *pSemaphoreData;
273
274 _ASSERTE(NULL != pthr);
275 _ASSERTE(NULL != phSemaphore);
276
277 ENTRY("InternalCreateSemaphore(pthr=%p, lpSemaphoreAttributes=%p, "
278 "lInitialCount=%d, lMaximumCount=%d, lpName=%p, phSemaphore=%p)\n",
279 pthr,
280 lpSemaphoreAttributes,
281 lInitialCount,
282 lMaximumCount,
283 lpName,
284 phSemaphore
285 );
286
287 if (lpName != nullptr)
288 {
289 ASSERT("lpName: Cross-process named objects are not supported in PAL");
290 palError = ERROR_NOT_SUPPORTED;
291 goto InternalCreateSemaphoreExit;
292 }
293
294 if (lMaximumCount <= 0)
295 {
296 ERROR("lMaximumCount is invalid (%d)\n", lMaximumCount);
297 palError = ERROR_INVALID_PARAMETER;
298 goto InternalCreateSemaphoreExit;
299 }
300
301 if ((lInitialCount < 0) || (lInitialCount > lMaximumCount))
302 {
303 ERROR("lInitialCount is invalid (%d)\n", lInitialCount);
304 palError = ERROR_INVALID_PARAMETER;
305 goto InternalCreateSemaphoreExit;
306 }
307
308 palError = g_pObjectManager->AllocateObject(
309 pthr,
310 &otSemaphore,
311 &oa,
312 &pobjSemaphore
313 );
314
315 if (NO_ERROR != palError)
316 {
317 goto InternalCreateSemaphoreExit;
318 }
319
320 palError = pobjSemaphore->GetImmutableData(reinterpret_cast<void**>(&pSemaphoreData));
321
322 if (NO_ERROR != palError)
323 {
324 ASSERT("Error %d obtaining object data\n", palError);
325 goto InternalCreateSemaphoreExit;
326 }
327
328 pSemaphoreData->lMaximumCount = lMaximumCount;
329
330 if (0 != lInitialCount)
331 {
332 ISynchStateController *pssc;
333
334 palError = pobjSemaphore->GetSynchStateController(
335 pthr,
336 &pssc
337 );
338
339 if (NO_ERROR == palError)
340 {
341 palError = pssc->SetSignalCount(lInitialCount);
342 pssc->ReleaseController();
343 }
344
345 if (NO_ERROR != palError)
346 {
347 ASSERT("Unable to set new semaphore state (%d)\n", palError);
348 goto InternalCreateSemaphoreExit;
349 }
350 }
351
352 palError = g_pObjectManager->RegisterObject(
353 pthr,
354 pobjSemaphore,
355 &aotSempahore,
356 0, // Should be SEMAPHORE_ALL_ACCESS; currently ignored (no Win32 security)
357 phSemaphore,
358 &pobjRegisteredSemaphore
359 );
360
361 //
362 // pobjSemaphore is invalidated by the call to RegisterObject, so NULL it
363 // out here to ensure that we don't try to release a reference on
364 // it down the line.
365 //
366
367 pobjSemaphore = NULL;
368
369InternalCreateSemaphoreExit:
370
371 if (NULL != pobjSemaphore)
372 {
373 pobjSemaphore->ReleaseReference(pthr);
374 }
375
376 if (NULL != pobjRegisteredSemaphore)
377 {
378 pobjRegisteredSemaphore->ReleaseReference(pthr);
379 }
380
381 LOGEXIT("InternalCreateSemaphore returns %d\n", palError);
382
383 return palError;
384}
385
386
387/*++
388Function:
389 ReleaseSemaphore
390
391Parameters:
392 See MSDN doc.
393--*/
394
395BOOL
396PALAPI
397ReleaseSemaphore(
398 IN HANDLE hSemaphore,
399 IN LONG lReleaseCount,
400 OUT LPLONG lpPreviousCount)
401{
402 PAL_ERROR palError = NO_ERROR;
403 CPalThread *pthr = NULL;
404
405 PERF_ENTRY(ReleaseSemaphore);
406 ENTRY("ReleaseSemaphore(hSemaphore=%p, lReleaseCount=%d, "
407 "lpPreviousCount=%p)\n",
408 hSemaphore, lReleaseCount, lpPreviousCount);
409
410 pthr = InternalGetCurrentThread();
411
412 palError = InternalReleaseSemaphore(
413 pthr,
414 hSemaphore,
415 lReleaseCount,
416 lpPreviousCount
417 );
418
419 if (NO_ERROR != palError)
420 {
421 pthr->SetLastError(palError);
422 }
423
424 LOGEXIT ("ReleaseSemaphore returns BOOL %d\n", (NO_ERROR == palError));
425 PERF_EXIT(ReleaseSemaphore);
426 return (NO_ERROR == palError);
427}
428
429/*++
430Function:
431 InternalReleaseSemaphore
432
433Parameters:
434 pthr -- thread data for calling thread
435
436 See MSDN docs on ReleaseSemaphore for all other parameters
437--*/
438
439PAL_ERROR
440CorUnix::InternalReleaseSemaphore(
441 CPalThread *pthr,
442 HANDLE hSemaphore,
443 LONG lReleaseCount,
444 LPLONG lpPreviousCount
445 )
446{
447 PAL_ERROR palError = NO_ERROR;
448 IPalObject *pobjSemaphore = NULL;
449 ISynchStateController *pssc = NULL;
450 SemaphoreImmutableData *pSemaphoreData;
451 LONG lOldCount;
452
453 _ASSERTE(NULL != pthr);
454
455 ENTRY("InternalReleaseSempahore(pthr=%p, hSemaphore=%p, lReleaseCount=%d, "
456 "lpPreviousCount=%p)\n",
457 pthr,
458 hSemaphore,
459 lReleaseCount,
460 lpPreviousCount
461 );
462
463 if (0 >= lReleaseCount)
464 {
465 palError = ERROR_INVALID_PARAMETER;
466 goto InternalReleaseSemaphoreExit;
467 }
468
469 palError = g_pObjectManager->ReferenceObjectByHandle(
470 pthr,
471 hSemaphore,
472 &aotSempahore,
473 0, // Should be SEMAPHORE_MODIFY_STATE; currently ignored (no Win32 security)
474 &pobjSemaphore
475 );
476
477 if (NO_ERROR != palError)
478 {
479 ERROR("Unable to obtain object for handle %p (error %d)!\n", hSemaphore, palError);
480 goto InternalReleaseSemaphoreExit;
481 }
482
483 palError = pobjSemaphore->GetImmutableData(reinterpret_cast<void**>(&pSemaphoreData));
484
485 if (NO_ERROR != palError)
486 {
487 ASSERT("Error %d obtaining object data\n", palError);
488 goto InternalReleaseSemaphoreExit;
489 }
490
491 palError = pobjSemaphore->GetSynchStateController(
492 pthr,
493 &pssc
494 );
495
496 if (NO_ERROR != palError)
497 {
498 ASSERT("Error %d obtaining synch state controller\n", palError);
499 goto InternalReleaseSemaphoreExit;
500 }
501
502 palError = pssc->GetSignalCount(&lOldCount);
503
504 if (NO_ERROR != palError)
505 {
506 ASSERT("Error %d obtaining current signal count\n", palError);
507 goto InternalReleaseSemaphoreExit;
508 }
509
510 _ASSERTE(lOldCount <= pSemaphoreData->lMaximumCount);
511 if (lReleaseCount > pSemaphoreData->lMaximumCount - lOldCount)
512 {
513 palError = ERROR_TOO_MANY_POSTS;
514 goto InternalReleaseSemaphoreExit;
515 }
516
517 palError = pssc->IncrementSignalCount(lReleaseCount);
518
519 if (NO_ERROR != palError)
520 {
521 ASSERT("Error %d incrementing signal count\n", palError);
522 goto InternalReleaseSemaphoreExit;
523 }
524
525 if (NULL != lpPreviousCount)
526 {
527 *lpPreviousCount = lOldCount;
528 }
529
530InternalReleaseSemaphoreExit:
531
532 if (NULL != pssc)
533 {
534 pssc->ReleaseController();
535 }
536
537 if (NULL != pobjSemaphore)
538 {
539 pobjSemaphore->ReleaseReference(pthr);
540 }
541
542 LOGEXIT("InternalReleaseSemaphore returns %d\n", palError);
543
544 return palError;
545}
546
547// TODO: Implementation of OpenSemaphoreA() doesn't exist, do we need it? More generally, do we need the A versions at all?
548
549/*++
550Function:
551 OpenSemaphoreW
552
553Note:
554 dwDesiredAccess is currently ignored (no Win32 object security support)
555 bInheritHandle is currently ignored (handles to semaphore are not inheritable)
556
557Parameters:
558 See MSDN doc.
559--*/
560
561HANDLE
562PALAPI
563OpenSemaphoreW(
564 IN DWORD dwDesiredAccess,
565 IN BOOL bInheritHandle,
566 IN LPCWSTR lpName)
567{
568 HANDLE hSemaphore = NULL;
569 PAL_ERROR palError = NO_ERROR;
570 CPalThread *pthr = NULL;
571
572 PERF_ENTRY(OpenSemaphoreW);
573 ENTRY("OpenSemaphoreW(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%S))\n",
574 dwDesiredAccess, bInheritHandle, lpName, lpName?lpName:W16_NULLSTRING);
575
576 pthr = InternalGetCurrentThread();
577
578 /* validate parameters */
579 if (lpName == nullptr)
580 {
581 ERROR("lpName is NULL\n");
582 palError = ERROR_INVALID_PARAMETER;
583 }
584 else
585 {
586 ASSERT("lpName: Cross-process named objects are not supported in PAL");
587 palError = ERROR_NOT_SUPPORTED;
588 }
589
590 if (NO_ERROR != palError)
591 {
592 pthr->SetLastError(palError);
593 }
594
595 LOGEXIT("OpenSemaphoreW returns HANDLE %p\n", hSemaphore);
596 PERF_EXIT(OpenSemaphoreW);
597
598 return hSemaphore;
599}
600