####################################################################################################
#
# PyDvi - A Python Library to Process DVI Stream
# Copyright (C) 2014 Fabrice Salvaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
####################################################################################################
####################################################################################################
#
# Derived from: Mathtran
# Copyright: (c) 2007 The Open University, Milton Keynes, UK
# License: GPL version 2 or (at your option) any later version.
#
####################################################################################################
####################################################################################################
#
# Audit
#
# - 17/12/2011 fabrice
# - license !
#
####################################################################################################
""" This module provides functions to run Daemon process.
"""
####################################################################################################
__ALL__ = ['make_nonblocking', 'SubprocessError', 'DaemonSubprocess']
####################################################################################################
import fcntl # For non-blocking file descriptor
import logging
import os
import signal
from subprocess import Popen, PIPE
####################################################################################################
logger = logging.getLogger(__name__)
####################################################################################################
[docs]def make_nonblocking(fd):
""" Makes a file descriptor non-blocking.
When a non-blocking file is read, the read does not wait for end-of-file. Instead, the read can
return just as soon as there is nothing left to read. This might be because a buffer is empty.
See Python Cookbook, Recipe 6.6.
"""
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
flags |= os.O_NONBLOCK
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
####################################################################################################
[docs]class SubprocessError(EnvironmentError):
pass
####################################################################################################
[docs]class DaemonSubprocess(object):
""" This class implements a Daemon sub-process.
"""
#: List of fifos to be created.
fifos = ()
##############################################
def __init__(self, working_directory):
# Create the working directory
self.working_directory = os.path.abspath(working_directory)
logger.info('Create working directory %s' % (self.working_directory))
# try
os.mkdir(working_directory)
# Create the Fifos
for name in self.fifos:
os.mkfifo(os.path.join(self.working_directory, name))
self.child = None
##############################################
def __del__(self):
""" Stop the child process and cleanup the working directory. """
try:
self.stop()
finally:
if self.working_directory is not None:
logger.info('Cleanup working directory %s' % (self.working_directory))
for filename in os.listdir(self.working_directory):
os.remove(os.path.join(self.working_directory, filename))
os.rmdir(self.working_directory)
##############################################
[docs] def start(self):
""" Start the child process. """
args = self.make_args()
logger.info('Start child process: ' + ' '.join(args))
child = self.child = Popen(args,
cwd=self.working_directory,
stdin=PIPE, stdout=PIPE, stderr=PIPE)
for fd in child.stdin, child.stdout, child.stderr:
make_nonblocking(fd)
##############################################
[docs] def make_args(self):
""" Return the args for Popen. To be implemented in subclass. """
raise NotImplementedError
##############################################
[docs] def stop(self):
""" Stop the child process. """
logger.info('Stop child process')
# poll: Check if child process has terminated.
if self.child is not None and self.child.poll() is None:
self.kill()
self.child = None
##############################################
[docs] def kill(self):
""" Send Kill signal to the child process. """
logger.info('Kill child process')
self.child.kill()
# Wait for child process to terminate.
self.child.wait()
##############################################
[docs] def restart(self):
""" Restart the child process. """
logger.info('Restart child process')
self.stop()
self.start()
####################################################################################################
#
# End
#
####################################################################################################