Communication.cpp revision b89274fed17a85aeb81968685af781f24db30ded
1//===-- Communication.cpp ---------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10// C Includes
11// C++ Includes
12// Other libraries and framework includes
13// Project includes
14#include "lldb/lldb-private-log.h"
15#include "lldb/Core/Communication.h"
16#include "lldb/Core/Connection.h"
17#include "lldb/Core/Log.h"
18#include "lldb/Core/Timer.h"
19#include "lldb/Core/Event.h"
20#include <string.h>
21
22using namespace lldb;
23using namespace lldb_private;
24
25//----------------------------------------------------------------------
26// Constructor
27//----------------------------------------------------------------------
28Communication::Communication(const char *name) :
29    Broadcaster (name),
30    m_connection_ap (),
31    m_read_thread (LLDB_INVALID_HOST_THREAD),
32    m_read_thread_enabled (false),
33    m_bytes(),
34    m_bytes_mutex (Mutex::eMutexTypeRecursive),
35    m_callback (NULL),
36    m_callback_baton (NULL),
37    m_close_on_eof (true)
38
39{
40    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_COMMUNICATION,
41                                 "%p Communication::Communication (name = %s)",
42                                 this, name);
43}
44
45//----------------------------------------------------------------------
46// Destructor
47//----------------------------------------------------------------------
48Communication::~Communication()
49{
50    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_COMMUNICATION,
51                                 "%p Communication::~Communication (name = %s)",
52                                 this, m_broadcaster_name.AsCString(""));
53    Clear();
54}
55
56void
57Communication::Clear()
58{
59    StopReadThread (NULL);
60    Disconnect (NULL);
61}
62
63ConnectionStatus
64Communication::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
65{
66    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
67
68    if (m_connection_ap.get())
69        return m_connection_ap->BytesAvailable (timeout_usec, error_ptr);
70    if (error_ptr)
71        error_ptr->SetErrorString("Invalid connection.");
72    return eConnectionStatusNoConnection;
73}
74
75ConnectionStatus
76Communication::Connect (const char *url, Error *error_ptr)
77{
78    Clear();
79
80    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::Connect (url = %s)", this, url);
81
82    if (m_connection_ap.get())
83        return m_connection_ap->Connect (url, error_ptr);
84    if (error_ptr)
85        error_ptr->SetErrorString("Invalid connection.");
86    return eConnectionStatusNoConnection;
87}
88
89ConnectionStatus
90Communication::Disconnect (Error *error_ptr)
91{
92    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::Disconnect ()", this);
93
94    if (m_connection_ap.get())
95    {
96        ConnectionStatus status = m_connection_ap->Disconnect (error_ptr);
97        // We currently don't protect m_connection_ap with any mutex for
98        // multi-threaded environments. So lets not nuke our connection class
99        // without putting some multi-threaded protections in. We also probably
100        // don't want to pay for the overhead it might cause if every time we
101        // access the connection we have to take a lock.
102        //
103        // This auto_ptr will cleanup after itself when this object goes away,
104        // so there is no need to currently have it destroy itself immediately
105        // upon disconnnect.
106        //m_connection_ap.reset();
107        return status;
108    }
109    return eConnectionStatusNoConnection;
110}
111
112bool
113Communication::IsConnected () const
114{
115    if (m_connection_ap.get())
116        return m_connection_ap->IsConnected ();
117    return false;
118}
119
120bool
121Communication::HasConnection () const
122{
123    return m_connection_ap.get() != NULL;
124}
125
126size_t
127Communication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr)
128{
129    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
130                                 "%p Communication::Write (dst = %p, dst_len = %zu, timeout_usec = %u) connection = %p",
131                                 this, dst, dst_len, timeout_usec, m_connection_ap.get());
132
133    if (m_read_thread != LLDB_INVALID_HOST_THREAD)
134    {
135        // We have a dedicated read thread that is getting data for us
136        size_t cached_bytes = GetCachedBytes (dst, dst_len);
137        if (cached_bytes > 0 || timeout_usec == 0)
138        {
139            status = eConnectionStatusSuccess;
140            return cached_bytes;
141        }
142
143        if (m_connection_ap.get() == NULL)
144        {
145            if (error_ptr)
146                error_ptr->SetErrorString("Invalid connection.");
147            status = eConnectionStatusNoConnection;
148            return 0;
149        }
150        // Set the timeout appropriately
151        TimeValue timeout_time;
152        if (timeout_usec != UINT32_MAX)
153        {
154            timeout_time = TimeValue::Now();
155            timeout_time.OffsetWithMicroSeconds (timeout_usec);
156        }
157
158        Listener listener ("Communication::Read");
159        listener.StartListeningForEvents (this, eBroadcastBitReadThreadGotBytes | eBroadcastBitReadThreadDidExit);
160        EventSP event_sp;
161        while (listener.WaitForEvent (timeout_time.IsValid() ? &timeout_time : NULL, event_sp))
162        {
163            const uint32_t event_type = event_sp->GetType();
164            if (event_type & eBroadcastBitReadThreadGotBytes)
165            {
166                return GetCachedBytes (dst, dst_len);
167            }
168
169            if (event_type & eBroadcastBitReadThreadDidExit)
170            {
171                Disconnect (NULL);
172                break;
173            }
174        }
175        return 0;
176    }
177
178    // We aren't using a read thread, just read the data synchronously in this
179    // thread.
180    if (m_connection_ap.get())
181    {
182        status = m_connection_ap->BytesAvailable (timeout_usec, error_ptr);
183        if (status == eConnectionStatusSuccess)
184            return m_connection_ap->Read (dst, dst_len, status, error_ptr);
185    }
186
187    if (error_ptr)
188        error_ptr->SetErrorString("Invalid connection.");
189    status = eConnectionStatusNoConnection;
190    return 0;
191}
192
193
194size_t
195Communication::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
196{
197    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
198                                 "%p Communication::Write (src = %p, src_len = %zu) connection = %p",
199                                 this, src, src_len, m_connection_ap.get());
200
201    if (m_connection_ap.get())
202        return m_connection_ap->Write (src, src_len, status, error_ptr);
203
204    if (error_ptr)
205        error_ptr->SetErrorString("Invalid connection.");
206    status = eConnectionStatusNoConnection;
207    return 0;
208}
209
210
211bool
212Communication::StartReadThread (Error *error_ptr)
213{
214    if (m_read_thread != LLDB_INVALID_HOST_THREAD)
215        return true;
216
217    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
218                                 "%p Communication::StartReadThread ()", this);
219
220
221    char thread_name[1024];
222    snprintf(thread_name, sizeof(thread_name), "<lldb.comm.%s>", m_broadcaster_name.AsCString());
223
224    m_read_thread_enabled = true;
225    m_read_thread = Host::ThreadCreate (thread_name, Communication::ReadThread, this, error_ptr);
226    if (m_read_thread == LLDB_INVALID_HOST_THREAD)
227        m_read_thread_enabled = false;
228    return m_read_thread_enabled;
229}
230
231bool
232Communication::StopReadThread (Error *error_ptr)
233{
234    if (m_read_thread == LLDB_INVALID_HOST_THREAD)
235        return true;
236
237    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
238                                 "%p Communication::StopReadThread ()", this);
239
240    m_read_thread_enabled = false;
241
242    BroadcastEvent (eBroadcastBitReadThreadShouldExit, NULL);
243
244    Host::ThreadCancel (m_read_thread, error_ptr);
245
246    return Host::ThreadJoin (m_read_thread, NULL, error_ptr);
247    m_read_thread = LLDB_INVALID_HOST_THREAD;
248}
249
250
251size_t
252Communication::GetCachedBytes (void *dst, size_t dst_len)
253{
254    Mutex::Locker locker(m_bytes_mutex);
255    if (m_bytes.size() > 0)
256    {
257        // If DST is NULL and we have a thread, then return the number
258        // of bytes that are available so the caller can call again
259        if (dst == NULL)
260            return m_bytes.size();
261
262        const size_t len = std::min<size_t>(dst_len, m_bytes.size());
263
264        ::memcpy (dst, m_bytes.c_str(), len);
265        m_bytes.erase(m_bytes.begin(), m_bytes.begin() + len);
266
267        return len;
268    }
269    return 0;
270}
271
272void
273Communication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, ConnectionStatus status)
274{
275    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
276                                 "%p Communication::AppendBytesToCache (src = %p, src_len = %zu, broadcast = %i)",
277                                 this, bytes, len, broadcast);
278    if (bytes == NULL || len == 0)
279        return;
280    if (m_callback)
281    {
282        // If the user registered a callback, then call it and do not broadcast
283        m_callback (m_callback_baton, bytes, len);
284    }
285    else
286    {
287        Mutex::Locker locker(m_bytes_mutex);
288        m_bytes.append ((const char *)bytes, len);
289        if (broadcast)
290            BroadcastEventIfUnique (eBroadcastBitReadThreadGotBytes);
291    }
292}
293
294size_t
295Communication::ReadFromConnection (void *dst, size_t dst_len, ConnectionStatus &status, Error *error_ptr)
296{
297    if (m_connection_ap.get())
298        return m_connection_ap->Read (dst, dst_len, status, error_ptr);
299    return 0;
300}
301
302bool
303Communication::ReadThreadIsRunning ()
304{
305    return m_read_thread != LLDB_INVALID_HOST_THREAD;
306}
307
308void *
309Communication::ReadThread (void *p)
310{
311    Communication *comm = (Communication *)p;
312
313    LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION));
314
315    if (log)
316        log->Printf ("%p Communication::ReadThread () thread starting...", p);
317
318    uint8_t buf[1024];
319
320    Error error;
321    ConnectionStatus status = eConnectionStatusSuccess;
322    bool done = false;
323    while (!done && comm->m_read_thread_enabled)
324    {
325        status = comm->BytesAvailable (UINT32_MAX, &error);
326
327        if (status == eConnectionStatusSuccess)
328        {
329            size_t bytes_read = comm->ReadFromConnection (buf, sizeof(buf), status, &error);
330            if (bytes_read > 0)
331                comm->AppendBytesToCache (buf, bytes_read, true, status);
332        }
333
334        switch (status)
335        {
336        case eConnectionStatusSuccess:
337            break;
338
339        case eConnectionStatusEndOfFile:
340        case eConnectionStatusNoConnection:     // No connection
341        case eConnectionStatusLostConnection:   // Lost connection while connected to a valid connection
342            done = true;
343            // Fall through...
344        default:
345        case eConnectionStatusError:            // Check GetError() for details
346        case eConnectionStatusTimedOut:         // Request timed out
347            if (log)
348                error.LogIfError(log.get(), "%p Communication::BytesAvailable () => status = %i", p, status);
349            break;
350        }
351    }
352    log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION);
353    if (log)
354        log->Printf ("%p Communication::ReadThread () thread exiting...", p);
355
356    // Let clients know that this thread is exiting
357    comm->BroadcastEvent (eBroadcastBitReadThreadDidExit);
358    comm->m_read_thread = LLDB_INVALID_HOST_THREAD;
359    comm->Disconnect();
360    return NULL;
361}
362
363void
364Communication::SetReadThreadBytesReceivedCallback
365(
366    ReadThreadBytesReceived callback,
367    void *callback_baton
368)
369{
370    m_callback = callback;
371    m_callback_baton = callback_baton;
372}
373
374void
375Communication::SetConnection (Connection *connection)
376{
377    StopReadThread(NULL);
378    Disconnect (NULL);
379    m_connection_ap.reset(connection);
380}
381
382const char *
383Communication::ConnectionStatusAsCString (lldb::ConnectionStatus status)
384{
385    switch (status)
386    {
387    case eConnectionStatusSuccess:        return "success";
388    case eConnectionStatusError:          return "error";
389    case eConnectionStatusTimedOut:       return "timed out";
390    case eConnectionStatusNoConnection:   return "no connection";
391    case eConnectionStatusLostConnection: return "lost connection";
392    }
393
394    static char unknown_state_string[64];
395    snprintf(unknown_state_string, sizeof (unknown_state_string), "ConnectionStatus = %i", status);
396    return unknown_state_string;
397}
398