Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 2aad54532799c04f2b9da79cc4969950eed3f8a4 (plain) (blame)
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 self._pending.has_key(token.id):
                self._lock.wait(timeout)
                if timeout: break
            else:
                if self._queue:
                    self._lock.wait(timeout)
                    while self._pending.has_key(token.id):
                        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)

Back to the top