forked from sonic-net/sonic-swss-common
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix SIGTERM can't terminate PubSub::listen issue by add cancellation …
…token support. (sonic-net#606) Why I did it There are infinite loops inside PubSub::listen() method, so application using this method can't handle SIGTERM correctly. sonic-net#603 How I did it Add following class: 1. CancellationToken: this class will help exist the infinite loops when SIGTERM or other signal happen. 2. SignalHandlerHelper: Provide a native signal handler. How to verify it 1. manually test. 2. Pass all test case.
- Loading branch information
1 parent
574bd87
commit 2ec06f2
Showing
10 changed files
with
184 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#include <signal.h> | ||
#include "common/logger.h" | ||
#include "signalhandlerhelper.h" | ||
|
||
using namespace swss; | ||
|
||
std::map<int, bool> SignalHandlerHelper::m_signalStatusMapping; | ||
std::map<int, SigActionPair> SignalHandlerHelper::m_sigActionMapping; | ||
|
||
void SignalHandlerHelper::registerSignalHandler(int signalNumber) | ||
{ | ||
auto result = m_sigActionMapping.find(signalNumber); | ||
if (result != m_sigActionMapping.end()) | ||
{ | ||
// signal action already registered | ||
SWSS_LOG_WARN("sigaction for %d already registered.", signalNumber); | ||
return; | ||
} | ||
|
||
m_signalStatusMapping[signalNumber] = false; | ||
|
||
SigActionPair sig_action_pair; | ||
auto *new_action = &sig_action_pair.first; | ||
auto *old_action = &sig_action_pair.second; | ||
|
||
new_action->sa_handler = SignalHandlerHelper::onSignal; | ||
sigemptyset(&new_action->sa_mask); | ||
new_action->sa_flags = 0; | ||
|
||
// always replace old action even old action is ignore signal | ||
sigaction(signalNumber, new_action, old_action); | ||
|
||
m_sigActionMapping[signalNumber] = sig_action_pair; | ||
} | ||
|
||
void SignalHandlerHelper::restoreSignalHandler(int signalNumber) | ||
{ | ||
auto result = m_sigActionMapping.find(signalNumber); | ||
if (result == m_sigActionMapping.end()) | ||
{ | ||
// signal action does not registered | ||
SWSS_LOG_WARN("sigaction for %d does not registered.",signalNumber); | ||
return; | ||
} | ||
|
||
auto *old_action = &result->second.second; | ||
|
||
sigaction(signalNumber, old_action, NULL); | ||
} | ||
|
||
void SignalHandlerHelper::onSignal(int signalNumber) | ||
{ | ||
m_signalStatusMapping[signalNumber] = true; | ||
} | ||
|
||
bool SignalHandlerHelper::checkSignal(int signalNumber) | ||
{ | ||
auto result = m_signalStatusMapping.find(signalNumber); | ||
if (result != m_signalStatusMapping.end()) | ||
{ | ||
return result->second; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
void SignalHandlerHelper::resetSignal(int signalNumber) | ||
{ | ||
m_signalStatusMapping[signalNumber] = false; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#pragma once | ||
#include <map> | ||
#include <signal.h> | ||
|
||
namespace swss { | ||
|
||
typedef std::pair<struct sigaction, struct sigaction> SigActionPair; | ||
|
||
// Define signal ID enum for python | ||
enum Signals | ||
{ | ||
SIGNAL_TERM = SIGTERM, | ||
SIGNAL_INT = SIGINT | ||
}; | ||
|
||
/* | ||
SignalHandlerHelper class provide a native signal handler. | ||
Python signal handler have following issue: | ||
A long-running calculation implemented purely in C (such as regular expression matching on a large body of text) may run uninterrupted for an arbitrary amount of time, regardless of any signals received. The Python signal handlers will be called when the calculation finishes. | ||
For more information, please check: https://docs.python.org/3/library/signal.html | ||
*/ | ||
class SignalHandlerHelper | ||
{ | ||
public: | ||
static void registerSignalHandler(int signalNumber); | ||
static void restoreSignalHandler(int signalNumber); | ||
static void onSignal(int signalNumber); | ||
static bool checkSignal(int signalNumber); | ||
static void resetSignal(int signalNumber); | ||
|
||
private: | ||
static std::map<int, bool> m_signalStatusMapping; | ||
static std::map<int, SigActionPair> m_sigActionMapping; | ||
}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import signal | ||
import os | ||
import pytest | ||
from swsscommon import swsscommon | ||
from swsscommon.swsscommon import SignalHandlerHelper | ||
|
||
def dummy_signal_handler(signum, stack): | ||
# ignore signal so UT will not break | ||
pass | ||
|
||
def test_SignalHandler(): | ||
signal.signal(signal.SIGUSR1, dummy_signal_handler) | ||
|
||
# Register SIGUSER1 | ||
SignalHandlerHelper.registerSignalHandler(signal.SIGUSR1) | ||
happened = SignalHandlerHelper.checkSignal(signal.SIGUSR1) | ||
assert happened == False | ||
|
||
# trigger SIGUSER manually | ||
os.kill(os.getpid(), signal.SIGUSR1) | ||
happened = SignalHandlerHelper.checkSignal(signal.SIGUSR1) | ||
assert happened == True | ||
|
||
# Reset signal | ||
SignalHandlerHelper.resetSignal(signal.SIGUSR1) | ||
happened = SignalHandlerHelper.checkSignal(signal.SIGUSR1) | ||
assert happened == False | ||
|
||
# un-register signal handler | ||
SignalHandlerHelper.restoreSignalHandler(signal.SIGUSR1) | ||
os.kill(os.getpid(), signal.SIGUSR1) | ||
happened = SignalHandlerHelper.checkSignal(signal.SIGUSR1) | ||
assert happened == False |