b1db390e25
Start timing when debug() has returned. When the specific timeout has reached (currently 1s) and the relay thread has not finish, tell the relay thread to stop. Test: while true; do date; lshal debug android.hardware.health.storage@1.0::IStorage/default; done Test: lshal_test Bug: 111997867 Change-Id: Ib9235d3bd2fc3a54eb316da8d8b59d987988b134
145 lines
3.4 KiB
C++
145 lines
3.4 KiB
C++
/*
|
|
* Copyright (C) 2017 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 "PipeRelay.h"
|
|
|
|
#include <sys/select.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include <atomic>
|
|
|
|
#include <android-base/logging.h>
|
|
#include <utils/Thread.h>
|
|
|
|
namespace android {
|
|
namespace lshal {
|
|
|
|
static constexpr struct timeval READ_TIMEOUT { .tv_sec = 1, .tv_usec = 0 };
|
|
|
|
struct PipeRelay::RelayThread : public Thread {
|
|
explicit RelayThread(int fd, std::ostream &os);
|
|
|
|
bool threadLoop() override;
|
|
void setFinished();
|
|
|
|
private:
|
|
int mFd;
|
|
std::ostream &mOutStream;
|
|
|
|
// If we were to use requestExit() and exitPending() instead, threadLoop()
|
|
// may not run at all by the time ~PipeRelay is called (i.e. debug() has
|
|
// returned from HAL). By using our own flag, we ensure that select() and
|
|
// read() are executed until data are drained.
|
|
std::atomic_bool mFinished;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(RelayThread);
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os)
|
|
: mFd(fd), mOutStream(os), mFinished(false) {}
|
|
|
|
bool PipeRelay::RelayThread::threadLoop() {
|
|
char buffer[1024];
|
|
|
|
fd_set set;
|
|
FD_ZERO(&set);
|
|
FD_SET(mFd, &set);
|
|
|
|
struct timeval timeout = READ_TIMEOUT;
|
|
|
|
int res = TEMP_FAILURE_RETRY(select(mFd + 1, &set, nullptr, nullptr, &timeout));
|
|
if (res < 0) {
|
|
PLOG(INFO) << "select() failed";
|
|
return false;
|
|
}
|
|
|
|
if (res == 0 || !FD_ISSET(mFd, &set)) {
|
|
if (mFinished) {
|
|
LOG(WARNING) << "debug: timeout reading from pipe, output may be truncated.";
|
|
return false;
|
|
}
|
|
// timeout, but debug() has not returned, so wait for HAL to finish.
|
|
return true;
|
|
}
|
|
|
|
// FD_ISSET(mFd, &set) == true. Data available, start reading
|
|
ssize_t n = TEMP_FAILURE_RETRY(read(mFd, buffer, sizeof(buffer)));
|
|
|
|
if (n < 0) {
|
|
PLOG(ERROR) << "read() failed";
|
|
}
|
|
|
|
if (n <= 0) {
|
|
return false;
|
|
}
|
|
|
|
mOutStream.write(buffer, n);
|
|
|
|
return true;
|
|
}
|
|
|
|
void PipeRelay::RelayThread::setFinished() {
|
|
mFinished = true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
PipeRelay::PipeRelay(std::ostream &os)
|
|
: mInitCheck(NO_INIT) {
|
|
int res = pipe(mFds);
|
|
|
|
if (res < 0) {
|
|
mInitCheck = -errno;
|
|
return;
|
|
}
|
|
|
|
mThread = new RelayThread(mFds[0], os);
|
|
mInitCheck = mThread->run("RelayThread");
|
|
}
|
|
|
|
void PipeRelay::CloseFd(int *fd) {
|
|
if (*fd >= 0) {
|
|
close(*fd);
|
|
*fd = -1;
|
|
}
|
|
}
|
|
|
|
PipeRelay::~PipeRelay() {
|
|
CloseFd(&mFds[1]);
|
|
|
|
if (mThread != nullptr) {
|
|
mThread->setFinished();
|
|
mThread->join();
|
|
mThread.clear();
|
|
}
|
|
|
|
CloseFd(&mFds[0]);
|
|
}
|
|
|
|
status_t PipeRelay::initCheck() const {
|
|
return mInitCheck;
|
|
}
|
|
|
|
int PipeRelay::fd() const {
|
|
return mFds[1];
|
|
}
|
|
|
|
} // namespace lshal
|
|
} // namespace android
|