Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
#include "SerialPortPumps.h"
#include "SerialLogging.h"
namespace mozilla::dom::webserial {
NS_IMPL_ISUPPORTS(SerialPortWritePump, nsIInputStreamCallback)
SerialPortWritePump::SerialPortWritePump(const nsString& aPortId,
nsIAsyncInputStream* aInput)
: mPortId(aPortId), mInput(aInput) {}
void SerialPortWritePump::Start() {
RefPtr<SerialPlatformService> service = SerialPlatformService::GetInstance();
if (service && mInput) {
mInput->AsyncWait(this, 0, 0, service->IOThread());
}
}
void SerialPortWritePump::Stop() {
MOZ_LOG(gWebSerialLog, LogLevel::Debug,
("SerialPortWritePump::Stop for port '%s'",
NS_ConvertUTF16toUTF8(mPortId).get()));
mStopped = true;
}
NS_IMETHODIMP SerialPortWritePump::OnInputStreamReady(
nsIAsyncInputStream* aStream) {
if (mStopped) {
return NS_OK;
}
RefPtr<SerialPlatformService> service = SerialPlatformService::GetInstance();
if (!service) {
return NS_OK;
}
service->AssertIsOnIOThread();
// Read available data from the DataPipeReceiver.
char buf[4096];
uint32_t bytesRead = 0;
nsresult rv = mInput->Read(buf, sizeof(buf), &bytesRead);
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
// No data yet, wait again.
mInput->AsyncWait(this, 0, 0, service->IOThread());
return NS_OK;
}
// NS_OK with 0 bytes is the nsIInputStream EOF convention. DataPipe
// returns this when the peer (sender) has closed and no data remains.
if (NS_FAILED(rv) || (NS_SUCCEEDED(rv) && bytesRead == 0)) {
MOZ_LOG(gWebSerialLog, LogLevel::Debug,
("SerialPortWritePump pipe closed/error for port '%s': 0x%08x",
NS_ConvertUTF16toUTF8(mPortId).get(), static_cast<uint32_t>(rv)));
mPipeClosed = true;
if (nsCOMPtr<nsIRunnable> cb = mClosedCallback.forget()) {
cb->Run();
}
return NS_OK;
}
if (bytesRead > 0) {
MOZ_LOG(gWebSerialLog, LogLevel::Verbose,
("SerialPortWritePump writing %u bytes to port '%s'", bytesRead,
NS_ConvertUTF16toUTF8(mPortId).get()));
nsTArray<uint8_t> data;
data.AppendElements(reinterpret_cast<const uint8_t*>(buf), bytesRead);
rv = service->Write(mPortId, data);
if (NS_FAILED(rv)) {
MOZ_LOG(
gWebSerialLog, LogLevel::Error,
("SerialPortWritePump device write failed for port '%s': 0x%08x",
NS_ConvertUTF16toUTF8(mPortId).get(), static_cast<uint32_t>(rv)));
// Close the pipe to signal the error back to the child.
mInput->CloseWithStatus(rv);
return NS_OK;
}
}
// Wait for more data.
if (!mStopped) {
mInput->AsyncWait(this, 0, 0, service->IOThread());
}
return NS_OK;
}
void SerialPortWritePump::OnPipeClosed(nsCOMPtr<nsIRunnable>&& aCallback) {
RefPtr<SerialPlatformService> service = SerialPlatformService::GetInstance();
MOZ_DIAGNOSTIC_ASSERT(service && service->IOThread()->IsOnCurrentThread());
if (mPipeClosed) {
aCallback->Run();
return;
}
mClosedCallback = std::move(aCallback);
}
} // namespace mozilla::dom::webserial