Loading logd/ChattyLogBuffer.cpp +15 −30 Original line number Diff line number Diff line Loading @@ -59,8 +59,6 @@ void ChattyLogBuffer::Init() { ChattyLogBuffer::ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune, LogStatistics* stats) : reader_list_(reader_list), tags_(tags), prune_(prune), stats_(stats) { pthread_rwlock_init(&mLogElementsLock, nullptr); log_id_for_each(i) { lastLoggedElements[i] = nullptr; droppedElements[i] = nullptr; Loading Loading @@ -162,10 +160,8 @@ int ChattyLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pi // b/137093665: don't coalesce security messages. if (log_id == LOG_ID_SECURITY) { wrlock(); auto lock = std::lock_guard{lock_}; log(elem); unlock(); return len; } Loading @@ -189,7 +185,7 @@ int ChattyLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pi return -EACCES; } wrlock(); auto lock = std::lock_guard{lock_}; LogBufferElement* currentLast = lastLoggedElements[log_id]; if (currentLast) { LogBufferElement* dropped = droppedElements[log_id]; Loading Loading @@ -289,14 +285,12 @@ int ChattyLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pi // check for overflow if (total >= std::numeric_limits<int32_t>::max()) { log(currentLast); unlock(); return len; } stats_->AddTotal(currentLast); delete currentLast; swab = total; event->payload.data = htole32(swab); unlock(); return len; } if (count == USHRT_MAX) { Loading @@ -313,7 +307,6 @@ int ChattyLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pi } droppedElements[log_id] = currentLast; lastLoggedElements[log_id] = elem; unlock(); return len; } if (dropped) { // State 1 or 2 Loading @@ -331,12 +324,9 @@ int ChattyLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pi lastLoggedElements[log_id] = new LogBufferElement(*elem); log(elem); unlock(); return len; } // assumes ChattyLogBuffer::wrlock() held, owns elem, look after garbage collection void ChattyLogBuffer::log(LogBufferElement* elem) { mLogElements.push_back(elem); stats_->Add(elem); Loading @@ -344,7 +334,6 @@ void ChattyLogBuffer::log(LogBufferElement* elem) { reader_list_->NotifyNewLog(1 << elem->getLogId()); } // ChattyLogBuffer::wrlock() must be held when this function is called. void ChattyLogBuffer::maybePrune(log_id_t id) { unsigned long prune_rows; if (stats_->ShouldPrune(id, log_buffer_size(id), &prune_rows)) { Loading Loading @@ -540,8 +529,6 @@ void ChattyLogBuffer::kickMe(LogReaderThread* me, log_id_t id, unsigned long pru // The third thread is optional, and only gets hit if there was a whitelist // and more needs to be pruned against the backstop of the region lock. // // ChattyLogBuffer::wrlock() must be held when this function is called. // bool ChattyLogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { LogReaderThread* oldest = nullptr; bool busy = false; Loading Loading @@ -846,9 +833,10 @@ bool ChattyLogBuffer::Clear(log_id_t id, uid_t uid) { // one entry, not another clear run, so we are looking for // the quick side effect of the return value to tell us if // we have a _blocked_ reader. wrlock(); { auto lock = std::lock_guard{lock_}; busy = prune(id, 1, uid); unlock(); } // It is still busy, blocked reader(s), lets kill them all! // otherwise, lets be a good citizen and preserve the slow // readers and let the clear run (below) deal with determining Loading @@ -865,9 +853,10 @@ bool ChattyLogBuffer::Clear(log_id_t id, uid_t uid) { } } } wrlock(); { auto lock = std::lock_guard{lock_}; busy = prune(id, ULONG_MAX, uid); unlock(); } if (!busy || !--retry) { break; } Loading @@ -882,17 +871,15 @@ int ChattyLogBuffer::SetSize(log_id_t id, unsigned long size) { if (!__android_logger_valid_buffer_size(size)) { return -1; } wrlock(); auto lock = std::lock_guard{lock_}; log_buffer_size(id) = size; unlock(); return 0; } // get the total space allocated to "id" unsigned long ChattyLogBuffer::GetSize(log_id_t id) { rdlock(); auto shared_lock = SharedLock{lock_}; size_t retval = log_buffer_size(id); unlock(); return retval; } Loading @@ -902,7 +889,7 @@ uint64_t ChattyLogBuffer::FlushTo( LogBufferElementCollection::iterator it; uid_t uid = writer->uid(); rdlock(); auto shared_lock = SharedLock{lock_}; if (start <= 1) { // client wants to start from the beginning Loading Loading @@ -957,7 +944,7 @@ uint64_t ChattyLogBuffer::FlushTo( (element->getDropped() && !sameTid) ? 0 : element->getTid(); } unlock(); shared_lock.unlock(); curr = element->getSequence(); // range locking in LastLogTimes looks after us Loading @@ -965,9 +952,7 @@ uint64_t ChattyLogBuffer::FlushTo( return FLUSH_ERROR; } rdlock(); shared_lock.lock_shared(); } unlock(); return curr; } logd/ChattyLogBuffer.h +16 −17 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <optional> #include <string> #include <android-base/thread_annotations.h> #include <android/log.h> #include <private/android_filesystem_config.h> #include <sysutils/SocketClient.h> Loading @@ -34,25 +35,25 @@ #include "LogTags.h" #include "LogWhiteBlackList.h" #include "LogWriter.h" #include "rwlock.h" typedef std::list<LogBufferElement*> LogBufferElementCollection; class ChattyLogBuffer : public LogBuffer { LogBufferElementCollection mLogElements; pthread_rwlock_t mLogElementsLock; LogBufferElementCollection mLogElements GUARDED_BY(lock_); // watermark of any worst/chatty uid processing typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator> LogBufferIteratorMap; LogBufferIteratorMap mLastWorst[LOG_ID_MAX]; LogBufferIteratorMap mLastWorst[LOG_ID_MAX] GUARDED_BY(lock_); // watermark of any worst/chatty pid of system processing typedef std::unordered_map<pid_t, LogBufferElementCollection::iterator> LogBufferPidIteratorMap; LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX]; LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX] GUARDED_BY(lock_); unsigned long mMaxSize[LOG_ID_MAX]; unsigned long mMaxSize[LOG_ID_MAX] GUARDED_BY(lock_); LogBufferElement* lastLoggedElements[LOG_ID_MAX]; LogBufferElement* droppedElements[LOG_ID_MAX]; void log(LogBufferElement* elem); LogBufferElement* lastLoggedElements[LOG_ID_MAX] GUARDED_BY(lock_); LogBufferElement* droppedElements[LOG_ID_MAX] GUARDED_BY(lock_); void log(LogBufferElement* elem) REQUIRES(lock_); public: ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune, Loading @@ -71,20 +72,16 @@ class ChattyLogBuffer : public LogBuffer { int SetSize(log_id_t id, unsigned long size) override; private: void wrlock() { pthread_rwlock_wrlock(&mLogElementsLock); } void rdlock() { pthread_rwlock_rdlock(&mLogElementsLock); } void unlock() { pthread_rwlock_unlock(&mLogElementsLock); } void maybePrune(log_id_t id) REQUIRES(lock_); void kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows) REQUIRES_SHARED(lock_); void maybePrune(log_id_t id); void kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows); bool prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT); bool prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT) REQUIRES(lock_); LogBufferElementCollection::iterator erase(LogBufferElementCollection::iterator it, bool coalesce = false); bool coalesce = false) REQUIRES(lock_); // Returns an iterator to the oldest element for a given log type, or mLogElements.end() if // there are no logs for the given log type. Requires mLogElementsLock to be held. LogBufferElementCollection::iterator GetOldest(log_id_t log_id); LogBufferElementCollection::iterator GetOldest(log_id_t log_id) REQUIRES(lock_); LogReaderList* reader_list_; LogTags* tags_; Loading @@ -94,4 +91,6 @@ class ChattyLogBuffer : public LogBuffer { // Keeps track of the iterator to the oldest log message of a given log type, as an // optimization when pruning logs. Use GetOldest() to retrieve. std::optional<LogBufferElementCollection::iterator> oldest_[LOG_ID_MAX]; RwLock lock_; }; logd/rwlock.h 0 → 100644 +56 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <pthread.h> #include <android-base/macros.h> #include <android-base/thread_annotations.h> // As of the end of May 2020, std::shared_mutex is *not* simply a pthread_rwlock, but rather a // combination of std::mutex and std::condition variable, which is obviously less efficient. This // immitates what std::shared_mutex should be doing and is compatible with RAII thread wrappers. class SHARED_CAPABILITY("mutex") RwLock { public: RwLock() {} ~RwLock() {} void lock() ACQUIRE() { pthread_rwlock_wrlock(&rwlock_); } void lock_shared() ACQUIRE_SHARED() { pthread_rwlock_rdlock(&rwlock_); } void unlock() RELEASE() { pthread_rwlock_unlock(&rwlock_); } private: pthread_rwlock_t rwlock_ = PTHREAD_RWLOCK_INITIALIZER; }; // std::shared_lock does not have thread annotations, so we need our own. class SCOPED_CAPABILITY SharedLock { public: SharedLock(RwLock& lock) ACQUIRE_SHARED(lock) : lock_(lock) { lock_.lock_shared(); } ~SharedLock() RELEASE() { lock_.unlock(); } void lock_shared() ACQUIRE_SHARED() { lock_.lock_shared(); } void unlock() RELEASE() { lock_.unlock(); } DISALLOW_IMPLICIT_CONSTRUCTORS(SharedLock); private: RwLock& lock_; }; Loading
logd/ChattyLogBuffer.cpp +15 −30 Original line number Diff line number Diff line Loading @@ -59,8 +59,6 @@ void ChattyLogBuffer::Init() { ChattyLogBuffer::ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune, LogStatistics* stats) : reader_list_(reader_list), tags_(tags), prune_(prune), stats_(stats) { pthread_rwlock_init(&mLogElementsLock, nullptr); log_id_for_each(i) { lastLoggedElements[i] = nullptr; droppedElements[i] = nullptr; Loading Loading @@ -162,10 +160,8 @@ int ChattyLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pi // b/137093665: don't coalesce security messages. if (log_id == LOG_ID_SECURITY) { wrlock(); auto lock = std::lock_guard{lock_}; log(elem); unlock(); return len; } Loading @@ -189,7 +185,7 @@ int ChattyLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pi return -EACCES; } wrlock(); auto lock = std::lock_guard{lock_}; LogBufferElement* currentLast = lastLoggedElements[log_id]; if (currentLast) { LogBufferElement* dropped = droppedElements[log_id]; Loading Loading @@ -289,14 +285,12 @@ int ChattyLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pi // check for overflow if (total >= std::numeric_limits<int32_t>::max()) { log(currentLast); unlock(); return len; } stats_->AddTotal(currentLast); delete currentLast; swab = total; event->payload.data = htole32(swab); unlock(); return len; } if (count == USHRT_MAX) { Loading @@ -313,7 +307,6 @@ int ChattyLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pi } droppedElements[log_id] = currentLast; lastLoggedElements[log_id] = elem; unlock(); return len; } if (dropped) { // State 1 or 2 Loading @@ -331,12 +324,9 @@ int ChattyLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pi lastLoggedElements[log_id] = new LogBufferElement(*elem); log(elem); unlock(); return len; } // assumes ChattyLogBuffer::wrlock() held, owns elem, look after garbage collection void ChattyLogBuffer::log(LogBufferElement* elem) { mLogElements.push_back(elem); stats_->Add(elem); Loading @@ -344,7 +334,6 @@ void ChattyLogBuffer::log(LogBufferElement* elem) { reader_list_->NotifyNewLog(1 << elem->getLogId()); } // ChattyLogBuffer::wrlock() must be held when this function is called. void ChattyLogBuffer::maybePrune(log_id_t id) { unsigned long prune_rows; if (stats_->ShouldPrune(id, log_buffer_size(id), &prune_rows)) { Loading Loading @@ -540,8 +529,6 @@ void ChattyLogBuffer::kickMe(LogReaderThread* me, log_id_t id, unsigned long pru // The third thread is optional, and only gets hit if there was a whitelist // and more needs to be pruned against the backstop of the region lock. // // ChattyLogBuffer::wrlock() must be held when this function is called. // bool ChattyLogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { LogReaderThread* oldest = nullptr; bool busy = false; Loading Loading @@ -846,9 +833,10 @@ bool ChattyLogBuffer::Clear(log_id_t id, uid_t uid) { // one entry, not another clear run, so we are looking for // the quick side effect of the return value to tell us if // we have a _blocked_ reader. wrlock(); { auto lock = std::lock_guard{lock_}; busy = prune(id, 1, uid); unlock(); } // It is still busy, blocked reader(s), lets kill them all! // otherwise, lets be a good citizen and preserve the slow // readers and let the clear run (below) deal with determining Loading @@ -865,9 +853,10 @@ bool ChattyLogBuffer::Clear(log_id_t id, uid_t uid) { } } } wrlock(); { auto lock = std::lock_guard{lock_}; busy = prune(id, ULONG_MAX, uid); unlock(); } if (!busy || !--retry) { break; } Loading @@ -882,17 +871,15 @@ int ChattyLogBuffer::SetSize(log_id_t id, unsigned long size) { if (!__android_logger_valid_buffer_size(size)) { return -1; } wrlock(); auto lock = std::lock_guard{lock_}; log_buffer_size(id) = size; unlock(); return 0; } // get the total space allocated to "id" unsigned long ChattyLogBuffer::GetSize(log_id_t id) { rdlock(); auto shared_lock = SharedLock{lock_}; size_t retval = log_buffer_size(id); unlock(); return retval; } Loading @@ -902,7 +889,7 @@ uint64_t ChattyLogBuffer::FlushTo( LogBufferElementCollection::iterator it; uid_t uid = writer->uid(); rdlock(); auto shared_lock = SharedLock{lock_}; if (start <= 1) { // client wants to start from the beginning Loading Loading @@ -957,7 +944,7 @@ uint64_t ChattyLogBuffer::FlushTo( (element->getDropped() && !sameTid) ? 0 : element->getTid(); } unlock(); shared_lock.unlock(); curr = element->getSequence(); // range locking in LastLogTimes looks after us Loading @@ -965,9 +952,7 @@ uint64_t ChattyLogBuffer::FlushTo( return FLUSH_ERROR; } rdlock(); shared_lock.lock_shared(); } unlock(); return curr; }
logd/ChattyLogBuffer.h +16 −17 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <optional> #include <string> #include <android-base/thread_annotations.h> #include <android/log.h> #include <private/android_filesystem_config.h> #include <sysutils/SocketClient.h> Loading @@ -34,25 +35,25 @@ #include "LogTags.h" #include "LogWhiteBlackList.h" #include "LogWriter.h" #include "rwlock.h" typedef std::list<LogBufferElement*> LogBufferElementCollection; class ChattyLogBuffer : public LogBuffer { LogBufferElementCollection mLogElements; pthread_rwlock_t mLogElementsLock; LogBufferElementCollection mLogElements GUARDED_BY(lock_); // watermark of any worst/chatty uid processing typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator> LogBufferIteratorMap; LogBufferIteratorMap mLastWorst[LOG_ID_MAX]; LogBufferIteratorMap mLastWorst[LOG_ID_MAX] GUARDED_BY(lock_); // watermark of any worst/chatty pid of system processing typedef std::unordered_map<pid_t, LogBufferElementCollection::iterator> LogBufferPidIteratorMap; LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX]; LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX] GUARDED_BY(lock_); unsigned long mMaxSize[LOG_ID_MAX]; unsigned long mMaxSize[LOG_ID_MAX] GUARDED_BY(lock_); LogBufferElement* lastLoggedElements[LOG_ID_MAX]; LogBufferElement* droppedElements[LOG_ID_MAX]; void log(LogBufferElement* elem); LogBufferElement* lastLoggedElements[LOG_ID_MAX] GUARDED_BY(lock_); LogBufferElement* droppedElements[LOG_ID_MAX] GUARDED_BY(lock_); void log(LogBufferElement* elem) REQUIRES(lock_); public: ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune, Loading @@ -71,20 +72,16 @@ class ChattyLogBuffer : public LogBuffer { int SetSize(log_id_t id, unsigned long size) override; private: void wrlock() { pthread_rwlock_wrlock(&mLogElementsLock); } void rdlock() { pthread_rwlock_rdlock(&mLogElementsLock); } void unlock() { pthread_rwlock_unlock(&mLogElementsLock); } void maybePrune(log_id_t id) REQUIRES(lock_); void kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows) REQUIRES_SHARED(lock_); void maybePrune(log_id_t id); void kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows); bool prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT); bool prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT) REQUIRES(lock_); LogBufferElementCollection::iterator erase(LogBufferElementCollection::iterator it, bool coalesce = false); bool coalesce = false) REQUIRES(lock_); // Returns an iterator to the oldest element for a given log type, or mLogElements.end() if // there are no logs for the given log type. Requires mLogElementsLock to be held. LogBufferElementCollection::iterator GetOldest(log_id_t log_id); LogBufferElementCollection::iterator GetOldest(log_id_t log_id) REQUIRES(lock_); LogReaderList* reader_list_; LogTags* tags_; Loading @@ -94,4 +91,6 @@ class ChattyLogBuffer : public LogBuffer { // Keeps track of the iterator to the oldest log message of a given log type, as an // optimization when pruning logs. Use GetOldest() to retrieve. std::optional<LogBufferElementCollection::iterator> oldest_[LOG_ID_MAX]; RwLock lock_; };
logd/rwlock.h 0 → 100644 +56 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <pthread.h> #include <android-base/macros.h> #include <android-base/thread_annotations.h> // As of the end of May 2020, std::shared_mutex is *not* simply a pthread_rwlock, but rather a // combination of std::mutex and std::condition variable, which is obviously less efficient. This // immitates what std::shared_mutex should be doing and is compatible with RAII thread wrappers. class SHARED_CAPABILITY("mutex") RwLock { public: RwLock() {} ~RwLock() {} void lock() ACQUIRE() { pthread_rwlock_wrlock(&rwlock_); } void lock_shared() ACQUIRE_SHARED() { pthread_rwlock_rdlock(&rwlock_); } void unlock() RELEASE() { pthread_rwlock_unlock(&rwlock_); } private: pthread_rwlock_t rwlock_ = PTHREAD_RWLOCK_INITIALIZER; }; // std::shared_lock does not have thread annotations, so we need our own. class SCOPED_CAPABILITY SharedLock { public: SharedLock(RwLock& lock) ACQUIRE_SHARED(lock) : lock_(lock) { lock_.lock_shared(); } ~SharedLock() RELEASE() { lock_.unlock(); } void lock_shared() ACQUIRE_SHARED() { lock_.lock_shared(); } void unlock() RELEASE() { lock_.unlock(); } DISALLOW_IMPLICIT_CONSTRUCTORS(SharedLock); private: RwLock& lock_; };