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, (
void*)event);
61 msg = winpr_backtrace_symbols(event->create_stack, &used);
63 for (
size_t i = 2; i < used; i++)
64 WLog_DBG(TAG,
"[%" PRIuz
"]: %s", i, msg[i]);
70#ifdef WINPR_HAVE_SYS_EVENTFD_H
71#if !defined(WITH_EVENTFD_READ_WRITE)
73static int eventfd_read(
int fd, eventfd_t* value)
75 return (read(fd, value,
sizeof(*value)) ==
sizeof(*value)) ? 0 : -1;
79static int eventfd_write(
int fd, eventfd_t value)
81 return (write(fd, &value,
sizeof(value)) ==
sizeof(value)) ? 0 : -1;
87static BOOL set_non_blocking_fd(
int fd)
89 int flags = fcntl(fd, F_GETFL);
93 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 | EFD_CLOEXEC);
102 if ((event->fds[0] < 0) && (errno == EINVAL))
106 event->fds[0] = eventfd(0, 0);
107 if (event->fds[0] >= 0)
109 if (!set_non_blocking_fd(event->fds[0]) || !winpr_set_cloexec(event->fds[0], TRUE))
111 close(event->fds[0]);
117 return event->fds[0] >= 0;
119#ifdef WINPR_HAVE_PIPE2
120 if (pipe2(event->fds, O_CLOEXEC) < 0)
123 if (pipe(event->fds) < 0)
126 if (!winpr_set_cloexec(event->fds[0], TRUE) || !winpr_set_cloexec(event->fds[1], TRUE))
130 if (!set_non_blocking_fd(event->fds[0]) || !set_non_blocking_fd(event->fds[1]))
136 winpr_event_uninit(event);
141void winpr_event_init_from_fd(WINPR_EVENT_IMPL* event,
int fd)
144#ifndef WINPR_HAVE_SYS_EVENTFD_H
149BOOL winpr_event_set(WINPR_EVENT_IMPL* event)
154#ifdef WINPR_HAVE_SYS_EVENTFD_H
156 ret = eventfd_write(event->fds[0], value);
158 ret = write(event->fds[1],
"-", 1);
160 }
while (ret < 0 && errno == EINTR);
165BOOL winpr_event_reset(WINPR_EVENT_IMPL* event)
172#ifdef WINPR_HAVE_SYS_EVENTFD_H
174 ret = eventfd_read(event->fds[0], &value);
177 ret = read(event->fds[0], &value, 1);
179 }
while (ret < 0 && errno == EINTR);
182 return (errno == EAGAIN);
185void winpr_event_uninit(WINPR_EVENT_IMPL* event)
187 if (event->fds[0] >= 0)
189 close(event->fds[0]);
193 if (event->fds[1] >= 0)
195 close(event->fds[1]);
200static BOOL EventCloseHandle(HANDLE handle);
203static BOOL EventIsHandled(HANDLE handle)
205 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_EVENT, FALSE);
209static int EventGetFd(HANDLE handle)
211 WINPR_EVENT*
event = (WINPR_EVENT*)handle;
213 if (!EventIsHandled(handle))
216 return event->impl.fds[0];
219static BOOL EventCloseHandle_(WINPR_EVENT* event)
224 if (event->bAttached)
227 event->impl.fds[0] = -1;
230 winpr_event_uninit(&event->impl);
232#if defined(WITH_DEBUG_EVENTS)
233 if (global_event_list)
235 ArrayList_Remove(global_event_list, event);
236 if (ArrayList_Count(global_event_list) < 1)
238 ArrayList_Free(global_event_list);
239 global_event_list =
nullptr;
243 winpr_backtrace_free(event->create_stack);
246 event->name =
nullptr;
250static BOOL EventCloseHandle(HANDLE handle)
252 WINPR_EVENT*
event = (WINPR_EVENT*)handle;
254 if (!EventIsHandled(handle))
257 return EventCloseHandle_(event);
260static HANDLE_OPS ops = { EventIsHandled, EventCloseHandle, EventGetFd,
nullptr,
261 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
262 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
263 nullptr,
nullptr,
nullptr,
nullptr,
nullptr };
265HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
268 HANDLE handle =
nullptr;
269 char* name =
nullptr;
273 name = ConvertWCharToUtf8Alloc(lpName,
nullptr);
278 handle = CreateEventA(lpEventAttributes, bManualReset, bInitialState, name);
283HANDLE CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
286 WINPR_EVENT*
event = (WINPR_EVENT*)calloc(1,
sizeof(WINPR_EVENT));
288 if (lpEventAttributes)
289 WLog_WARN(TAG,
"[%s] does not support lpEventAttributes", lpName);
295 event->name = strdup(lpName);
297 event->impl.fds[0] = -1;
298 event->impl.fds[1] = -1;
299 event->bAttached = FALSE;
300 event->bManualReset = bManualReset;
301 event->common.ops = &ops;
302 WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, FD_READ);
304 if (!event->bManualReset)
305 WLog_ERR(TAG,
"auto-reset events not yet implemented");
307 if (!winpr_event_init(&event->impl))
312 if (!SetEvent(event))
316#if defined(WITH_DEBUG_EVENTS)
317 event->create_stack = winpr_backtrace(20);
318 if (!global_event_list)
319 global_event_list = ArrayList_New(TRUE);
321 if (global_event_list)
322 ArrayList_Append(global_event_list, event);
324 return (HANDLE)event;
326 EventCloseHandle_(event);
331HANDLE CreateEventExW(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCWSTR lpName, DWORD dwFlags,
332 DWORD dwDesiredAccess)
334 BOOL initial = FALSE;
337 if (dwFlags & CREATE_EVENT_INITIAL_SET)
340 if (dwFlags & CREATE_EVENT_MANUAL_RESET)
343 if (dwDesiredAccess != 0)
345 char name[MAX_PATH] = WINPR_C_ARRAY_INIT;
346 ConvertWCharToUtf8(lpName, name,
sizeof(name) - 1);
347 WLog_WARN(TAG,
"[%s] does not support dwDesiredAccess 0x%08" PRIx32, name, dwDesiredAccess);
350 return CreateEventW(lpEventAttributes, manual, initial, lpName);
353HANDLE CreateEventExA(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCSTR lpName, DWORD dwFlags,
354 DWORD dwDesiredAccess)
356 BOOL initial = FALSE;
359 if (dwFlags & CREATE_EVENT_INITIAL_SET)
362 if (dwFlags & CREATE_EVENT_MANUAL_RESET)
365 if (dwDesiredAccess != 0)
366 WLog_WARN(TAG,
"[%s] does not support dwDesiredAccess 0x%08" PRIx32, lpName,
369 return CreateEventA(lpEventAttributes, manual, initial, lpName);
372HANDLE OpenEventW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
375 WINPR_UNUSED(dwDesiredAccess);
376 WINPR_UNUSED(bInheritHandle);
377 WINPR_UNUSED(lpName);
378 WLog_ERR(TAG,
"not implemented");
382HANDLE OpenEventA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName)
385 WINPR_UNUSED(dwDesiredAccess);
386 WINPR_UNUSED(bInheritHandle);
387 WINPR_UNUSED(lpName);
388 WLog_ERR(TAG,
"not implemented");
392BOOL SetEvent(HANDLE hEvent)
396 WINPR_EVENT*
event =
nullptr;
398 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
400 WLog_ERR(TAG,
"SetEvent: hEvent is not an event");
401 SetLastError(ERROR_INVALID_PARAMETER);
405 event = (WINPR_EVENT*)Object;
406 return winpr_event_set(&event->impl);
409BOOL ResetEvent(HANDLE hEvent)
413 WINPR_EVENT*
event =
nullptr;
415 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
417 WLog_ERR(TAG,
"ResetEvent: hEvent is not an event");
418 SetLastError(ERROR_INVALID_PARAMETER);
422 event = (WINPR_EVENT*)Object;
423 return winpr_event_reset(&event->impl);
428HANDLE CreateFileDescriptorEventW(WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpEventAttributes,
429 BOOL bManualReset, WINPR_ATTR_UNUSED BOOL bInitialState,
430 int FileDescriptor, ULONG mode)
433 WINPR_EVENT*
event =
nullptr;
434 HANDLE handle =
nullptr;
435 event = (WINPR_EVENT*)calloc(1,
sizeof(WINPR_EVENT));
439 event->impl.fds[0] = -1;
440 event->impl.fds[1] = -1;
441 event->bAttached = TRUE;
442 event->bManualReset = bManualReset;
443 winpr_event_init_from_fd(&event->impl, FileDescriptor);
444 event->common.ops = &ops;
445 WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, mode);
446 handle = (HANDLE)event;
455HANDLE CreateFileDescriptorEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
456 BOOL bInitialState,
int FileDescriptor, ULONG mode)
458 return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
459 FileDescriptor, mode);
465HANDLE CreateWaitObjectEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
466 BOOL bInitialState,
void* pObject)
469 return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
470 (
int)(ULONG_PTR)pObject, WINPR_FD_READ);
472 HANDLE hEvent =
nullptr;
473 DuplicateHandle(GetCurrentProcess(), pObject, GetCurrentProcess(), &hEvent, 0, FALSE,
474 DUPLICATE_SAME_ACCESS);
484int GetEventFileDescriptor(HANDLE hEvent)
487 return winpr_Handle_getFd(hEvent);
498int SetEventFileDescriptor(HANDLE hEvent,
int FileDescriptor, ULONG mode)
503 WINPR_EVENT*
event =
nullptr;
505 if (!winpr_Handle_GetInfo(hEvent, &Type, &Object) || Type != HANDLE_TYPE_EVENT)
507 WLog_ERR(TAG,
"SetEventFileDescriptor: hEvent is not an event");
508 SetLastError(ERROR_INVALID_PARAMETER);
512 event = (WINPR_EVENT*)Object;
514 if (!event->bAttached && event->impl.fds[0] >= 0 && event->impl.fds[0] != FileDescriptor)
515 close(event->impl.fds[0]);
517 event->bAttached = TRUE;
518 event->common.Mode = mode;
519 event->impl.fds[0] = FileDescriptor;
536void* GetEventWaitObject(HANDLE hEvent)
541 fd = GetEventFileDescriptor(hEvent);
542 obj = ((
void*)(
long)fd);
548#if defined(WITH_DEBUG_EVENTS)
552#include <sys/resource.h>
554static BOOL dump_handle_list(
void* data,
size_t index, WINPR_ATTR_UNUSED va_list ap)
556 WINPR_EVENT*
event = data;
557 dump_event(event, index);
561void DumpEventHandles_(
const char* fkt,
const char* file,
size_t line)
563 struct rlimit r = WINPR_C_ARRAY_INIT;
564 int rc = getrlimit(RLIMIT_NOFILE, &r);
568 for (rlim_t x = 0; x < r.rlim_cur; x++)
570 const int fd = WINPR_ASSERTING_INT_CAST(
int, x);
571 int flags = fcntl(fd, F_GETFD);
575 WLog_INFO(TAG,
"------- limits [%lu/%lu] open files %" PRIuz, (
unsigned long)r.rlim_cur,
576 (
unsigned long)r.rlim_max, count);
578 WLog_DBG(TAG,
"--------- Start dump [%s %s:%" PRIuz
"]", fkt, file, line);
579 if (global_event_list)
581 ArrayList_Lock(global_event_list);
582 (void)ArrayList_ForEach(global_event_list, dump_handle_list);
583 ArrayList_Unlock(global_event_list);
585 WLog_DBG(TAG,
"--------- End dump [%s %s:%" PRIuz
"]", fkt, file, line);