void *LogTimeEntry::threadStart(void *obj) { prctl(PR_SET_NAME, "logd.reader.per"); LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); pthread_cleanup_push(threadStop, obj); SocketClient *client = me->mClient; if (!client) { me->error(); return NULL; } LogBuffer &logbuf = me->mReader.logbuf(); bool privileged = FlushCommand::hasReadLogs(client); lock(); while (me->threadRunning && !me->isError_Locked()) { uint64_t start = me->mStart; unlock(); if (me->mTail) { logbuf.flushTo(client, start, privileged, FilterFirstPass, me); } start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me); lock(); if (start == LogBufferElement::FLUSH_ERROR) { me->error_Locked(); } if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) { break; } me->cleanSkip_Locked(); pthread_cond_wait(&me->threadTriggeredCondition, ×Lock); } unlock(); pthread_cleanup_pop(true); return NULL; }
// A second pass to send the selected elements int LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) { LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); LogTimeEntry::lock(); me->mStart = element->getSequence(); if (me->skipAhead[element->getLogId()]) { me->skipAhead[element->getLogId()]--; goto skip; } // Truncate to close race between first and second pass if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) { goto stop; } if (!me->isWatching(element->getLogId())) { goto skip; } if (me->mPid && (me->mPid != element->getPid())) { goto skip; } if (me->isError_Locked()) { goto stop; } if (!me->mTail) { goto ok; } ++me->mIndex; if ((me->mCount > me->mTail) && (me->mIndex <= (me->mCount - me->mTail))) { goto skip; } if (!me->mNonBlock) { me->mTail = 0; } ok: if (!me->skipAhead[element->getLogId()]) { LogTimeEntry::unlock(); return true; } // FALLTHRU skip: LogTimeEntry::unlock(); return false; stop: LogTimeEntry::unlock(); return -1; }
void *LogTimeEntry::threadStart(void *obj) { prctl(PR_SET_NAME, "logd.reader.per"); LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); pthread_cleanup_push(threadStop, obj); SocketClient *client = me->mClient; if (!client) { me->error(); pthread_exit(NULL); } LogBuffer &logbuf = me->mReader.logbuf(); bool privileged = FlushCommand::hasReadLogs(client); lock(); me->threadTriggered = true; while(me->threadTriggered && !me->isError_Locked()) { me->threadTriggered = false; log_time start = me->mStart; unlock(); if (me->mTail) { logbuf.flushTo(client, start, privileged, FilterFirstPass, me); } start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me); if (start == LogBufferElement::FLUSH_ERROR) { me->error(); } if (me->mNonBlock) { lock(); break; } sched_yield(); lock(); } unlock(); pthread_exit(NULL); pthread_cleanup_pop(true); return NULL; }
// A second pass to send the selected elements bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) { LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); LogTimeEntry::lock(); if (me->skipAhead) { me->skipAhead--; } me->mStart = element->getMonotonicTime(); // Truncate to close race between first and second pass if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) { goto skip; } if ((me->mLogMask & (1 << element->getLogId())) == 0) { goto skip; } if (me->mPid && (me->mPid != element->getPid())) { goto skip; } if (me->isError_Locked()) { goto skip; } if (!me->mTail) { goto ok; } ++me->mIndex; if ((me->mCount > me->mTail) && (me->mIndex <= (me->mCount - me->mTail))) { goto skip; } if (!me->mNonBlock) { me->mTail = 0; } ok: if (!me->skipAhead) { LogTimeEntry::unlock(); return true; } // FALLTHRU skip: LogTimeEntry::unlock(); return false; }
void LogTimeEntry::threadStop(void *obj) { LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); lock(); if (me->mNonBlock) { me->error_Locked(); } SocketClient *client = me->mClient; if (me->isError_Locked()) { LogReader &reader = me->mReader; LastLogTimes × = reader.logbuf().mTimes; LastLogTimes::iterator it = times.begin(); while(it != times.end()) { if (*it == me) { times.erase(it); me->release_Locked(); break; } it++; } me->mClient = NULL; reader.release(client); } if (client) { client->decRef(); } me->threadRunning = false; me->decRef_Locked(); unlock(); }