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

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

Issue 870103005: Adding a server side, non-blocking subprocess mechanism. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 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 | « no previous file | testing/legion/examples/hello_world/host_test.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 client RPC methods.""" 5 """Defines the client RPC methods."""
6 6
7 import logging 7 import logging
8 import subprocess 8 import subprocess
9 import threading 9 import threading
10 10
11 11
12 class RPCMethods(object): 12 class RPCMethods(object):
13 """Class exposing RPC methods.""" 13 """Class exposing RPC methods."""
14 14
15 _dotted_whitelist = ['subprocess']
16
15 def __init__(self, server): 17 def __init__(self, server):
16 self.server = server 18 self._server = server
19 self.subprocess = Subprocess
20
21 def _dispatch(self, method, params):
22 obj = self
23 if '.' in method:
24 # Allow only white listed dotted names
25 name, method = method.split('.')
26 assert name in self._dotted_whitelist
27 obj = getattr(self, name)
28 return getattr(obj, method)(*params)
M-A Ruel 2015/02/10 19:52:19 I generally prefer to prefix all the rpc methods w
Mike Meade 2015/02/11 00:25:34 With SimpleXMLRPCServer any public method is consi
17 29
18 def Echo(self, message): 30 def Echo(self, message):
19 """Simple RPC method to print and return a message.""" 31 """Simple RPC method to print and return a message."""
20 logging.info('Echoing %s', message) 32 logging.info('Echoing %s', message)
21 return 'echo %s' % str(message) 33 return 'echo %s' % str(message)
22 34
23 def Subprocess(self, cmd):
24 """Run the commands in a subprocess.
25
26 Returns:
27 (returncode, stdout, stderr).
28 """
29 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
30 stderr=subprocess.PIPE)
31 stdout, stderr = p.communicate()
32 return (p.returncode, stdout, stderr)
33
34 def Quit(self): 35 def Quit(self):
35 """Call server.shutdown in another thread. 36 """Call _server.shutdown in another thread.
36 37
37 This is needed because server.shutdown waits for the server to actually 38 This is needed because server.shutdown waits for the server to actually
38 quit. However the server cannot shutdown until it completes handling this 39 quit. However the server cannot shutdown until it completes handling this
39 call. Calling this in the same thread results in a deadlock. 40 call. Calling this in the same thread results in a deadlock.
40 """ 41 """
41 t = threading.Thread(target=self.server.shutdown) 42 t = threading.Thread(target=self._server.shutdown)
42 t.start() 43 t.start()
44
45
46 class Subprocess(object):
47 """Implements a server-based non-blocking subprocess.
48
49 This non-blocking subprocess allows the caller to continue operating while
50 also able to interact with this subprocess based on an index returned to
51 the caller at the time of creation.
52 """
53
54 _processes = []
55
56 def __init__(self, cmd):
57 self.proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
58 stderr=subprocess.PIPE)
59 self.stdout = ''
60 self.stderr = ''
61 threading.Thread(target=self._run).start()
62
63 def _run(self):
64 self.stdout, self.stderr = self.proc.communicate()
M-A Ruel 2015/02/10 19:52:19 Note that you may like subprocess42.py, which supp
Mike Meade 2015/02/11 00:25:34 I ended up using subprocess42, but mainly for the
Mike Meade 2015/02/12 21:46:59 The need for streaming reads actually came up pret
65
66 @classmethod
67 def Popen(cls, cmd):
68 process = cls(cmd)
69 cls._processes.append(process)
70 return len(cls._processes) - 1
71
72 @classmethod
73 def Terminate(cls, index):
M-A Ruel 2015/02/10 19:52:19 This index based access is surprising, especially
Mike Meade 2015/02/11 00:25:34 Changed this to a dictionary, added a Delete metho
74 return cls._processes[index].proc.terminate()
75
76 @classmethod
77 def Kill(cls, index):
78 return cls._processes[index].proc.kill()
79
80 @classmethod
81 def GetReturncode(cls, index):
82 return cls._processes[index].proc.returncode
83
84 @classmethod
85 def GetStdout(cls, index):
86 return cls._processes[index].stdout
87
88 @classmethod
89 def GetStderr(cls, index):
90 return cls._processes[index].stderr
91
92 @classmethod
93 def Wait(cls, index):
94 return cls._processes[index].proc.wait()
95
96 @classmethod
97 def Poll(cls, index):
98 return cls._processes[index].proc.poll()
99
100 @classmethod
101 def GetPid(cls, index):
102 return cls._processes[index].proc.pid
OLDNEW
« no previous file with comments | « no previous file | testing/legion/examples/hello_world/host_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698