Path: blob/main/system/lib/wasmfs/file_table.h
6174 views
// Copyright 2021 The Emscripten Authors. All rights reserved.1// Emscripten is available under two separate licenses, the MIT license and the2// University of Illinois/NCSA Open Source License. Both these licenses can be3// found in the LICENSE file.45// This file defines the open file table.67#pragma once89#include "file.h"10#include <assert.h>11#include <fcntl.h>12#include <mutex>13#include <utility>14#include <vector>15#include <wasi/api.h>1617// Copied from legacy FS (FS.MAX_OPEN_FDS)18#define WASMFS_FD_MAX 40961920namespace wasmfs {21static_assert(std::is_same<size_t, __wasi_size_t>::value,22"size_t should be the same as __wasi_size_t");23static_assert(std::is_same<off_t, __wasi_filedelta_t>::value,24"off_t should be the same as __wasi_filedelta_t");2526// Overflow and underflow behaviour are only defined for unsigned types.27template<typename T> bool addWillOverFlow(T a, T b) {28if (a > 0 && b > std::numeric_limits<T>::max() - a) {29return true;30}31return false;32}3334class FileTable;3536class OpenFileState : public std::enable_shared_from_this<OpenFileState> {37std::shared_ptr<File> file;38off_t position = 0;39oflags_t flags; // RD_ONLY, WR_ONLY, RDWR4041// An OpenFileState needs a mutex if there are concurrent accesses on one open42// file descriptor. This could occur if there are multiple seeks on the same43// open file descriptor.44std::recursive_mutex mutex;4546// The number of times this OpenFileState appears in the table. Use this47// instead of shared_ptr::use_count to avoid accidentally counting temporary48// objects.49int uses = 0;5051// We can't make the constructor private because std::make_shared needs to be52// able to call it, but we can make it unusable publicly.53struct private_key {54explicit private_key(int) {}55};5657// `uses` is protected by the FileTable lock and can be accessed directly by58// `FileTable::Handle.59friend FileTable;6061public:62// Cache directory entries at the moment the directory is opened so that63// subsequent getdents calls have a stable view of the contents. Including64// files removed after the open and excluding files added after the open is65// allowed, and trying to recalculate the directory contents on each getdents66// call could lead to missed directory entries if there are concurrent67// deletions that effectively move entries back past the current read position68// in the open directory.69const std::vector<Directory::Entry> dirents;7071OpenFileState(private_key,72oflags_t flags,73std::shared_ptr<File> file,74std::vector<Directory::Entry>&& dirents)75: file(file), flags(flags), dirents(std::move(dirents)) {}7677[[nodiscard]] static int create(std::shared_ptr<File> file,78oflags_t flags,79std::shared_ptr<OpenFileState>& out);8081class Handle {82std::shared_ptr<OpenFileState> openFileState;83std::unique_lock<std::recursive_mutex> lock;8485public:86Handle(std::shared_ptr<OpenFileState> openFileState)87: openFileState(openFileState), lock(openFileState->mutex) {}8889std::shared_ptr<File>& getFile() { return openFileState->file; };9091off_t getPosition() const { return openFileState->position; };92void setPosition(off_t pos) { openFileState->position = pos; };9394oflags_t getFlags() const { return openFileState->flags; };95void setFlags(oflags_t flags) { openFileState->flags = flags; };96};9798Handle locked() { return Handle(shared_from_this()); }99};100101class FileTable {102// Allow WasmFS to construct the FileTable singleton.103friend class WasmFS;104105std::vector<std::shared_ptr<OpenFileState>> entries;106std::recursive_mutex mutex;107108FileTable();109110public:111// Access to the FileTable must go through a Handle, which holds its lock.112class Handle {113FileTable& fileTable;114std::unique_lock<std::recursive_mutex> lock;115116public:117Handle(FileTable& fileTable)118: fileTable(fileTable), lock(fileTable.mutex) {}119120std::shared_ptr<OpenFileState> getEntry(__wasi_fd_t fd);121122// Set the table slot at `fd` to the given file. If this overwrites the last123// reference to an OpenFileState for a data file in the table, return the124// file so it can be closed by the caller. Do not close the file directly in125// this method so it can be closed later while the FileTable lock is not126// held.127[[nodiscard]] std::shared_ptr<DataFile>128setEntry(__wasi_fd_t fd, std::shared_ptr<OpenFileState> openFile);129__wasi_fd_t addEntry(std::shared_ptr<OpenFileState> openFileState);130};131132Handle locked() { return Handle(*this); }133};134135} // namespace wasmfs136137138