Home | History | Annotate | Download | only in linux
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "chre/platform/shared/platform_log.h"
     18 
     19 #include <cstdarg>
     20 #include <cstdio>
     21 #include <iostream>
     22 
     23 namespace chre {
     24 
     25 void PlatformLogBase::logLooper() {
     26   while (1) {
     27     std::unique_ptr<char> logMessage;
     28 
     29     {
     30       std::unique_lock<std::mutex> lock(mMutex);
     31       mConditionVariable.wait(lock, [this]{
     32         return (!mLogQueue.empty() || mStopLogger);
     33       });
     34 
     35       if (!mLogQueue.empty()) {
     36         // Move the log message to avoid holding a lock for longer than
     37         // required.
     38         logMessage = std::move(mLogQueue.front());
     39         mLogQueue.pop();
     40       } else if (mStopLogger) {
     41         // The stop logger is checked in an else-if to allow the main log queue
     42         // to drain when the logger is stopping.
     43         break;
     44       }
     45     }
     46 
     47     // If we get here, there must be a log message to output. This is outside of
     48     // the context of the lock which means that the logging thread will only be
     49     // blocked for the minimum amount of time.
     50     std::cerr << logMessage.get() << std::endl;
     51   }
     52 }
     53 
     54 PlatformLog::PlatformLog() {
     55   mLoggerThread = std::thread(&PlatformLog::logLooper, this);
     56 }
     57 
     58 PlatformLog::~PlatformLog() {
     59   {
     60     std::unique_lock<std::mutex> lock(mMutex);
     61     mStopLogger = true;
     62     mConditionVariable.notify_one();
     63   }
     64 
     65   mLoggerThread.join();
     66 }
     67 
     68 void PlatformLog::log(const char *formatStr, ...) {
     69   char *formattedStr;
     70   va_list argList;
     71   va_start(argList, formatStr);
     72   int result = vasprintf(&formattedStr, formatStr, argList);
     73   va_end(argList);
     74 
     75   if (result >= 0) {
     76     // Wrap the formatted string into a unique_ptr so that it will be free'd
     77     // once it has been logged.
     78     std::unique_ptr<char> log(formattedStr);
     79 
     80     std::unique_lock<std::mutex> lock(mMutex);
     81     mLogQueue.push(std::move(log));
     82     mConditionVariable.notify_one();
     83   } else {
     84     std::cerr << "Failed to allocate log message" << std::endl;
     85     abort();
     86   }
     87 }
     88 
     89 }  // namespace chre
     90