主要负责运行可执行程序。通过文件名就能运行程序。
run运行模块: 不需要关心运行结果是否正确,只具备基本运行功能并只关心是否运行出错。
一个程序的时候,有三种IO需要关心,标准错误,标准输出,标准输入,可能不会使用到但离不开这些功能。创建出这三个文件和文件描述符,并继承给子进程。同样让子进程执行运行逻辑,父进程等待判断运行是否成功。通过信号提取运行状态
status的低16位的高8位保存子进程的返回值,高8位表示的是退出码的数字(这里不关心)
status的低16位的低8位中保存子进程异常退出的信号值,其实也只用到了其中的低7位,没用的那个是核心转储标记位
static int Run(const std::string &file_name, int cpu_limit, int mem_limit)
{
// 标准输入: 不处理
// 标准输出: 程序运行完成,输出结果是什么
// 标准错误: 运行时错误信息
// 运行时可能会需要输入输出,同时有可能出现错误
// 所以需要这些位置的路径
std::string _execute = PathUtil::Exe(file_name); // 执行程序路径
std::string _stdin = PathUtil::Stdin(file_name); // 新的输入路径
std::string _stdout = PathUtil::Stdout(file_name); // 新的输出路径
std::string _stderr = PathUtil::Stderr(file_name); // 新的错误路径
// 打开文件描述符(主进程打开文件描述符需要关闭)
umask(0);
// 输入只提供创建和读的权限
int _stdin_fd = open(_stdin.c_str(), O_CREAT | O_RDONLY, 0644);
// 输出只提供创建和写的权限
int _stdout_fd = open(_stdout.c_str(), O_CREAT | O_WRONLY, 0644);
// 错误只提供创建和写的权限
int _stderr_fd = open(_stderr.c_str(), O_CREAT | O_WRONLY, 0644);
if (_stdin_fd < 0 || _stdout_fd < 0 || _stderr_fd < 0)
{
LOG(ERROR) << "程序运行时打开文件描述符失败"
<< "\n";
return -1; // 代表打开文件失败
}
// 创建子进程程序替换
pid_t pid = fork();
if (pid < 0)
{
LOG(ERROR) << "程序运行时创建子进程失败"
<< "\n";
close(_stdin_fd);
close(_stdout_fd);
close(_stderr_fd);
return -2; // 代表创建子进程失败
}
else if (pid == 0) // 子进程执行程序替换执行用户的程序
{
// 文件描述符重定向后程序替换
dup2(_stdin_fd, 0);
dup2(_stdout_fd, 1);
dup2(_stderr_fd, 2);
SetProcLimit(cpu_limit, mem_limit);
execl(_execute.c_str() /*我要执行谁*/, _execute.c_str() /*我想在命令行上如何执行该程序*/, nullptr);
exit(1);
}
else // 主进程回收
{
close(_stdin_fd);
close(_stdout_fd);
close(_stderr_fd);
// status的低16位的低8位中保存子进程异常退出的信号值
int status = 0; // 将子进程的退出码保存在status内并判断状态,通过信号
waitpid(pid, &status, 0);
// 程序运行异常,可以通过信号判断
LOG(INFO) << "运行完毕, info: " << (status & 0x7F) << "\n";
return status & 0x7F;
}
}
添加资源限制:
可以通过下图所示函数对用户的程序进行限制。这样当到达限制条件的时候此进程就会被操作系统通过信号杀掉,经过测验,cpu触发终止发送的是24号信号,内存终止条件发送的是6号信号。
// 限制用户程序的运行时间和可使用内存大小
static void SetProcLimit(int _cpu_limit, int _mem_limit) // 内存大小以kb为单位
{
// 设置cpu调度时间上限
struct rlimit cpu_limit;
cpu_limit.rlim_cur = _cpu_limit; // 人为设置的上限
cpu_limit.rlim_max = RLIM_INFINITY; // 硬件上限
// 将参数设置进限制函数内
setrlimit(RLIMIT_CPU, &cpu_limit);
// 设置内存上限
struct rlimit mem_limit;
mem_limit.rlim_cur = _mem_limit * 1024; // 人为设置的上限
mem_limit.rlim_max = RLIM_INFINITY; // 硬件上限
// 将参数设置进限制函数内
setrlimit(RLIMIT_AS, &mem_limit);
}