Files
neko-daemonizer-dante/neko_daemonizer_dante/daemonizer/_signals_common.py
2024-02-11 17:12:19 +02:00

178 lines
4.5 KiB
Python

'''
LICENSING
-------------------------------------------------
daemoniker: Cross-platform daemonization tools.
Copyright (C) 2016 Muterra, Inc.
Contributors
------------
Nick Badger
badg@muterra.io | badg@nickbadger.com | nickbadger.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the
Free Software Foundation, Inc.,
51 Franklin Street,
Fifth Floor,
Boston, MA 02110-1301 USA
------------------------------------------------------
'''
# Global dependencies
import os
import sys
import signal
import logging
import atexit
import traceback
import shutil
# Intra-package dependencies
from .utils import default_to
from .exceptions import DaemonikerSignal
# ###############################################
# Boilerplate
# ###############################################
import logging
logger = logging.getLogger(__name__)
# Control * imports.
__all__ = [
# 'Inquisitor',
]
# ###############################################
# Library
# ###############################################
IGNORE_SIGNAL = 1793
def _noop(*args, **kwargs):
''' Used for ignoring signals.
'''
pass
def send(pid_file, signal):
''' Sends the signal in signum to the pid_file. Num can be either
int or one of the exceptions.
'''
if isinstance(signal, DaemonikerSignal):
signum = signal.SIGNUM
elif isinstance(signal, type) and issubclass(signal, DaemonikerSignal):
signum = signal.SIGNUM
else:
signum = int(signal)
with open(pid_file, 'r') as f:
pid = int(f.read())
os.kill(pid, signum)
def ping(pid_file):
''' Returns True if the process in pid_file is available, and False
otherwise. Note that availability does not imply the process is
running, just that it recently has been. For example, recently-
exited processes will still return True.
Uhhh shit, this isn't going to work well, windows converts signal 0
into an interrupt. Okay, punt for now.
'''
try:
send(pid_file, 0)
except OSError:
return False
else:
return True
def _normalize_handler(handler, default_handler):
''' Normalizes a signal handler. Converts None to the default, and
IGNORE_SIGNAL to noop.
'''
# None -> _default_handler
handler = default_to(handler, default_handler)
# IGNORE_SIGNAL -> _noop
handler = default_to(handler, _noop, comparator=IGNORE_SIGNAL)
return handler
class _SighandlerCore:
''' Core, platform-independent functionality for signal handlers.
'''
@property
def sigint(self):
''' Gets sigint.
'''
return self._sigint
@sigint.setter
def sigint(self, handler):
''' Normalizes and sets sigint.
'''
self._sigint = _normalize_handler(handler, self._default_handler)
@sigint.deleter
def sigint(self):
''' Returns the sigint handler to the default.
'''
self.sigint = None
@property
def sigterm(self):
''' Gets sigterm.
'''
return self._sigterm
@sigterm.setter
def sigterm(self, handler):
''' Normalizes and sets sigterm.
'''
self._sigterm = _normalize_handler(handler, self._default_handler)
@sigterm.deleter
def sigterm(self):
''' Returns the sigterm handler to the default.
'''
self.sigterm = None
@property
def sigabrt(self):
''' Gets sigabrt.
'''
return self._sigabrt
@sigabrt.setter
def sigabrt(self, handler):
''' Normalizes and sets sigabrt.
'''
self._sigabrt = _normalize_handler(handler, self._default_handler)
@sigabrt.deleter
def sigabrt(self):
''' Returns the sigabrt handler to the default.
'''
self.sigabrt = None