Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: testing/legion/rpc_methods.py

Issue 1001833005: Update from https://crrev.com/320343 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Supress Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « testing/legion/examples/subprocess/subprocess_test.py ('k') | testing/legion/run_task.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2015 The Chromium Authors. All rights reserved. 1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Defines the task RPC methods.""" 5 """Defines the task RPC methods."""
6 6
7 import os 7 import os
8 import sys 8 import sys
9 import logging 9 import logging
10 import threading 10 import threading
(...skipping 23 matching lines...) Expand all
34 name, method = method.split('.') 34 name, method = method.split('.')
35 assert name in self._dotted_whitelist 35 assert name in self._dotted_whitelist
36 obj = getattr(self, name) 36 obj = getattr(self, name)
37 return getattr(obj, method)(*params) 37 return getattr(obj, method)(*params)
38 38
39 def Echo(self, message): 39 def Echo(self, message):
40 """Simple RPC method to print and return a message.""" 40 """Simple RPC method to print and return a message."""
41 logging.info('Echoing %s', message) 41 logging.info('Echoing %s', message)
42 return 'echo %s' % str(message) 42 return 'echo %s' % str(message)
43 43
44 def AbsPath(self, path):
45 """Returns the absolute path."""
46 return os.path.abspath(path)
47
44 def Quit(self): 48 def Quit(self):
45 """Call _server.shutdown in another thread. 49 """Call _server.shutdown in another thread.
46 50
47 This is needed because server.shutdown waits for the server to actually 51 This is needed because server.shutdown waits for the server to actually
48 quit. However the server cannot shutdown until it completes handling this 52 quit. However the server cannot shutdown until it completes handling this
49 call. Calling this in the same thread results in a deadlock. 53 call. Calling this in the same thread results in a deadlock.
50 """ 54 """
51 t = threading.Thread(target=self._server.shutdown) 55 t = threading.Thread(target=self._server.shutdown)
52 t.start() 56 t.start()
53 57
54 58
55 class Subprocess(object): 59 class Subprocess(object):
56 """Implements a server-based non-blocking subprocess. 60 """Implements a server-based non-blocking subprocess.
57 61
58 This non-blocking subprocess allows the caller to continue operating while 62 This non-blocking subprocess allows the caller to continue operating while
59 also able to interact with this subprocess based on a key returned to 63 also able to interact with this subprocess based on a key returned to
60 the caller at the time of creation. 64 the caller at the time of creation.
65
66 Creation args are set via Set* methods called after calling Process but
67 before calling Start. This is due to a limitation of the XML-RPC
68 implementation not supporting keyword arguments.
61 """ 69 """
62 70
63 _processes = {} 71 _processes = {}
64 _process_next_id = 0 72 _process_next_id = 0
65 _creation_lock = threading.Lock() 73 _creation_lock = threading.Lock()
66 74
67 def __init__(self, cmd): 75 def __init__(self, cmd):
68 self.proc = subprocess42.Popen(cmd, stdout=subprocess42.PIPE,
69 stderr=subprocess42.PIPE)
70 self.stdout = '' 76 self.stdout = ''
71 self.stderr = '' 77 self.stderr = ''
78 self.cmd = cmd
79 self.proc = None
80 self.cwd = None
81 self.verbose = False
82 self.detached = False
72 self.data_lock = threading.Lock() 83 self.data_lock = threading.Lock()
73 threading.Thread(target=self._run).start()
74 84
75 def _run(self): 85 def __str__(self):
86 return '%r, cwd=%r, verbose=%r, detached=%r' % (
87 self.cmd, self.cwd, self.verbose, self.detached)
88
89 def _reader(self):
76 for pipe, data in self.proc.yield_any(): 90 for pipe, data in self.proc.yield_any():
77 with self.data_lock: 91 with self.data_lock:
78 if pipe == 'stdout': 92 if pipe == 'stdout':
79 self.stdout += data 93 self.stdout += data
94 if self.verbose:
95 sys.stdout.write(data)
80 else: 96 else:
81 self.stderr += data 97 self.stderr += data
98 if self.verbose:
99 sys.stderr.write(data)
82 100
83 @classmethod 101 @classmethod
84 def Popen(cls, cmd): 102 def KillAll(cls):
103 for key in cls._processes:
104 cls.Kill(key)
105
106 @classmethod
107 def Process(cls, cmd):
85 with cls._creation_lock: 108 with cls._creation_lock:
86 key = 'Process%d' % cls._process_next_id 109 key = 'Process%d' % cls._process_next_id
87 cls._process_next_id += 1 110 cls._process_next_id += 1
88 logging.debug('Creating process %s', key) 111 logging.debug('Creating process %s', key)
89 process = cls(cmd) 112 process = cls(cmd)
90 cls._processes[key] = process 113 cls._processes[key] = process
91 return key 114 return key
92 115
116 def _Start(self):
117 logging.info('Starting process %s', self)
118 self.proc = subprocess42.Popen(self.cmd, stdout=subprocess42.PIPE,
119 stderr=subprocess42.PIPE,
120 detached=self.detached, cwd=self.cwd)
121 threading.Thread(target=self._reader).start()
122
123 @classmethod
124 def Start(cls, key):
125 cls._processes[key]._Start()
126
127 @classmethod
128 def SetCwd(cls, key, cwd):
129 """Sets the process's cwd."""
130 logging.debug('Setting %s cwd to %s', key, cwd)
131 cls._processes[key].cwd = cwd
132
133 @classmethod
134 def SetDetached(cls, key):
135 """Creates a detached process."""
136 logging.debug('Setting %s to run detached', key)
137 cls._processes[key].detached = True
138
139 @classmethod
140 def SetVerbose(cls, key):
141 """Sets the stdout and stderr to be emitted locally."""
142 logging.debug('Setting %s to be verbose', key)
143 cls._processes[key].verbose = True
144
93 @classmethod 145 @classmethod
94 def Terminate(cls, key): 146 def Terminate(cls, key):
95 logging.debug('Terminating and deleting process %s', key) 147 logging.debug('Terminating process %s', key)
96 return cls._processes.pop(key).proc.terminate() 148 cls._processes[key].proc.terminate()
97 149
98 @classmethod 150 @classmethod
99 def Kill(cls, key): 151 def Kill(cls, key):
100 logging.debug('Killing and deleting process %s', key) 152 logging.debug('Killing process %s', key)
101 return cls._processes.pop(key).proc.kill() 153 cls._processes[key].proc.kill()
102 154
103 @classmethod 155 @classmethod
104 def Delete(cls, key): 156 def Delete(cls, key):
157 if cls.GetReturncode(key) is None:
158 logging.warning('Killing %s before deleting it', key)
159 cls.Kill(key)
105 logging.debug('Deleting process %s', key) 160 logging.debug('Deleting process %s', key)
106 cls._processes.pop(key) 161 cls._processes.pop(key)
107 162
108 @classmethod 163 @classmethod
109 def GetReturncode(cls, key): 164 def GetReturncode(cls, key):
110 return cls._processes[key].proc.returncode 165 return cls._processes[key].proc.returncode
111 166
112 @classmethod 167 @classmethod
113 def ReadStdout(cls, key): 168 def ReadStdout(cls, key):
114 """Returns all stdout since the last call to ReadStdout. 169 """Returns all stdout since the last call to ReadStdout.
(...skipping 17 matching lines...) Expand all
132 See ReadStdout for additional details. 187 See ReadStdout for additional details.
133 """ 188 """
134 proc = cls._processes[key] 189 proc = cls._processes[key]
135 with proc.data_lock: 190 with proc.data_lock:
136 # Perform a "read" on the stderr data 191 # Perform a "read" on the stderr data
137 stderr = proc.stderr 192 stderr = proc.stderr
138 proc.stderr = '' 193 proc.stderr = ''
139 return stderr 194 return stderr
140 195
141 @classmethod 196 @classmethod
197 def ReadOutput(cls, key):
198 """Returns the (stdout, stderr) since the last Read* call.
199
200 See ReadStdout for additional details.
201 """
202 return cls.ReadStdout(key), cls.ReadStderr(key)
203
204 @classmethod
142 def Wait(cls, key): 205 def Wait(cls, key):
143 return cls._processes[key].proc.wait() 206 return cls._processes[key].proc.wait()
144 207
145 @classmethod 208 @classmethod
146 def Poll(cls, key): 209 def Poll(cls, key):
147 return cls._processes[key].proc.poll() 210 return cls._processes[key].proc.poll()
148 211
149 @classmethod 212 @classmethod
150 def GetPid(cls, key): 213 def GetPid(cls, key):
151 return cls._processes[key].proc.pid 214 return cls._processes[key].proc.pid
OLDNEW
« no previous file with comments | « testing/legion/examples/subprocess/subprocess_test.py ('k') | testing/legion/run_task.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698