2020-01-07 15:10:59 +08:00
/*
2023-12-09 16:23:51 +08:00
* Copyright ( c ) 2016 - present The ZLMediaKit project authors . All Rights Reserved .
2019-06-11 09:25:54 +08:00
*
2023-12-09 16:23:51 +08:00
* This file is part of ZLMediaKit ( https : //github.com/ZLMediaKit/ZLMediaKit).
2019-06-11 09:25:54 +08:00
*
2023-12-09 16:23:51 +08:00
* Use of this source code is governed by MIT - like license that can be found in the
2020-04-04 20:30:09 +08:00
* LICENSE file in the root of the source tree . All contributing project authors
* may be found in the AUTHORS file in the root of the source tree .
2019-06-11 09:25:54 +08:00
*/
2019-06-24 14:57:12 +08:00
# include <limits.h>
2019-09-27 09:58:42 +08:00
# include <sys/stat.h>
2020-01-07 14:37:18 +08:00
# ifndef _WIN32
2019-06-24 14:57:12 +08:00
# include <sys/resource.h>
2019-05-20 11:22:59 +08:00
# include <unistd.h>
2020-01-07 14:37:18 +08:00
# else
2020-06-08 14:56:17 +08:00
# include <io.h>
2022-03-27 21:47:00 +08:00
# include <windows.h>
2020-01-07 14:37:18 +08:00
# endif
2022-03-27 21:47:00 +08:00
# include <csignal>
2019-05-20 11:22:59 +08:00
# include <stdexcept>
2022-03-27 21:47:00 +08:00
# include "Process.h"
2019-05-20 11:22:59 +08:00
# include "Util/File.h"
2022-03-27 21:47:00 +08:00
# include "Util/util.h"
2019-05-20 11:22:59 +08:00
# include "Util/logger.h"
# include "Util/uv_errno.h"
2020-10-01 18:49:36 +08:00
# include "Poller/EventPoller.h"
2022-03-27 21:25:40 +08:00
2022-03-27 21:47:00 +08:00
# define STACK_SIZE (8192 * 1024)
2022-02-02 20:34:50 +08:00
using namespace std ;
2022-03-27 21:47:00 +08:00
using namespace toolkit ;
2019-05-20 11:22:59 +08:00
2022-03-27 21:25:40 +08:00
# ifndef _WIN32
2022-03-27 21:47:00 +08:00
static void setupChildProcess ( ) {
2024-09-19 14:53:50 +08:00
// 取消cpu亲和性设置, 防止FFmpeg进程cpu占用率不能超过100%的问题 [AUTO-TRANSLATED:d168129d]
// Cancel CPU affinity settings to prevent FFmpeg process from exceeding 100% CPU usage.
2022-03-27 21:25:40 +08:00
setThreadAffinity ( - 1 ) ;
2024-09-19 14:53:50 +08:00
// 子进程关闭core文件生成 [AUTO-TRANSLATED:721d2925]
// Disable core file generation for child processes.
2022-03-27 21:47:00 +08:00
struct rlimit rlim = { 0 , 0 } ;
2022-03-27 21:25:40 +08:00
setrlimit ( RLIMIT_CORE , & rlim ) ;
2024-09-19 14:53:50 +08:00
// 子进程恢复默认信号处理 [AUTO-TRANSLATED:1bc7387b]
// Restore default signal handling for child processes.
2022-03-27 21:47:00 +08:00
signal ( SIGINT , SIG_DFL ) ;
signal ( SIGTERM , SIG_DFL ) ;
signal ( SIGSEGV , SIG_DFL ) ;
signal ( SIGABRT , SIG_DFL ) ;
}
/* Start function for cloned child */
2022-03-27 22:37:41 +08:00
static int runChildProcess ( string cmd , string log_file ) {
2022-03-27 21:47:00 +08:00
setupChildProcess ( ) ;
2022-03-27 22:37:41 +08:00
if ( log_file . empty ( ) ) {
2024-09-19 14:53:50 +08:00
// 未指定子进程日志文件时,重定向至/dev/null [AUTO-TRANSLATED:dd0c9853]
// Redirect child process logs to /dev/null if no log file is specified.
2022-03-27 21:47:00 +08:00
log_file = " /dev/null " ;
2022-03-27 21:25:40 +08:00
} else {
2022-03-27 22:37:41 +08:00
log_file = StrPrinter < < log_file < < " . " < < getpid ( ) ;
2022-03-27 21:25:40 +08:00
}
2022-03-27 21:47:00 +08:00
2022-10-29 17:44:55 +08:00
if ( isatty ( STDIN_FILENO ) ) {
/* bb_error_msg("ignoring input"); */
close ( STDIN_FILENO ) ;
open ( " /dev/null " , O_RDONLY , 0666 ) ; /* will be fd 0 (STDIN_FILENO) */
}
2024-09-19 14:53:50 +08:00
// 重定向shell日志至文件 [AUTO-TRANSLATED:3480502b]
// Redirect shell logs to file.
2023-12-02 19:49:28 +08:00
auto fp = File : : create_file ( log_file , " ab " ) ;
2022-03-27 21:25:40 +08:00
if ( ! fp ) {
2022-03-27 21:47:00 +08:00
fprintf ( stderr , " open log file %s failed:%d(%s) \r \n " , log_file . data ( ) , get_uv_error ( ) , get_uv_errmsg ( ) ) ;
2022-03-27 21:25:40 +08:00
} else {
auto log_fd = fileno ( fp ) ;
// dup to stdout and stderr.
if ( dup2 ( log_fd , STDOUT_FILENO ) < 0 ) {
2022-03-27 21:47:00 +08:00
fprintf ( stderr , " dup2 stdout file %s failed:%d(%s) \r \n " , log_file . data ( ) , get_uv_error ( ) , get_uv_errmsg ( ) ) ;
2022-03-27 21:25:40 +08:00
}
if ( dup2 ( log_fd , STDERR_FILENO ) < 0 ) {
2022-03-27 21:47:00 +08:00
fprintf ( stderr , " dup2 stderr file %s failed:%d(%s) \r \n " , log_file . data ( ) , get_uv_error ( ) , get_uv_errmsg ( ) ) ;
2022-03-27 21:25:40 +08:00
}
2024-09-19 14:53:50 +08:00
// 关闭日志文件 [AUTO-TRANSLATED:9fb6e256]
// Close log file.
2022-03-27 21:25:40 +08:00
: : fclose ( fp ) ;
}
2022-03-27 21:47:00 +08:00
fprintf ( stderr , " \r \n \r \n #### pid=%d,cmd=%s ##### \r \n \r \n " , getpid ( ) , cmd . data ( ) ) ;
2022-03-27 21:25:40 +08:00
2022-03-27 21:47:00 +08:00
auto params = split ( cmd , " " ) ;
// memory leak in child process, it's ok.
char * * charpv_params = new char * [ params . size ( ) + 1 ] ;
for ( int i = 0 ; i < ( int ) params . size ( ) ; i + + ) {
std : : string & p = params [ i ] ;
charpv_params [ i ] = ( char * ) p . data ( ) ;
}
// EOF: NULL
charpv_params [ params . size ( ) ] = NULL ;
2022-03-27 21:25:40 +08:00
// TODO: execv or execvp
2022-03-27 21:47:00 +08:00
auto ret = execv ( params [ 0 ] . c_str ( ) , charpv_params ) ;
delete [ ] charpv_params ;
2022-03-27 21:25:40 +08:00
if ( ret < 0 ) {
2022-03-27 21:47:00 +08:00
fprintf ( stderr , " execv process failed:%d(%s) \r \n " , get_uv_error ( ) , get_uv_errmsg ( ) ) ;
2022-03-27 21:25:40 +08:00
}
return ret ;
}
2022-03-27 21:47:00 +08:00
static int cloneFunc ( void * ptr ) {
auto pair = reinterpret_cast < std : : pair < string , string > * > ( ptr ) ;
return runChildProcess ( pair - > first , pair - > second ) ;
}
2022-03-27 21:25:40 +08:00
# endif
2023-09-23 20:34:36 +08:00
void Process : : run ( const string & cmd , string log_file ) {
2020-03-20 11:51:24 +08:00
kill ( 2000 ) ;
2020-01-07 14:37:18 +08:00
# ifdef _WIN32
2022-03-27 21:47:00 +08:00
STARTUPINFO si = { 0 } ;
PROCESS_INFORMATION pi = { 0 } ;
2022-03-27 22:37:41 +08:00
if ( log_file . empty ( ) ) {
2024-09-19 14:53:50 +08:00
// 未指定子进程日志文件时,重定向至/dev/null [AUTO-TRANSLATED:dd0c9853]
// Redirect child process logs to /dev/null if no log file is specified.
2020-06-08 14:56:17 +08:00
log_file = " NUL " ;
2020-06-08 16:41:49 +08:00
} else {
2022-03-27 22:37:41 +08:00
log_file = StrPrinter < < log_file < < " . " < < getCurrentMillisecond ( ) ;
2020-06-08 14:56:17 +08:00
}
2020-03-20 11:51:24 +08:00
2024-09-19 14:53:50 +08:00
// 重定向shell日志至文件 [AUTO-TRANSLATED:3480502b]
// Redirect shell logs to file.
2023-12-02 19:49:28 +08:00
auto fp = File : : create_file ( log_file , " ab " ) ;
2020-06-08 14:56:17 +08:00
if ( ! fp ) {
2020-06-08 16:41:49 +08:00
fprintf ( stderr , " open log file %s failed:%d(%s) \r \n " , log_file . data ( ) , get_uv_error ( ) , get_uv_errmsg ( ) ) ;
2020-06-08 14:56:17 +08:00
} else {
2021-01-17 18:31:50 +08:00
auto log_fd = ( HANDLE ) ( _get_osfhandle ( _fileno ( fp ) ) ) ;
2020-06-08 14:56:17 +08:00
// dup to stdout and stderr.
si . wShowWindow = SW_HIDE ;
2022-03-27 21:47:00 +08:00
// STARTF_USESHOWWINDOW:The wShowWindow member contains additional information.
// STARTF_USESTDHANDLES:The hStdInput, hStdOutput, and hStdError members contain additional information.
2020-06-08 14:56:17 +08:00
si . dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES ;
si . hStdError = log_fd ;
si . hStdOutput = log_fd ;
}
2020-03-20 11:51:24 +08:00
2022-03-27 21:47:00 +08:00
LPTSTR lpDir = const_cast < char * > ( cmd . data ( ) ) ;
if ( CreateProcess ( NULL , lpDir , NULL , NULL , TRUE , 0 , NULL , NULL , & si , & pi ) ) {
2024-09-19 14:53:50 +08:00
// 下面两行关闭句柄,解除本进程和新进程的关系,不然有可能 不小心调用TerminateProcess函数关掉子进程 [AUTO-TRANSLATED:d50fada2]
// The following two lines close the handle and break the relationship between the current process and the new process. Otherwise, the TerminateProcess function may accidentally close the child process.
2020-03-20 11:51:24 +08:00
CloseHandle ( pi . hThread ) ;
_pid = pi . dwProcessId ;
2020-06-08 16:26:55 +08:00
_handle = pi . hProcess ;
fprintf ( fp , " \r \n \r \n #### pid=%d,cmd=%s ##### \r \n \r \n " , _pid , cmd . data ( ) ) ;
2020-06-08 16:41:49 +08:00
InfoL < < " start child process " < < _pid < < " , log file: " < < log_file ;
2020-03-20 11:51:24 +08:00
} else {
2020-06-08 16:41:49 +08:00
WarnL < < " start child process fail: " < < get_uv_errmsg ( ) ;
2020-03-20 11:51:24 +08:00
}
2020-06-08 16:26:55 +08:00
fclose ( fp ) ;
2022-03-27 22:37:41 +08:00
# else
# if (defined(__linux) || defined(__linux__))
2022-03-27 21:25:40 +08:00
_process_stack = malloc ( STACK_SIZE ) ;
2022-03-27 22:37:41 +08:00
auto args = std : : make_pair ( cmd , log_file ) ;
_pid = clone ( reinterpret_cast < int ( * ) ( void * ) > ( & cloneFunc ) , ( char * ) _process_stack + STACK_SIZE , CLONE_FS | SIGCHLD , ( void * ) ( & args ) ) ;
if ( _pid = = - 1 ) {
2022-03-27 21:25:40 +08:00
WarnL < < " clone process failed: " < < get_uv_errmsg ( ) ;
free ( _process_stack ) ;
2022-03-27 22:37:41 +08:00
_process_stack = nullptr ;
2023-12-09 16:23:51 +08:00
throw std : : runtime_error ( StrPrinter < < " clone child process failed, cmd: " < < cmd < < " ,err: " < < get_uv_errmsg ( ) ) ;
2022-03-27 21:25:40 +08:00
}
2020-06-08 16:26:55 +08:00
# else
2022-03-27 21:47:00 +08:00
_pid = fork ( ) ;
2022-03-27 22:37:41 +08:00
if ( _pid = = - 1 ) {
2023-12-09 16:23:51 +08:00
throw std : : runtime_error ( StrPrinter < < " fork child process failed, cmd: " < < cmd < < " ,err: " < < get_uv_errmsg ( ) ) ;
2020-03-20 11:51:24 +08:00
}
if ( _pid = = 0 ) {
2024-09-19 14:53:50 +08:00
// 子进程 [AUTO-TRANSLATED:3f793797]
// Child process.
2022-03-27 22:37:41 +08:00
exit ( runChildProcess ( cmd , log_file ) ) ;
2020-03-20 11:51:24 +08:00
}
2022-03-27 22:37:41 +08:00
# endif
if ( log_file . empty ( ) ) {
2024-09-19 14:53:50 +08:00
// 未指定子进程日志文件时,重定向至/dev/null [AUTO-TRANSLATED:dd0c9853]
// Redirect child process logs to /dev/null if no log file is specified.
2020-06-11 09:22:28 +08:00
log_file = " /dev/null " ;
} else {
2022-03-27 22:37:41 +08:00
log_file = StrPrinter < < log_file < < " . " < < _pid ;
2020-06-11 09:22:28 +08:00
}
2020-06-08 16:41:49 +08:00
InfoL < < " start child process " < < _pid < < " , log file: " < < log_file ;
2020-01-07 14:37:18 +08:00
# endif // _WIN32
2019-05-20 11:22:59 +08:00
}
2019-10-24 11:42:39 +08:00
/**
* 获 取 进 程 是 否 存 活 状 态
* @ param pid 进 程 号
* @ param exit_code_ptr 进 程 返 回 代 码
* @ param block 是 否 阻 塞 等 待
* @ return 进 程 是 否 还 在 运 行
2024-09-19 14:53:50 +08:00
* Get the process ' s alive status .
* @ param pid Process ID
* @ param exit_code_ptr Process return code
* @ param block Whether to block and wait
* @ return Whether the process is still running
* [ AUTO - TRANSLATED : ef80ff17 ]
2019-10-24 11:42:39 +08:00
*/
2020-06-08 16:26:55 +08:00
static bool s_wait ( pid_t pid , void * handle , int * exit_code_ptr , bool block ) {
2019-10-24 11:42:39 +08:00
if ( pid < = 0 ) {
return false ;
}
2020-01-07 14:37:18 +08:00
# ifdef _WIN32
2020-06-08 14:56:17 +08:00
DWORD code = 0 ;
if ( block ) {
2024-09-19 14:53:50 +08:00
// 一直等待 [AUTO-TRANSLATED:ca8a5e14]
// Wait indefinitely.
2020-06-08 16:26:55 +08:00
code = WaitForSingleObject ( handle , INFINITE ) ;
2020-06-08 14:56:17 +08:00
} else {
2020-06-08 16:26:55 +08:00
code = WaitForSingleObject ( handle , 0 ) ;
2020-06-08 14:56:17 +08:00
}
2020-06-08 16:26:55 +08:00
2022-03-27 21:47:00 +08:00
if ( code = = WAIT_FAILED | | code = = WAIT_OBJECT_0 ) {
2024-09-19 14:53:50 +08:00
// 子进程已经退出了,获取子进程退出代码 [AUTO-TRANSLATED:c39663b2]
// The child process has exited, get the child process exit code.
2020-06-08 14:56:17 +08:00
DWORD exitCode = 0 ;
2022-03-27 21:47:00 +08:00
if ( exit_code_ptr & & GetExitCodeProcess ( handle , & exitCode ) ) {
2020-06-08 14:56:17 +08:00
* exit_code_ptr = exitCode ;
}
2020-03-20 11:51:24 +08:00
return false ;
}
2020-01-07 14:37:18 +08:00
2022-03-27 21:47:00 +08:00
if ( code = = WAIT_TIMEOUT ) {
2024-09-19 14:53:50 +08:00
// 子进程还在线 [AUTO-TRANSLATED:3d32ef56]
// The child process is still online.
2020-06-08 14:56:17 +08:00
return true ;
}
2024-09-19 14:53:50 +08:00
// 不太可能运行到此处 [AUTO-TRANSLATED:b1fde65d]
// It is unlikely to run to this point.
2020-06-08 14:56:17 +08:00
WarnL < < " WaitForSingleObject ret: " < < code ;
return false ;
2020-01-07 14:37:18 +08:00
# else
2020-06-08 14:56:17 +08:00
int status = 0 ;
2020-03-20 11:51:24 +08:00
pid_t p = waitpid ( pid , & status , block ? 0 : WNOHANG ) ;
int exit_code = ( status & 0xFF00 ) > > 8 ;
if ( exit_code_ptr ) {
2020-05-14 10:23:12 +08:00
* exit_code_ptr = exit_code ;
2020-03-20 11:51:24 +08:00
}
if ( p < 0 ) {
WarnL < < " waitpid failed, pid= " < < pid < < " , err= " < < get_uv_errmsg ( ) ;
return false ;
}
if ( p > 0 ) {
InfoL < < " process terminated, pid= " < < pid < < " , exit code= " < < exit_code ;
return false ;
}
2020-06-08 14:56:17 +08:00
return true ;
2020-01-07 14:37:18 +08:00
# endif // _WIN32
2020-06-08 14:56:17 +08:00
}
2020-01-07 14:37:18 +08:00
2020-06-08 14:56:17 +08:00
# ifdef _WIN32
// Inspired from http://stackoverflow.com/a/15281070/1529139
// and http://stackoverflow.com/q/40059902/1529139
2022-03-27 21:47:00 +08:00
bool signalCtrl ( DWORD dwProcessId , DWORD dwCtrlEvent ) {
2020-06-08 14:56:17 +08:00
bool success = false ;
DWORD thisConsoleId = GetCurrentProcessId ( ) ;
// Leave current console if it exists
// (otherwise AttachConsole will return ERROR_ACCESS_DENIED)
bool consoleDetached = ( FreeConsole ( ) ! = FALSE ) ;
2022-03-27 21:47:00 +08:00
if ( AttachConsole ( dwProcessId ) ! = FALSE ) {
2020-06-08 14:56:17 +08:00
// Add a fake Ctrl-C handler for avoid instant kill is this console
// WARNING: do not revert it or current program will be also killed
SetConsoleCtrlHandler ( nullptr , true ) ;
success = ( GenerateConsoleCtrlEvent ( dwCtrlEvent , 0 ) ! = FALSE ) ;
FreeConsole ( ) ;
}
2022-03-27 21:47:00 +08:00
if ( consoleDetached ) {
2020-06-08 14:56:17 +08:00
// Create a new console if previous was deleted by OS
2022-03-27 21:47:00 +08:00
if ( AttachConsole ( thisConsoleId ) = = FALSE ) {
2020-06-08 14:56:17 +08:00
int errorCode = GetLastError ( ) ;
2022-03-27 21:47:00 +08:00
if ( errorCode = = 31 ) {
2020-06-08 14:56:17 +08:00
// 31=ERROR_GEN_FAILURE
AllocConsole ( ) ;
}
}
}
return success ;
2019-10-24 11:42:39 +08:00
}
2020-06-08 14:56:17 +08:00
# endif // _WIN32
2019-10-24 11:42:39 +08:00
2020-06-08 16:26:55 +08:00
static void s_kill ( pid_t pid , void * handle , int max_delay , bool force ) {
2019-10-24 11:42:39 +08:00
if ( pid < = 0 ) {
2024-09-19 14:53:50 +08:00
// pid无效 [AUTO-TRANSLATED:6665d7a0]
// Invalid pid.
2019-05-20 11:22:59 +08:00
return ;
}
2020-01-07 14:37:18 +08:00
# ifdef _WIN32
2024-09-19 14:53:50 +08:00
// windows下目前没有比较好的手段往子进程发送SIGTERM或信号 [AUTO-TRANSLATED:cd32ad25]
// Currently, there is no good way to send SIGTERM or signals to child processes under Windows.
// 所以杀死子进程的方式全部强制为立即关闭 [AUTO-TRANSLATED:2fc31f2b]
// Therefore, all methods of killing child processes are forced to be immediate closure.
2020-06-08 15:49:32 +08:00
force = true ;
2022-03-27 21:47:00 +08:00
if ( force ) {
2024-09-19 14:53:50 +08:00
// 强制关闭子进程 [AUTO-TRANSLATED:f3c712f6]
// Force close the child process.
2020-06-08 16:26:55 +08:00
TerminateProcess ( handle , 0 ) ;
2022-03-27 21:47:00 +08:00
} else {
2024-09-19 14:53:50 +08:00
// 非强制关闭, 发送Ctr+C信号 [AUTO-TRANSLATED:fe9bf53f]
// Non-forced closure, send Ctrl+C signal.
2020-06-08 14:56:17 +08:00
signalCtrl ( pid , CTRL_C_EVENT ) ;
2020-03-20 11:51:24 +08:00
}
2020-01-07 14:37:18 +08:00
# else
2020-03-20 11:51:24 +08:00
if ( : : kill ( pid , force ? SIGKILL : SIGTERM ) = = - 1 ) {
2024-09-19 14:53:50 +08:00
// 进程可能已经退出了 [AUTO-TRANSLATED:682a8b61]
// The process may have already exited.
2020-03-20 11:51:24 +08:00
WarnL < < " kill process " < < pid < < " failed: " < < get_uv_errmsg ( ) ;
return ;
}
2020-01-07 14:37:18 +08:00
# endif // _WIN32
2019-10-24 11:42:39 +08:00
2020-06-08 16:26:55 +08:00
if ( force ) {
2024-09-19 14:53:50 +08:00
// 发送SIGKILL信号后, 阻塞等待退出 [AUTO-TRANSLATED:4fc03dae]
// After sending the SIGKILL signal, block and wait for exit.
2020-06-08 16:26:55 +08:00
s_wait ( pid , handle , nullptr , true ) ;
2019-10-24 11:42:39 +08:00
DebugL < < " force kill " < < pid < < " success! " ;
return ;
}
2024-09-19 14:53:50 +08:00
// 发送SIGTERM信号后, 2秒后检查子进程是否已经退出 [AUTO-TRANSLATED:b9878b28]
// After sending the SIGTERM signal, check if the child process has exited after 2 seconds.
2020-10-01 18:49:36 +08:00
EventPollerPool : : Instance ( ) . getPoller ( ) - > doDelayTask ( max_delay , [ pid , handle ] ( ) {
2020-06-08 16:26:55 +08:00
if ( ! s_wait ( pid , handle , nullptr , false ) ) {
2024-09-19 14:53:50 +08:00
// 进程已经退出了 [AUTO-TRANSLATED:ad02bb63]
// The process has exited.
2019-05-20 11:22:59 +08:00
return 0 ;
2019-10-24 11:42:39 +08:00
}
2024-09-19 14:53:50 +08:00
// 进程还在运行 [AUTO-TRANSLATED:b1aa9ba4]
// The process is still running.
2019-10-24 11:42:39 +08:00
WarnL < < " process still working,force kill it: " < < pid ;
2020-06-08 16:26:55 +08:00
s_kill ( pid , handle , 0 , true ) ;
2019-10-24 11:42:39 +08:00
return 0 ;
} ) ;
}
2020-06-08 16:26:55 +08:00
void Process : : kill ( int max_delay , bool force ) {
2019-10-24 11:42:39 +08:00
if ( _pid < = 0 ) {
return ;
2019-05-20 11:22:59 +08:00
}
2020-06-08 16:26:55 +08:00
s_kill ( _pid , _handle , max_delay , force ) ;
2019-05-20 11:22:59 +08:00
_pid = - 1 ;
2020-06-08 16:26:55 +08:00
# ifdef _WIN32
2022-03-27 21:47:00 +08:00
if ( _handle ) {
2020-06-08 16:26:55 +08:00
CloseHandle ( _handle ) ;
_handle = nullptr ;
}
2022-03-27 21:25:40 +08:00
# elif ((defined(__linux) || defined(__linux__)))
2022-03-27 21:47:00 +08:00
if ( _process_stack ) {
2022-03-27 21:25:40 +08:00
free ( _process_stack ) ;
_process_stack = nullptr ;
}
2020-06-08 16:26:55 +08:00
# endif
2019-05-20 11:22:59 +08:00
}
Process : : ~ Process ( ) {
kill ( 2000 ) ;
}
2019-10-24 11:42:39 +08:00
Process : : Process ( ) { }
2019-05-20 11:22:59 +08:00
bool Process : : wait ( bool block ) {
2020-06-08 16:26:55 +08:00
return s_wait ( _pid , _handle , & _exit_code , block ) ;
2019-05-20 11:22:59 +08:00
}
int Process : : exit_code ( ) {
return _exit_code ;
}