Home | History | Annotate | Download | only in impl
      1 //
      2 // detail/impl/handler_tracking.ipp
      3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      4 //
      5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
      6 //
      7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
      8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      9 //
     10 
     11 #ifndef ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP
     12 #define ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP
     13 
     14 
     15 #include "asio/detail/config.hpp"
     16 
     17 #if defined(ASIO_ENABLE_HANDLER_TRACKING)
     18 
     19 #include <cstdarg>
     20 #include <cstdio>
     21 #include "asio/detail/handler_tracking.hpp"
     22 
     23 #  include <chrono>
     24 # include "asio/detail/chrono_time_traits.hpp"
     25 # include "asio/wait_traits.hpp"
     26 
     27 # include <unistd.h>
     28 
     29 #include "asio/detail/push_options.hpp"
     30 
     31 namespace asio {
     32 namespace detail {
     33 
     34 struct handler_tracking_timestamp
     35 {
     36   uint64_t seconds;
     37   uint64_t microseconds;
     38 
     39   handler_tracking_timestamp()
     40   {
     41     typedef chrono_time_traits<std::chrono::system_clock,
     42         asio::wait_traits<std::chrono::system_clock> > traits_helper;
     43     traits_helper::posix_time_duration now(
     44         std::chrono::system_clock::now().time_since_epoch());
     45     seconds = static_cast<uint64_t>(now.total_seconds());
     46     microseconds = static_cast<uint64_t>(now.total_microseconds() % 1000000);
     47   }
     48 };
     49 
     50 struct handler_tracking::tracking_state
     51 {
     52   static_mutex mutex_;
     53   uint64_t next_id_;
     54   tss_ptr<completion>* current_completion_;
     55 };
     56 
     57 handler_tracking::tracking_state* handler_tracking::get_state()
     58 {
     59   static tracking_state state = { ASIO_STATIC_MUTEX_INIT, 1, 0 };
     60   return &state;
     61 }
     62 
     63 void handler_tracking::init()
     64 {
     65   static tracking_state* state = get_state();
     66 
     67   state->mutex_.init();
     68 
     69   static_mutex::scoped_lock lock(state->mutex_);
     70   if (state->current_completion_ == 0)
     71     state->current_completion_ = new tss_ptr<completion>;
     72 }
     73 
     74 void handler_tracking::creation(handler_tracking::tracked_handler* h,
     75     const char* object_type, void* object, const char* op_name)
     76 {
     77   static tracking_state* state = get_state();
     78 
     79   static_mutex::scoped_lock lock(state->mutex_);
     80   h->id_ = state->next_id_++;
     81   lock.unlock();
     82 
     83   handler_tracking_timestamp timestamp;
     84 
     85   uint64_t current_id = 0;
     86   if (completion* current_completion = *state->current_completion_)
     87     current_id = current_completion->id_;
     88 
     89   write_line(
     90       "@asio|%llu.%06llu|%llu*%llu|%.20s@%p.%.50s\n",
     91       timestamp.seconds, timestamp.microseconds,
     92       current_id, h->id_, object_type, object, op_name);
     93 }
     94 
     95 handler_tracking::completion::completion(handler_tracking::tracked_handler* h)
     96   : id_(h->id_),
     97     invoked_(false),
     98     next_(*get_state()->current_completion_)
     99 {
    100   *get_state()->current_completion_ = this;
    101 }
    102 
    103 handler_tracking::completion::~completion()
    104 {
    105   if (id_)
    106   {
    107     handler_tracking_timestamp timestamp;
    108 
    109     write_line(
    110         "@asio|%llu.%06llu|%c%llu|\n",
    111         timestamp.seconds, timestamp.microseconds,
    112         invoked_ ? '!' : '~', id_);
    113   }
    114 
    115   *get_state()->current_completion_ = next_;
    116 }
    117 
    118 void handler_tracking::completion::invocation_begin()
    119 {
    120   handler_tracking_timestamp timestamp;
    121 
    122   write_line(
    123       "@asio|%llu.%06llu|>%llu|\n",
    124       timestamp.seconds, timestamp.microseconds, id_);
    125 
    126   invoked_ = true;
    127 }
    128 
    129 void handler_tracking::completion::invocation_begin(
    130     const asio::error_code& ec)
    131 {
    132   handler_tracking_timestamp timestamp;
    133 
    134   write_line(
    135       "@asio|%llu.%06llu|>%llu|ec=%.20s:%d\n",
    136       timestamp.seconds, timestamp.microseconds,
    137       id_, ec.category().name(), ec.value());
    138 
    139   invoked_ = true;
    140 }
    141 
    142 void handler_tracking::completion::invocation_begin(
    143     const asio::error_code& ec, std::size_t bytes_transferred)
    144 {
    145   handler_tracking_timestamp timestamp;
    146 
    147   write_line(
    148       "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,bytes_transferred=%llu\n",
    149       timestamp.seconds, timestamp.microseconds,
    150       id_, ec.category().name(), ec.value(),
    151       static_cast<uint64_t>(bytes_transferred));
    152 
    153   invoked_ = true;
    154 }
    155 
    156 void handler_tracking::completion::invocation_begin(
    157     const asio::error_code& ec, int signal_number)
    158 {
    159   handler_tracking_timestamp timestamp;
    160 
    161   write_line(
    162       "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,signal_number=%d\n",
    163       timestamp.seconds, timestamp.microseconds,
    164       id_, ec.category().name(), ec.value(), signal_number);
    165 
    166   invoked_ = true;
    167 }
    168 
    169 void handler_tracking::completion::invocation_begin(
    170     const asio::error_code& ec, const char* arg)
    171 {
    172   handler_tracking_timestamp timestamp;
    173 
    174   write_line(
    175       "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,%.50s\n",
    176       timestamp.seconds, timestamp.microseconds,
    177       id_, ec.category().name(), ec.value(), arg);
    178 
    179   invoked_ = true;
    180 }
    181 
    182 void handler_tracking::completion::invocation_end()
    183 {
    184   if (id_)
    185   {
    186     handler_tracking_timestamp timestamp;
    187 
    188     write_line(
    189         "@asio|%llu.%06llu|<%llu|\n",
    190         timestamp.seconds, timestamp.microseconds, id_);
    191 
    192     id_ = 0;
    193   }
    194 }
    195 
    196 void handler_tracking::operation(const char* object_type,
    197     void* object, const char* op_name)
    198 {
    199   static tracking_state* state = get_state();
    200 
    201   handler_tracking_timestamp timestamp;
    202 
    203   unsigned long long current_id = 0;
    204   if (completion* current_completion = *state->current_completion_)
    205     current_id = current_completion->id_;
    206 
    207   write_line(
    208       "@asio|%llu.%06llu|%llu|%.20s@%p.%.50s\n",
    209       timestamp.seconds, timestamp.microseconds,
    210       current_id, object_type, object, op_name);
    211 }
    212 
    213 void handler_tracking::write_line(const char* format, ...)
    214 {
    215   using namespace std; // For sprintf (or equivalent).
    216 
    217   va_list args;
    218   va_start(args, format);
    219 
    220   char line[256] = "";
    221 #if defined(ASIO_HAS_SECURE_RTL)
    222   int length = vsprintf_s(line, sizeof(line), format, args);
    223 #else // defined(ASIO_HAS_SECURE_RTL)
    224   int length = vsprintf(line, format, args);
    225 #endif // defined(ASIO_HAS_SECURE_RTL)
    226 
    227   va_end(args);
    228 
    229   ::write(STDERR_FILENO, line, length);
    230 }
    231 
    232 } // namespace detail
    233 } // namespace asio
    234 
    235 #include "asio/detail/pop_options.hpp"
    236 
    237 #endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
    238 
    239 #endif // ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP
    240