From 6243a9374b201d9a46511afe9a7570303d365c54 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 3 Jul 2015 09:25:41 +0200 Subject: [PATCH] Added write event support to handle functions. Allows the WinPR HANDLE functions WaitForSingleObject and WaitForMultipleObjects to signal in case of write events. This is used by CreateFileDescriptor and SetEventFileDescriptor, which got an API change accomodating for this new feature. --- winpr/include/winpr/handle.h | 8 ++- winpr/include/winpr/synch.h | 7 +-- winpr/libwinpr/handle/handle.c | 2 +- winpr/libwinpr/handle/handle.h | 18 +++++-- winpr/libwinpr/synch/event.c | 61 ++++++++++++---------- winpr/libwinpr/synch/wait.c | 94 +++++++++++++++++++++++++--------- 6 files changed, 128 insertions(+), 62 deletions(-) diff --git a/winpr/include/winpr/handle.h b/winpr/include/winpr/handle.h index 3a278e93a..482c4330c 100644 --- a/winpr/include/winpr/handle.h +++ b/winpr/include/winpr/handle.h @@ -41,8 +41,12 @@ extern "C" { WINPR_API BOOL CloseHandle(HANDLE hObject); -WINPR_API BOOL DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, - LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions); +WINPR_API BOOL DuplicateHandle(HANDLE hSourceProcessHandle, + HANDLE hSourceHandle, + HANDLE hTargetProcessHandle, + LPHANDLE lpTargetHandle, + DWORD dwDesiredAccess, + BOOL bInheritHandle, DWORD dwOptions); WINPR_API BOOL GetHandleInformation(HANDLE hObject, LPDWORD lpdwFlags); WINPR_API BOOL SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags); diff --git a/winpr/include/winpr/synch.h b/winpr/include/winpr/synch.h index 4b554431d..249a9e30e 100644 --- a/winpr/include/winpr/synch.h +++ b/winpr/include/winpr/synch.h @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -338,9 +339,9 @@ WINPR_API BOOL WINAPI DeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpB WINPR_API VOID USleep(DWORD dwMicroseconds); WINPR_API HANDLE CreateFileDescriptorEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, - BOOL bManualReset, BOOL bInitialState, int FileDescriptor); + BOOL bManualReset, BOOL bInitialState, int FileDescriptor, ULONG mode); WINPR_API HANDLE CreateFileDescriptorEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, - BOOL bManualReset, BOOL bInitialState, int FileDescriptor); + BOOL bManualReset, BOOL bInitialState, int FileDescriptor, ULONG mode); WINPR_API HANDLE CreateWaitObjectEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, void* pObject); @@ -352,7 +353,7 @@ WINPR_API HANDLE CreateWaitObjectEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, #endif WINPR_API int GetEventFileDescriptor(HANDLE hEvent); -WINPR_API int SetEventFileDescriptor(HANDLE hEvent, int FileDescriptor); +WINPR_API int SetEventFileDescriptor(HANDLE hEvent, int FileDescriptor, ULONG mode); WINPR_API void* GetEventWaitObject(HANDLE hEvent); diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index 5cc5e4178..b57dacd95 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -48,7 +48,7 @@ BOOL CloseHandle(HANDLE hObject) ULONG Type; WINPR_HANDLE *Object; - if (!winpr_Handle_GetInfo(hObject, &Type, (PVOID*) &Object)) + if (!winpr_Handle_GetInfo(hObject, &Type, &Object)) return FALSE; if (!Object) diff --git a/winpr/libwinpr/handle/handle.h b/winpr/libwinpr/handle/handle.h index faaea58dd..728cd8160 100644 --- a/winpr/libwinpr/handle/handle.h +++ b/winpr/libwinpr/handle/handle.h @@ -23,6 +23,7 @@ #include #include #include +#include #define HANDLE_TYPE_NONE 0 #define HANDLE_TYPE_PROCESS 1 @@ -41,6 +42,7 @@ #define WINPR_HANDLE_DEF() \ ULONG Type; \ + ULONG Mode; \ HANDLE_OPS *ops typedef BOOL (*pcIsHandled)(HANDLE handle); @@ -68,10 +70,16 @@ struct winpr_handle }; typedef struct winpr_handle WINPR_HANDLE; -#define WINPR_HANDLE_SET_TYPE(_handle, _type) \ - _handle->Type = _type +static INLINE void WINPR_HANDLE_SET_TYPE_AND_MODE(void* _handle, + ULONG _type, ULONG _mode) +{ + WINPR_HANDLE* hdl = (WINPR_HANDLE*)_handle; -static INLINE BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, PVOID* pObject) + hdl->Type = _type; + hdl->Mode = _mode; +} + +static INLINE BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, WINPR_HANDLE** pObject) { WINPR_HANDLE* wHandle; @@ -91,7 +99,7 @@ static INLINE int winpr_Handle_getFd(HANDLE handle) WINPR_HANDLE *hdl; ULONG type; - if (!winpr_Handle_GetInfo(handle, &type, (PVOID*)&hdl)) + if (!winpr_Handle_GetInfo(handle, &type, &hdl)) return -1; if (!hdl || !hdl->ops->GetFd) @@ -105,7 +113,7 @@ static INLINE DWORD winpr_Handle_cleanup(HANDLE handle) WINPR_HANDLE *hdl; ULONG type; - if (!winpr_Handle_GetInfo(handle, &type, (PVOID*)&hdl)) + if (!winpr_Handle_GetInfo(handle, &type, &hdl)) return WAIT_FAILED; if (!hdl) diff --git a/winpr/libwinpr/synch/event.c b/winpr/libwinpr/synch/event.c index 0157c652b..e561eaa41 100644 --- a/winpr/libwinpr/synch/event.c +++ b/winpr/libwinpr/synch/event.c @@ -78,23 +78,22 @@ BOOL EventCloseHandle(HANDLE handle) { if (!EventIsHandled(handle)) return FALSE; - if (!event->bAttached) - { - if (event->pipe_fd[0] != -1) - { - close(event->pipe_fd[0]); - event->pipe_fd[0] = -1; - } + if (!event->bAttached) + { + if (event->pipe_fd[0] != -1) + { + close(event->pipe_fd[0]); + event->pipe_fd[0] = -1; + } + if (event->pipe_fd[1] != -1) + { + close(event->pipe_fd[1]); + event->pipe_fd[1] = -1; + } + } - if (event->pipe_fd[1] != -1) - { - close(event->pipe_fd[1]); - event->pipe_fd[1] = -1; - } - } - - free(event); - return TRUE; + free(event); + return TRUE; } static HANDLE_OPS ops = { @@ -114,7 +113,7 @@ HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, event->bAttached = FALSE; event->bManualReset = bManualReset; event->ops = &ops; - WINPR_HANDLE_SET_TYPE(event, HANDLE_TYPE_EVENT); + WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, FD_READ); if (!event->bManualReset) { @@ -200,7 +199,7 @@ static int eventfd_write(int fd, eventfd_t value) BOOL SetEvent(HANDLE hEvent) { ULONG Type; - PVOID Object; + WINPR_HANDLE* Object; int length; BOOL status; WINPR_EVENT* event; @@ -241,7 +240,7 @@ BOOL SetEvent(HANDLE hEvent) BOOL ResetEvent(HANDLE hEvent) { ULONG Type; - PVOID Object; + WINPR_HANDLE* Object; int length; BOOL status = TRUE; WINPR_EVENT* event; @@ -274,7 +273,9 @@ BOOL ResetEvent(HANDLE hEvent) #endif -HANDLE CreateFileDescriptorEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, int FileDescriptor) +HANDLE CreateFileDescriptorEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, + BOOL bManualReset, BOOL bInitialState, + int FileDescriptor, ULONG mode) { #ifndef _WIN32 WINPR_EVENT* event; @@ -288,7 +289,7 @@ HANDLE CreateFileDescriptorEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL event->pipe_fd[0] = FileDescriptor; event->pipe_fd[1] = -1; event->ops = &ops; - WINPR_HANDLE_SET_TYPE(event, HANDLE_TYPE_EVENT); + WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, mode); handle = (HANDLE) event; } @@ -298,9 +299,12 @@ HANDLE CreateFileDescriptorEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL #endif } -HANDLE CreateFileDescriptorEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, int FileDescriptor) +HANDLE CreateFileDescriptorEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, + BOOL bManualReset, BOOL bInitialState, + int FileDescriptor, ULONG mode) { - return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState, FileDescriptor); + return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, + bInitialState, FileDescriptor, mode); } /** @@ -310,7 +314,8 @@ HANDLE CreateWaitObjectEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, void* pObject) { #ifndef _WIN32 - return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState, (int)(ULONG_PTR) pObject); + return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, + bInitialState, (int)(ULONG_PTR) pObject, FD_READ); #else HANDLE hEvent = NULL; DuplicateHandle(GetCurrentProcess(), pObject, GetCurrentProcess(), &hEvent, 0, FALSE, DUPLICATE_SAME_ACCESS); @@ -327,7 +332,7 @@ int GetEventFileDescriptor(HANDLE hEvent) { #ifndef _WIN32 ULONG Type; - PVOID Object; + WINPR_HANDLE* Object; WINPR_EVENT* event; if (!winpr_Handle_GetInfo(hEvent, &Type, &Object)) @@ -360,17 +365,19 @@ int GetEventFileDescriptor(HANDLE hEvent) * This file descriptor is not usable on Windows */ -int SetEventFileDescriptor(HANDLE hEvent, int FileDescriptor) +int SetEventFileDescriptor(HANDLE hEvent, int FileDescriptor, ULONG mode) { #ifndef _WIN32 ULONG Type; - PVOID Object; + WINPR_HANDLE* Object; WINPR_EVENT* event; if (!winpr_Handle_GetInfo(hEvent, &Type, &Object)) return -1; event = (WINPR_EVENT*) Object; + event->bAttached = TRUE; + event->Mode = mode; event->pipe_fd[0] = FileDescriptor; return 0; #else diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index 9a33487dc..2658776ef 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -44,6 +44,7 @@ #include "synch.h" #include "../thread/thread.h" #include +#include #include "../log.h" #define TAG WINPR_TAG("sync.wait") @@ -132,6 +133,19 @@ static int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec } #endif +#ifdef HAVE_POLL_H +static DWORD handle_mode_to_pollevent(ULONG mode) +{ + DWORD event = 0; + if (mode & FD_READ) + event |= POLLIN; + if (mode & FD_WRITE) + event |= POLLOUT; + + return event; +} +#endif + static void ts_add_ms(struct timespec *ts, DWORD dwMilliseconds) { ts->tv_sec += dwMilliseconds / 1000L; @@ -140,13 +154,13 @@ static void ts_add_ms(struct timespec *ts, DWORD dwMilliseconds) ts->tv_nsec = ts->tv_nsec % 1000000000L; } -static int waitOnFd(int fd, DWORD dwMilliseconds) +static int waitOnFd(int fd, ULONG mode, DWORD dwMilliseconds) { int status; #ifdef HAVE_POLL_H struct pollfd pollfds; pollfds.fd = fd; - pollfds.events = POLLIN; + pollfds.events = handle_mode_to_pollevent(mode); pollfds.revents = 0; do @@ -157,11 +171,21 @@ static int waitOnFd(int fd, DWORD dwMilliseconds) #else struct timeval timeout; - fd_set rfds; + fd_set rfds, wfds; + fd_set* prfds = NULL; + fd_set* pwfds = NULL; + fd_set* pefds = NULL; FD_ZERO(&rfds); FD_SET(fd, &rfds); + FD_ZERO(&wfds); + FD_SET(fd, &wfds); ZeroMemory(&timeout, sizeof(timeout)); + if (mode & FD_READ) + prfds = &rfds; + if (mode & FD_WRITE) + pwfds = &wfds; + if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) { timeout.tv_sec = dwMilliseconds / 1000; @@ -170,7 +194,7 @@ static int waitOnFd(int fd, DWORD dwMilliseconds) do { - status = select(fd + 1, &rfds, NULL, NULL, (dwMilliseconds == INFINITE) ? NULL : &timeout); + status = select(fd + 1, prfds, pwfds, pefds, (dwMilliseconds == INFINITE) ? NULL : &timeout); } while (status < 0 && (errno == EINTR)); @@ -181,7 +205,7 @@ static int waitOnFd(int fd, DWORD dwMilliseconds) DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { ULONG Type; - PVOID Object; + WINPR_HANDLE* Object; if (!winpr_Handle_GetInfo(hHandle, &Type, &Object)) { @@ -193,8 +217,10 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { WINPR_PROCESS *process; process = (WINPR_PROCESS *) Object; + int rc; - if (waitpid(process->pid, &(process->status), 0) != -1) + rc = waitpid(process->pid, &(process->status), 0); + if (rc != process->pid) { WLog_ERR(TAG, "waitpid failure [%d] %s", errno, strerror(errno)); return WAIT_FAILED; @@ -233,7 +259,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (fd < 0) return WAIT_FAILED; - status = waitOnFd(fd, dwMilliseconds); + status = waitOnFd(fd, Object->Mode, dwMilliseconds); if (status < 0) { @@ -270,12 +296,14 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl int index; int status; ULONG Type; - PVOID Object; + BOOL signal_handled = FALSE; + WINPR_HANDLE* Object; #ifdef HAVE_POLL_H struct pollfd *pollfds; #else int maxfd; - fd_set fds; + fd_set rfds; + fd_set wfds; struct timeval timeout; #endif @@ -300,14 +328,18 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl do { +#ifndef HAVE_POLL_H + fd_set* prfds = NULL; + fd_set* pwfds = NULL; + maxfd = 0; + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + ZeroMemory(&timeout, sizeof(timeout)); +#endif if (bWaitAll && (dwMilliseconds != INFINITE)) clock_gettime(CLOCK_MONOTONIC, &starttime); -#ifndef HAVE_POLL_H - maxfd = 0; - FD_ZERO(&fds); - ZeroMemory(&timeout, sizeof(timeout)); -#endif polled = 0; for (index = 0; index < nCount; index++) @@ -336,10 +368,16 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl #ifdef HAVE_POLL_H pollfds[polled].fd = fd; - pollfds[polled].events = POLLIN; + pollfds[polled].events = handle_mode_to_pollevent(Object->Mode); pollfds[polled].revents = 0; #else - FD_SET(fd, &fds); + FD_SET(fd, &rfds); + FD_SET(fd, &wfds); + + if (Object->Mode & FD_READ) + prfds = &rfds; + if (Object->Mode & FD_WRITE) + pwfds = &wfds; if (fd > maxfd) maxfd = fd; @@ -366,8 +404,8 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl do { - status = select(maxfd + 1, &fds, 0, 0, - (dwMilliseconds == INFINITE) ? NULL : &timeout); + status = select(maxfd + 1, prfds, pwfds, 0, + (dwMilliseconds == INFINITE) ? NULL : &timeout); } while (status < 0 && errno == EINTR); @@ -376,12 +414,13 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl if (status < 0) { #ifdef HAVE_POLL_H - WLog_ERR(TAG, "poll() failure [%d] %s", errno, + WLog_ERR(TAG, "poll() handle %d (%d) failure [%d] %s", index, nCount, errno, strerror(errno)); #else - WLog_ERR(TAG, "select() failure [%d] %s", errno, + WLog_ERR(TAG, "select() handle %d (%d) failure [%d] %s", index, nCount, errno, strerror(errno)); #endif + winpr_log_backtrace(TAG, WLOG_ERROR, 20); return WAIT_FAILED; } @@ -399,9 +438,11 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl dwMilliseconds -= (diff / 1000); } + signal_handled = FALSE; for (index = 0; index < polled; index++) { DWORD idx; + BOOL signal_set = FALSE; if (bWaitAll) idx = poll_map[index]; @@ -423,11 +464,14 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl } #ifdef HAVE_POLL_H - - if (pollfds[index].revents & POLLIN) + signal_set = pollfds[index].revents & pollfds[index].events; #else - if (FD_ISSET(fd, &fds)) + if (Object->Mode & FD_READ) + signal_set = FD_ISSET(fd, &rfds); + if (Object->Mode & FD_WRITE) + signal_set = FD_ISSET(fd, &wfds); #endif + if (signal_set) { DWORD rc = winpr_Handle_cleanup(lpHandles[idx]); if (rc != WAIT_OBJECT_0) @@ -450,10 +494,12 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAl if (bWaitAll && (signalled >= nCount)) return (WAIT_OBJECT_0); + + signal_handled = TRUE; } } } - while (bWaitAll); + while (bWaitAll || !signal_handled); WLog_ERR(TAG, "failed (unknown error)"); return WAIT_FAILED;