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, 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 = nullptr;
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, EventCloseHandle, EventGetFd, nullptr, /* CleanupHandle */
236 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
237 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
238 nullptr, nullptr, nullptr, nullptr, nullptr };
239
240HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
241 LPCWSTR lpName)
242{
243 HANDLE handle = nullptr;
244 char* name = nullptr;
245
246 if (lpName)
247 {
248 name = ConvertWCharToUtf8Alloc(lpName, nullptr);
249 if (!name)
250 return nullptr;
251 }
252
253 handle = CreateEventA(lpEventAttributes, bManualReset, bInitialState, name);
254 free(name);
255 return handle;
256}
257
258HANDLE CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
259 LPCSTR lpName)
260{
261 WINPR_EVENT* event = (WINPR_EVENT*)calloc(1, sizeof(WINPR_EVENT));
262
263 if (lpEventAttributes)
264 WLog_WARN(TAG, "[%s] does not support lpEventAttributes", lpName);
265
266 if (!event)
267 return nullptr;
268
269 if (lpName)
270 event->name = strdup(lpName);
271
272 event->impl.fds[0] = -1;
273 event->impl.fds[1] = -1;
274 event->bAttached = FALSE;
275 event->bManualReset = bManualReset;
276 event->common.ops = &ops;
277 WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, FD_READ);
278
279 if (!event->bManualReset)
280 WLog_ERR(TAG, "auto-reset events not yet implemented");
281
282 if (!winpr_event_init(&event->impl))
283 goto fail;
284
285 if (bInitialState)
286 {
287 if (!SetEvent(event))
288 goto fail;
289 }
290
291#if defined(WITH_DEBUG_EVENTS)
292 event->create_stack = winpr_backtrace(20);
293 if (!global_event_list)
294 global_event_list = ArrayList_New(TRUE);
295
296 if (global_event_list)
297 ArrayList_Append(global_event_list, event);
298#endif
299 return (HANDLE)event;
300fail:
301 EventCloseHandle_(event);
302 return nullptr;
303}
304
305HANDLE CreateEventExW(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCWSTR lpName, DWORD dwFlags,
306 DWORD dwDesiredAccess)
307{
308 BOOL initial = FALSE;
309 BOOL manual = FALSE;
310
311 if (dwFlags & CREATE_EVENT_INITIAL_SET)
312 initial = TRUE;
313
314 if (dwFlags & CREATE_EVENT_MANUAL_RESET)
315 manual = TRUE;
316
317 if (dwDesiredAccess != 0)
318 {
319 char name[MAX_PATH] = WINPR_C_ARRAY_INIT;
320 ConvertWCharToUtf8(lpName, name, sizeof(name) - 1);
321 WLog_WARN(TAG, "[%s] does not support dwDesiredAccess 0x%08" PRIx32, name, dwDesiredAccess);
322 }
323
324 return CreateEventW(lpEventAttributes, manual, initial, lpName);
325}
326
327HANDLE CreateEventExA(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCSTR lpName, DWORD dwFlags,
328 DWORD dwDesiredAccess)
329{
330 BOOL initial = FALSE;
331 BOOL manual = FALSE;
332
333 if (dwFlags & CREATE_EVENT_INITIAL_SET)
334 initial = TRUE;
335
336 if (dwFlags & CREATE_EVENT_MANUAL_RESET)
337 manual = TRUE;
338
339 if (dwDesiredAccess != 0)
340 WLog_WARN(TAG, "[%s] does not support dwDesiredAccess 0x%08" PRIx32, lpName,
341 dwDesiredAccess);
342
343 return CreateEventA(lpEventAttributes, manual, initial, lpName);
344}
345
346HANDLE OpenEventW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
347{
348 /* TODO: Implement */
349 WINPR_UNUSED(dwDesiredAccess);
350 WINPR_UNUSED(bInheritHandle);
351 WINPR_UNUSED(lpName);
352 WLog_ERR(TAG, "not implemented");
353 return nullptr;
354}
355
356HANDLE OpenEventA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName)
357{
358 /* TODO: Implement */
359 WINPR_UNUSED(dwDesiredAccess);
360 WINPR_UNUSED(bInheritHandle);
361 WINPR_UNUSED(lpName);
362 WLog_ERR(TAG, "not implemented");
363 return nullptr;
364}
365
366BOOL SetEvent(HANDLE hEvent)
367{
368 ULONG Type = 0;
369 WINPR_HANDLE* Object = nullptr;
370 WINPR_EVENT* event = nullptr;
371
372 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
373 {
374 WLog_ERR(TAG, "SetEvent: hEvent is not an event");
375 SetLastError(ERROR_INVALID_PARAMETER);
376 return FALSE;
377 }
378
379 event = (WINPR_EVENT*)Object;
380 return winpr_event_set(&event->impl);
381}
382
383BOOL ResetEvent(HANDLE hEvent)
384{
385 ULONG Type = 0;
386 WINPR_HANDLE* Object = nullptr;
387 WINPR_EVENT* event = nullptr;
388
389 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
390 {
391 WLog_ERR(TAG, "ResetEvent: hEvent is not an event");
392 SetLastError(ERROR_INVALID_PARAMETER);
393 return FALSE;
394 }
395
396 event = (WINPR_EVENT*)Object;
397 return winpr_event_reset(&event->impl);
398}
399
400#endif
401
402HANDLE CreateFileDescriptorEventW(WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpEventAttributes,
403 BOOL bManualReset, WINPR_ATTR_UNUSED BOOL bInitialState,
404 int FileDescriptor, ULONG mode)
405{
406#ifndef _WIN32
407 WINPR_EVENT* event = nullptr;
408 HANDLE handle = nullptr;
409 event = (WINPR_EVENT*)calloc(1, sizeof(WINPR_EVENT));
410
411 if (event)
412 {
413 event->impl.fds[0] = -1;
414 event->impl.fds[1] = -1;
415 event->bAttached = TRUE;
416 event->bManualReset = bManualReset;
417 winpr_event_init_from_fd(&event->impl, FileDescriptor);
418 event->common.ops = &ops;
419 WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, mode);
420 handle = (HANDLE)event;
421 }
422
423 return handle;
424#else
425 return nullptr;
426#endif
427}
428
429HANDLE CreateFileDescriptorEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
430 BOOL bInitialState, int FileDescriptor, ULONG mode)
431{
432 return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
433 FileDescriptor, mode);
434}
435
439HANDLE CreateWaitObjectEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
440 BOOL bInitialState, void* pObject)
441{
442#ifndef _WIN32
443 return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
444 (int)(ULONG_PTR)pObject, WINPR_FD_READ);
445#else
446 HANDLE hEvent = nullptr;
447 DuplicateHandle(GetCurrentProcess(), pObject, GetCurrentProcess(), &hEvent, 0, FALSE,
448 DUPLICATE_SAME_ACCESS);
449 return hEvent;
450#endif
451}
452
453/*
454 * Returns inner file descriptor for usage with select()
455 * This file descriptor is not usable on Windows
456 */
457
458int GetEventFileDescriptor(HANDLE hEvent)
459{
460#ifndef _WIN32
461 return winpr_Handle_getFd(hEvent);
462#else
463 return -1;
464#endif
465}
466
467/*
468 * Set inner file descriptor for usage with select()
469 * This file descriptor is not usable on Windows
470 */
471
472int SetEventFileDescriptor(HANDLE hEvent, int FileDescriptor, ULONG mode)
473{
474#ifndef _WIN32
475 ULONG Type = 0;
476 WINPR_HANDLE* Object = nullptr;
477 WINPR_EVENT* event = nullptr;
478
479 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
480 {
481 WLog_ERR(TAG, "SetEventFileDescriptor: hEvent is not an event");
482 SetLastError(ERROR_INVALID_PARAMETER);
483 return -1;
484 }
485
486 event = (WINPR_EVENT*)Object;
487
488 if (!event->bAttached && event->impl.fds[0] >= 0 && event->impl.fds[0] != FileDescriptor)
489 close(event->impl.fds[0]);
490
491 event->bAttached = TRUE;
492 event->common.Mode = mode;
493 event->impl.fds[0] = FileDescriptor;
494 return 0;
495#else
496 return -1;
497#endif
498}
499
510void* GetEventWaitObject(HANDLE hEvent)
511{
512#ifndef _WIN32
513 int fd = 0;
514 void* obj = nullptr;
515 fd = GetEventFileDescriptor(hEvent);
516 obj = ((void*)(long)fd);
517 return obj;
518#else
519 return hEvent;
520#endif
521}
522#if defined(WITH_DEBUG_EVENTS)
523#include <unistd.h>
524#include <fcntl.h>
525#include <sys/time.h>
526#include <sys/resource.h>
527
528static BOOL dump_handle_list(void* data, size_t index, va_list ap)
529{
530 WINPR_EVENT* event = data;
531 dump_event(event, index);
532 return TRUE;
533}
534
535void DumpEventHandles_(const char* fkt, const char* file, size_t line)
536{
537 struct rlimit r = WINPR_C_ARRAY_INIT;
538 int rc = getrlimit(RLIMIT_NOFILE, &r);
539 if (rc >= 0)
540 {
541 size_t count = 0;
542 for (rlim_t x = 0; x < r.rlim_cur; x++)
543 {
544 int flags = fcntl(x, F_GETFD);
545 if (flags >= 0)
546 count++;
547 }
548 WLog_INFO(TAG, "------- limits [%d/%d] open files %" PRIuz, r.rlim_cur, r.rlim_max, count);
549 }
550 WLog_DBG(TAG, "--------- Start dump [%s %s:%" PRIuz "]", fkt, file, line);
551 if (global_event_list)
552 {
553 ArrayList_Lock(global_event_list);
554 ArrayList_ForEach(global_event_list, dump_handle_list);
555 ArrayList_Unlock(global_event_list);
556 }
557 WLog_DBG(TAG, "--------- End dump [%s %s:%" PRIuz "]", fkt, file, line);
558}
559#endif