Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/wasmfs/file_table.h
6174 views
1
// Copyright 2021 The Emscripten Authors. All rights reserved.
2
// Emscripten is available under two separate licenses, the MIT license and the
3
// University of Illinois/NCSA Open Source License. Both these licenses can be
4
// found in the LICENSE file.
5
6
// This file defines the open file table.
7
8
#pragma once
9
10
#include "file.h"
11
#include <assert.h>
12
#include <fcntl.h>
13
#include <mutex>
14
#include <utility>
15
#include <vector>
16
#include <wasi/api.h>
17
18
// Copied from legacy FS (FS.MAX_OPEN_FDS)
19
#define WASMFS_FD_MAX 4096
20
21
namespace wasmfs {
22
static_assert(std::is_same<size_t, __wasi_size_t>::value,
23
"size_t should be the same as __wasi_size_t");
24
static_assert(std::is_same<off_t, __wasi_filedelta_t>::value,
25
"off_t should be the same as __wasi_filedelta_t");
26
27
// Overflow and underflow behaviour are only defined for unsigned types.
28
template<typename T> bool addWillOverFlow(T a, T b) {
29
if (a > 0 && b > std::numeric_limits<T>::max() - a) {
30
return true;
31
}
32
return false;
33
}
34
35
class FileTable;
36
37
class OpenFileState : public std::enable_shared_from_this<OpenFileState> {
38
std::shared_ptr<File> file;
39
off_t position = 0;
40
oflags_t flags; // RD_ONLY, WR_ONLY, RDWR
41
42
// An OpenFileState needs a mutex if there are concurrent accesses on one open
43
// file descriptor. This could occur if there are multiple seeks on the same
44
// open file descriptor.
45
std::recursive_mutex mutex;
46
47
// The number of times this OpenFileState appears in the table. Use this
48
// instead of shared_ptr::use_count to avoid accidentally counting temporary
49
// objects.
50
int uses = 0;
51
52
// We can't make the constructor private because std::make_shared needs to be
53
// able to call it, but we can make it unusable publicly.
54
struct private_key {
55
explicit private_key(int) {}
56
};
57
58
// `uses` is protected by the FileTable lock and can be accessed directly by
59
// `FileTable::Handle.
60
friend FileTable;
61
62
public:
63
// Cache directory entries at the moment the directory is opened so that
64
// subsequent getdents calls have a stable view of the contents. Including
65
// files removed after the open and excluding files added after the open is
66
// allowed, and trying to recalculate the directory contents on each getdents
67
// call could lead to missed directory entries if there are concurrent
68
// deletions that effectively move entries back past the current read position
69
// in the open directory.
70
const std::vector<Directory::Entry> dirents;
71
72
OpenFileState(private_key,
73
oflags_t flags,
74
std::shared_ptr<File> file,
75
std::vector<Directory::Entry>&& dirents)
76
: file(file), flags(flags), dirents(std::move(dirents)) {}
77
78
[[nodiscard]] static int create(std::shared_ptr<File> file,
79
oflags_t flags,
80
std::shared_ptr<OpenFileState>& out);
81
82
class Handle {
83
std::shared_ptr<OpenFileState> openFileState;
84
std::unique_lock<std::recursive_mutex> lock;
85
86
public:
87
Handle(std::shared_ptr<OpenFileState> openFileState)
88
: openFileState(openFileState), lock(openFileState->mutex) {}
89
90
std::shared_ptr<File>& getFile() { return openFileState->file; };
91
92
off_t getPosition() const { return openFileState->position; };
93
void setPosition(off_t pos) { openFileState->position = pos; };
94
95
oflags_t getFlags() const { return openFileState->flags; };
96
void setFlags(oflags_t flags) { openFileState->flags = flags; };
97
};
98
99
Handle locked() { return Handle(shared_from_this()); }
100
};
101
102
class FileTable {
103
// Allow WasmFS to construct the FileTable singleton.
104
friend class WasmFS;
105
106
std::vector<std::shared_ptr<OpenFileState>> entries;
107
std::recursive_mutex mutex;
108
109
FileTable();
110
111
public:
112
// Access to the FileTable must go through a Handle, which holds its lock.
113
class Handle {
114
FileTable& fileTable;
115
std::unique_lock<std::recursive_mutex> lock;
116
117
public:
118
Handle(FileTable& fileTable)
119
: fileTable(fileTable), lock(fileTable.mutex) {}
120
121
std::shared_ptr<OpenFileState> getEntry(__wasi_fd_t fd);
122
123
// Set the table slot at `fd` to the given file. If this overwrites the last
124
// reference to an OpenFileState for a data file in the table, return the
125
// file so it can be closed by the caller. Do not close the file directly in
126
// this method so it can be closed later while the FileTable lock is not
127
// held.
128
[[nodiscard]] std::shared_ptr<DataFile>
129
setEntry(__wasi_fd_t fd, std::shared_ptr<OpenFileState> openFile);
130
__wasi_fd_t addEntry(std::shared_ptr<OpenFileState> openFileState);
131
};
132
133
Handle locked() { return Handle(*this); }
134
};
135
136
} // namespace wasmfs
137
138