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
|
# distbuild/subprocess_eventsrc.py -- for managing subprocesses
#
# Copyright (C) 2014-2015 Codethink Limited
#
# 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; version 2 of the License.
#
# 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/>.
import logging
import os
import signal
import distbuild
class FileReadable(object):
def __init__(self, request_id, p, f):
self.request_id = request_id
self.process = p
self.file = f
class FileWriteable(object):
def __init__(self, request_id, p, f):
self.request_id = request_id
self.process = p
self.file = f
class SubprocessEventSource(distbuild.EventSource):
'''Event source for monitoring one or more subprocesses.
This will send FileReadable and FileWritable events based on the
stdin and stdout and stderr handles of each subprocesses.
When the subprocess terminates, you'll receive final FileReadable events
for stdout and for stderr. At that point, reading from those file
descriptors will return None, at which point you can be sure that the
subprocess is no longer running.
'''
def __init__(self):
self.procs = []
self.closed = False
def get_select_params(self):
r = []
w = []
for requst_id, p in self.procs:
if p.stdin_contents is not None:
w.append(p.stdin)
if p.stdout is not None:
r.append(p.stdout)
if p.stderr is not None:
r.append(p.stderr)
return r, w, [], None
def get_events(self, r, w, x):
events = []
for request_id, p in self.procs:
if p.stdin in w:
events.append(FileWriteable(request_id, p, p.stdin))
if p.stdout in r:
events.append(FileReadable(request_id, p, p.stdout))
if p.stderr in r:
events.append(FileReadable(request_id, p, p.stderr))
return events
def add(self, request_id, process):
self.procs.append((request_id, process))
distbuild.set_nonblocking(process.stdin)
distbuild.set_nonblocking(process.stdout)
distbuild.set_nonblocking(process.stderr)
def remove(self, process):
self.procs = [t for t in self.procs if t[1] != process]
def kill_by_id(self, request_id):
logging.debug('SES: Killing all processes for %s', request_id)
for id, process in self.procs:
if id == request_id:
logging.debug('SES: killing process group of %r', process)
os.killpg(process.pid, signal.SIGKILL)
def close(self):
self.procs = []
self.closed = True
def is_finished(self):
return self.closed
|