FreeRDP
Loading...
Searching...
No Matches
event.c
1
22#include <winpr/config.h>
23
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27
28#include <winpr/synch.h>
29
30#ifndef _WIN32
31
32#include "synch.h"
33
34#ifdef WINPR_HAVE_UNISTD_H
35#include <unistd.h>
36#endif
37
38#ifdef WINPR_HAVE_SYS_EVENTFD_H
39#include <sys/eventfd.h>
40#endif
41
42#include <fcntl.h>
43#include <errno.h>
44
45#include "../handle/handle.h"
46#include "../pipe/pipe.h"
47
48#include "../log.h"
49#include "event.h"
50#define TAG WINPR_TAG("synch.event")
51
52#if defined(WITH_DEBUG_EVENTS)
53static wArrayList* global_event_list = nullptr;
54
55static void dump_event(WINPR_EVENT* event, size_t index)
56{
57 char** msg = nullptr;
58 size_t used = 0;
59
60 WLog_DBG(TAG, "Event handle created still not closed! [%" PRIuz ", %p]", index, (void*)event);
61 msg = winpr_backtrace_symbols(event->create_stack, &used);
62
63 for (size_t i = 2; i < used; i++)
64 WLog_DBG(TAG, "[%" PRIuz "]: %s", i, msg[i]);
65
66 free(msg);
67}
68#endif /* WITH_DEBUG_EVENTS */
69
70#ifdef WINPR_HAVE_SYS_EVENTFD_H
71#if !defined(WITH_EVENTFD_READ_WRITE)
72WINPR_ATTR_NODISCARD
73static int eventfd_read(int fd, eventfd_t* value)
74{
75 return (read(fd, value, sizeof(*value)) == sizeof(*value)) ? 0 : -1;
76}
77
78WINPR_ATTR_NODISCARD
79static int eventfd_write(int fd, eventfd_t value)
80{
81 return (write(fd, &value, sizeof(value)) == sizeof(value)) ? 0 : -1;
82}
83#endif
84#endif
85
86WINPR_ATTR_NODISCARD
87static BOOL set_non_blocking_fd(int fd)
88{
89 int flags = fcntl(fd, F_GETFL);
90 if (flags < 0)
91 return FALSE;
92
93 return fcntl(fd, F_SETFL, flags | O_NONBLOCK) >= 0;
94}
95
96BOOL winpr_event_init(WINPR_EVENT_IMPL* event)
97{
98#ifdef WINPR_HAVE_SYS_EVENTFD_H
99 event->fds[1] = -1;
100 event->fds[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
101
102 if ((event->fds[0] < 0) && (errno == EINVAL))
103 {
104 /* kernels older than 2.6.27 only support the flag-less eventfd() call; fall back to
105 * that and apply non-blocking/close-on-exec separately afterward */
106 event->fds[0] = eventfd(0, 0);
107 if (event->fds[0] >= 0)
108 {
109 if (!set_non_blocking_fd(event->fds[0]) || !winpr_set_cloexec(event->fds[0], TRUE))
110 {
111 close(event->fds[0]);
112 event->fds[0] = -1;
113 }
114 }
115 }
116
117 return event->fds[0] >= 0;
118#else
119#ifdef WINPR_HAVE_PIPE2
120 if (pipe2(event->fds, O_CLOEXEC) < 0)
121 return FALSE;
122#else
123 if (pipe(event->fds) < 0)
124 return FALSE;
125
126 if (!winpr_set_cloexec(event->fds[0], TRUE) || !winpr_set_cloexec(event->fds[1], TRUE))
127 goto out_error;
128#endif
129
130 if (!set_non_blocking_fd(event->fds[0]) || !set_non_blocking_fd(event->fds[1]))
131 goto out_error;
132
133 return TRUE;
134
135out_error:
136 winpr_event_uninit(event);
137 return FALSE;
138#endif
139}
140
141void winpr_event_init_from_fd(WINPR_EVENT_IMPL* event, int fd)
142{
143 event->fds[0] = fd;
144#ifndef WINPR_HAVE_SYS_EVENTFD_H
145 event->fds[1] = fd;
146#endif
147}
148
149BOOL winpr_event_set(WINPR_EVENT_IMPL* event)
150{
151 SSIZE_T ret = 0;
152 do
153 {
154#ifdef WINPR_HAVE_SYS_EVENTFD_H
155 eventfd_t value = 1;
156 ret = eventfd_write(event->fds[0], value);
157#else
158 ret = write(event->fds[1], "-", 1);
159#endif
160 } while (ret < 0 && errno == EINTR);
161
162 return ret >= 0;
163}
164
165BOOL winpr_event_reset(WINPR_EVENT_IMPL* event)
166{
167 SSIZE_T ret = 0;
168 do
169 {
170 do
171 {
172#ifdef WINPR_HAVE_SYS_EVENTFD_H
173 eventfd_t value = 1;
174 ret = eventfd_read(event->fds[0], &value);
175#else
176 char value;
177 ret = read(event->fds[0], &value, 1);
178#endif
179 } while (ret < 0 && errno == EINTR);
180 } while (ret >= 0);
181
182 return (errno == EAGAIN);
183}
184
185void winpr_event_uninit(WINPR_EVENT_IMPL* event)
186{
187 if (event->fds[0] >= 0)
188 {
189 close(event->fds[0]);
190 event->fds[0] = -1;
191 }
192
193 if (event->fds[1] >= 0)
194 {
195 close(event->fds[1]);
196 event->fds[1] = -1;
197 }
198}
199
200static BOOL EventCloseHandle(HANDLE handle);
201
202WINPR_ATTR_NODISCARD
203static BOOL EventIsHandled(HANDLE handle)
204{
205 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_EVENT, FALSE);
206}
207
208WINPR_ATTR_NODISCARD
209static int EventGetFd(HANDLE handle)
210{
211 WINPR_EVENT* event = (WINPR_EVENT*)handle;
212
213 if (!EventIsHandled(handle))
214 return -1;
215
216 return event->impl.fds[0];
217}
218
219static BOOL EventCloseHandle_(WINPR_EVENT* event)
220{
221 if (!event)
222 return FALSE;
223
224 if (event->bAttached)
225 {
226 // don't close attached file descriptor
227 event->impl.fds[0] = -1; // mark as invalid
228 }
229
230 winpr_event_uninit(&event->impl);
231
232#if defined(WITH_DEBUG_EVENTS)
233 if (global_event_list)
234 {
235 ArrayList_Remove(global_event_list, event);
236 if (ArrayList_Count(global_event_list) < 1)
237 {
238 ArrayList_Free(global_event_list);
239 global_event_list = nullptr;
240 }
241 }
242
243 winpr_backtrace_free(event->create_stack);
244#endif
245 free(event->name);
246 event->name = nullptr;
247 return TRUE;
248}
249
250static BOOL EventCloseHandle(HANDLE handle)
251{
252 WINPR_EVENT* event = (WINPR_EVENT*)handle;
253
254 if (!EventIsHandled(handle))
255 return FALSE;
256
257 return EventCloseHandle_(event);
258}
259
260static HANDLE_OPS ops = { EventIsHandled, EventCloseHandle, EventGetFd, nullptr, /* CleanupHandle */
261 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
262 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
263 nullptr, nullptr, nullptr, nullptr, nullptr };
264
265HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
266 LPCWSTR lpName)
267{
268 HANDLE handle = nullptr;
269 char* name = nullptr;
270
271 if (lpName)
272 {
273 name = ConvertWCharToUtf8Alloc(lpName, nullptr);
274 if (!name)
275 return nullptr;
276 }
277
278 handle = CreateEventA(lpEventAttributes, bManualReset, bInitialState, name);
279 free(name);
280 return handle;
281}
282
283HANDLE CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
284 LPCSTR lpName)
285{
286 WINPR_EVENT* event = (WINPR_EVENT*)calloc(1, sizeof(WINPR_EVENT));
287
288 if (lpEventAttributes)
289 WLog_WARN(TAG, "[%s] does not support lpEventAttributes", lpName);
290
291 if (!event)
292 return nullptr;
293
294 if (lpName)
295 event->name = strdup(lpName);
296
297 event->impl.fds[0] = -1;
298 event->impl.fds[1] = -1;
299 event->bAttached = FALSE;
300 event->bManualReset = bManualReset;
301 event->common.ops = &ops;
302 WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, FD_READ);
303
304 if (!event->bManualReset)
305 WLog_ERR(TAG, "auto-reset events not yet implemented");
306
307 if (!winpr_event_init(&event->impl))
308 goto fail;
309
310 if (bInitialState)
311 {
312 if (!SetEvent(event))
313 goto fail;
314 }
315
316#if defined(WITH_DEBUG_EVENTS)
317 event->create_stack = winpr_backtrace(20);
318 if (!global_event_list)
319 global_event_list = ArrayList_New(TRUE);
320
321 if (global_event_list)
322 ArrayList_Append(global_event_list, event);
323#endif
324 return (HANDLE)event;
325fail:
326 EventCloseHandle_(event);
327 free(event);
328 return nullptr;
329}
330
331HANDLE CreateEventExW(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCWSTR lpName, DWORD dwFlags,
332 DWORD dwDesiredAccess)
333{
334 BOOL initial = FALSE;
335 BOOL manual = FALSE;
336
337 if (dwFlags & CREATE_EVENT_INITIAL_SET)
338 initial = TRUE;
339
340 if (dwFlags & CREATE_EVENT_MANUAL_RESET)
341 manual = TRUE;
342
343 if (dwDesiredAccess != 0)
344 {
345 char name[MAX_PATH] = WINPR_C_ARRAY_INIT;
346 ConvertWCharToUtf8(lpName, name, sizeof(name) - 1);
347 WLog_WARN(TAG, "[%s] does not support dwDesiredAccess 0x%08" PRIx32, name, dwDesiredAccess);
348 }
349
350 return CreateEventW(lpEventAttributes, manual, initial, lpName);
351}
352
353HANDLE CreateEventExA(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCSTR lpName, DWORD dwFlags,
354 DWORD dwDesiredAccess)
355{
356 BOOL initial = FALSE;
357 BOOL manual = FALSE;
358
359 if (dwFlags & CREATE_EVENT_INITIAL_SET)
360 initial = TRUE;
361
362 if (dwFlags & CREATE_EVENT_MANUAL_RESET)
363 manual = TRUE;
364
365 if (dwDesiredAccess != 0)
366 WLog_WARN(TAG, "[%s] does not support dwDesiredAccess 0x%08" PRIx32, lpName,
367 dwDesiredAccess);
368
369 return CreateEventA(lpEventAttributes, manual, initial, lpName);
370}
371
372HANDLE OpenEventW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
373{
374 /* TODO: Implement */
375 WINPR_UNUSED(dwDesiredAccess);
376 WINPR_UNUSED(bInheritHandle);
377 WINPR_UNUSED(lpName);
378 WLog_ERR(TAG, "not implemented");
379 return nullptr;
380}
381
382HANDLE OpenEventA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName)
383{
384 /* TODO: Implement */
385 WINPR_UNUSED(dwDesiredAccess);
386 WINPR_UNUSED(bInheritHandle);
387 WINPR_UNUSED(lpName);
388 WLog_ERR(TAG, "not implemented");
389 return nullptr;
390}
391
392BOOL SetEvent(HANDLE hEvent)
393{
394 ULONG Type = 0;
395 WINPR_HANDLE* Object = nullptr;
396 WINPR_EVENT* event = nullptr;
397
398 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
399 {
400 WLog_ERR(TAG, "SetEvent: hEvent is not an event");
401 SetLastError(ERROR_INVALID_PARAMETER);
402 return FALSE;
403 }
404
405 event = (WINPR_EVENT*)Object;
406 return winpr_event_set(&event->impl);
407}
408
409BOOL ResetEvent(HANDLE hEvent)
410{
411 ULONG Type = 0;
412 WINPR_HANDLE* Object = nullptr;
413 WINPR_EVENT* event = nullptr;
414
415 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
416 {
417 WLog_ERR(TAG, "ResetEvent: hEvent is not an event");
418 SetLastError(ERROR_INVALID_PARAMETER);
419 return FALSE;
420 }
421
422 event = (WINPR_EVENT*)Object;
423 return winpr_event_reset(&event->impl);
424}
425
426#endif
427
428HANDLE CreateFileDescriptorEventW(WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpEventAttributes,
429 BOOL bManualReset, WINPR_ATTR_UNUSED BOOL bInitialState,
430 int FileDescriptor, ULONG mode)
431{
432#ifndef _WIN32
433 WINPR_EVENT* event = nullptr;
434 HANDLE handle = nullptr;
435 event = (WINPR_EVENT*)calloc(1, sizeof(WINPR_EVENT));
436
437 if (event)
438 {
439 event->impl.fds[0] = -1;
440 event->impl.fds[1] = -1;
441 event->bAttached = TRUE;
442 event->bManualReset = bManualReset;
443 winpr_event_init_from_fd(&event->impl, FileDescriptor);
444 event->common.ops = &ops;
445 WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, mode);
446 handle = (HANDLE)event;
447 }
448
449 return handle;
450#else
451 return nullptr;
452#endif
453}
454
455HANDLE CreateFileDescriptorEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
456 BOOL bInitialState, int FileDescriptor, ULONG mode)
457{
458 return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
459 FileDescriptor, mode);
460}
461
465HANDLE CreateWaitObjectEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
466 BOOL bInitialState, void* pObject)
467{
468#ifndef _WIN32
469 return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
470 (int)(ULONG_PTR)pObject, WINPR_FD_READ);
471#else
472 HANDLE hEvent = nullptr;
473 DuplicateHandle(GetCurrentProcess(), pObject, GetCurrentProcess(), &hEvent, 0, FALSE,
474 DUPLICATE_SAME_ACCESS);
475 return hEvent;
476#endif
477}
478
479/*
480 * Returns inner file descriptor for usage with select()
481 * This file descriptor is not usable on Windows
482 */
483
484int GetEventFileDescriptor(HANDLE hEvent)
485{
486#ifndef _WIN32
487 return winpr_Handle_getFd(hEvent);
488#else
489 return -1;
490#endif
491}
492
493/*
494 * Set inner file descriptor for usage with select()
495 * This file descriptor is not usable on Windows
496 */
497
498int SetEventFileDescriptor(HANDLE hEvent, int FileDescriptor, ULONG mode)
499{
500#ifndef _WIN32
501 ULONG Type = 0;
502 WINPR_HANDLE* Object = nullptr;
503 WINPR_EVENT* event = nullptr;
504
505 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
506 {
507 WLog_ERR(TAG, "SetEventFileDescriptor: hEvent is not an event");
508 SetLastError(ERROR_INVALID_PARAMETER);
509 return -1;
510 }
511
512 event = (WINPR_EVENT*)Object;
513
514 if (!event->bAttached && event->impl.fds[0] >= 0 && event->impl.fds[0] != FileDescriptor)
515 close(event->impl.fds[0]);
516
517 event->bAttached = TRUE;
518 event->common.Mode = mode;
519 event->impl.fds[0] = FileDescriptor;
520 return 0;
521#else
522 return -1;
523#endif
524}
525
536void* GetEventWaitObject(HANDLE hEvent)
537{
538#ifndef _WIN32
539 int fd = 0;
540 void* obj = nullptr;
541 fd = GetEventFileDescriptor(hEvent);
542 obj = ((void*)(long)fd);
543 return obj;
544#else
545 return hEvent;
546#endif
547}
548#if defined(WITH_DEBUG_EVENTS)
549#include <unistd.h>
550#include <fcntl.h>
551#include <sys/time.h>
552#include <sys/resource.h>
553
554static BOOL dump_handle_list(void* data, size_t index, WINPR_ATTR_UNUSED va_list ap)
555{
556 WINPR_EVENT* event = data;
557 dump_event(event, index);
558 return TRUE;
559}
560
561void DumpEventHandles_(const char* fkt, const char* file, size_t line)
562{
563 struct rlimit r = WINPR_C_ARRAY_INIT;
564 int rc = getrlimit(RLIMIT_NOFILE, &r);
565 if (rc >= 0)
566 {
567 size_t count = 0;
568 for (rlim_t x = 0; x < r.rlim_cur; x++)
569 {
570 const int fd = WINPR_ASSERTING_INT_CAST(int, x);
571 int flags = fcntl(fd, F_GETFD);
572 if (flags >= 0)
573 count++;
574 }
575 WLog_INFO(TAG, "------- limits [%lu/%lu] open files %" PRIuz, (unsigned long)r.rlim_cur,
576 (unsigned long)r.rlim_max, count);
577 }
578 WLog_DBG(TAG, "--------- Start dump [%s %s:%" PRIuz "]", fkt, file, line);
579 if (global_event_list)
580 {
581 ArrayList_Lock(global_event_list);
582 (void)ArrayList_ForEach(global_event_list, dump_handle_list);
583 ArrayList_Unlock(global_event_list);
584 }
585 WLog_DBG(TAG, "--------- End dump [%s %s:%" PRIuz "]", fkt, file, line);
586}
587#endif