Home | History | Annotate | Download | only in Core
      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 
     23 using namespace lldb;
     24 using namespace lldb_private;
     25 
     26 ConstString &
     27 Communication::GetStaticBroadcasterClass ()
     28 {
     29     static ConstString class_name ("lldb.communication");
     30     return class_name;
     31 }
     32 
     33 //----------------------------------------------------------------------
     34 // Constructor
     35 //----------------------------------------------------------------------
     36 Communication::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 //----------------------------------------------------------------------
     65 Communication::~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 
     73 void
     74 Communication::Clear()
     75 {
     76     SetReadThreadBytesReceivedCallback (NULL, NULL);
     77     Disconnect (NULL);
     78     StopReadThread (NULL);
     79 }
     80 
     81 ConnectionStatus
     82 Communication::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 
     96 ConnectionStatus
     97 Communication::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 
    120 bool
    121 Communication::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 
    129 bool
    130 Communication::HasConnection () const
    131 {
    132     return m_connection_sp.get() != NULL;
    133 }
    134 
    135 size_t
    136 Communication::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 
    206 size_t
    207 Communication::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 
    229 bool
    230 Communication::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 
    252 bool
    253 Communication::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 
    272 
    273 size_t
    274 Communication::GetCachedBytes (void *dst, size_t dst_len)
    275 {
    276     Mutex::Locker locker(m_bytes_mutex);
    277     if (m_bytes.size() > 0)
    278     {
    279         // If DST is NULL and we have a thread, then return the number
    280         // of bytes that are available so the caller can call again
    281         if (dst == NULL)
    282             return m_bytes.size();
    283 
    284         const size_t len = std::min<size_t>(dst_len, m_bytes.size());
    285 
    286         ::memcpy (dst, m_bytes.c_str(), len);
    287         m_bytes.erase(m_bytes.begin(), m_bytes.begin() + len);
    288 
    289         return len;
    290     }
    291     return 0;
    292 }
    293 
    294 void
    295 Communication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, ConnectionStatus status)
    296 {
    297     lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
    298                                  "%p Communication::AppendBytesToCache (src = %p, src_len = %" PRIu64 ", broadcast = %i)",
    299                                  this, bytes, (uint64_t)len, broadcast);
    300     if ((bytes == NULL || len == 0)
    301         && (status != lldb::eConnectionStatusEndOfFile))
    302         return;
    303     if (m_callback)
    304     {
    305         // If the user registered a callback, then call it and do not broadcast
    306         m_callback (m_callback_baton, bytes, len);
    307     }
    308     else if (bytes != NULL && len > 0)
    309     {
    310         Mutex::Locker locker(m_bytes_mutex);
    311         m_bytes.append ((const char *)bytes, len);
    312         if (broadcast)
    313             BroadcastEventIfUnique (eBroadcastBitReadThreadGotBytes);
    314     }
    315 }
    316 
    317 size_t
    318 Communication::ReadFromConnection (void *dst,
    319                                    size_t dst_len,
    320                                    uint32_t timeout_usec,
    321                                    ConnectionStatus &status,
    322                                    Error *error_ptr)
    323 {
    324     lldb::ConnectionSP connection_sp (m_connection_sp);
    325     if (connection_sp.get())
    326         return connection_sp->Read (dst, dst_len, timeout_usec, status, error_ptr);
    327     return 0;
    328 }
    329 
    330 bool
    331 Communication::ReadThreadIsRunning ()
    332 {
    333     return m_read_thread_enabled;
    334 }
    335 
    336 void *
    337 Communication::ReadThread (void *p)
    338 {
    339     Communication *comm = (Communication *)p;
    340 
    341     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION));
    342 
    343     if (log)
    344         log->Printf ("%p Communication::ReadThread () thread starting...", p);
    345 
    346     uint8_t buf[1024];
    347 
    348     Error error;
    349     ConnectionStatus status = eConnectionStatusSuccess;
    350     bool done = false;
    351     while (!done && comm->m_read_thread_enabled)
    352     {
    353         size_t bytes_read = comm->ReadFromConnection (buf, sizeof(buf), 5 * TimeValue::MicroSecPerSec, status, &error);
    354         if (bytes_read > 0)
    355             comm->AppendBytesToCache (buf, bytes_read, true, status);
    356         else if ((bytes_read == 0)
    357                 && status == eConnectionStatusEndOfFile)
    358         {
    359             if (comm->GetCloseOnEOF ())
    360                 comm->Disconnect ();
    361             comm->AppendBytesToCache (buf, bytes_read, true, status);
    362         }
    363 
    364         switch (status)
    365         {
    366         case eConnectionStatusSuccess:
    367             break;
    368 
    369         case eConnectionStatusEndOfFile:
    370             if (comm->GetCloseOnEOF())
    371                  done = true;
    372              break;
    373         case eConnectionStatusNoConnection:     // No connection
    374         case eConnectionStatusLostConnection:   // Lost connection while connected to a valid connection
    375             done = true;
    376             // Fall through...
    377         case eConnectionStatusError:            // Check GetError() for details
    378         case eConnectionStatusTimedOut:         // Request timed out
    379             if (log)
    380                 error.LogIfError (log,
    381                                   "%p Communication::ReadFromConnection () => status = %s",
    382                                   p,
    383                                   Communication::ConnectionStatusAsCString (status));
    384             break;
    385         }
    386     }
    387     log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION);
    388     if (log)
    389         log->Printf ("%p Communication::ReadThread () thread exiting...", p);
    390 
    391     // Let clients know that this thread is exiting
    392     comm->BroadcastEvent (eBroadcastBitReadThreadDidExit);
    393     return NULL;
    394 }
    395 
    396 void
    397 Communication::SetReadThreadBytesReceivedCallback
    398 (
    399     ReadThreadBytesReceived callback,
    400     void *callback_baton
    401 )
    402 {
    403     m_callback = callback;
    404     m_callback_baton = callback_baton;
    405 }
    406 
    407 void
    408 Communication::SetConnection (Connection *connection)
    409 {
    410     Disconnect (NULL);
    411     StopReadThread(NULL);
    412     m_connection_sp.reset(connection);
    413 }
    414 
    415 const char *
    416 Communication::ConnectionStatusAsCString (lldb::ConnectionStatus status)
    417 {
    418     switch (status)
    419     {
    420     case eConnectionStatusSuccess:        return "success";
    421     case eConnectionStatusError:          return "error";
    422     case eConnectionStatusTimedOut:       return "timed out";
    423     case eConnectionStatusNoConnection:   return "no connection";
    424     case eConnectionStatusLostConnection: return "lost connection";
    425     case eConnectionStatusEndOfFile:      return "end of file";
    426     }
    427 
    428     static char unknown_state_string[64];
    429     snprintf(unknown_state_string, sizeof (unknown_state_string), "ConnectionStatus = %i", status);
    430     return unknown_state_string;
    431 }
    432