LogTimes.cpp revision 3e76e0a49760c4970b7cda6153e51026af98e4f3
1/* 2 * Copyright (C) 2014 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 "FlushCommand.h" 18#include "LogBuffer.h" 19#include "LogTimes.h" 20#include "LogReader.h" 21 22pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER; 23 24const struct timespec LogTimeEntry::EPOCH = { 0, 1 }; 25 26LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client, 27 bool nonBlock, unsigned long tail, 28 unsigned int logMask, pid_t pid) 29 : mRefCount(1) 30 , mRelease(false) 31 , mError(false) 32 , threadRunning(false) 33 , threadTriggered(true) 34 , mReader(reader) 35 , mLogMask(logMask) 36 , mPid(pid) 37 , skipAhead(0) 38 , mCount(0) 39 , mTail(tail) 40 , mIndex(0) 41 , mClient(client) 42 , mStart(EPOCH) 43 , mNonBlock(nonBlock) 44 , mEnd(CLOCK_MONOTONIC) 45{ } 46 47void LogTimeEntry::startReader_Locked(void) { 48 threadRunning = true; 49 if (pthread_create(&mThread, NULL, LogTimeEntry::threadStart, this)) { 50 threadRunning = false; 51 if (mClient) { 52 mClient->decRef(); 53 } 54 decRef_Locked(); 55 } 56} 57 58void LogTimeEntry::threadStop(void *obj) { 59 LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); 60 61 lock(); 62 63 me->threadRunning = false; 64 if (me->mNonBlock) { 65 me->error_Locked(); 66 } 67 68 SocketClient *client = me->mClient; 69 70 if (me->isError_Locked()) { 71 LogReader &reader = me->mReader; 72 LastLogTimes × = reader.logbuf().mTimes; 73 74 LastLogTimes::iterator it = times.begin(); 75 while(it != times.end()) { 76 if (*it == me) { 77 times.erase(it); 78 me->release_Locked(); 79 break; 80 } 81 it++; 82 } 83 84 me->mClient = NULL; 85 reader.release(client); 86 } 87 88 if (client) { 89 client->decRef(); 90 } 91 92 me->decRef_Locked(); 93 94 unlock(); 95} 96 97void *LogTimeEntry::threadStart(void *obj) { 98 LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); 99 100 pthread_cleanup_push(threadStop, obj); 101 102 SocketClient *client = me->mClient; 103 if (!client) { 104 me->error(); 105 pthread_exit(NULL); 106 } 107 108 LogBuffer &logbuf = me->mReader.logbuf(); 109 110 bool privileged = FlushCommand::hasReadLogs(client); 111 112 lock(); 113 114 me->threadTriggered = true; 115 116 while(me->threadTriggered && !me->isError_Locked()) { 117 118 me->threadTriggered = false; 119 120 log_time start = me->mStart; 121 122 unlock(); 123 124 if (me->mTail) { 125 logbuf.flushTo(client, start, privileged, FilterFirstPass, me); 126 } 127 start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me); 128 129 if (start == LogBufferElement::FLUSH_ERROR) { 130 me->error(); 131 } 132 133 if (me->mNonBlock) { 134 lock(); 135 break; 136 } 137 138 sched_yield(); 139 140 lock(); 141 } 142 143 unlock(); 144 145 pthread_exit(NULL); 146 147 pthread_cleanup_pop(true); 148 149 return NULL; 150} 151 152// A first pass to count the number of elements 153bool LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) { 154 LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); 155 156 LogTimeEntry::lock(); 157 158 if (me->mCount == 0) { 159 me->mStart = element->getMonotonicTime(); 160 } 161 162 if ((!me->mPid || (me->mPid == element->getPid())) 163 && (me->mLogMask & (1 << element->getLogId()))) { 164 ++me->mCount; 165 } 166 167 LogTimeEntry::unlock(); 168 169 return false; 170} 171 172// A second pass to send the selected elements 173bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) { 174 LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); 175 176 LogTimeEntry::lock(); 177 178 if (me->skipAhead) { 179 me->skipAhead--; 180 } 181 182 me->mStart = element->getMonotonicTime(); 183 184 // Truncate to close race between first and second pass 185 if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) { 186 goto skip; 187 } 188 189 if ((me->mLogMask & (1 << element->getLogId())) == 0) { 190 goto skip; 191 } 192 193 if (me->mPid && (me->mPid != element->getPid())) { 194 goto skip; 195 } 196 197 if (me->isError_Locked()) { 198 goto skip; 199 } 200 201 if (!me->mTail) { 202 goto ok; 203 } 204 205 ++me->mIndex; 206 207 if ((me->mCount > me->mTail) && (me->mIndex <= (me->mCount - me->mTail))) { 208 goto skip; 209 } 210 211 if (!me->mNonBlock) { 212 me->mTail = 0; 213 } 214 215ok: 216 if (!me->skipAhead) { 217 LogTimeEntry::unlock(); 218 return true; 219 } 220 // FALLTHRU 221 222skip: 223 LogTimeEntry::unlock(); 224 return false; 225} 226