mirror of https://github.com/aria2/aria2
Win: Use SetConsoleCtrlHandler for SIGINT/SIGTERM
parent
9e25335850
commit
79fcafc31f
|
@ -83,6 +83,7 @@ namespace global {
|
|||
// 2 ... stop signal processed by DownloadEngine
|
||||
// 3 ... 2nd stop signal(force shutdown) detected
|
||||
// 4 ... 2nd stop signal processed by DownloadEngine
|
||||
// 5 ... main loop exited
|
||||
volatile sig_atomic_t globalHaltRequested = 0;
|
||||
|
||||
} // namespace global
|
||||
|
@ -141,6 +142,13 @@ void executeCommand(std::deque<std::unique_ptr<Command>>& commands,
|
|||
|
||||
int DownloadEngine::run(bool oneshot)
|
||||
{
|
||||
class GHR {
|
||||
public:
|
||||
~GHR() {
|
||||
global::globalHaltRequested = 5;
|
||||
}
|
||||
} ghr;
|
||||
|
||||
while(!commands_.empty() || !routineCommands_.empty()) {
|
||||
if(!commands_.empty()) {
|
||||
waitData();
|
||||
|
|
|
@ -86,21 +86,44 @@ extern volatile sig_atomic_t globalHaltRequested;
|
|||
} // namespace global
|
||||
|
||||
namespace {
|
||||
void handler(int signal) {
|
||||
|
||||
#ifdef _WIN32
|
||||
static const DWORD mainThread = GetCurrentThreadId();
|
||||
#endif
|
||||
|
||||
static void handler(int signal)
|
||||
{
|
||||
if(
|
||||
#ifdef SIGHUP
|
||||
signal == SIGHUP ||
|
||||
#endif // SIGHUP
|
||||
signal == SIGTERM) {
|
||||
if(global::globalHaltRequested == 0 || global::globalHaltRequested == 2) {
|
||||
if(global::globalHaltRequested <= 2) {
|
||||
global::globalHaltRequested = 3;
|
||||
}
|
||||
} else {
|
||||
if(global::globalHaltRequested == 0) {
|
||||
global::globalHaltRequested = 1;
|
||||
} else if(global::globalHaltRequested == 2) {
|
||||
global::globalHaltRequested = 3;
|
||||
#ifdef _WIN32
|
||||
if (::GetCurrentThreadId() != mainThread) {
|
||||
// SIGTERM may arrive on another thread (via SetConsoleCtrlHandler), and
|
||||
// the process will be forcefully terminated as soon as that thread is
|
||||
// done. So better make sure it isn't done prematurely. ;)
|
||||
while (global::globalHaltRequested != 5) {
|
||||
::Sleep(100); // Yeah, semi-busy waiting for now.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// SIGINT
|
||||
|
||||
if (global::globalHaltRequested == 0) {
|
||||
global::globalHaltRequested = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (global::globalHaltRequested == 2) {
|
||||
global::globalHaltRequested = 3;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
|
76
src/util.cc
76
src/util.cc
|
@ -84,6 +84,7 @@
|
|||
#include "BufferedFile.h"
|
||||
#include "SocketCore.h"
|
||||
#include "prefs.h"
|
||||
#include "Lock.h"
|
||||
|
||||
#ifdef ENABLE_MESSAGE_DIGEST
|
||||
# include "MessageDigest.h"
|
||||
|
@ -1232,8 +1233,83 @@ bool isNumericHost(const std::string& name)
|
|||
return true;
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
namespace {
|
||||
static Lock win_signal_lock;
|
||||
|
||||
static void(*win_int_handler)(int) = nullptr;
|
||||
static void(*win_term_handler)(int) = nullptr;
|
||||
|
||||
static void win_ign_handler(int) {}
|
||||
|
||||
static BOOL WINAPI HandlerRoutine(DWORD ctrlType)
|
||||
{
|
||||
void(*handler)(int) = nullptr;
|
||||
switch (ctrlType) {
|
||||
case CTRL_C_EVENT:
|
||||
case CTRL_BREAK_EVENT:
|
||||
{
|
||||
// Handler will be called on a new/different thread.
|
||||
LockGuard lg(win_signal_lock);
|
||||
handler = win_int_handler;
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
handler(SIGINT);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
case CTRL_LOGOFF_EVENT:
|
||||
case CTRL_CLOSE_EVENT:
|
||||
case CTRL_SHUTDOWN_EVENT:
|
||||
{
|
||||
// Handler will be called on a new/different thread.
|
||||
LockGuard lg(win_signal_lock);
|
||||
handler = win_term_handler;;
|
||||
}
|
||||
if (handler) {
|
||||
handler(SIGTERM);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void setGlobalSignalHandler(int sig, sigset_t* mask, void (*handler)(int),
|
||||
int flags) {
|
||||
#if _WIN32
|
||||
if (sig == SIGINT || sig == SIGTERM) {
|
||||
// Handler will be called on a new/different thread.
|
||||
LockGuard lg(win_signal_lock);
|
||||
|
||||
if (handler == SIG_DFL) {
|
||||
handler = nullptr;
|
||||
}
|
||||
else if (handler == SIG_IGN) {
|
||||
handler = win_ign_handler;
|
||||
}
|
||||
// Not yet in use: add console handler.
|
||||
if (handler && !win_int_handler && !win_term_handler) {
|
||||
::SetConsoleCtrlHandler(HandlerRoutine, TRUE);
|
||||
}
|
||||
if (sig == SIGINT) {
|
||||
win_int_handler = handler;
|
||||
}
|
||||
else {
|
||||
win_term_handler = handler;
|
||||
}
|
||||
// No handlers set: remove.
|
||||
if (!win_int_handler && !win_term_handler) {
|
||||
::SetConsoleCtrlHandler(HandlerRoutine, FALSE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SIGACTION
|
||||
struct sigaction sigact;
|
||||
sigact.sa_handler = handler;
|
||||
|
|
Loading…
Reference in New Issue