DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { ULONG Type; PVOID Object; if (!winpr_Handle_GetInfo(hHandle, &Type, &Object)) { WLog_ERR(TAG, "invalid hHandle."); return WAIT_FAILED; } if (Type == HANDLE_TYPE_PROCESS) { WINPR_PROCESS *process; process = (WINPR_PROCESS *) Object; if (waitpid(process->pid, &(process->status), 0) != -1) { WLog_ERR(TAG, "waitpid failure [%d] %s", errno, strerror(errno)); return WAIT_FAILED; } process->dwExitCode = (DWORD) process->status; return WAIT_OBJECT_0; } else if (Type == HANDLE_TYPE_MUTEX) { WINPR_MUTEX *mutex; mutex = (WINPR_MUTEX *) Object; if (dwMilliseconds != INFINITE) { int status; struct timespec timeout; clock_gettime(CLOCK_MONOTONIC, &timeout); ts_add_ms(&timeout, dwMilliseconds); status = pthread_mutex_timedlock(&mutex->mutex, &timeout); if (ETIMEDOUT == status) return WAIT_TIMEOUT; } else { pthread_mutex_lock(&mutex->mutex); } return WAIT_OBJECT_0; } else { int status; int fd = winpr_Handle_getFd(Object); if (fd < 0) return WAIT_FAILED; status = waitOnFd(fd, dwMilliseconds); if (status < 0) { WLog_ERR(TAG, "waitOnFd() failure [%d] %s", errno, strerror(errno)); return WAIT_FAILED; } if (status != 1) return WAIT_TIMEOUT; return winpr_Handle_cleanup(Object); } return WAIT_FAILED; }
DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAll, DWORD dwMilliseconds) { struct timespec starttime; struct timespec timenow; unsigned long long diff; DWORD signalled; DWORD polled; DWORD *poll_map; BOOL *signalled_idx; int fd = -1; int index; int status; ULONG Type; PVOID Object; #ifdef HAVE_POLL_H struct pollfd *pollfds; #else int maxfd; fd_set fds; struct timeval timeout; #endif if (!nCount || (nCount > MAXIMUM_WAIT_OBJECTS)) { WLog_ERR(TAG, "invalid handles count(%d)", nCount); return WAIT_FAILED; } if (bWaitAll) { signalled_idx = alloca(nCount * sizeof(BOOL)); memset(signalled_idx, FALSE, nCount * sizeof(BOOL)); poll_map = alloca(nCount * sizeof(DWORD)); memset(poll_map, 0, nCount * sizeof(DWORD)); } #ifdef HAVE_POLL_H pollfds = alloca(nCount * sizeof(struct pollfd)); #endif signalled = 0; do { 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++) { if (bWaitAll) { if (signalled_idx[index]) continue; poll_map[polled] = index; } if (!winpr_Handle_GetInfo(lpHandles[index], &Type, &Object)) { WLog_ERR(TAG, "invalid event file descriptor"); return WAIT_FAILED; } fd = winpr_Handle_getFd(Object); if (fd == -1) { WLog_ERR(TAG, "invalid file descriptor"); return WAIT_FAILED; } #ifdef HAVE_POLL_H pollfds[polled].fd = fd; pollfds[polled].events = POLLIN; pollfds[polled].revents = 0; #else FD_SET(fd, &fds); if (fd > maxfd) maxfd = fd; #endif polled++; } #ifdef HAVE_POLL_H do { status = poll(pollfds, polled, dwMilliseconds); } while (status < 0 && errno == EINTR); #else if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) { timeout.tv_sec = dwMilliseconds / 1000; timeout.tv_usec = (dwMilliseconds % 1000) * 1000; } do { status = select(maxfd + 1, &fds, 0, 0, (dwMilliseconds == INFINITE) ? NULL : &timeout); } while (status < 0 && errno == EINTR); #endif if (status < 0) { #ifdef HAVE_POLL_H WLog_ERR(TAG, "poll() failure [%d] %s", errno, strerror(errno)); #else WLog_ERR(TAG, "select() failure [%d] %s", errno, strerror(errno)); #endif return WAIT_FAILED; } if (status == 0) return WAIT_TIMEOUT; if (bWaitAll && (dwMilliseconds != INFINITE)) { clock_gettime(CLOCK_MONOTONIC, &timenow); diff = ts_difftime(&timenow, &starttime); if (diff / 1000 > dwMilliseconds) return WAIT_TIMEOUT; else dwMilliseconds -= (diff / 1000); } for (index = 0; index < polled; index++) { DWORD idx; if (bWaitAll) idx = poll_map[index]; else idx = index; if (!winpr_Handle_GetInfo(lpHandles[idx], &Type, &Object)) { WLog_ERR(TAG, "invalid hHandle."); return WAIT_FAILED; } fd = winpr_Handle_getFd(lpHandles[idx]); if (fd == -1) { WLog_ERR(TAG, "invalid file descriptor"); return WAIT_FAILED; } #ifdef HAVE_POLL_H if (pollfds[index].revents & POLLIN) #else if (FD_ISSET(fd, &fds)) #endif { DWORD rc = winpr_Handle_cleanup(lpHandles[idx]); if (rc != WAIT_OBJECT_0) return rc; if (bWaitAll) { signalled_idx[idx] = TRUE; /* Continue checks from last position. */ for (; signalled < nCount; signalled++) { if (!signalled_idx[signalled]) break; } } if (!bWaitAll) return (WAIT_OBJECT_0 + index); if (bWaitAll && (signalled >= nCount)) return (WAIT_OBJECT_0); } } } while (bWaitAll); WLog_ERR(TAG, "failed (unknown error)"); return WAIT_FAILED; }
DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds) { struct timespec starttime; struct timespec timenow; unsigned long long diff; DWORD signalled; DWORD polled; DWORD* poll_map = NULL; BOOL* signalled_idx = NULL; int fd = -1; DWORD index; int status; ULONG Type; BOOL signal_handled = FALSE; WINPR_HANDLE* Object; #ifdef HAVE_POLL_H struct pollfd* pollfds; #else int maxfd; fd_set rfds; fd_set wfds; struct timeval timeout; #endif if (!nCount || (nCount > MAXIMUM_WAIT_OBJECTS)) { WLog_ERR(TAG, "invalid handles count(%"PRIu32")", nCount); return WAIT_FAILED; } if (bWaitAll) { signalled_idx = alloca(nCount * sizeof(BOOL)); memset(signalled_idx, FALSE, nCount * sizeof(BOOL)); poll_map = alloca(nCount * sizeof(DWORD)); memset(poll_map, 0, nCount * sizeof(DWORD)); } #ifdef HAVE_POLL_H pollfds = alloca(nCount * sizeof(struct pollfd)); #endif signalled = 0; 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); polled = 0; for (index = 0; index < nCount; index++) { if (bWaitAll) { if (signalled_idx[index]) continue; poll_map[polled] = index; } if (!winpr_Handle_GetInfo(lpHandles[index], &Type, &Object)) { WLog_ERR(TAG, "invalid event file descriptor"); SetLastError(ERROR_INVALID_HANDLE); return WAIT_FAILED; } fd = winpr_Handle_getFd(Object); if (fd == -1) { WLog_ERR(TAG, "invalid file descriptor"); SetLastError(ERROR_INVALID_HANDLE); return WAIT_FAILED; } #ifdef HAVE_POLL_H pollfds[polled].fd = fd; pollfds[polled].events = handle_mode_to_pollevent(Object->Mode); pollfds[polled].revents = 0; #else FD_SET(fd, &rfds); FD_SET(fd, &wfds); if (Object->Mode & WINPR_FD_READ) prfds = &rfds; if (Object->Mode & WINPR_FD_WRITE) pwfds = &wfds; if (fd > maxfd) maxfd = fd; #endif polled++; } #ifdef HAVE_POLL_H do { status = poll(pollfds, polled, dwMilliseconds); } while (status < 0 && errno == EINTR); #else if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) { timeout.tv_sec = dwMilliseconds / 1000; timeout.tv_usec = (dwMilliseconds % 1000) * 1000; } do { status = select(maxfd + 1, prfds, pwfds, 0, (dwMilliseconds == INFINITE) ? NULL : &timeout); } while (status < 0 && errno == EINTR); #endif if (status < 0) { #ifdef HAVE_POLL_H WLog_ERR(TAG, "poll() handle %d (%"PRIu32") failure [%d] %s", index, nCount, errno, strerror(errno)); #else WLog_ERR(TAG, "select() handle %d (%"PRIu32") failure [%d] %s", index, nCount, errno, strerror(errno)); #endif winpr_log_backtrace(TAG, WLOG_ERROR, 20); SetLastError(ERROR_INTERNAL_ERROR); return WAIT_FAILED; } if (status == 0) return WAIT_TIMEOUT; if (bWaitAll && (dwMilliseconds != INFINITE)) { clock_gettime(CLOCK_MONOTONIC, &timenow); diff = ts_difftime(&timenow, &starttime); if (diff / 1000 > dwMilliseconds) return WAIT_TIMEOUT; else dwMilliseconds -= (diff / 1000); } signal_handled = FALSE; for (index = 0; index < polled; index++) { DWORD idx; BOOL signal_set = FALSE; if (bWaitAll) idx = poll_map[index]; else idx = index; if (!winpr_Handle_GetInfo(lpHandles[idx], &Type, &Object)) { WLog_ERR(TAG, "invalid hHandle."); SetLastError(ERROR_INVALID_HANDLE); return WAIT_FAILED; } fd = winpr_Handle_getFd(lpHandles[idx]); if (fd == -1) { WLog_ERR(TAG, "invalid file descriptor"); SetLastError(ERROR_INVALID_HANDLE); return WAIT_FAILED; } #ifdef HAVE_POLL_H signal_set = pollfds[index].revents & pollfds[index].events; #else if (Object->Mode & WINPR_FD_READ) signal_set = FD_ISSET(fd, &rfds) ? 1 : 0; if (Object->Mode & WINPR_FD_WRITE) signal_set |= FD_ISSET(fd, &wfds) ? 1 : 0; #endif if (signal_set) { DWORD rc = winpr_Handle_cleanup(lpHandles[idx]); if (rc != WAIT_OBJECT_0) return rc; if (bWaitAll) { signalled_idx[idx] = TRUE; /* Continue checks from last position. */ for (; signalled < nCount; signalled++) { if (!signalled_idx[signalled]) break; } } if (!bWaitAll) return (WAIT_OBJECT_0 + index); if (signalled >= nCount) return (WAIT_OBJECT_0); signal_handled = TRUE; } } } while (bWaitAll || !signal_handled); WLog_ERR(TAG, "failed (unknown error)"); SetLastError(ERROR_INTERNAL_ERROR); return WAIT_FAILED; }