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 | |
9 | Module Name: |
10 | |
11 | semaphore.cpp |
12 | |
13 | Abstract: |
14 | |
15 | Implementation of the sempahore synchroniztion object as described in |
16 | the WIN32 API |
17 | |
18 | Revision History: |
19 | |
20 | |
21 | |
22 | --*/ |
23 | |
24 | #include "pal/semaphore.hpp" |
25 | #include "pal/thread.hpp" |
26 | #include "pal/dbgmsg.h" |
27 | |
28 | using namespace CorUnix; |
29 | |
30 | /* ------------------- Definitions ------------------------------*/ |
31 | SET_DEFAULT_DEBUG_CHANNEL(SYNC); |
32 | |
33 | CObjectType 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 | |
54 | CAllowedObjectTypes aotSempahore(otiSemaphore); |
55 | |
56 | /*++ |
57 | Function: |
58 | CreateSemaphoreExA |
59 | |
60 | Note: |
61 | lpSemaphoreAttributes currently ignored: |
62 | -- Win32 object security not supported |
63 | -- handles to semaphore objects are not inheritable |
64 | |
65 | Parameters: |
66 | See MSDN doc. |
67 | --*/ |
68 | |
69 | HANDLE |
70 | PALAPI |
71 | CreateSemaphoreExA( |
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 | /*++ |
92 | Function: |
93 | CreateSemaphoreA |
94 | |
95 | Note: |
96 | lpSemaphoreAttributes currently ignored: |
97 | -- Win32 object security not supported |
98 | -- handles to semaphore objects are not inheritable |
99 | |
100 | Parameters: |
101 | See MSDN doc. |
102 | --*/ |
103 | |
104 | HANDLE |
105 | PALAPI |
106 | CreateSemaphoreA( |
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 | /*++ |
155 | Function: |
156 | CreateSemaphoreExW |
157 | |
158 | Note: |
159 | lpSemaphoreAttributes currentely ignored: |
160 | -- Win32 object security not supported |
161 | -- handles to semaphore objects are not inheritable |
162 | |
163 | Parameters: |
164 | See MSDN doc. |
165 | --*/ |
166 | |
167 | HANDLE |
168 | PALAPI |
169 | CreateSemaphoreExW( |
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 | /*++ |
187 | Function: |
188 | CreateSemaphoreW |
189 | |
190 | Note: |
191 | lpSemaphoreAttributes currentely ignored: |
192 | -- Win32 object security not supported |
193 | -- handles to semaphore objects are not inheritable |
194 | |
195 | Parameters: |
196 | See MSDN doc. |
197 | --*/ |
198 | |
199 | HANDLE |
200 | PALAPI |
201 | CreateSemaphoreW( |
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 | /*++ |
243 | Function: |
244 | InternalCreateSemaphore |
245 | |
246 | Note: |
247 | lpSemaphoreAttributes currentely ignored: |
248 | -- Win32 object security not supported |
249 | -- handles to semaphore objects are not inheritable |
250 | |
251 | Parameters |
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 | |
258 | PAL_ERROR |
259 | CorUnix::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 | |
369 | InternalCreateSemaphoreExit: |
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 | /*++ |
388 | Function: |
389 | ReleaseSemaphore |
390 | |
391 | Parameters: |
392 | See MSDN doc. |
393 | --*/ |
394 | |
395 | BOOL |
396 | PALAPI |
397 | ReleaseSemaphore( |
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 | /*++ |
430 | Function: |
431 | InternalReleaseSemaphore |
432 | |
433 | Parameters: |
434 | pthr -- thread data for calling thread |
435 | |
436 | See MSDN docs on ReleaseSemaphore for all other parameters |
437 | --*/ |
438 | |
439 | PAL_ERROR |
440 | CorUnix::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 | |
530 | InternalReleaseSemaphoreExit: |
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 | /*++ |
550 | Function: |
551 | OpenSemaphoreW |
552 | |
553 | Note: |
554 | dwDesiredAccess is currently ignored (no Win32 object security support) |
555 | bInheritHandle is currently ignored (handles to semaphore are not inheritable) |
556 | |
557 | Parameters: |
558 | See MSDN doc. |
559 | --*/ |
560 | |
561 | HANDLE |
562 | PALAPI |
563 | OpenSemaphoreW( |
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 | |