使用posix_spawn为非标准文件描述符创建管道时的异常问题求助
posix_spawn为非标准文件描述符创建管道时的异常问题求助
大家好,我现在遇到一个关于posix_spawn创建管道的问题,想请各位帮忙排查一下。
我在macOS上尝试用posix_spawn启动进程(原本目标是Chrome,目前先用简单的Python脚本测试),需要为描述符1(STDOUT)、2(STDERR),以及自定义的描述符3(用于读取)和4(用于写入)创建管道。
测试下来的情况是:描述符3可以正常读取数据,但描述符4完全无法访问——不管是尝试打开它还是用fcntl测试,都会抛出错误:OSError: [Errno 9] Bad file descriptor,启动Chrome时也会遇到同样的问题。
以下是我用来测试的Python代码:
#!/usr/bin/env python3 import os import sys import time import fcntl print("fcntl 3:", fcntl.fcntl(3, fcntl.F_GETFD)) print("fcntl 4:", fcntl.fcntl(4, fcntl.F_GETFD)) fd4 = os.fdopen(4, 'wb') while True: print('Cycle') time.sleep(2) while chunk := os.read(3, 1024): print('REQ:', chunk.decode('utf8', errors='backslashreplace'), file=sys.stderr) fd4.write(b'FOO')
还有用来启动进程的简化版C++代码(基于posix_spawn实现):
#include "pipes.h" #include <cerrno> #include <cstring> #include <spawn.h> #include <stdio.h> #include <sys/poll.h> #include <sys/wait.h> extern "C" char** environ; constexpr int CDP_WRITE_FILENO = 3; constexpr int CDP_READ_FILENO = 4; void RunBrowser(const char* exePath, const std::vector<const char*>& launchArgs) { posix_spawn_file_actions_t childFdActions{}; posix_spawn_file_actions_init(&childFdActions); DEFER(&childFdActions) { posix_spawn_file_actions_destroy(&childFdActions); }; int stdoutPipe[2]; int stderrPipe[2]; int cdpWritePipe[2]; int cdpReadPipe[2]; if (pipe(stdoutPipe) || pipe(stderrPipe) || pipe(cdpWritePipe) || pipe(cdpReadPipe)) { throw TBrowserError() << "Could not create a pipe: " << std::strerror(errno); } posix_spawn_file_actions_addclose(&childFdActions, stdoutPipe[0]); posix_spawn_file_actions_addclose(&childFdActions, stderrPipe[0]); posix_spawn_file_actions_addclose(&childFdActions, cdpWritePipe[1]); posix_spawn_file_actions_addclose(&childFdActions, cdpReadPipe[0]); posix_spawn_file_actions_adddup2(&childFdActions, stdoutPipe[1], STDOUT_FILENO); posix_spawn_file_actions_adddup2(&childFdActions, stderrPipe[1], STDERR_FILENO); posix_spawn_file_actions_adddup2(&childFdActions, cdpWritePipe[0], CDP_WRITE_FILENO); posix_spawn_file_actions_adddup2(&childFdActions, cdpReadPipe[1], CDP_READ_FILENO); posix_spawn_file_actions_addclose(&childFdActions, stdoutPipe[1]); posix_spawn_file_actions_addclose(&childFdActions, stderrPipe[1]); posix_spawn_file_actions_addclose(&childFdActions, cdpWritePipe[0]); posix_spawn_file_actions_addclose(&childFdActions, cdpReadPipe[1]); pid_t childPid{}; if (const int ret = posix_spawn(&childPid, exePath, &childFdActions, nullptr, const_cast<char* const*>(launchArgs.data()), environ)) { throw TBrowserError() << "Failed to spawn a process: " << std::strerror(ret); } close(stdoutPipe[1]); close(stderrPipe[1]); close(cdpWritePipe[0]); close(cdpReadPipe[1]); int status; do { const int ret = waitpid(childPid, &status, WUNTRACED | WCONTINUED); if (ret == -1) { kill(childPid, SIGKILL); throw TBrowserError() << "waitpid error: -1"; } if (WIFEXITED(status)) { const auto retCode = WEXITSTATUS(status); if (retCode == 0) { break; } throw TBrowserError() << std::format("Browser process failed with exit code {}", retCode); } if (WIFSIGNALED(status)) { throw TBrowserError() << "Browser process killed by signal " << WTERMSIG(status); } if (WIFSTOPPED(status)) { std::cerr << "Browser process stopped by signal " << WSTOPSIG(status) << std::endl; } if (WIFCONTINUED(status)) { std::cerr << "Browser process is continued" << std::endl; } } while (WIFEXITED(status) || WIFSIGNALED(status)); }
备注:内容来源于stack exchange,提问作者andre487
相关产品推荐
相关产品推荐

