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