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