Simplified interface + fixed segfault when eof is reached. ref #287
This commit is contained in:
@@ -46,6 +46,8 @@ namespace Av
|
|||||||
{
|
{
|
||||||
if (_estimatedContentLength)
|
if (_estimatedContentLength)
|
||||||
LMS_LOG(TRANSCODE, DEBUG) << "Estimated content length = " << *_estimatedContentLength;
|
LMS_LOG(TRANSCODE, DEBUG) << "Estimated content length = " << *_estimatedContentLength;
|
||||||
|
else
|
||||||
|
LMS_LOG(TRANSCODE, DEBUG) << "Not using estimated content length";
|
||||||
}
|
}
|
||||||
|
|
||||||
Wt::Http::ResponseContinuation*
|
Wt::Http::ResponseContinuation*
|
||||||
@@ -58,8 +60,8 @@ namespace Av
|
|||||||
if (_bytesReadyCount > 0)
|
if (_bytesReadyCount > 0)
|
||||||
{
|
{
|
||||||
response.out().write(reinterpret_cast<const char *>(&_buffer[0]), _bytesReadyCount);
|
response.out().write(reinterpret_cast<const char *>(&_buffer[0]), _bytesReadyCount);
|
||||||
_bytesReadyCount = 0;
|
|
||||||
_totalServedByteCount += _bytesReadyCount;
|
_totalServedByteCount += _bytesReadyCount;
|
||||||
|
_bytesReadyCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_transcoder.finished())
|
if (!_transcoder.finished())
|
||||||
|
|||||||
@@ -178,19 +178,6 @@ Transcoder::start()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Transcoder::asyncWaitForData(WaitCallback cb)
|
|
||||||
{
|
|
||||||
assert(_childProcess);
|
|
||||||
|
|
||||||
LOG(DEBUG) << "Want to wait for data";
|
|
||||||
|
|
||||||
_childProcess->asyncWaitForData([cb = std::move(cb)]
|
|
||||||
{
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Transcoder::asyncRead(std::byte* buffer, std::size_t bufferSize, ReadCallback readCallback)
|
Transcoder::asyncRead(std::byte* buffer, std::size_t bufferSize, ReadCallback readCallback)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,9 +40,6 @@ namespace Av
|
|||||||
Transcoder(Transcoder&&) = delete;
|
Transcoder(Transcoder&&) = delete;
|
||||||
Transcoder& operator=(Transcoder&&) = delete;
|
Transcoder& operator=(Transcoder&&) = delete;
|
||||||
|
|
||||||
using WaitCallback = std::function<void()>;
|
|
||||||
void asyncWaitForData(WaitCallback cb);
|
|
||||||
|
|
||||||
// non blocking calls
|
// non blocking calls
|
||||||
using ReadCallback = std::function<void(std::size_t nbReadBytes)>;
|
using ReadCallback = std::function<void(std::size_t nbReadBytes)>;
|
||||||
void asyncRead(std::byte* buffer, std::size_t bufferSize, ReadCallback);
|
void asyncRead(std::byte* buffer, std::size_t bufferSize, ReadCallback);
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ namespace
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SystemException(int err, const std::string& errMsg)
|
SystemException(int err, const std::string& errMsg)
|
||||||
: ChildProcessException {errMsg + ": " + strerror(err)}
|
: ChildProcessException {errMsg + ": " + ::strerror(err)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
SystemException(boost::system::error_code ec, const std::string& errMsg)
|
SystemException(boost::system::error_code ec, const std::string& errMsg)
|
||||||
@@ -117,42 +117,36 @@ ChildProcess::ChildProcess(boost::asio::io_context& ioContext, const std::filesy
|
|||||||
|
|
||||||
ChildProcess::~ChildProcess()
|
ChildProcess::~ChildProcess()
|
||||||
{
|
{
|
||||||
if (!_waited)
|
LMS_LOG(CHILDPROCESS, DEBUG) << "Closing child process...";
|
||||||
{
|
{
|
||||||
LMS_LOG(CHILDPROCESS, DEBUG) << "Closing child process...";
|
boost::system::error_code closeError;
|
||||||
{
|
_childStdout.close(closeError);
|
||||||
boost::system::error_code closeError;
|
if (closeError)
|
||||||
_childStdout.close(closeError);
|
LMS_LOG(CHILDPROCESS, ERROR) << "Closed failed: " << closeError.message();
|
||||||
if (closeError)
|
|
||||||
LMS_LOG(CHILDPROCESS, ERROR) << "Closed failed: " << closeError.message();
|
|
||||||
}
|
|
||||||
kill();
|
|
||||||
wait(true);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
if (!_finished)
|
||||||
ChildProcess::drain()
|
kill();
|
||||||
{
|
|
||||||
char buf[128];
|
|
||||||
|
|
||||||
while (boost::asio::read(_childStdout, boost::asio::buffer(buf)) > 0)
|
wait(true);
|
||||||
LMS_LOG(CHILDPROCESS, DEBUG) << "drained some bytes" << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ChildProcess::kill()
|
ChildProcess::kill()
|
||||||
{
|
{
|
||||||
|
// process may already have finished
|
||||||
LMS_LOG(CHILDPROCESS, DEBUG) << "Killing child process...";
|
LMS_LOG(CHILDPROCESS, DEBUG) << "Killing child process...";
|
||||||
::kill(_childPID, SIGKILL);
|
if (::kill(_childPID, SIGKILL) == -1)
|
||||||
|
LMS_LOG(CHILDPROCESS, DEBUG) << "Kill failed: " << ::strerror(errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ChildProcess::wait(bool block)
|
ChildProcess::wait(bool block)
|
||||||
{
|
{
|
||||||
int wstatus {};
|
assert(!_waited);
|
||||||
|
|
||||||
pid_t pid {waitpid(_childPID, &wstatus, block ? 0 : WNOHANG)};
|
int wstatus {};
|
||||||
|
const pid_t pid {waitpid(_childPID, &wstatus, block ? 0 : WNOHANG)};
|
||||||
|
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
throw SystemException {errno, "waitpid failed!"};
|
throw SystemException {errno, "waitpid failed!"};
|
||||||
@@ -160,18 +154,22 @@ ChildProcess::wait(bool block)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (WIFEXITED(wstatus))
|
if (WIFEXITED(wstatus))
|
||||||
|
{
|
||||||
_exitCode = WEXITSTATUS(wstatus);
|
_exitCode = WEXITSTATUS(wstatus);
|
||||||
|
LMS_LOG(CHILDPROCESS, DEBUG) << "Exit code = " << *_exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
_waited = true;
|
_waited = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ChildProcess::asyncRead(std::byte* data, std::size_t bufferSize, ReadCallback callback)
|
ChildProcess::asyncRead(std::byte* data, std::size_t bufferSize, ReadCallback callback)
|
||||||
{
|
{
|
||||||
assert(!finished());
|
assert(!finished());
|
||||||
|
|
||||||
|
LMS_LOG(CHILDPROCESS, DEBUG) << "Async read, bufferSize = " << bufferSize;
|
||||||
|
|
||||||
boost::asio::async_read(_childStdout, boost::asio::buffer(data, bufferSize),
|
boost::asio::async_read(_childStdout, boost::asio::buffer(data, bufferSize),
|
||||||
[this, callback {std::move(callback)}](const boost::system::error_code& error, std::size_t bytesTransferred)
|
[this, callback {std::move(callback)}](const boost::system::error_code& error, std::size_t bytesTransferred)
|
||||||
{
|
{
|
||||||
@@ -180,33 +178,20 @@ ChildProcess::asyncRead(std::byte* data, std::size_t bufferSize, ReadCallback ca
|
|||||||
ReadResult readResult {ReadResult::Success};
|
ReadResult readResult {ReadResult::Success};
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
_finished = true;
|
if (error != boost::asio::error::eof)
|
||||||
|
{
|
||||||
if (error == boost::asio::error::eof)
|
// forbidden to read any captured param here as the ChildProcess instance may already have been killed
|
||||||
readResult = ReadResult::EndOfFile;
|
|
||||||
else
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
readResult = ReadResult::EndOfFile;
|
||||||
|
_finished = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(readResult, bytesTransferred);
|
callback(readResult, bytesTransferred);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ChildProcess::asyncWaitForData(WaitCallback cb)
|
|
||||||
{
|
|
||||||
LMS_LOG(CHILDPROCESS, DEBUG) << "Async wait requested";
|
|
||||||
assert(!finished());
|
|
||||||
|
|
||||||
_childStdout.async_wait(boost::asio::posix::stream_descriptor::wait_read,
|
|
||||||
[cb {std::move(cb)}](const boost::system::error_code& ec)
|
|
||||||
{
|
|
||||||
LMS_LOG(CHILDPROCESS, DEBUG) << "Wait CB, error = " << ec.message();
|
|
||||||
if (!ec)
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t
|
std::size_t
|
||||||
ChildProcess::readSome(std::byte* data, std::size_t bufferSize)
|
ChildProcess::readSome(std::byte* data, std::size_t bufferSize)
|
||||||
{
|
{
|
||||||
@@ -220,7 +205,7 @@ ChildProcess::readSome(std::byte* data, std::size_t bufferSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ChildProcess::finished()
|
ChildProcess::finished() const
|
||||||
{
|
{
|
||||||
return _finished;
|
return _finished;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,12 +40,10 @@ class ChildProcess : public IChildProcess
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void asyncRead(std::byte* data, std::size_t bufferSize, ReadCallback callback) override;
|
void asyncRead(std::byte* data, std::size_t bufferSize, ReadCallback callback) override;
|
||||||
void asyncWaitForData(WaitCallback cb) override;
|
|
||||||
std::size_t readSome(std::byte* data, std::size_t bufferSize) override;
|
std::size_t readSome(std::byte* data, std::size_t bufferSize) override;
|
||||||
bool finished() override;
|
bool finished() const override;
|
||||||
|
|
||||||
void kill();
|
void kill();
|
||||||
void drain();
|
|
||||||
bool wait(bool block); // return true if waited
|
bool wait(bool block); // return true if waited
|
||||||
|
|
||||||
using FileDescriptor = boost::asio::posix::stream_descriptor;
|
using FileDescriptor = boost::asio::posix::stream_descriptor;
|
||||||
|
|||||||
@@ -48,9 +48,7 @@ class IChildProcess
|
|||||||
using ReadCallback = std::function<void(ReadResult, std::size_t)>;
|
using ReadCallback = std::function<void(ReadResult, std::size_t)>;
|
||||||
virtual void asyncRead(std::byte* data, std::size_t bufferSize, ReadCallback callback) = 0;
|
virtual void asyncRead(std::byte* data, std::size_t bufferSize, ReadCallback callback) = 0;
|
||||||
|
|
||||||
using WaitCallback = std::function<void(void)>;
|
|
||||||
virtual void asyncWaitForData(WaitCallback cb) = 0;
|
|
||||||
virtual std::size_t readSome(std::byte* data, std::size_t bufferSize) = 0;
|
virtual std::size_t readSome(std::byte* data, std::size_t bufferSize) = 0;
|
||||||
virtual bool finished() = 0;
|
virtual bool finished() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user