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 | event.cpp |
12 | |
13 | Abstract: |
14 | |
15 | Implementation of event synchronization object as described in |
16 | the WIN32 API |
17 | |
18 | Revision History: |
19 | |
20 | |
21 | |
22 | --*/ |
23 | |
24 | #include "pal/event.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::otManualResetEvent( |
34 | otiManualResetEvent, |
35 | NULL, // No cleanup routine |
36 | NULL, // No initialization routine |
37 | 0, // No immutable data |
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 | EVENT_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::ThreadReleaseHasNoSideEffects, |
51 | CObjectType::NoOwner |
52 | ); |
53 | |
54 | CObjectType CorUnix::otAutoResetEvent( |
55 | otiAutoResetEvent, |
56 | NULL, // No cleanup routine |
57 | NULL, // No initialization routine |
58 | 0, // No immutable data |
59 | NULL, // No immutable data copy routine |
60 | NULL, // No immutable data cleanup routine |
61 | 0, // No process local data |
62 | NULL, // No process local data cleanup routine |
63 | 0, // No shared data |
64 | EVENT_ALL_ACCESS, // Currently ignored (no Win32 security) |
65 | CObjectType::SecuritySupported, |
66 | CObjectType::SecurityInfoNotPersisted, |
67 | CObjectType::UnnamedObject, |
68 | CObjectType::LocalDuplicationOnly, |
69 | CObjectType::WaitableObject, |
70 | CObjectType::ObjectCanBeUnsignaled, |
71 | CObjectType::ThreadReleaseAltersSignalCount, |
72 | CObjectType::NoOwner |
73 | ); |
74 | |
75 | PalObjectTypeId rgEventIds[] = {otiManualResetEvent, otiAutoResetEvent}; |
76 | CAllowedObjectTypes aotEvent(rgEventIds, sizeof(rgEventIds)/sizeof(rgEventIds[0])); |
77 | |
78 | /*++ |
79 | Function: |
80 | CreateEventA |
81 | |
82 | Note: |
83 | lpEventAttributes currentely ignored: |
84 | -- Win32 object security not supported |
85 | -- handles to event objects are not inheritable |
86 | |
87 | Parameters: |
88 | See MSDN doc. |
89 | --*/ |
90 | |
91 | HANDLE |
92 | PALAPI |
93 | CreateEventA( |
94 | IN LPSECURITY_ATTRIBUTES lpEventAttributes, |
95 | IN BOOL bManualReset, |
96 | IN BOOL bInitialState, |
97 | IN LPCSTR lpName) |
98 | { |
99 | HANDLE hEvent = NULL; |
100 | CPalThread *pthr = NULL; |
101 | PAL_ERROR palError; |
102 | |
103 | PERF_ENTRY(CreateEventA); |
104 | ENTRY("CreateEventA(lpEventAttr=%p, bManualReset=%d, bInitialState=%d, lpName=%p (%s)\n" , |
105 | lpEventAttributes, bManualReset, bInitialState, lpName, lpName?lpName:"NULL" ); |
106 | |
107 | pthr = InternalGetCurrentThread(); |
108 | |
109 | if (lpName != nullptr) |
110 | { |
111 | ASSERT("lpName: Cross-process named objects are not supported in PAL" ); |
112 | palError = ERROR_NOT_SUPPORTED; |
113 | } |
114 | else |
115 | { |
116 | palError = InternalCreateEvent( |
117 | pthr, |
118 | lpEventAttributes, |
119 | bManualReset, |
120 | bInitialState, |
121 | NULL, |
122 | &hEvent |
123 | ); |
124 | } |
125 | |
126 | // |
127 | // We always need to set last error, even on success: |
128 | // we need to protect ourselves from the situation |
129 | // where last error is set to ERROR_ALREADY_EXISTS on |
130 | // entry to the function |
131 | // |
132 | |
133 | pthr->SetLastError(palError); |
134 | |
135 | LOGEXIT("CreateEventA returns HANDLE %p\n" , hEvent); |
136 | PERF_EXIT(CreateEventA); |
137 | return hEvent; |
138 | } |
139 | |
140 | |
141 | /*++ |
142 | Function: |
143 | CreateEventW |
144 | |
145 | Note: |
146 | lpEventAttributes currentely ignored: |
147 | -- Win32 object security not supported |
148 | -- handles to event objects are not inheritable |
149 | |
150 | Parameters: |
151 | See MSDN doc. |
152 | --*/ |
153 | |
154 | HANDLE |
155 | PALAPI |
156 | CreateEventW( |
157 | IN LPSECURITY_ATTRIBUTES lpEventAttributes, |
158 | IN BOOL bManualReset, |
159 | IN BOOL bInitialState, |
160 | IN LPCWSTR lpName) |
161 | { |
162 | HANDLE hEvent = NULL; |
163 | PAL_ERROR palError; |
164 | CPalThread *pthr = NULL; |
165 | |
166 | PERF_ENTRY(CreateEventW); |
167 | ENTRY("CreateEventW(lpEventAttr=%p, bManualReset=%d, " |
168 | "bInitialState=%d, lpName=%p (%S)\n" , lpEventAttributes, bManualReset, |
169 | bInitialState, lpName, lpName?lpName:W16_NULLSTRING); |
170 | |
171 | pthr = InternalGetCurrentThread(); |
172 | |
173 | palError = InternalCreateEvent( |
174 | pthr, |
175 | lpEventAttributes, |
176 | bManualReset, |
177 | bInitialState, |
178 | lpName, |
179 | &hEvent |
180 | ); |
181 | |
182 | // |
183 | // We always need to set last error, even on success: |
184 | // we need to protect ourselves from the situation |
185 | // where last error is set to ERROR_ALREADY_EXISTS on |
186 | // entry to the function |
187 | // |
188 | |
189 | pthr->SetLastError(palError); |
190 | |
191 | LOGEXIT("CreateEventW returns HANDLE %p\n" , hEvent); |
192 | PERF_EXIT(CreateEventW); |
193 | return hEvent; |
194 | } |
195 | |
196 | /*++ |
197 | Function: |
198 | CreateEventExW |
199 | |
200 | Note: |
201 | lpEventAttributes and dwDesiredAccess are currently ignored: |
202 | -- Win32 object security not supported |
203 | -- handles to event objects are not inheritable |
204 | -- Access rights are not supported |
205 | |
206 | Parameters: |
207 | See MSDN doc. |
208 | --*/ |
209 | |
210 | HANDLE |
211 | PALAPI |
212 | CreateEventExW( |
213 | IN LPSECURITY_ATTRIBUTES lpEventAttributes, |
214 | IN LPCWSTR lpName, |
215 | IN DWORD dwFlags, |
216 | IN DWORD dwDesiredAccess) |
217 | { |
218 | return |
219 | CreateEventW( |
220 | lpEventAttributes, |
221 | (dwFlags & CREATE_EVENT_MANUAL_RESET) != 0, |
222 | (dwFlags & CREATE_EVENT_INITIAL_SET) != 0, |
223 | lpName); |
224 | } |
225 | |
226 | /*++ |
227 | Function: |
228 | InternalCreateEvent |
229 | |
230 | Note: |
231 | lpEventAttributes currentely ignored: |
232 | -- Win32 object security not supported |
233 | -- handles to event objects are not inheritable |
234 | |
235 | Parameters: |
236 | pthr -- thread data for calling thread |
237 | phEvent -- on success, receives the allocated event handle |
238 | |
239 | See MSDN docs on CreateEvent for all other parameters |
240 | --*/ |
241 | |
242 | PAL_ERROR |
243 | CorUnix::InternalCreateEvent( |
244 | CPalThread *pthr, |
245 | LPSECURITY_ATTRIBUTES lpEventAttributes, |
246 | BOOL bManualReset, |
247 | BOOL bInitialState, |
248 | LPCWSTR lpName, |
249 | HANDLE *phEvent |
250 | ) |
251 | { |
252 | CObjectAttributes oa(lpName, lpEventAttributes); |
253 | PAL_ERROR palError = NO_ERROR; |
254 | IPalObject *pobjEvent = NULL; |
255 | IPalObject *pobjRegisteredEvent = NULL; |
256 | |
257 | _ASSERTE(NULL != pthr); |
258 | _ASSERTE(NULL != phEvent); |
259 | |
260 | ENTRY("InternalCreateEvent(pthr=%p, lpEventAttributes=%p, bManualReset=%i, " |
261 | "bInitialState=%i, lpName=%p, phEvent=%p)\n" , |
262 | pthr, |
263 | lpEventAttributes, |
264 | bManualReset, |
265 | bInitialState, |
266 | lpName, |
267 | phEvent |
268 | ); |
269 | |
270 | if (lpName != nullptr) |
271 | { |
272 | ASSERT("lpName: Cross-process named objects are not supported in PAL" ); |
273 | palError = ERROR_NOT_SUPPORTED; |
274 | goto InternalCreateEventExit; |
275 | } |
276 | |
277 | palError = g_pObjectManager->AllocateObject( |
278 | pthr, |
279 | bManualReset ? &otManualResetEvent : &otAutoResetEvent, |
280 | &oa, |
281 | &pobjEvent |
282 | ); |
283 | |
284 | if (NO_ERROR != palError) |
285 | { |
286 | goto InternalCreateEventExit; |
287 | } |
288 | |
289 | if (bInitialState) |
290 | { |
291 | ISynchStateController *pssc; |
292 | |
293 | palError = pobjEvent->GetSynchStateController( |
294 | pthr, |
295 | &pssc |
296 | ); |
297 | |
298 | if (NO_ERROR == palError) |
299 | { |
300 | palError = pssc->SetSignalCount(1); |
301 | pssc->ReleaseController(); |
302 | } |
303 | |
304 | if (NO_ERROR != palError) |
305 | { |
306 | ASSERT("Unable to set new event state (%d)\n" , palError); |
307 | goto InternalCreateEventExit; |
308 | } |
309 | } |
310 | |
311 | palError = g_pObjectManager->RegisterObject( |
312 | pthr, |
313 | pobjEvent, |
314 | &aotEvent, |
315 | EVENT_ALL_ACCESS, // Currently ignored (no Win32 security) |
316 | phEvent, |
317 | &pobjRegisteredEvent |
318 | ); |
319 | |
320 | // |
321 | // pobjEvent is invalidated by the call to RegisterObject, so NULL it |
322 | // out here to ensure that we don't try to release a reference on |
323 | // it down the line. |
324 | // |
325 | |
326 | pobjEvent = NULL; |
327 | |
328 | InternalCreateEventExit: |
329 | |
330 | if (NULL != pobjEvent) |
331 | { |
332 | pobjEvent->ReleaseReference(pthr); |
333 | } |
334 | |
335 | if (NULL != pobjRegisteredEvent) |
336 | { |
337 | pobjRegisteredEvent->ReleaseReference(pthr); |
338 | } |
339 | |
340 | LOGEXIT("InternalCreateEvent returns %i\n" , palError); |
341 | |
342 | return palError; |
343 | } |
344 | |
345 | |
346 | /*++ |
347 | Function: |
348 | SetEvent |
349 | |
350 | See MSDN doc. |
351 | --*/ |
352 | |
353 | BOOL |
354 | PALAPI |
355 | SetEvent( |
356 | IN HANDLE hEvent) |
357 | { |
358 | PAL_ERROR palError = NO_ERROR; |
359 | CPalThread *pthr = NULL; |
360 | |
361 | PERF_ENTRY(SetEvent); |
362 | ENTRY("SetEvent(hEvent=%p)\n" , hEvent); |
363 | |
364 | pthr = InternalGetCurrentThread(); |
365 | |
366 | palError = InternalSetEvent(pthr, hEvent, TRUE); |
367 | |
368 | if (NO_ERROR != palError) |
369 | { |
370 | pthr->SetLastError(palError); |
371 | } |
372 | |
373 | LOGEXIT("SetEvent returns BOOL %d\n" , (NO_ERROR == palError)); |
374 | PERF_EXIT(SetEvent); |
375 | return (NO_ERROR == palError); |
376 | } |
377 | |
378 | |
379 | /*++ |
380 | Function: |
381 | ResetEvent |
382 | |
383 | See MSDN doc. |
384 | --*/ |
385 | |
386 | BOOL |
387 | PALAPI |
388 | ResetEvent( |
389 | IN HANDLE hEvent) |
390 | { |
391 | PAL_ERROR palError = NO_ERROR; |
392 | CPalThread *pthr = NULL; |
393 | |
394 | PERF_ENTRY(ResetEvent); |
395 | ENTRY("ResetEvent(hEvent=%p)\n" , hEvent); |
396 | |
397 | pthr = InternalGetCurrentThread(); |
398 | |
399 | palError = InternalSetEvent(pthr, hEvent, FALSE); |
400 | |
401 | if (NO_ERROR != palError) |
402 | { |
403 | pthr->SetLastError(palError); |
404 | } |
405 | |
406 | LOGEXIT("ResetEvent returns BOOL %d\n" , (NO_ERROR == palError)); |
407 | PERF_EXIT(ResetEvent); |
408 | return (NO_ERROR == palError); |
409 | } |
410 | |
411 | /*++ |
412 | Function: |
413 | InternalCreateEvent |
414 | |
415 | Parameters: |
416 | pthr -- thread data for calling thread |
417 | hEvent -- handle to the event to set |
418 | fSetEvent -- if TRUE, set the event; if FALSE, reset it |
419 | --*/ |
420 | |
421 | PAL_ERROR |
422 | CorUnix::InternalSetEvent( |
423 | CPalThread *pthr, |
424 | HANDLE hEvent, |
425 | BOOL fSetEvent |
426 | ) |
427 | { |
428 | PAL_ERROR palError = NO_ERROR; |
429 | IPalObject *pobjEvent = NULL; |
430 | ISynchStateController *pssc = NULL; |
431 | |
432 | _ASSERTE(NULL != pthr); |
433 | |
434 | ENTRY("InternalSetEvent(pthr=%p, hEvent=%p, fSetEvent=%i\n" , |
435 | pthr, |
436 | hEvent, |
437 | fSetEvent |
438 | ); |
439 | |
440 | palError = g_pObjectManager->ReferenceObjectByHandle( |
441 | pthr, |
442 | hEvent, |
443 | &aotEvent, |
444 | 0, // Should be EVENT_MODIFY_STATE; currently ignored (no Win32 security) |
445 | &pobjEvent |
446 | ); |
447 | |
448 | if (NO_ERROR != palError) |
449 | { |
450 | ERROR("Unable to obtain object for handle %p (error %d)!\n" , hEvent, palError); |
451 | goto InternalSetEventExit; |
452 | } |
453 | |
454 | palError = pobjEvent->GetSynchStateController( |
455 | pthr, |
456 | &pssc |
457 | ); |
458 | |
459 | if (NO_ERROR != palError) |
460 | { |
461 | ASSERT("Error %d obtaining synch state controller\n" , palError); |
462 | goto InternalSetEventExit; |
463 | } |
464 | |
465 | palError = pssc->SetSignalCount(fSetEvent ? 1 : 0); |
466 | |
467 | if (NO_ERROR != palError) |
468 | { |
469 | ASSERT("Error %d setting event state\n" , palError); |
470 | goto InternalSetEventExit; |
471 | } |
472 | |
473 | InternalSetEventExit: |
474 | |
475 | if (NULL != pssc) |
476 | { |
477 | pssc->ReleaseController(); |
478 | } |
479 | |
480 | if (NULL != pobjEvent) |
481 | { |
482 | pobjEvent->ReleaseReference(pthr); |
483 | } |
484 | |
485 | LOGEXIT("InternalSetEvent returns %d\n" , palError); |
486 | |
487 | return palError; |
488 | } |
489 | |
490 | // TODO: Implementation of OpenEventA() doesn't exist, do we need it? More generally, do we need the A versions at all? |
491 | |
492 | /*++ |
493 | Function: |
494 | OpenEventW |
495 | |
496 | Note: |
497 | dwDesiredAccess is currently ignored (no Win32 object security support) |
498 | bInheritHandle is currently ignored (handles to events are not inheritable) |
499 | |
500 | Parameters: |
501 | See MSDN doc. |
502 | --*/ |
503 | |
504 | HANDLE |
505 | PALAPI |
506 | OpenEventW( |
507 | IN DWORD dwDesiredAccess, |
508 | IN BOOL bInheritHandle, |
509 | IN LPCWSTR lpName) |
510 | { |
511 | HANDLE hEvent = NULL; |
512 | PAL_ERROR palError = NO_ERROR; |
513 | CPalThread *pthr = NULL; |
514 | |
515 | PERF_ENTRY(OpenEventW); |
516 | ENTRY("OpenEventW(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%S))\n" , |
517 | dwDesiredAccess, bInheritHandle, lpName, lpName?lpName:W16_NULLSTRING); |
518 | |
519 | pthr = InternalGetCurrentThread(); |
520 | |
521 | /* validate parameters */ |
522 | if (lpName == nullptr) |
523 | { |
524 | ERROR("name is NULL\n" ); |
525 | palError = ERROR_INVALID_PARAMETER; |
526 | goto OpenEventWExit; |
527 | } |
528 | else |
529 | { |
530 | ASSERT("lpName: Cross-process named objects are not supported in PAL" ); |
531 | palError = ERROR_NOT_SUPPORTED; |
532 | } |
533 | |
534 | OpenEventWExit: |
535 | |
536 | if (NO_ERROR != palError) |
537 | { |
538 | pthr->SetLastError(palError); |
539 | } |
540 | |
541 | LOGEXIT("OpenEventW returns HANDLE %p\n" , hEvent); |
542 | PERF_EXIT(OpenEventW); |
543 | |
544 | return hEvent; |
545 | } |