diff options
| author | Mark Salyzyn <salyzyn@google.com> | 2014-02-26 21:29:13 +0000 |
|---|---|---|
| committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-02-26 21:29:14 +0000 |
| commit | e9c8fb900a460699201208870ce9997a734261cc (patch) | |
| tree | ad732d45fc8de64bad45ddb57582bc8930482a16 /logd/LogBuffer.cpp | |
| parent | ca1e34385706b954e6974094285924d8ff59f860 (diff) | |
| parent | 0175b0747a1f55329109e84c9a1322dcb95e2848 (diff) | |
| download | system_core-e9c8fb900a460699201208870ce9997a734261cc.zip system_core-e9c8fb900a460699201208870ce9997a734261cc.tar.gz system_core-e9c8fb900a460699201208870ce9997a734261cc.tar.bz2 | |
Merge "logd: initial checkin."
Diffstat (limited to 'logd/LogBuffer.cpp')
| -rw-r--r-- | logd/LogBuffer.cpp | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp new file mode 100644 index 0000000..8b273e2 --- /dev/null +++ b/logd/LogBuffer.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2012-2014 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/LICENSE-2.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. + */ + +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include <log/logger.h> + +#include "LogBuffer.h" +#include "LogReader.h" + +#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here? + +LogBuffer::LogBuffer(LastLogTimes *times) + : mTimes(*times) { + int i; + for (i = 0; i < LOG_ID_MAX; i++) { + mSizes[i] = 0; + mElements[i] = 0; + } + pthread_mutex_init(&mLogElementsLock, NULL); +} + +void LogBuffer::log(log_id_t log_id, struct timespec realtime, + uid_t uid, pid_t pid, const char *msg, + unsigned short len) { + if ((log_id >= LOG_ID_MAX) || (log_id < 0)) { + return; + } + LogBufferElement *elem = new LogBufferElement(log_id, realtime, + uid, pid, msg, len); + + pthread_mutex_lock(&mLogElementsLock); + + // Insert elements in time sorted order if possible + // NB: if end is region locked, place element at end of list + LogBufferElementCollection::iterator it = mLogElements.end(); + LogBufferElementCollection::iterator last = it; + while (--it != mLogElements.begin()) { + if ((*it)->getRealTime() <= elem->getRealTime()) { + break; + } + last = it; + } + if (last == mLogElements.end()) { + mLogElements.push_back(elem); + } else { + log_time end; + bool end_set = false; + bool end_always = false; + + LogTimeEntry::lock(); + + LastLogTimes::iterator t = mTimes.begin(); + while(t != mTimes.end()) { + LogTimeEntry *entry = (*t); + if (entry->owned_Locked()) { + if (!entry->mNonBlock) { + end_always = true; + break; + } + if (!end_set || (end <= entry->mEnd)) { + end = entry->mEnd; + end_set = true; + } + } + t++; + } + + if (end_always + || (end_set && (end >= (*last)->getMonotonicTime()))) { + mLogElements.push_back(elem); + } else { + mLogElements.insert(last,elem); + } + + LogTimeEntry::unlock(); + } + + mSizes[log_id] += len; + mElements[log_id]++; + maybePrune(log_id); + pthread_mutex_unlock(&mLogElementsLock); +} + +// If we're using more than 256K of memory for log entries, prune +// 10% of the log entries. +// +// mLogElementsLock must be held when this function is called. +void LogBuffer::maybePrune(log_id_t id) { + if (mSizes[id] > LOG_BUFFER_SIZE) { + prune(id, mElements[id] / 10); + } +} + +// prune "pruneRows" of type "id" from the buffer. +// +// mLogElementsLock must be held when this function is called. +void LogBuffer::prune(log_id_t id, unsigned long pruneRows) { + LogTimeEntry *oldest = NULL; + + LogTimeEntry::lock(); + + // Region locked? + LastLogTimes::iterator t = mTimes.begin(); + while(t != mTimes.end()) { + LogTimeEntry *entry = (*t); + if (entry->owned_Locked() + && (!oldest || (oldest->mStart > entry->mStart))) { + oldest = entry; + } + t++; + } + + LogBufferElementCollection::iterator it = mLogElements.begin(); + while((pruneRows > 0) && (it != mLogElements.end())) { + LogBufferElement *e = *it; + if (e->getLogId() == id) { + if (oldest && (oldest->mStart <= e->getMonotonicTime())) { + if (mSizes[id] > (2 * LOG_BUFFER_SIZE)) { + // kick a misbehaving log reader client off the island + oldest->release_Locked(); + } else { + oldest->triggerSkip_Locked(pruneRows); + } + break; + } + it = mLogElements.erase(it); + mSizes[id] -= e->getMsgLen(); + mElements[id]--; + delete e; + pruneRows--; + } else { + it++; + } + } + + LogTimeEntry::unlock(); +} + +// clear all rows of type "id" from the buffer. +void LogBuffer::clear(log_id_t id) { + pthread_mutex_lock(&mLogElementsLock); + prune(id, ULONG_MAX); + pthread_mutex_unlock(&mLogElementsLock); +} + +// get the used space associated with "id". +unsigned long LogBuffer::getSizeUsed(log_id_t id) { + pthread_mutex_lock(&mLogElementsLock); + unsigned long retval = mSizes[id]; + pthread_mutex_unlock(&mLogElementsLock); + return retval; +} + +// get the total space allocated to "id" +unsigned long LogBuffer::getSize(log_id_t /*id*/) { + return LOG_BUFFER_SIZE; +} + +struct timespec LogBuffer::flushTo( + SocketClient *reader, const struct timespec start, bool privileged, + bool (*filter)(const LogBufferElement *element, void *arg), void *arg) { + LogBufferElementCollection::iterator it; + log_time max = start; + uid_t uid = reader->getUid(); + + pthread_mutex_lock(&mLogElementsLock); + for (it = mLogElements.begin(); it != mLogElements.end(); ++it) { + LogBufferElement *element = *it; + + if (!privileged && (element->getUid() != uid)) { + continue; + } + + if (element->getMonotonicTime() <= start) { + continue; + } + + // NB: calling out to another object with mLogElementsLock held (safe) + if (filter && !(*filter)(element, arg)) { + continue; + } + + pthread_mutex_unlock(&mLogElementsLock); + + // range locking in LastLogTimes looks after us + max = element->flushTo(reader); + + if (max == element->FLUSH_ERROR) { + return max; + } + + pthread_mutex_lock(&mLogElementsLock); + } + pthread_mutex_unlock(&mLogElementsLock); + + return max; +} |
