LCOV - code coverage report
Current view: top level - media/libcubeb/src - cubeb_log.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 48 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright © 2016 Mozilla Foundation
       3             :  *
       4             :  * This program is made available under an ISC-style license.  See the
       5             :  * accompanying file LICENSE for details.
       6             :  */
       7             : #define NOMINMAX
       8             : 
       9             : #include "cubeb_log.h"
      10             : #include "cubeb_ringbuffer.h"
      11             : #include <cstdarg>
      12             : #ifdef _WIN32
      13             : #include <windows.h>
      14             : #else
      15             : #include <time.h>
      16             : #endif
      17             : 
      18             : cubeb_log_level g_cubeb_log_level;
      19             : cubeb_log_callback g_cubeb_log_callback;
      20             : 
      21             : /** The maximum size of a log message, after having been formatted. */
      22             : const size_t CUBEB_LOG_MESSAGE_MAX_SIZE = 256;
      23             : /** The maximum number of log messages that can be queued before dropping
      24             :  * messages. */
      25             : const size_t CUBEB_LOG_MESSAGE_QUEUE_DEPTH = 40;
      26             : /** Number of milliseconds to wait before dequeuing log messages. */
      27             : #define CUBEB_LOG_BATCH_PRINT_INTERVAL_MS 10
      28             : 
      29             : /**
      30             :   * This wraps an inline buffer, that represents a log message, that must be
      31             :   * null-terminated.
      32             :   * This class should not use system calls or other potentially blocking code.
      33             :   */
      34             : class cubeb_log_message
      35             : {
      36             : public:
      37           0 :   cubeb_log_message()
      38           0 :   {
      39           0 :     *storage = '\0';
      40           0 :   }
      41           0 :   cubeb_log_message(char const str[CUBEB_LOG_MESSAGE_MAX_SIZE])
      42           0 :   {
      43           0 :     size_t length = strlen(str);
      44             :     /* paranoia against malformed message */
      45           0 :     assert(length < CUBEB_LOG_MESSAGE_MAX_SIZE);
      46           0 :     if (length > CUBEB_LOG_MESSAGE_MAX_SIZE - 1) {
      47           0 :       return;
      48             :     }
      49           0 :     PodCopy(storage, str, length);
      50           0 :     storage[length] = '\0';
      51             :   }
      52           0 :   char const * get() {
      53           0 :     return storage;
      54             :   }
      55             : private:
      56             :   char storage[CUBEB_LOG_MESSAGE_MAX_SIZE];
      57             : };
      58             : 
      59             : /** Lock-free asynchronous logger, made so that logging from a
      60             :  *  real-time audio callback does not block the audio thread. */
      61           0 : class cubeb_async_logger
      62             : {
      63             : public:
      64             :   /* This is thread-safe since C++11 */
      65           0 :   static cubeb_async_logger & get() {
      66           0 :     static cubeb_async_logger instance;
      67           0 :     return instance;
      68             :   }
      69           0 :   void push(char const str[CUBEB_LOG_MESSAGE_MAX_SIZE])
      70             :   {
      71           0 :     cubeb_log_message msg(str);
      72           0 :     msg_queue.enqueue(msg);
      73           0 :   }
      74           0 :   void run()
      75             :   {
      76           0 :     std::thread([this]() {
      77             :       while (true) {
      78           0 :         cubeb_log_message msg;
      79           0 :         while (msg_queue.dequeue(&msg, 1)) {
      80           0 :           LOGV("%s", msg.get());
      81             :         }
      82             : #ifdef _WIN32
      83             :         Sleep(CUBEB_LOG_BATCH_PRINT_INTERVAL_MS);
      84             : #else
      85           0 :         timespec sleep_duration = sleep_for;
      86             :         timespec remainder;
      87           0 :         do {
      88           0 :           if (nanosleep(&sleep_duration, &remainder) == 0 ||
      89           0 :               errno != EINTR) {
      90           0 :             break;
      91             :           }
      92           0 :           sleep_duration = remainder;
      93           0 :         } while (remainder.tv_sec || remainder.tv_nsec);
      94             : #endif
      95           0 :       }
      96           0 :     }).detach();
      97           0 :   }
      98             : private:
      99             : #ifndef _WIN32
     100             :   const struct timespec sleep_for = {
     101             :     CUBEB_LOG_BATCH_PRINT_INTERVAL_MS/1000,
     102             :     (CUBEB_LOG_BATCH_PRINT_INTERVAL_MS%1000)*1000*1000
     103             :   };
     104             : #endif
     105           0 :   cubeb_async_logger()
     106           0 :     : msg_queue(CUBEB_LOG_MESSAGE_QUEUE_DEPTH)
     107             :   {
     108           0 :     run();
     109           0 :   }
     110             :   /** This is quite a big data structure, but is only instantiated if the
     111             :    * asynchronous logger is used.*/
     112             :   lock_free_queue<cubeb_log_message> msg_queue;
     113             : };
     114             : 
     115             : 
     116           0 : void cubeb_async_log(char const * fmt, ...)
     117             : {
     118           0 :   if (!g_cubeb_log_callback) {
     119           0 :     return;
     120             :   }
     121             :   // This is going to copy a 256 bytes array around, which is fine.
     122             :   // We don't want to allocate memory here, because this is made to
     123             :   // be called from a real-time callback.
     124             :   va_list args;
     125           0 :   va_start(args, fmt);
     126             :   char msg[CUBEB_LOG_MESSAGE_MAX_SIZE];
     127           0 :   vsnprintf(msg, CUBEB_LOG_MESSAGE_MAX_SIZE, fmt, args);
     128           0 :   cubeb_async_logger::get().push(msg);
     129           0 :   va_end(args);
     130             : }

Generated by: LCOV version 1.13