windows下子进程支持日志重定向、等待子进程推出、获取子进程退出码等特性
This commit is contained in:
parent
8ef8c91f2e
commit
b08ea0fcc7
|
|
@ -24,19 +24,16 @@ const string kSnap = FFmpeg_FIELD"snap";
|
||||||
|
|
||||||
onceToken token([]() {
|
onceToken token([]() {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
string ffmpeg_bin = System::execute("where ffmpeg");
|
string ffmpeg_bin = trim(System::execute("where ffmpeg"));
|
||||||
//windows下先关闭FFmpeg日志(目前不支持日志重定向)
|
|
||||||
mINI::Instance()[kCmd] = "%s -re -i %s -loglevel quiet -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s";
|
|
||||||
mINI::Instance()[kSnap] = "%s -i %s -loglevel quiet -y -f mjpeg -t 0.001 %s";
|
|
||||||
#else
|
#else
|
||||||
string ffmpeg_bin = System::execute("which ffmpeg");
|
string ffmpeg_bin = trim(System::execute("which ffmpeg"));
|
||||||
mINI::Instance()[kCmd] = "%s -re -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s";
|
|
||||||
mINI::Instance()[kSnap] = "%s -i %s -y -f mjpeg -t 0.001 %s";
|
|
||||||
#endif
|
#endif
|
||||||
//默认ffmpeg命令路径为环境变量中路径
|
//默认ffmpeg命令路径为环境变量中路径
|
||||||
mINI::Instance()[kBin] = ffmpeg_bin.empty() ? "ffmpeg" : ffmpeg_bin;
|
mINI::Instance()[kBin] = ffmpeg_bin.empty() ? "ffmpeg" : ffmpeg_bin;
|
||||||
//ffmpeg日志保存路径
|
//ffmpeg日志保存路径
|
||||||
mINI::Instance()[kLog] = "./ffmpeg/ffmpeg.log";
|
mINI::Instance()[kLog] = "./ffmpeg/ffmpeg.log";
|
||||||
|
mINI::Instance()[kCmd] = "%s -re -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s";
|
||||||
|
mINI::Instance()[kSnap] = "%s -i %s -y -f mjpeg -t 0.001 %s";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
#else
|
#else
|
||||||
//#include <TlHelp32.h>
|
//#include <TlHelp32.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <io.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
@ -31,23 +32,44 @@ using namespace toolkit;
|
||||||
void Process::run(const string &cmd, const string &log_file_tmp) {
|
void Process::run(const string &cmd, const string &log_file_tmp) {
|
||||||
kill(2000);
|
kill(2000);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
STARTUPINFO si;
|
STARTUPINFO si = {0};
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi = {0};
|
||||||
ZeroMemory(&si, sizeof(si)); //结构体初始化;
|
string log_file;
|
||||||
ZeroMemory(&pi, sizeof(pi));
|
if (log_file_tmp.empty()) {
|
||||||
|
//未指定子进程日志文件时,重定向至/dev/null
|
||||||
|
log_file = "NUL";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log_file = StrPrinter << log_file_tmp << "." << getCurrentMillisecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
//重定向shell日志至文件
|
||||||
|
auto fp = File::create_file(log_file.data(), "ab");
|
||||||
|
if (!fp) {
|
||||||
|
fprintf(stderr, "open log file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno));
|
||||||
|
} else {
|
||||||
|
auto log_fd = (HANDLE)(_get_osfhandle(fileno(fp)));
|
||||||
|
// dup to stdout and stderr.
|
||||||
|
si.wShowWindow = SW_HIDE;
|
||||||
|
// STARTF_USESHOWWINDOW:The wShowWindow member contains additional information.
|
||||||
|
// STARTF_USESTDHANDLES:The hStdInput, hStdOutput, and hStdError members contain additional information.
|
||||||
|
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
|
||||||
|
si.hStdError = log_fd;
|
||||||
|
si.hStdOutput = log_fd;
|
||||||
|
}
|
||||||
|
|
||||||
LPTSTR lpDir = const_cast<char*>(cmd.data());
|
LPTSTR lpDir = const_cast<char*>(cmd.data());
|
||||||
|
if (CreateProcess(NULL, lpDir, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)){
|
||||||
if (CreateProcess(NULL, lpDir, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)){
|
|
||||||
//下面两行关闭句柄,解除本进程和新进程的关系,不然有可能 不小心调用TerminateProcess函数关掉子进程
|
//下面两行关闭句柄,解除本进程和新进程的关系,不然有可能 不小心调用TerminateProcess函数关掉子进程
|
||||||
CloseHandle(pi.hProcess);
|
CloseHandle(pi.hProcess);
|
||||||
CloseHandle(pi.hThread);
|
CloseHandle(pi.hThread);
|
||||||
|
|
||||||
_pid = pi.dwProcessId;
|
_pid = pi.dwProcessId;
|
||||||
|
fprintf(fp, "\r\n\r\n#### pid=%d,cmd=%s #####\r\n\r\n", _pid, cmd.data());
|
||||||
InfoL << "start child proces " << _pid;
|
InfoL << "start child proces " << _pid;
|
||||||
} else {
|
} else {
|
||||||
WarnL << "start child proces fail: " << GetLastError();
|
WarnL << "start child proces fail: " << get_uv_errmsg();
|
||||||
}
|
}
|
||||||
|
fclose(fp);
|
||||||
#else
|
#else
|
||||||
_pid = fork();
|
_pid = fork();
|
||||||
if (_pid < 0) {
|
if (_pid < 0) {
|
||||||
|
|
@ -125,16 +147,42 @@ static bool s_wait(pid_t pid,int *exit_code_ptr,bool block) {
|
||||||
if (pid <= 0) {
|
if (pid <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int status = 0;
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE hProcess = NULL;
|
HANDLE hProcess = NULL;
|
||||||
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程
|
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); //打开目标进程
|
||||||
if (hProcess == NULL) {
|
if (!hProcess) {
|
||||||
|
WarnL << "OpenProcess failed:" << get_uv_errmsg();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD code = 0;
|
||||||
|
if (block) {
|
||||||
|
//一直等待
|
||||||
|
code = WaitForSingleObject(hProcess, INFINITE);
|
||||||
|
} else {
|
||||||
|
code = WaitForSingleObject(hProcess, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(code == WAIT_FAILED || code == WAIT_OBJECT_0){
|
||||||
|
//子进程已经退出了,获取子进程退出代码
|
||||||
|
DWORD exitCode = 0;
|
||||||
|
if(GetExitCodeProcess(hProcess, &exitCode) && exit_code_ptr){
|
||||||
|
*exit_code_ptr = exitCode;
|
||||||
|
}
|
||||||
|
CloseHandle(hProcess);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseHandle(hProcess);
|
CloseHandle(hProcess);
|
||||||
|
if(code == WAIT_TIMEOUT){
|
||||||
|
//子进程还在线
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//不太可能运行到此处
|
||||||
|
WarnL << "WaitForSingleObject ret:" << code;
|
||||||
|
return false;
|
||||||
#else
|
#else
|
||||||
|
int status = 0;
|
||||||
pid_t p = waitpid(pid, &status, block ? 0 : WNOHANG);
|
pid_t p = waitpid(pid, &status, block ? 0 : WNOHANG);
|
||||||
int exit_code = (status & 0xFF00) >> 8;
|
int exit_code = (status & 0xFF00) >> 8;
|
||||||
if (exit_code_ptr) {
|
if (exit_code_ptr) {
|
||||||
|
|
@ -148,11 +196,42 @@ static bool s_wait(pid_t pid,int *exit_code_ptr,bool block) {
|
||||||
InfoL << "process terminated, pid=" << pid << ", exit code=" << exit_code;
|
InfoL << "process terminated, pid=" << pid << ", exit code=" << exit_code;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
#endif // _WIN32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Inspired from http://stackoverflow.com/a/15281070/1529139
|
||||||
|
// and http://stackoverflow.com/q/40059902/1529139
|
||||||
|
bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent){
|
||||||
|
bool success = false;
|
||||||
|
DWORD thisConsoleId = GetCurrentProcessId();
|
||||||
|
// Leave current console if it exists
|
||||||
|
// (otherwise AttachConsole will return ERROR_ACCESS_DENIED)
|
||||||
|
bool consoleDetached = (FreeConsole() != FALSE);
|
||||||
|
|
||||||
|
if (AttachConsole(dwProcessId) != FALSE){
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (consoleDetached){
|
||||||
|
// Create a new console if previous was deleted by OS
|
||||||
|
if (AttachConsole(thisConsoleId) == FALSE){
|
||||||
|
int errorCode = GetLastError();
|
||||||
|
if (errorCode == 31){
|
||||||
|
// 31=ERROR_GEN_FAILURE
|
||||||
|
AllocConsole();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
static void s_kill(pid_t pid,int max_delay,bool force){
|
static void s_kill(pid_t pid,int max_delay,bool force){
|
||||||
if (pid <= 0) {
|
if (pid <= 0) {
|
||||||
//pid无效
|
//pid无效
|
||||||
|
|
@ -161,13 +240,20 @@ static void s_kill(pid_t pid,int max_delay,bool force){
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE hProcess = NULL;
|
HANDLE hProcess = NULL;
|
||||||
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程
|
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程
|
||||||
if (hProcess == NULL) {
|
if (!hProcess) {
|
||||||
WarnL << "\nOpen Process fAiled: " << GetLastError();
|
//子进程可能已经推出了
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DWORD ret = TerminateProcess(hProcess, 0); //结束目标进程
|
if(force){
|
||||||
if (ret == 0) {
|
//强制关闭
|
||||||
WarnL << GetLastError;
|
DWORD ret = TerminateProcess(hProcess, 0); //结束目标进程
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
if (ret == 0) {
|
||||||
|
WarnL << "TerminateProcess " << pid << " failed:" << get_uv_errmsg();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
//非强制关闭,发生Ctr+C信号
|
||||||
|
signalCtrl(pid, CTRL_C_EVENT);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (::kill(pid, force ? SIGKILL : SIGTERM) == -1) {
|
if (::kill(pid, force ? SIGKILL : SIGTERM) == -1) {
|
||||||
|
|
@ -177,7 +263,6 @@ static void s_kill(pid_t pid,int max_delay,bool force){
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
|
|
||||||
if(force){
|
if(force){
|
||||||
//发送SIGKILL信号后,阻塞等待退出
|
//发送SIGKILL信号后,阻塞等待退出
|
||||||
s_wait(pid, NULL, true);
|
s_wait(pid, NULL, true);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue