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 = 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 {
336 char name[MAX_PATH] = { 0 };
337 ConvertWCharToUtf8(lpName, name, sizeof(name) - 1);
338 WLog_WARN(TAG, "[%s] does not support dwDesiredAccess 0x%08" PRIx32, name, dwDesiredAccess);
339 }
340
341 return CreateEventW(lpEventAttributes, manual, initial, lpName);
342}
343
344HANDLE CreateEventExA(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCSTR lpName, DWORD dwFlags,
345 DWORD dwDesiredAccess)
346{
347 BOOL initial = FALSE;
348 BOOL manual = FALSE;
349
350 if (dwFlags & CREATE_EVENT_INITIAL_SET)
351 initial = TRUE;
352
353 if (dwFlags & CREATE_EVENT_MANUAL_RESET)
354 manual = TRUE;
355
356 if (dwDesiredAccess != 0)
357 WLog_WARN(TAG, "[%s] does not support dwDesiredAccess 0x%08" PRIx32, lpName,
358 dwDesiredAccess);
359
360 return CreateEventA(lpEventAttributes, manual, initial, lpName);
361}
362
363HANDLE OpenEventW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
364{
365 /* TODO: Implement */
366 WINPR_UNUSED(dwDesiredAccess);
367 WINPR_UNUSED(bInheritHandle);
368 WINPR_UNUSED(lpName);
369 WLog_ERR(TAG, "not implemented");
370 return NULL;
371}
372
373HANDLE OpenEventA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName)
374{
375 /* TODO: Implement */
376 WINPR_UNUSED(dwDesiredAccess);
377 WINPR_UNUSED(bInheritHandle);
378 WINPR_UNUSED(lpName);
379 WLog_ERR(TAG, "not implemented");
380 return NULL;
381}
382
383BOOL SetEvent(HANDLE hEvent)
384{
385 ULONG Type = 0;
386 WINPR_HANDLE* Object = NULL;
387 WINPR_EVENT* event = NULL;
388
389 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
390 {
391 WLog_ERR(TAG, "SetEvent: hEvent is not an event");
392 SetLastError(ERROR_INVALID_PARAMETER);
393 return FALSE;
394 }
395
396 event = (WINPR_EVENT*)Object;
397 return winpr_event_set(&event->impl);
398}
399
400BOOL ResetEvent(HANDLE hEvent)
401{
402 ULONG Type = 0;
403 WINPR_HANDLE* Object = NULL;
404 WINPR_EVENT* event = NULL;
405
406 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
407 {
408 WLog_ERR(TAG, "ResetEvent: hEvent is not an event");
409 SetLastError(ERROR_INVALID_PARAMETER);
410 return FALSE;
411 }
412
413 event = (WINPR_EVENT*)Object;
414 return winpr_event_reset(&event->impl);
415}
416
417#endif
418
419HANDLE CreateFileDescriptorEventW(WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpEventAttributes,
420 BOOL bManualReset, WINPR_ATTR_UNUSED BOOL bInitialState,
421 int FileDescriptor, ULONG mode)
422{
423#ifndef _WIN32
424 WINPR_EVENT* event = NULL;
425 HANDLE handle = NULL;
426 event = (WINPR_EVENT*)calloc(1, sizeof(WINPR_EVENT));
427
428 if (event)
429 {
430 event->impl.fds[0] = -1;
431 event->impl.fds[1] = -1;
432 event->bAttached = TRUE;
433 event->bManualReset = bManualReset;
434 winpr_event_init_from_fd(&event->impl, FileDescriptor);
435 event->common.ops = &ops;
436 WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, mode);
437 handle = (HANDLE)event;
438 }
439
440 return handle;
441#else
442 return NULL;
443#endif
444}
445
446HANDLE CreateFileDescriptorEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
447 BOOL bInitialState, int FileDescriptor, ULONG mode)
448{
449 return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
450 FileDescriptor, mode);
451}
452
456HANDLE CreateWaitObjectEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
457 BOOL bInitialState, void* pObject)
458{
459#ifndef _WIN32
460 return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
461 (int)(ULONG_PTR)pObject, WINPR_FD_READ);
462#else
463 HANDLE hEvent = NULL;
464 DuplicateHandle(GetCurrentProcess(), pObject, GetCurrentProcess(), &hEvent, 0, FALSE,
465 DUPLICATE_SAME_ACCESS);
466 return hEvent;
467#endif
468}
469
470/*
471 * Returns inner file descriptor for usage with select()
472 * This file descriptor is not usable on Windows
473 */
474
475int GetEventFileDescriptor(HANDLE hEvent)
476{
477#ifndef _WIN32
478 return winpr_Handle_getFd(hEvent);
479#else
480 return -1;
481#endif
482}
483
484/*
485 * Set inner file descriptor for usage with select()
486 * This file descriptor is not usable on Windows
487 */
488
489int SetEventFileDescriptor(HANDLE hEvent, int FileDescriptor, ULONG mode)
490{
491#ifndef _WIN32
492 ULONG Type = 0;
493 WINPR_HANDLE* Object = NULL;
494 WINPR_EVENT* event = NULL;
495
496 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
497 {
498 WLog_ERR(TAG, "SetEventFileDescriptor: hEvent is not an event");
499 SetLastError(ERROR_INVALID_PARAMETER);
500 return -1;
501 }
502
503 event = (WINPR_EVENT*)Object;
504
505 if (!event->bAttached && event->impl.fds[0] >= 0 && event->impl.fds[0] != FileDescriptor)
506 close(event->impl.fds[0]);
507
508 event->bAttached = TRUE;
509 event->common.Mode = mode;
510 event->impl.fds[0] = FileDescriptor;
511 return 0;
512#else
513 return -1;
514#endif
515}
516
527void* GetEventWaitObject(HANDLE hEvent)
528{
529#ifndef _WIN32
530 int fd = 0;
531 void* obj = NULL;
532 fd = GetEventFileDescriptor(hEvent);
533 obj = ((void*)(long)fd);
534 return obj;
535#else
536 return hEvent;
537#endif
538}
539#if defined(WITH_DEBUG_EVENTS)
540#include <unistd.h>
541#include <fcntl.h>
542#include <sys/time.h>
543#include <sys/resource.h>
544
545static BOOL dump_handle_list(void* data, size_t index, va_list ap)
546{
547 WINPR_EVENT* event = data;
548 dump_event(event, index);
549 return TRUE;
550}
551
552void DumpEventHandles_(const char* fkt, const char* file, size_t line)
553{
554 struct rlimit r = { 0 };
555 int rc = getrlimit(RLIMIT_NOFILE, &r);
556 if (rc >= 0)
557 {
558 size_t count = 0;
559 for (rlim_t x = 0; x < r.rlim_cur; x++)
560 {
561 int flags = fcntl(x, F_GETFD);
562 if (flags >= 0)
563 count++;
564 }
565 WLog_INFO(TAG, "------- limits [%d/%d] open files %" PRIuz, r.rlim_cur, r.rlim_max, count);
566 }
567 WLog_DBG(TAG, "--------- Start dump [%s %s:%" PRIuz "]", fkt, file, line);
568 if (global_event_list)
569 {
570 ArrayList_Lock(global_event_list);
571 ArrayList_ForEach(global_event_list, dump_handle_list);
572 ArrayList_Unlock(global_event_list);
573 }
574 WLog_DBG(TAG, "--------- End dump [%s %s:%" PRIuz "]", fkt, file, line);
575}
576#endif