分离子终端的stdout和stderr

This commit is contained in:
Pan Qiancheng 2025-04-12 10:47:15 +08:00
parent 3f49fdedb1
commit 0b5815897d
15 changed files with 201 additions and 18 deletions

View File

@ -23,7 +23,8 @@
"init_cleanup.h": "c",
"stdbool.h": "c",
"stat.h": "c",
"debug.h": "c"
"debug.h": "c",
"types.h": "c"
},
"C_Cpp.errorSquiggles": "disabled"
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -100,3 +100,20 @@ arg[1]: --color=auto
arg[0]: pip
arg[1]: install
arg[2]: torch
[Sat Apr 12 10:41:47 2025
] Command: /home/qcqcqc/miniconda3/bin/pip
arg[0]: pip
arg[1]: install
arg[2]: torch
[Sat Apr 12 10:41:56 2025
] Command: /home/qcqcqc/miniconda3/bin/pip
arg[0]: pip
arg[1]: install
arg[2]: torch
arg[3]: abglpkhnjokb
[Sat Apr 12 10:43:13 2025
] Command: /home/qcqcqc/miniconda3/bin/pip
arg[0]: pip
arg[1]: install
arg[2]: torch
arg[3]: abglpkhnjokb

View File

View File

@ -0,0 +1,28 @@
欢迎使用北冥云计算服务!
[DEBUG][PID 2277570] src/pty_dup.c:95:dupIO(): forkpty result is: 0.
[DEBUG][PID 2277570] src/pty_dup.c:103:dupIO(): Child process ready.
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Requirement already satisfied: torch in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (2.6.0)
Requirement already satisfied: filelock in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (3.18.0)
Requirement already satisfied: typing-extensions>=4.10.0 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (4.12.2)
Requirement already satisfied: networkx in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (3.4.2)
Requirement already satisfied: jinja2 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (3.1.6)
Requirement already satisfied: fsspec in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (2025.3.2)
Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.4.127 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (12.4.127)
Requirement already satisfied: nvidia-cuda-runtime-cu12==12.4.127 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (12.4.127)
Requirement already satisfied: nvidia-cuda-cupti-cu12==12.4.127 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (12.4.127)
Requirement already satisfied: nvidia-cudnn-cu12==9.1.0.70 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (9.1.0.70)
Requirement already satisfied: nvidia-cublas-cu12==12.4.5.8 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (12.4.5.8)
Requirement already satisfied: nvidia-cufft-cu12==11.2.1.3 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (11.2.1.3)
Requirement already satisfied: nvidia-curand-cu12==10.3.5.147 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (10.3.5.147)
Requirement already satisfied: nvidia-cusolver-cu12==11.6.1.9 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (11.6.1.9)
Requirement already satisfied: nvidia-cusparse-cu12==12.3.1.170 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (12.3.1.170)
Requirement already satisfied: nvidia-cusparselt-cu12==0.6.2 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (0.6.2)
Requirement already satisfied: nvidia-nccl-cu12==2.21.5 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (2.21.5)
Requirement already satisfied: nvidia-nvtx-cu12==12.4.127 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (12.4.127)
Requirement already satisfied: nvidia-nvjitlink-cu12==12.4.127 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (12.4.127)
Requirement already satisfied: triton==3.2.0 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (3.2.0)
Requirement already satisfied: setuptools in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (75.8.0)
Requirement already satisfied: sympy==1.13.1 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from torch) (1.13.1)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from sympy==1.13.1->torch) (1.3.0)
Requirement already satisfied: MarkupSafe>=2.0 in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (from jinja2->torch) (3.0.2)

View File

@ -0,0 +1,2 @@
ERROR: Could not find a version that satisfies the requirement abglpkhnjokb (from versions: none)
ERROR: No matching distribution found for abglpkhnjokb

View File

@ -0,0 +1,5 @@
欢迎使用北冥云计算服务!
[DEBUG][PID 2277714] src/pty_dup.c:95:dupIO(): forkpty result is: 0.
[DEBUG][PID 2277714] src/pty_dup.c:103:dupIO(): Child process ready.
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Requirement already satisfied: torch in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (2.6.0)

View File

@ -0,0 +1,2 @@
ERROR: Could not find a version that satisfies the requirement abglpkhnjokb (from versions: none)
ERROR: No matching distribution found for abglpkhnjokb

View File

