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; }
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; }
BOOL _CreateProcessExA(HANDLE hToken, DWORD dwLogonFlags, LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { pid_t pid; int numArgs; LPSTR* pArgs = NULL; char** envp = NULL; char* filename = NULL; HANDLE thread; HANDLE process; WINPR_ACCESS_TOKEN* token; LPTCH lpszEnvironmentBlock; BOOL ret = FALSE; sigset_t oldSigMask; sigset_t newSigMask; BOOL restoreSigMask = FALSE; numArgs = 0; lpszEnvironmentBlock = NULL; pArgs = CommandLineToArgvA(lpCommandLine, &numArgs); if (!pArgs) return FALSE; token = (WINPR_ACCESS_TOKEN*) hToken; if (lpEnvironment) { envp = EnvironmentBlockToEnvpA(lpEnvironment); } else { lpszEnvironmentBlock = GetEnvironmentStrings(); if (!lpszEnvironmentBlock) goto finish; envp = EnvironmentBlockToEnvpA(lpszEnvironmentBlock); } if (!envp) goto finish; filename = FindApplicationPath(pArgs[0]); if (NULL == filename) goto finish; /* block all signals so that the child can safely reset the caller's handlers */ sigfillset(&newSigMask); restoreSigMask = !pthread_sigmask(SIG_SETMASK, &newSigMask, &oldSigMask); /* fork and exec */ pid = fork(); if (pid < 0) { /* fork failure */ goto finish; } if (pid == 0) { /* child process */ #ifndef __sun int maxfd; #endif int fd; int sig; sigset_t set; struct sigaction act; /* set default signal handlers */ memset(&act, 0, sizeof(act)); act.sa_handler = SIG_DFL; act.sa_flags = 0; sigemptyset(&act.sa_mask); for (sig = 1; sig < NSIG; sig++) sigaction(sig, &act, NULL); /* unblock all signals */ sigfillset(&set); pthread_sigmask(SIG_UNBLOCK, &set, NULL); if (lpStartupInfo) { int handle_fd; handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdOutput); if (handle_fd != -1) dup2(handle_fd, STDOUT_FILENO); handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdError); if (handle_fd != -1) dup2(handle_fd, STDERR_FILENO); handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdInput); if (handle_fd != -1) dup2(handle_fd, STDIN_FILENO); } #ifdef __sun closefrom(3); #else #ifdef F_MAXFD // on some BSD derivates maxfd = fcntl(0, F_MAXFD); #else maxfd = sysconf(_SC_OPEN_MAX); #endif for (fd = 3; fd < maxfd; fd++) close(fd); #endif // __sun if (token) { if (token->GroupId) { int rc = setgid((gid_t) token->GroupId); if (rc < 0) { } else { initgroups(token->Username, (gid_t) token->GroupId); } } if (token->UserId) setuid((uid_t) token->UserId); } /* TODO: add better cwd handling and error checking */ if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0) chdir(lpCurrentDirectory); if (execve(filename, pArgs, envp) < 0) { /* execve failed - end the process */ _exit(1); } } else { /* parent process */ } process = CreateProcessHandle(pid); if (!process) { goto finish; } thread = CreateNoneHandle(); if (!thread) { ProcessHandleCloseHandle(process); goto finish; } lpProcessInformation->hProcess = process; lpProcessInformation->hThread = thread; lpProcessInformation->dwProcessId = (DWORD) pid; lpProcessInformation->dwThreadId = (DWORD) pid; ret = TRUE; finish: /* restore caller's original signal mask */ if (restoreSigMask) pthread_sigmask(SIG_SETMASK, &oldSigMask, NULL); free(filename); if (pArgs) { HeapFree(GetProcessHeap(), 0, pArgs); } if (lpszEnvironmentBlock) FreeEnvironmentStrings(lpszEnvironmentBlock); if (envp) { int i = 0; while (envp[i]) { free(envp[i]); i++; } free(envp); } return ret; }