diff options
Diffstat (limited to 'logd/LogTimes.cpp')
-rw-r--r-- | logd/LogTimes.cpp | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp new file mode 100644 index 000000000..d6d4e9331 --- /dev/null +++ b/logd/LogTimes.cpp | |||
@@ -0,0 +1,225 @@ | |||
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 | |||
22 | pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER; | ||
23 | |||
24 | const struct timespec LogTimeEntry::EPOCH = { 0, 1 }; | ||
25 | |||
26 | LogTimeEntry::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 | |||
47 | void 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 | |||
58 | void 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 | |||
97 | void *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 | ||
153 | bool 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 | ||
173 | bool 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 | |||
215 | ok: | ||
216 | if (!me->skipAhead) { | ||
217 | LogTimeEntry::unlock(); | ||
218 | return true; | ||
219 | } | ||
220 | // FALLTHRU | ||
221 | |||
222 | skip: | ||
223 | LogTimeEntry::unlock(); | ||
224 | return false; | ||
225 | } | ||