22#include <winpr/config.h>
28#include <winpr/synch.h>
34#ifdef WINPR_HAVE_UNISTD_H
38#ifdef WINPR_HAVE_SYS_EVENTFD_H
39#include <sys/eventfd.h>
45#include "../handle/handle.h"
46#include "../pipe/pipe.h"
50#define TAG WINPR_TAG("synch.event")
52#if defined(WITH_DEBUG_EVENTS)
53static wArrayList* global_event_list =
nullptr;
55static void dump_event(WINPR_EVENT* event,
size_t index)
60 WLog_DBG(TAG,
"Event handle created still not closed! [%" PRIuz
", %p]", index, event);
61 msg = winpr_backtrace_symbols(event->create_stack, &used);
63 for (
size_t i = 2; i < used; i++)
64 WLog_DBG(TAG,
"[%" PRIdz
"]: %s", i, msg[i]);
70#ifdef WINPR_HAVE_SYS_EVENTFD_H
71#if !defined(WITH_EVENTFD_READ_WRITE)
72static int eventfd_read(
int fd, eventfd_t* value)
74 return (read(fd, value,
sizeof(*value)) ==
sizeof(*value)) ? 0 : -1;
77static int eventfd_write(
int fd, eventfd_t value)
79 return (write(fd, &value,
sizeof(value)) ==
sizeof(value)) ? 0 : -1;
84#ifndef WINPR_HAVE_SYS_EVENTFD_H
85static BOOL set_non_blocking_fd(
int fd)
88 flags = fcntl(fd, F_GETFL);
92 return fcntl(fd, F_SETFL, flags | O_NONBLOCK) >= 0;
96BOOL winpr_event_init(WINPR_EVENT_IMPL* event)
98#ifdef WINPR_HAVE_SYS_EVENTFD_H
100 event->fds[0] = eventfd(0, EFD_NONBLOCK);
102 return event->fds[0] >= 0;
104 if (pipe(event->fds) < 0)
107 if (!set_non_blocking_fd(event->fds[0]) || !set_non_blocking_fd(event->fds[1]))
113 winpr_event_uninit(event);
118void winpr_event_init_from_fd(WINPR_EVENT_IMPL* event,
int fd)
121#ifndef WINPR_HAVE_SYS_EVENTFD_H
126BOOL winpr_event_set(WINPR_EVENT_IMPL* event)
131#ifdef WINPR_HAVE_SYS_EVENTFD_H
133 ret = eventfd_write(event->fds[0], value);
135 ret = write(event->fds[1],
"-", 1);
137 }
while (ret < 0 && errno == EINTR);
142BOOL winpr_event_reset(WINPR_EVENT_IMPL* event)
149#ifdef WINPR_HAVE_SYS_EVENTFD_H
151 ret = eventfd_read(event->fds[0], &value);
154 ret = read(event->fds[0], &value, 1);
156 }
while (ret < 0 && errno == EINTR);
159 return (errno == EAGAIN);
162void winpr_event_uninit(WINPR_EVENT_IMPL* event)
164 if (event->fds[0] >= 0)
166 close(event->fds[0]);
170 if (event->fds[1] >= 0)
172 close(event->fds[1]);
177static BOOL EventCloseHandle(HANDLE handle);
179static BOOL EventIsHandled(HANDLE handle)
181 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_EVENT, FALSE);
184static int EventGetFd(HANDLE handle)
186 WINPR_EVENT*
event = (WINPR_EVENT*)handle;
188 if (!EventIsHandled(handle))
191 return event->impl.fds[0];
194static BOOL EventCloseHandle_(WINPR_EVENT* event)
199 if (event->bAttached)
202 event->impl.fds[0] = -1;
205 winpr_event_uninit(&event->impl);
207#if defined(WITH_DEBUG_EVENTS)
208 if (global_event_list)
210 ArrayList_Remove(global_event_list, event);
211 if (ArrayList_Count(global_event_list) < 1)
213 ArrayList_Free(global_event_list);
214 global_event_list =
nullptr;
218 winpr_backtrace_free(event->create_stack);
225static BOOL EventCloseHandle(HANDLE handle)
227 WINPR_EVENT*
event = (WINPR_EVENT*)handle;
229 if (!EventIsHandled(handle))
232 return EventCloseHandle_(event);
235static HANDLE_OPS ops = { EventIsHandled, EventCloseHandle, EventGetFd,
nullptr,
236 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
237 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
238 nullptr,
nullptr,
nullptr,
nullptr,
nullptr };
240HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
243 HANDLE handle =
nullptr;
244 char* name =
nullptr;
248 name = ConvertWCharToUtf8Alloc(lpName,
nullptr);
253 handle = CreateEventA(lpEventAttributes, bManualReset, bInitialState, name);
258HANDLE CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
261 WINPR_EVENT*
event = (WINPR_EVENT*)calloc(1,
sizeof(WINPR_EVENT));
263 if (lpEventAttributes)
264 WLog_WARN(TAG,
"[%s] does not support lpEventAttributes", lpName);
270 event->name = strdup(lpName);
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);
279 if (!event->bManualReset)
280 WLog_ERR(TAG,
"auto-reset events not yet implemented");
282 if (!winpr_event_init(&event->impl))
287 if (!SetEvent(event))
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);
296 if (global_event_list)
297 ArrayList_Append(global_event_list, event);
299 return (HANDLE)event;
301 EventCloseHandle_(event);
305HANDLE CreateEventExW(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCWSTR lpName, DWORD dwFlags,
306 DWORD dwDesiredAccess)
308 BOOL initial = FALSE;
311 if (dwFlags & CREATE_EVENT_INITIAL_SET)
314 if (dwFlags & CREATE_EVENT_MANUAL_RESET)
317 if (dwDesiredAccess != 0)
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);
324 return CreateEventW(lpEventAttributes, manual, initial, lpName);
327HANDLE CreateEventExA(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCSTR lpName, DWORD dwFlags,
328 DWORD dwDesiredAccess)
330 BOOL initial = FALSE;
333 if (dwFlags & CREATE_EVENT_INITIAL_SET)
336 if (dwFlags & CREATE_EVENT_MANUAL_RESET)
339 if (dwDesiredAccess != 0)
340 WLog_WARN(TAG,
"[%s] does not support dwDesiredAccess 0x%08" PRIx32, lpName,
343 return CreateEventA(lpEventAttributes, manual, initial, lpName);
346HANDLE OpenEventW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
349 WINPR_UNUSED(dwDesiredAccess);
350 WINPR_UNUSED(bInheritHandle);
351 WINPR_UNUSED(lpName);
352 WLog_ERR(TAG,
"not implemented");
356HANDLE OpenEventA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName)
359 WINPR_UNUSED(dwDesiredAccess);
360 WINPR_UNUSED(bInheritHandle);
361 WINPR_UNUSED(lpName);
362 WLog_ERR(TAG,
"not implemented");
366BOOL SetEvent(HANDLE hEvent)
370 WINPR_EVENT*
event =
nullptr;
372 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
374 WLog_ERR(TAG,
"SetEvent: hEvent is not an event");
375 SetLastError(ERROR_INVALID_PARAMETER);
379 event = (WINPR_EVENT*)Object;
380 return winpr_event_set(&event->impl);
383BOOL ResetEvent(HANDLE hEvent)
387 WINPR_EVENT*
event =
nullptr;
389 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
391 WLog_ERR(TAG,
"ResetEvent: hEvent is not an event");
392 SetLastError(ERROR_INVALID_PARAMETER);
396 event = (WINPR_EVENT*)Object;
397 return winpr_event_reset(&event->impl);
402HANDLE CreateFileDescriptorEventW(WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpEventAttributes,
403 BOOL bManualReset, WINPR_ATTR_UNUSED BOOL bInitialState,
404 int FileDescriptor, ULONG mode)
407 WINPR_EVENT*
event =
nullptr;
408 HANDLE handle =
nullptr;
409 event = (WINPR_EVENT*)calloc(1,
sizeof(WINPR_EVENT));
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;
429HANDLE CreateFileDescriptorEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
430 BOOL bInitialState,
int FileDescriptor, ULONG mode)
432 return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
433 FileDescriptor, mode);
439HANDLE CreateWaitObjectEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
440 BOOL bInitialState,
void* pObject)
443 return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
444 (
int)(ULONG_PTR)pObject, WINPR_FD_READ);
446 HANDLE hEvent =
nullptr;
447 DuplicateHandle(GetCurrentProcess(), pObject, GetCurrentProcess(), &hEvent, 0, FALSE,
448 DUPLICATE_SAME_ACCESS);
458int GetEventFileDescriptor(HANDLE hEvent)
461 return winpr_Handle_getFd(hEvent);
472int SetEventFileDescriptor(HANDLE hEvent,
int FileDescriptor, ULONG mode)
477 WINPR_EVENT*
event =
nullptr;
479 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
481 WLog_ERR(TAG,
"SetEventFileDescriptor: hEvent is not an event");
482 SetLastError(ERROR_INVALID_PARAMETER);
486 event = (WINPR_EVENT*)Object;
488 if (!event->bAttached && event->impl.fds[0] >= 0 && event->impl.fds[0] != FileDescriptor)
489 close(event->impl.fds[0]);
491 event->bAttached = TRUE;
492 event->common.Mode = mode;
493 event->impl.fds[0] = FileDescriptor;
510void* GetEventWaitObject(HANDLE hEvent)
515 fd = GetEventFileDescriptor(hEvent);
516 obj = ((
void*)(
long)fd);
522#if defined(WITH_DEBUG_EVENTS)
526#include <sys/resource.h>
528static BOOL dump_handle_list(
void* data,
size_t index, va_list ap)
530 WINPR_EVENT*
event = data;
531 dump_event(event, index);
535void DumpEventHandles_(
const char* fkt,
const char* file,
size_t line)
537 struct rlimit r = WINPR_C_ARRAY_INIT;
538 int rc = getrlimit(RLIMIT_NOFILE, &r);
542 for (rlim_t x = 0; x < r.rlim_cur; x++)
544 int flags = fcntl(x, F_GETFD);
548 WLog_INFO(TAG,
"------- limits [%d/%d] open files %" PRIuz, r.rlim_cur, r.rlim_max, count);
550 WLog_DBG(TAG,
"--------- Start dump [%s %s:%" PRIuz
"]", fkt, file, line);
551 if (global_event_list)
553 ArrayList_Lock(global_event_list);
554 ArrayList_ForEach(global_event_list, dump_handle_list);
555 ArrayList_Unlock(global_event_list);
557 WLog_DBG(TAG,
"--------- End dump [%s %s:%" PRIuz
"]", fkt, file, line);