@ -0,0 +1,5 @@
欢迎使用北冥云计算服务!
[DEBUG][PID 2278618] src/pty_dup.c:95:dupIO(): forkpty result is: 0.
[DEBUG][PID 2278618] src/pty_dup.c:103:dupIO(): Child process ready.
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Requirement already satisfied: torch in /home/qcqcqc/miniconda3/lib/python3.12/site-packages (2.6.0)

View File

@ -35,6 +35,17 @@
#endif
#define MAX_PATH_LEN 256
#define GET_LOG_FILE(c_pid, is_stdout) ({ \
static char filename[MAX_PATH_LEN]; \
snprintf(filename, MAX_PATH_LEN, "%s.%ld.%s", \
LOG_OUT_FILE, \
(long)c_pid, \
(is_stdout) ? "stdout" : "stderr"); \
filename; \
})
#define ANSI_COLOR_RED "\033[31m"
#define ANSI_COLOR_YELLOW "\033[33m"
#define ANSI_COLOR_RESET "\033[0m"

View File

@ -2,6 +2,7 @@
#include "signal_handlers.h"
#include "terminal_utils.h"
#include "debug.h"
#include <sys/types.h>
FILE *log_file = NULL;
pid_t child_pid;
@ -22,15 +23,66 @@ void print_child_status() {
}
}
// void dupIO() {
// pid_t pid;
// int master;
// struct termios term;
// struct winsize win;
// DEBUG_LOG("Setup termios....");
// setup_termios(&term);
// signal(SIGINT, handle_sigint);
// signal(SIGCHLD, handle_sigchld);
// if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win) < 0) {
// perror("ioctl TIOCGWINSZ failed");
// exit(1);
// }
// pid = forkpty(&master, NULL, &term, &win);
// DEBUG_LOG("forkpty result is: %d.", pid);
// child_pid = pid;
// if (pid < 0) {
// perror("forkpty failed");
// exit(1);
// } else if (pid == 0) {
// DEBUG_LOG("Child process ready.");
// signal(SIGINT, SIG_DFL);
// return;
// }
// DEBUG_LOG("Ready to handle IO");
// handle_io(master);
// close(master);
// if (WIFEXITED(child_status)) {
// exit(WEXITSTATUS(child_status));
// } else if (WIFSIGNALED(child_status)) {
// exit(128 + WTERMSIG(child_status));
// }
// exit(1);
// }
void dupIO() {
pid_t pid;
int master;
int stderr_pipe[2];
struct termios term;
struct winsize win;
DEBUG_LOG("Setup termios....");
setup_termios(&term);
// 创建stderr的pipe
if (pipe(stderr_pipe) < 0) {
perror("pipe failed");
exit(1);
}
signal(SIGINT, handle_sigint);
signal(SIGCHLD, handle_sigchld);
@ -47,14 +99,35 @@ void dupIO() {
perror("forkpty failed");
exit(1);
} else if (pid == 0) {
// 子进程
DEBUG_LOG("Child process ready.");
signal(SIGINT, SIG_DFL);
// 关闭pipe读端
close(stderr_pipe[0]);
// 重定向stderr到pipe写端
if (dup2(stderr_pipe[1], STDERR_FILENO) < 0) {
perror("dup2 failed");
exit(1);
}
close(stderr_pipe[1]);
return;
}
// 父进程
// 关闭pipe写端
close(stderr_pipe[1]);
// 设置pipe读端为非阻塞
fcntl(stderr_pipe[0], F_SETFL, O_NONBLOCK);
DEBUG_LOG("Ready to handle IO");
handle_io(master);
handle_io(master, stderr_pipe[0], child_pid); // 需要修改handle_io函数签名传入stderr_pipe读端
close(master);
close(stderr_pipe[0]);
if (WIFEXITED(child_status)) {
exit(WEXITSTATUS(child_status));

View File

@ -44,8 +44,10 @@ void setup_termios(struct termios *term) {
cfsetospeed(term, B38400);
}
void handle_io(int master_fd) {
void handle_io(int master_fd, int stderr_fd, pid_t c_pid) {
struct termios orig_term, raw_term;
char buffer[BUFFER_SIZE];
struct pollfd fds[3]; // 增加一个pollfd用于stderr
// 保存原始终端设置
DEBUG_LOG("Saving original config.");
@ -57,9 +59,6 @@ void handle_io(int master_fd) {
cfmakeraw(&raw_term);
tcsetattr(STDIN_FILENO, TCSANOW, &raw_term);
char buffer[BUFFER_SIZE];
struct pollfd fds[2];
// 设置非阻塞模式
fcntl(master_fd, F_SETFL, O_NONBLOCK);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
@ -70,16 +69,24 @@ void handle_io(int master_fd) {
fds[1].fd = master_fd;
fds[1].events = POLLIN;
// 打开日志文件(以追加写模式)
int log_fd = open(LOG_OUT_FILE, O_WRONLY | O_CREAT | O_APPEND, 0644);
if (log_fd == -1) {
fds[2].fd = stderr_fd; // 新增stderr的fd
fds[2].events = POLLIN;
// 打开两个日志文件
// 获取stderr日志文件名
const char *stdout_log = GET_LOG_FILE(c_pid, 1);
const char *stderr_log = GET_LOG_FILE(c_pid, 0);
int stdout_log_fd = open(stdout_log, O_WRONLY | O_CREAT | O_APPEND, 0644);
int stderr_log_fd = open(stderr_log, O_WRONLY | O_CREAT | O_APPEND, 0644);
if (stdout_log_fd == -1 || stderr_log_fd == -1) {
perror("Failed to open log file");
return;
}
while (1) {
DEBUG_LOG("poll.....");
int ret = poll(fds, 2, 100); // 设置超时以便定期检查子进程状态
int ret = poll(fds, 3, 100); // 修改为监控3个fd
if (ret < 0) {
if (errno == EINTR) continue;
perror("poll failed");
@ -89,12 +96,39 @@ void handle_io(int master_fd) {
// 优先处理 PTY 输出,确保缓冲区中的数据被完全读出
DEBUG_LOG("Handling pty output...");
if (fds[1].revents & (POLLIN | POLLHUP)) {
DEBUG_LOG("Read from: %d \n\r", master_fd);
ssize_t n = read(master_fd, buffer, sizeof(buffer));
if (n > 0) {
// 直接写入,让终端自己处理控制序列
write(STDOUT_FILENO, buffer, n);
write(log_fd, buffer, n);
write(stdout_log_fd, buffer, n);
}
}
// 处理stderr
// 处理stderr
DEBUG_LOG("Handling stderr output...");
if (fds[2].revents & (POLLIN | POLLHUP)) {
ssize_t n = read(stderr_fd, buffer, sizeof(buffer));
if (n > 0) {
// 先保存当前光标位置
// write(STDERR_FILENO, "\033[s", 3); // 保存光标位置
// 移动到最后一行
write(STDERR_FILENO, "\033[999B", 6); // 移动到底部
write(STDERR_FILENO, "\r", 1); // 回到行首
// 输出带颜色的错误信息
write(STDERR_FILENO, "\033[31m", 5); // 设置红色
write(STDERR_FILENO, buffer, n);
write(STDERR_FILENO, "\033[0m", 4); // 重置颜色
// 恢复光标位置
// write(STDERR_FILENO, "\033[u", 3); // 恢复光标位置
write(STDERR_FILENO, "\033[999B", 6); // 移动到底部
write(STDERR_FILENO, "\r", 1); // 回到行首
// 写入日志
write(stderr_log_fd, buffer, n);
}
}
@ -120,8 +154,8 @@ void handle_io(int master_fd) {
break;
}
if (log_fd >= 0) {
written = write(log_fd, buffer, n);
if (stdout_log_fd >= 0) {
written = write(stdout_log_fd, buffer, n);
if (written < 0) {
perror("write to log failed");
break;
@ -152,9 +186,14 @@ void handle_io(int master_fd) {
}
}
DEBUG_LOG("Try to close log_fd: %d", log_fd);
if (log_fd > 0) {
close(log_fd);
DEBUG_LOG("Try to close stdout_log_fd: %d", stdout_log_fd);
if (stdout_log_fd > 0) {
close(stdout_log_fd);
}
DEBUG_LOG("Try to close stderr_log_fd: %d", stderr_log_fd);
if (stderr_log_fd > 0) {
close(stderr_log_fd);
}
// 确保输出缓冲区被刷新

View File

@ -4,6 +4,6 @@
#define TERMINAL_UTILS_H
void setup_termios(struct termios *term);
void handle_io(int master_fd);
void handle_io(int master_fd, int stderr_fd, pid_t c_pid) ;
#endif