一.目的
主要负责运行可执行程序。通过文件名就能运行程序。
二.runner
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);}