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