mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-27 04:20:13 +08:00
windows下子进程支持日志重定向、等待子进程推出、获取子进程退出码等特性
This commit is contained in:
parent
8ef8c91f2e
commit
b08ea0fcc7
@ -24,19 +24,16 @@ const string kSnap = FFmpeg_FIELD"snap";
|
||||
|
||||
onceToken token([]() {
|
||||
#ifdef _WIN32
|
||||
string ffmpeg_bin = 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";
|
||||
string ffmpeg_bin = trim(System::execute("where ffmpeg"));
|
||||
#else
|
||||
string ffmpeg_bin = 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";
|
||||
string ffmpeg_bin = trim(System::execute("which ffmpeg"));
|
||||
#endif
|
||||
//默认ffmpeg命令路径为环境变量中路径
|
||||
mINI::Instance()[kBin] = ffmpeg_bin.empty() ? "ffmpeg" : ffmpeg_bin;
|
||||
//ffmpeg日志保存路径
|
||||
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
|
||||
//#include <TlHelp32.h>
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
@ -31,23 +32,44 @@ using namespace toolkit;
|
||||
void Process::run(const string &cmd, const string &log_file_tmp) {
|
||||
kill(2000);
|
||||
#ifdef _WIN32
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
ZeroMemory(&si, sizeof(si)); //结构体初始化;
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
STARTUPINFO si = {0};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
string log_file;
|
||||
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());
|
||||
|
||||
if (CreateProcess(NULL, lpDir, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)){
|
||||
if (CreateProcess(NULL, lpDir, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)){
|
||||
//下面两行关闭句柄,解除本进程和新进程的关系,不然有可能 不小心调用TerminateProcess函数关掉子进程
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
|
||||
_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;
|
||||
} else {
|
||||
WarnL << "start child proces fail: " << GetLastError();
|
||||
WarnL << "start child proces fail: " << get_uv_errmsg();
|
||||
}
|
||||
fclose(fp);
|
||||
#else
|
||||
_pid = fork();
|
||||
if (_pid < 0) {
|
||||
@ -125,16 +147,42 @@ static bool s_wait(pid_t pid,int *exit_code_ptr,bool block) {
|
||||
if (pid <= 0) {
|
||||
return false;
|
||||
}
|
||||
int status = 0;
|
||||
#ifdef _WIN32
|
||||
HANDLE hProcess = NULL;
|
||||
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程
|
||||
if (hProcess == NULL) {
|
||||
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); //打开目标进程
|
||||
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;
|
||||
}
|
||||
|
||||
CloseHandle(hProcess);
|
||||
if(code == WAIT_TIMEOUT){
|
||||
//子进程还在线
|
||||
return true;
|
||||
}
|
||||
//不太可能运行到此处
|
||||
WarnL << "WaitForSingleObject ret:" << code;
|
||||
return false;
|
||||
#else
|
||||
int status = 0;
|
||||
pid_t p = waitpid(pid, &status, block ? 0 : WNOHANG);
|
||||
int exit_code = (status & 0xFF00) >> 8;
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
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){
|
||||
if (pid <= 0) {
|
||||
//pid无效
|
||||
@ -161,13 +240,20 @@ static void s_kill(pid_t pid,int max_delay,bool force){
|
||||
#ifdef _WIN32
|
||||
HANDLE hProcess = NULL;
|
||||
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程
|
||||
if (hProcess == NULL) {
|
||||
WarnL << "\nOpen Process fAiled: " << GetLastError();
|
||||
if (!hProcess) {
|
||||
//子进程可能已经推出了
|
||||
return;
|
||||
}
|
||||
DWORD ret = TerminateProcess(hProcess, 0); //结束目标进程
|
||||
if (ret == 0) {
|
||||
WarnL << GetLastError;
|
||||
if(force){
|
||||
//强制关闭
|
||||
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
|
||||
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
|
||||
|
||||
|
||||
if(force){
|
||||
//发送SIGKILL信号后,阻塞等待退出
|
||||
s_wait(pid, NULL, true);
|
||||
|
Loading…
Reference in New Issue
Block a user