flst / upstream /emscripten /system /lib /wasmfs /special_files.cpp
arudradey's picture
Upload folder using huggingface_hub
00df61d verified
Raw
History Blame Contribute Delete
5.73 kB
// Copyright 2021 The Emscripten Authors. All rights reserved.
// Emscripten is available under two separate licenses, the MIT license and the
// University of Illinois/NCSA Open Source License. Both these licenses can be
// found in the LICENSE file.
// This file defines the standard streams.
#include <emscripten/html5.h>
#include <unistd.h>
#include <vector>
#include <wasi/api.h>
#include "special_files.h"
#include "wasmfs_internal.h"
namespace wasmfs::SpecialFiles {
namespace {
// No-op reads and writes: /dev/null
class NullFile : public DataFile {
int open(oflags_t) override { return 0; }
int close() override { return 0; }
ssize_t write(const uint8_t* buf, size_t len, off_t offset) override {
return len;
}
ssize_t read(uint8_t* buf, size_t len, off_t offset) override { return 0; }
int flush() override { return 0; }
off_t getSize() override { return 0; }
int setSize(off_t size) override { return -EPERM; }
public:
NullFile() : DataFile(S_IRUGO | S_IWUGO, NullBackend, S_IFCHR) {}
};
class StdinFile : public DataFile {
int open(oflags_t) override { return 0; }
int close() override { return 0; }
ssize_t write(const uint8_t* buf, size_t len, off_t offset) override {
return -__WASI_ERRNO_INVAL;
}
ssize_t read(uint8_t* buf, size_t len, off_t offset) override {
for (size_t i = 0; i < len; i++) {
auto c = _wasmfs_stdin_get_char();
if (c < 0) {
// No more input can be read, return what we did read.
return i;
}
buf[i] = c;
}
return len;
};
int flush() override { return 0; }
off_t getSize() override { return 0; }
int setSize(off_t size) override { return -EPERM; }
public:
StdinFile() : DataFile(S_IRUGO, NullBackend, S_IFCHR) { seekable = false; }
};
// A standard stream that writes: stdout or stderr.
class WritingStdFile : public DataFile {
protected:
std::vector<char> writeBuffer;
int open(oflags_t) override { return 0; }
int close() override { return 0; }
ssize_t read(uint8_t* buf, size_t len, off_t offset) override {
return -__WASI_ERRNO_INVAL;
};
int flush() override {
// Write a null to flush the output if we have content.
if (!writeBuffer.empty()) {
const uint8_t nothing = '\0';
write(&nothing, 1, 0);
}
return 0;
}
off_t getSize() override { return 0; }
int setSize(off_t size) override { return -EPERM; }
ssize_t writeToJS(const uint8_t* buf,
size_t len,
void (*console_write)(const char*),
std::vector<char>& fd_write_buffer) {
for (size_t j = 0; j < len; j++) {
uint8_t current = buf[j];
// Flush on either a null or a newline.
if (current == '\0' || current == '\n') {
fd_write_buffer.push_back('\0'); // for null-terminated C strings
console_write(fd_write_buffer.data());
fd_write_buffer.clear();
} else {
fd_write_buffer.push_back(current);
}
}
return len;
}
public:
WritingStdFile() : DataFile(S_IWUGO, NullBackend, S_IFCHR) {
seekable = false;
}
};
class StdoutFile : public WritingStdFile {
ssize_t write(const uint8_t* buf, size_t len, off_t offset) override {
// Node and worker threads issue in Emscripten:
// https://github.com/emscripten-core/emscripten/issues/14804.
// Issue filed in Node: https://github.com/nodejs/node/issues/40961
// This is confirmed to occur when running with EXIT_RUNTIME and
// PROXY_TO_PTHREAD. This results in only a single console.log statement
// being outputted. The solution for now is to use out() and err() instead.
return writeToJS(buf, len, &emscripten_out, writeBuffer);
}
public:
StdoutFile() {}
};
class StderrFile : public WritingStdFile {
ssize_t write(const uint8_t* buf, size_t len, off_t offset) override {
// Similar issue with Node and worker threads as emscripten_out.
// TODO: May not want to proxy stderr (fd == 2) to the main thread, as
// emscripten_err does.
// This will not show in HTML - a console.warn in a worker is
// sufficient. This would be a change from the current FS.
return writeToJS(buf, len, &emscripten_err, writeBuffer);
}
public:
StderrFile() {}
};
class RandomFile : public DataFile {
int open(oflags_t) override { return 0; }
int close() override { return 0; }
ssize_t write(const uint8_t* buf, size_t len, off_t offset) override {
return -__WASI_ERRNO_INVAL;
}
ssize_t read(uint8_t* buf, size_t len, off_t offset) override {
uint8_t* end = buf + len;
for (; buf < end; buf += 256) {
[[maybe_unused]] int err = getentropy(buf, std::min(end - buf, 256l));
assert(err == 0);
}
return len;
};
int flush() override { return 0; }
off_t getSize() override { return 0; }
int setSize(off_t size) override { return -EPERM; }
public:
RandomFile() : DataFile(S_IRUGO, NullBackend, S_IFCHR) { seekable = false; }
};
} // anonymous namespace
std::shared_ptr<DataFile> getNull() {
static auto null = std::make_shared<NullFile>();
return null;
}
std::shared_ptr<DataFile> getStdin() {
static auto stdin = std::make_shared<StdinFile>();
return stdin;
}
std::shared_ptr<DataFile> getStdout() {
static auto stdout = std::make_shared<StdoutFile>();
return stdout;
}
std::shared_ptr<DataFile> getStderr() {
static auto stderr = std::make_shared<StderrFile>();
return stderr;
}
std::shared_ptr<DataFile> getRandom() {
static auto random = std::make_shared<RandomFile>();
return random;
}
std::shared_ptr<DataFile> getURandom() {
static auto urandom = std::make_shared<RandomFile>();
return urandom;
}
} // namespace wasmfs::SpecialFiles