/usr/lib/python2.7/dist-packages/Mailnag/common/subproc.py is in mailnag 1.0.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | #!/usr/bin/env python2
# -*- coding: utf-8 -*-
#
# subproc.py
#
# Copyright 2013 Patrick Ulbrich <zulu99@gmx.net>
#
# 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 2 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, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
import subprocess
import threading
import logging
import time
# Note : All functions of this module *are* thread-safe.
# Protects access to the proc dictionary.
_proc_lock = threading.Lock()
# Intended to prevent simultaneous execution of
# (start_subprocess, terminate_subprocesses),
# (terminate_subprocesses, terminate_subprocesses).
_func_lock = threading.Lock()
# Dictionary holding popen objects
# and associated thread objects.
_procs = {}
# Starts a subprocess and an associated thread that waits for
# the subprocess to terminate (prevents zombie processes).
def start_subprocess(args, shell = False, callback = None):
def thread():
t = threading.currentThread()
try:
p = None
with _proc_lock: p = _procs[t]
retcode = p.wait()
if callback != None:
callback(retcode)
finally:
with _proc_lock: del _procs[t]
with _func_lock:
p = None
pid = -1
try:
p = subprocess.Popen(args, shell = shell)
except: logging.exception('Caught an exception.')
if p != None:
pid = p.pid
t = threading.Thread(target = thread)
with _proc_lock:
_procs[t] = p
t.start()
return pid
# Terminates all subprocesses that were started by
# start_subprocess(). Subprocesses that don't terminate
# within the timeframe (seconds) specified by the
# timeout argument, are sent a kill signal.
def terminate_subprocesses(timeout = 3.0):
with _func_lock:
threads = []
with _proc_lock:
if len(_procs) == 0:
return
for t, p in _procs.iteritems():
threads.append(t)
# Ask all runnig processes to terminate.
# This will also terminate associated threads
# waiting for p.wait().
# Note : terminate() does not block.
try: p.terminate()
except: logging.debug('p.terminate() failed')
# Start a watchdog thread that will kill
# all processes that didn't terminate within <timeout> seconds.
wd = _Watchdog(timeout)
wd.start()
# Wait for all threads to terminate
for t in threads:
t.join()
wd.stop()
if not wd.triggered:
logging.info('All subprocesses exited normally.')
# Internal Watchdog class
class _Watchdog(threading.Thread):
def __init__(self, timeout):
threading.Thread.__init__(self)
self.triggered = False
self._timeout = timeout
self._event = threading.Event()
def run(self):
self._event.wait(self._timeout)
if not self._event.is_set():
logging.warning('Process termination took too long - watchdog starts killing...')
self.triggered = True
with _proc_lock:
for t, p in _procs.iteritems():
try:
# Kill process p and quit the thread
# waiting for p to terminate (p.wait()).
p.kill()
logging.info('Watchdog killed process %s' % p.pid)
except: logging.debug('p.kill() failed')
def stop(self):
# Abort watchdog thread (may have been triggered already)
self._event.set()
# Wait for watchdog thread (may be inactive already)
self.join()
|