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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
|
# *******************************************************************************
# * Copyright (c) 2011 Wind River Systems, Inc. and others.
# * All rights reserved. This program and the accompanying materials
# * are made available under the terms of the Eclipse Public License v1.0
# * which accompanies this distribution, and is available at
# * http://www.eclipse.org/legal/epl-v10.html
# *
# * Contributors:
# * Wind River Systems - initial API and implementation
# *******************************************************************************
import threading, types
from tcf import protocol
from tcf.channel.Command import Command
class DispatchWrapper(object):
"Simple wrapper for attribute access and invocation on TCF dispatch thread"
def __init__(self, inner):
self.inner = inner
def __getattr__(self, attr):
val = protocol.invokeAndWait(getattr, self.inner, attr)
if type(val) in (types.FunctionType, types.MethodType):
return DispatchWrapper(val)
return val
def __call__(self, *args, **kwargs):
return protocol.invokeAndWait(self.inner, *args, **kwargs)
class CommandControl(object):
"""Provides a simple interface to send commands to remote services
and receive results.
Usage:
> cmd = CommandControl(channel)
> cmd.<service>.<command>(<args>)
Examples:
# send command, but don't wait for result:
> cmd.RunControl.suspend("system")
# getE() returns the result and raises an exception in case of error response:
> result = cmd.RunControl.getChildren(None).getE()
# to get error and result at the same time, use this form:
> error, result = cmd.Breakpoints.getIDs()
"""
def __init__(self, channel, onDone=None, interactive=False):
self._lock = threading.Condition()
self._channel = channel
self._onDone = onDone
self._interactive = interactive
self._queue = []
self._pending = {}
self._complete = []
def __getattr__(self, attr):
val = getattr(self._channel, attr, None)
if val:
if self._interactive and type(val) in (types.FunctionType, types.MethodType):
val = DispatchWrapper(val)
return val
services = protocol.invokeAndWait(self._channel.getRemoteServices)
if attr == "services":
return services
if attr in services:
return ServiceWrapper(self, attr)
raise AttributeError("Unknown service: %s. Use one of %s" % (attr, services))
def invoke(self, service, command, *args, **kwargs):
cmd = None
if not protocol.isDispatchThread():
if not kwargs.get("async"):
cmd = protocol.invokeAndWait(self._invoke, service, command, *args, **kwargs)
if cmd and self._interactive:
return cmd.getE()
else:
with self._lock:
self._queue.append((service, command, args, kwargs))
if len(self._queue) == 1:
protocol.invokeLater(self._processQueue)
return
return cmd
def _invoke(self, service, command, *args, **kwargs):
cmdCtrl = self
class GenericCommand(Command):
_result = None
def done(self, error, args):
resultArgs = None
if not error and args:
# error result is usually in args[0], but there are exceptions
if service == "StackTrace" and command == "getContext":
error = self.toError(args[1])
resultArgs = (args[0],)
elif service == "Expressions" and command == "evaluate":
error = self.toError(args[1])
resultArgs = (args[0], args[2])
elif service == "FileSystem" and command in ('read', 'readdir', 'roots'):
error = self.toError(args[1])
resultArgs = (args[0],) + tuple(args[2:])
elif service == "Diagnostics" and command.startswith("echo"):
resultArgs = (args[0],)
else:
error = self.toError(args[0])
resultArgs = args[1:]
cmdCtrl._doneCommand(self.token, error, resultArgs)
def wait(self, timeout=None):
cmdCtrl._waitForCommand(self.token, timeout)
def cancel(self):
return protocol.invokeAndWait(self.token.cancel)
def getResult(self, wait=None):
if wait:
cmdCtrl._waitForCommand(self.token)
return self._result
def getE(self):
r = self.getResult(True)
if r.error:
raise r.error
return r.args
def get(self):
r = self.getResult(True)
return r.args
def getError(self):
r = self.getResult(True)
return r.error
def __str__(self):
if self._async:
return self.getCommandString()
return str(self.get())
def __iter__(self):
return iter(self.getResult(True))
cmd = GenericCommand(self._channel, service, command, args)
cmd._async = kwargs.get("async")
cmd._onDone = kwargs.get("onDone")
self._addPending(cmd)
return cmd
def _processQueue(self):
assert protocol.isDispatchThread()
with self._lock:
for cmd in self._queue:
service, command, args, kwargs = cmd
self._invoke(service, command, *args, **kwargs)
del self._queue[:]
def _addPending(self, cmd):
with self._lock:
self._pending[cmd.token.id] = cmd
self._lock.notifyAll()
def _doneCommand(self, token, error, args):
with self._lock:
cmd = self._pending.get(token.id)
assert cmd
del self._pending[token.id]
cmd._result = CommandResult(token, error, args)
if cmd._async: self._complete.append(cmd)
isDone = self.isDone()
if isDone: self._lock.notifyAll()
if cmd._onDone:
if args is None: args = (None,)
cmd._onDone(error, *args)
if isDone and self._onDone: self._onDone()
def isDone(self):
with self._lock:
return not self._pending and not self._queue
def wait(self, timeout=None):
assert not protocol.isDispatchThread()
with self._lock:
while self._pending or self._queue:
self._lock.wait(timeout)
if timeout: break
def _waitForCommand(self, token, timeout=None):
assert not protocol.isDispatchThread()
with self._lock:
while token.id in self._pending:
self._lock.wait(timeout)
if timeout: break
else:
if self._queue:
self._lock.wait(timeout)
while token.id in self._pending:
self._lock.wait(timeout)
if timeout: break
def cancel(self):
if not protocol.isDispatchThread():
protocol.invokeLater(self.cancel)
return
with self._lock:
for cmd in self._pending.values():
cmd.token.cancel()
del self._queue[:]
def getResult(self, wait=True):
if wait:
self.wait()
with self._lock:
result = map(lambda c: c.getResult(), self._complete)
del self._complete[:]
return result
class CommandResult(object):
def __init__(self, token, error, args):
self.token = token
self.error = error
# unwrap result if only one element
if args and len(args) == 1:
args = args[0]
self.args = args
def __str__(self):
if self.error:
return "[%s] error: %s" % (self.token.id, self.error)
return "[%s] result: %s" % (self.token.id, self.args)
__repr__ = __str__
def __iter__(self):
yield self.error
yield self.args
class ServiceWrapper(object):
def __init__(self, control, service):
self._control = control
self._service = service
def __getattr__(self, attr):
return CommandWrapper(self._control, self._service, attr)
class CommandWrapper(object):
def __init__(self, control, service, command):
self._control = control
self._service = service
self._command = command
def __call__(self, *args, **kwargs):
return self._control.invoke(self._service, self._command, *args, **kwargs)
|