@delali/narsil-react-native 0.0.0-stage → 0.3.1-next.146
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/NarsilReactNative.podspec +57 -0
- package/README.md +46 -2
- package/android/CMakeLists.txt +48 -0
- package/android/build.gradle +151 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/AndroidEnvironment.cpp +44 -0
- package/android/src/main/cpp/AndroidEnvironment.hpp +11 -0
- package/android/src/main/cpp/cpp-adapter.cpp +11 -0
- package/android/src/main/java/com/margelo/nitro/narsil/NarsilAndroidEnvironment.kt +29 -0
- package/android/src/main/java/com/margelo/nitro/narsil/NarsilReactNativePackage.kt +22 -0
- package/app.plugin.js +25 -0
- package/cpp/AttachedField.cpp +234 -0
- package/cpp/AttachedField.hpp +61 -0
- package/cpp/Compression.cpp +113 -0
- package/cpp/Compression.hpp +16 -0
- package/cpp/GraphHeldAlone.cpp +29 -0
- package/cpp/GraphHeldAlone.hpp +25 -0
- package/cpp/HostMemory.cpp +123 -0
- package/cpp/HostMemory.hpp +53 -0
- package/cpp/HybridNarsilCoreImpl.cpp +390 -0
- package/cpp/HybridNarsilCoreImpl.hpp +68 -0
- package/cpp/HybridNarsilFilesImpl.cpp +245 -0
- package/cpp/HybridNarsilFilesImpl.hpp +34 -0
- package/cpp/HybridNarsilHostImpl.cpp +126 -0
- package/cpp/HybridNarsilHostImpl.hpp +42 -0
- package/cpp/NativeAtomics.cpp +110 -0
- package/cpp/NativeAtomics.hpp +11 -0
- package/cpp/ProcessInfo.cpp +83 -0
- package/cpp/ProcessInfo.hpp +11 -0
- package/cpp/ThreadPriority.cpp +77 -0
- package/cpp/ThreadPriority.hpp +8 -0
- package/cpp/WorkletRuntimeDispatcher.cpp +61 -0
- package/cpp/WorkletRuntimeDispatcher.hpp +9 -0
- package/cpp/core/include/narsil_core.h +208 -0
- package/cpp/core/src/connect.c +213 -0
- package/cpp/core/src/distance.c +103 -0
- package/cpp/core/src/files.c +99 -0
- package/cpp/core/src/heap.c +84 -0
- package/cpp/core/src/internal.h +284 -0
- package/cpp/core/src/kernels_code.c +209 -0
- package/cpp/core/src/kernels_float.c +197 -0
- package/cpp/core/src/kernels_pair.c +133 -0
- package/cpp/core/src/last_links.c +145 -0
- package/cpp/core/src/links.c +195 -0
- package/cpp/core/src/locks.c +168 -0
- package/cpp/core/src/nearest_links.c +147 -0
- package/cpp/core/src/place.c +215 -0
- package/cpp/core/src/quantize.c +226 -0
- package/cpp/core/src/records.c +97 -0
- package/cpp/core/src/remove.c +205 -0
- package/cpp/core/src/vectors.c +139 -0
- package/cpp/core/src/walk.c +231 -0
- package/cpp/core/src/workspace.c +167 -0
- package/ios/PrivacyInfo.xcprivacy +23 -0
- package/lib/client.d.ts +19 -0
- package/lib/client.js +41 -0
- package/lib/constants.d.ts +9 -0
- package/lib/constants.js +9 -0
- package/lib/engine/byte-files.d.ts +5 -0
- package/lib/engine/byte-files.js +97 -0
- package/lib/engine/core.d.ts +3 -0
- package/lib/engine/core.js +113 -0
- package/lib/engine/files.d.ts +3 -0
- package/lib/engine/files.js +188 -0
- package/lib/engine/host.d.ts +13 -0
- package/lib/engine/host.js +102 -0
- package/lib/engine/install.d.ts +4 -0
- package/lib/engine/install.js +29 -0
- package/lib/engine/native-error.d.ts +1 -0
- package/lib/engine/native-error.js +12 -0
- package/lib/engine/stand-ins/atomics.d.ts +5 -0
- package/lib/engine/stand-ins/atomics.js +236 -0
- package/lib/engine/stand-ins/crypto.d.ts +2 -0
- package/lib/engine/stand-ins/crypto.js +65 -0
- package/lib/engine/stand-ins/process.d.ts +2 -0
- package/lib/engine/stand-ins/process.js +22 -0
- package/lib/engine/stand-ins/streams.d.ts +1 -0
- package/lib/engine/stand-ins/streams.js +31 -0
- package/lib/engine/stand-ins/structured-clone.d.ts +1 -0
- package/lib/engine/stand-ins/structured-clone.js +121 -0
- package/lib/engine/streamed.d.ts +6 -0
- package/lib/engine/streamed.js +29 -0
- package/lib/engine/transfer.d.ts +3 -0
- package/lib/engine/transfer.js +77 -0
- package/lib/errors.d.ts +25 -0
- package/lib/errors.js +59 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +2 -0
- package/lib/methods.d.ts +5 -0
- package/lib/methods.js +47 -0
- package/lib/native-objects.d.ts +2 -0
- package/lib/native-objects.js +24 -0
- package/lib/specs/core.nitro.d.ts +79 -0
- package/lib/specs/core.nitro.js +1 -0
- package/lib/specs/files.nitro.d.ts +36 -0
- package/lib/specs/files.nitro.js +1 -0
- package/lib/specs/host.nitro.d.ts +24 -0
- package/lib/specs/host.nitro.js +1 -0
- package/lib/transferred.d.ts +15 -0
- package/lib/transferred.js +6 -0
- package/lib/types.d.ts +136 -0
- package/lib/types.js +1 -0
- package/lib/worklets/app-turns.d.ts +1 -0
- package/lib/worklets/app-turns.js +44 -0
- package/lib/worklets/client.d.ts +30 -0
- package/lib/worklets/client.js +144 -0
- package/lib/worklets/index.d.ts +4 -0
- package/lib/worklets/index.js +2 -0
- package/lib/worklets/instances.d.ts +15 -0
- package/lib/worklets/instances.js +194 -0
- package/lib/worklets/json-part.d.ts +1 -0
- package/lib/worklets/json-part.js +42 -0
- package/lib/worklets/runtime.d.ts +25 -0
- package/lib/worklets/runtime.js +80 -0
- package/lib/worklets/transfer-queue.d.ts +7 -0
- package/lib/worklets/transfer-queue.js +79 -0
- package/lib/worklets/types.d.ts +26 -0
- package/lib/worklets/types.js +1 -0
- package/nitro.json +32 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/NarsilReactNative+autolinking.cmake +85 -0
- package/nitrogen/generated/android/NarsilReactNative+autolinking.gradle +27 -0
- package/nitrogen/generated/android/NarsilReactNativeOnLoad.cpp +69 -0
- package/nitrogen/generated/android/NarsilReactNativeOnLoad.hpp +34 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/narsil/NarsilReactNativeOnLoad.kt +35 -0
- package/nitrogen/generated/ios/NarsilReactNative+autolinking.rb +62 -0
- package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Bridge.cpp +17 -0
- package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Bridge.hpp +27 -0
- package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Umbrella.hpp +38 -0
- package/nitrogen/generated/ios/NarsilReactNativeAutolinking.mm +55 -0
- package/nitrogen/generated/ios/NarsilReactNativeAutolinking.swift +16 -0
- package/nitrogen/generated/shared/c++/DirectoryEntry.hpp +91 -0
- package/nitrogen/generated/shared/c++/FileStatus.hpp +103 -0
- package/nitrogen/generated/shared/c++/GraphMemory.hpp +120 -0
- package/nitrogen/generated/shared/c++/HybridNarsilAttachedGraphSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridNarsilAttachedGraphSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/HybridNarsilAttachedStoreSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridNarsilAttachedStoreSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.cpp +35 -0
- package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.hpp +100 -0
- package/nitrogen/generated/shared/c++/HybridNarsilFilesSpec.cpp +37 -0
- package/nitrogen/generated/shared/c++/HybridNarsilFilesSpec.hpp +86 -0
- package/nitrogen/generated/shared/c++/HybridNarsilHostSpec.cpp +34 -0
- package/nitrogen/generated/shared/c++/HybridNarsilHostSpec.hpp +78 -0
- package/nitrogen/generated/shared/c++/MemoryView.hpp +91 -0
- package/nitrogen/generated/shared/c++/NativeConnectOutcome.hpp +87 -0
- package/nitrogen/generated/shared/c++/NativeScores.hpp +87 -0
- package/nitrogen/generated/shared/c++/NativeSearchHits.hpp +91 -0
- package/nitrogen/generated/shared/c++/ProcessMemory.hpp +87 -0
- package/nitrogen/generated/shared/c++/StoreMemory.hpp +142 -0
- package/package.json +87 -3
- package/react-native.config.js +8 -0
- package/src/client.ts +44 -0
- package/src/constants.ts +9 -0
- package/src/engine/byte-files.ts +99 -0
- package/src/engine/core.ts +162 -0
- package/src/engine/files.ts +186 -0
- package/src/engine/host.ts +111 -0
- package/src/engine/install.ts +31 -0
- package/src/engine/native-error.ts +10 -0
- package/src/engine/stand-ins/atomics.ts +288 -0
- package/src/engine/stand-ins/crypto.ts +81 -0
- package/src/engine/stand-ins/process.ts +30 -0
- package/src/engine/stand-ins/streams.ts +45 -0
- package/src/engine/stand-ins/structured-clone.ts +118 -0
- package/src/engine/streamed.ts +40 -0
- package/src/engine/transfer.ts +72 -0
- package/src/errors.ts +73 -0
- package/src/index.ts +3 -0
- package/src/methods.ts +52 -0
- package/src/native-objects.ts +30 -0
- package/src/specs/core.nitro.ts +140 -0
- package/src/specs/files.nitro.ts +42 -0
- package/src/specs/host.nitro.ts +30 -0
- package/src/transferred.ts +18 -0
- package/src/types.ts +164 -0
- package/src/worklets/app-turns.ts +48 -0
- package/src/worklets/client.ts +165 -0
- package/src/worklets/index.ts +4 -0
- package/src/worklets/instances.ts +231 -0
- package/src/worklets/json-part.ts +38 -0
- package/src/worklets/runtime.ts +190 -0
- package/src/worklets/transfer-queue.ts +98 -0
- package/src/worklets/types.ts +37 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
#include "HybridNarsilFilesImpl.hpp"
|
|
2
|
+
#include "HostMemory.hpp"
|
|
3
|
+
|
|
4
|
+
#include <cerrno>
|
|
5
|
+
#include <cmath>
|
|
6
|
+
#include <cstdint>
|
|
7
|
+
#include <dirent.h>
|
|
8
|
+
#include <fcntl.h>
|
|
9
|
+
#include <string>
|
|
10
|
+
#include <sys/stat.h>
|
|
11
|
+
#include <unistd.h>
|
|
12
|
+
#include <vector>
|
|
13
|
+
|
|
14
|
+
namespace margelo::nitro::narsil {
|
|
15
|
+
|
|
16
|
+
namespace {
|
|
17
|
+
|
|
18
|
+
constexpr mode_t PRIVATE_FILE_MODE = 0600;
|
|
19
|
+
constexpr mode_t PRIVATE_DIRECTORY_MODE = 0700;
|
|
20
|
+
constexpr double CURRENT_POSITION = -1;
|
|
21
|
+
|
|
22
|
+
int openFlagsOf(const std::string& flags) {
|
|
23
|
+
if (flags == "r") return O_RDONLY;
|
|
24
|
+
if (flags == "r+") return O_RDWR;
|
|
25
|
+
if (flags == "w") return O_WRONLY | O_CREAT | O_TRUNC;
|
|
26
|
+
if (flags == "wx") return O_WRONLY | O_CREAT | O_EXCL;
|
|
27
|
+
if (flags == "w+") return O_RDWR | O_CREAT | O_TRUNC;
|
|
28
|
+
if (flags == "wx+") return O_RDWR | O_CREAT | O_EXCL;
|
|
29
|
+
if (flags == "a") return O_WRONLY | O_CREAT | O_APPEND;
|
|
30
|
+
if (flags == "a+") return O_RDWR | O_CREAT | O_APPEND;
|
|
31
|
+
throwInvalid("A file opens with r, r+, w, wx, w+, wx+, a, or a+, not " + flags);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
int descriptorOf(double value) {
|
|
35
|
+
if (!std::isfinite(value) || value < 0 || value > INT32_MAX || std::floor(value) != value) {
|
|
36
|
+
throwSystemError(EBADF, "use the file descriptor", "");
|
|
37
|
+
}
|
|
38
|
+
return static_cast<int>(value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
void requirePath(const std::string& path) {
|
|
42
|
+
if (path.empty() || path.find('\0') != std::string::npos) throwInvalid("A path must be non-empty text without NUL");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
double millisecondsOf(const struct timespec& time) {
|
|
46
|
+
return static_cast<double>(time.tv_sec) * 1000 + static_cast<double>(time.tv_nsec) / 1e6;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
FileStatus statusOf(const struct stat& status) {
|
|
50
|
+
#if defined(__APPLE__)
|
|
51
|
+
double modifiedMs = millisecondsOf(status.st_mtimespec);
|
|
52
|
+
#else
|
|
53
|
+
double modifiedMs = millisecondsOf(status.st_mtim);
|
|
54
|
+
#endif
|
|
55
|
+
return FileStatus(static_cast<double>(status.st_size), S_ISDIR(status.st_mode), S_ISREG(status.st_mode),
|
|
56
|
+
std::to_string(static_cast<uint64_t>(status.st_dev)),
|
|
57
|
+
std::to_string(static_cast<uint64_t>(status.st_ino)), modifiedMs);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
void syncDescriptor(int descriptor) {
|
|
61
|
+
#if defined(__APPLE__)
|
|
62
|
+
if (fcntl(descriptor, F_FULLFSYNC) == 0) return;
|
|
63
|
+
if (errno != ENOTSUP && errno != EINVAL && errno != ENOTTY) throwSystemError(errno, "flush the file", "");
|
|
64
|
+
#endif
|
|
65
|
+
int result = 0;
|
|
66
|
+
do {
|
|
67
|
+
result = fsync(descriptor);
|
|
68
|
+
} while (result != 0 && errno == EINTR);
|
|
69
|
+
if (result != 0) throwSystemError(errno, "flush the file", "");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
double HybridNarsilFilesImpl::open(const std::string& path, const std::string& flags) {
|
|
75
|
+
requirePath(path);
|
|
76
|
+
int mode = openFlagsOf(flags) | O_CLOEXEC;
|
|
77
|
+
int descriptor = -1;
|
|
78
|
+
do {
|
|
79
|
+
descriptor = ::open(path.c_str(), mode, PRIVATE_FILE_MODE);
|
|
80
|
+
} while (descriptor < 0 && errno == EINTR);
|
|
81
|
+
if (descriptor < 0) throwSystemError(errno, "open", path);
|
|
82
|
+
return static_cast<double>(descriptor);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
void HybridNarsilFilesImpl::close(double descriptor) {
|
|
86
|
+
if (::close(descriptorOf(descriptor)) != 0 && errno != EINTR) throwSystemError(errno, "close the file", "");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
double HybridNarsilFilesImpl::read(double descriptor, const std::shared_ptr<ArrayBuffer>& target, double byteOffset,
|
|
90
|
+
double byteLength, double position) {
|
|
91
|
+
int file = descriptorOf(descriptor);
|
|
92
|
+
uint8_t* bytes = bytesWithin(target, byteOffset, byteLength, "The read target");
|
|
93
|
+
size_t length = static_cast<size_t>(byteLength);
|
|
94
|
+
if (length == 0) return 0;
|
|
95
|
+
ssize_t count = -1;
|
|
96
|
+
do {
|
|
97
|
+
count = position == CURRENT_POSITION
|
|
98
|
+
? ::read(file, bytes, length)
|
|
99
|
+
: pread(file, bytes, length, static_cast<off_t>(requireByteCount(position, "A read position")));
|
|
100
|
+
} while (count < 0 && errno == EINTR);
|
|
101
|
+
if (count < 0) throwSystemError(errno, "read the file", "");
|
|
102
|
+
return static_cast<double>(count);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
double HybridNarsilFilesImpl::write(double descriptor, const std::shared_ptr<ArrayBuffer>& source, double byteOffset,
|
|
106
|
+
double byteLength, double position) {
|
|
107
|
+
int file = descriptorOf(descriptor);
|
|
108
|
+
uint8_t* bytes = bytesWithin(source, byteOffset, byteLength, "The write source");
|
|
109
|
+
size_t length = static_cast<size_t>(byteLength);
|
|
110
|
+
if (length == 0) return 0;
|
|
111
|
+
ssize_t count = -1;
|
|
112
|
+
do {
|
|
113
|
+
count = position == CURRENT_POSITION
|
|
114
|
+
? ::write(file, bytes, length)
|
|
115
|
+
: pwrite(file, bytes, length, static_cast<off_t>(requireByteCount(position, "A write position")));
|
|
116
|
+
} while (count < 0 && errno == EINTR);
|
|
117
|
+
if (count < 0) throwSystemError(errno, "write the file", "");
|
|
118
|
+
return static_cast<double>(count);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
void HybridNarsilFilesImpl::sync(double descriptor) { syncDescriptor(descriptorOf(descriptor)); }
|
|
122
|
+
|
|
123
|
+
std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>>
|
|
124
|
+
HybridNarsilFilesImpl::readAsync(double descriptor, double byteLength, double position) {
|
|
125
|
+
int file = descriptorOf(descriptor);
|
|
126
|
+
size_t length = requireByteCount(byteLength, "A read length");
|
|
127
|
+
bool atCurrentPosition = position == CURRENT_POSITION;
|
|
128
|
+
off_t offset = atCurrentPosition ? 0 : static_cast<off_t>(requireByteCount(position, "A read position"));
|
|
129
|
+
return Promise<std::shared_ptr<ArrayBuffer>>::async([file, length, atCurrentPosition, offset]() {
|
|
130
|
+
std::vector<uint8_t> bytes(length);
|
|
131
|
+
ssize_t count = 0;
|
|
132
|
+
if (length > 0) {
|
|
133
|
+
do {
|
|
134
|
+
count = atCurrentPosition ? ::read(file, bytes.data(), length) : pread(file, bytes.data(), length, offset);
|
|
135
|
+
} while (count < 0 && errno == EINTR);
|
|
136
|
+
if (count < 0) throwSystemError(errno, "read the file", "");
|
|
137
|
+
}
|
|
138
|
+
bytes.resize(static_cast<size_t>(count));
|
|
139
|
+
return ArrayBuffer::move(std::move(bytes));
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
std::shared_ptr<Promise<double>> HybridNarsilFilesImpl::writeAsync(double descriptor,
|
|
144
|
+
const std::shared_ptr<ArrayBuffer>& source,
|
|
145
|
+
double byteOffset, double byteLength,
|
|
146
|
+
double position) {
|
|
147
|
+
int file = descriptorOf(descriptor);
|
|
148
|
+
uint8_t* start = bytesWithin(source, byteOffset, byteLength, "The write source");
|
|
149
|
+
size_t length = static_cast<size_t>(byteLength);
|
|
150
|
+
bool atCurrentPosition = position == CURRENT_POSITION;
|
|
151
|
+
off_t offset = atCurrentPosition ? 0 : static_cast<off_t>(requireByteCount(position, "A write position"));
|
|
152
|
+
auto bytes = std::make_shared<std::vector<uint8_t>>(start, start + length);
|
|
153
|
+
return Promise<double>::async([file, bytes, atCurrentPosition, offset]() {
|
|
154
|
+
if (bytes->empty()) return 0.0;
|
|
155
|
+
ssize_t count = -1;
|
|
156
|
+
do {
|
|
157
|
+
count = atCurrentPosition ? ::write(file, bytes->data(), bytes->size())
|
|
158
|
+
: pwrite(file, bytes->data(), bytes->size(), offset);
|
|
159
|
+
} while (count < 0 && errno == EINTR);
|
|
160
|
+
if (count < 0) throwSystemError(errno, "write the file", "");
|
|
161
|
+
return static_cast<double>(count);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
std::shared_ptr<Promise<void>> HybridNarsilFilesImpl::syncAsync(double descriptor) {
|
|
166
|
+
int file = descriptorOf(descriptor);
|
|
167
|
+
return Promise<void>::async([file]() { syncDescriptor(file); });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
void HybridNarsilFilesImpl::truncate(double descriptor, double byteLength) {
|
|
171
|
+
off_t length = static_cast<off_t>(requireByteCount(byteLength, "A file length"));
|
|
172
|
+
if (ftruncate(descriptorOf(descriptor), length) != 0) throwSystemError(errno, "truncate the file", "");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
FileStatus HybridNarsilFilesImpl::descriptorStatus(double descriptor) {
|
|
176
|
+
struct stat status {};
|
|
177
|
+
if (fstat(descriptorOf(descriptor), &status) != 0) throwSystemError(errno, "read the file's status", "");
|
|
178
|
+
return statusOf(status);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
FileStatus HybridNarsilFilesImpl::pathStatus(const std::string& path) {
|
|
182
|
+
requirePath(path);
|
|
183
|
+
struct stat status {};
|
|
184
|
+
if (stat(path.c_str(), &status) != 0) throwSystemError(errno, "stat", path);
|
|
185
|
+
return statusOf(status);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
void HybridNarsilFilesImpl::makeDirectory(const std::string& path) {
|
|
189
|
+
requirePath(path);
|
|
190
|
+
if (mkdir(path.c_str(), PRIVATE_DIRECTORY_MODE) != 0) throwSystemError(errno, "mkdir", path);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
std::vector<DirectoryEntry> HybridNarsilFilesImpl::readDirectory(const std::string& path) {
|
|
194
|
+
requirePath(path);
|
|
195
|
+
DIR* directory = opendir(path.c_str());
|
|
196
|
+
if (directory == nullptr) throwSystemError(errno, "scandir", path);
|
|
197
|
+
std::vector<DirectoryEntry> entries;
|
|
198
|
+
errno = 0;
|
|
199
|
+
while (struct dirent* entry = readdir(directory)) {
|
|
200
|
+
std::string name = entry->d_name;
|
|
201
|
+
if (name == "." || name == "..") continue;
|
|
202
|
+
bool isDirectory = entry->d_type == DT_DIR;
|
|
203
|
+
bool isFile = entry->d_type == DT_REG;
|
|
204
|
+
if (entry->d_type == DT_UNKNOWN) {
|
|
205
|
+
struct stat status {};
|
|
206
|
+
std::string full = path + "/" + name;
|
|
207
|
+
if (lstat(full.c_str(), &status) == 0) {
|
|
208
|
+
isDirectory = S_ISDIR(status.st_mode);
|
|
209
|
+
isFile = S_ISREG(status.st_mode);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
entries.emplace_back(name, isDirectory, isFile);
|
|
213
|
+
errno = 0;
|
|
214
|
+
}
|
|
215
|
+
int failure = errno;
|
|
216
|
+
closedir(directory);
|
|
217
|
+
if (failure != 0) throwSystemError(failure, "scandir", path);
|
|
218
|
+
return entries;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
void HybridNarsilFilesImpl::rename(const std::string& from, const std::string& to) {
|
|
222
|
+
requirePath(from);
|
|
223
|
+
requirePath(to);
|
|
224
|
+
if (::rename(from.c_str(), to.c_str()) != 0) throwSystemError(errno, "rename", from + "' -> '" + to);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
void HybridNarsilFilesImpl::unlink(const std::string& path) {
|
|
228
|
+
requirePath(path);
|
|
229
|
+
if (::unlink(path.c_str()) != 0) throwSystemError(errno, "unlink", path);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
void HybridNarsilFilesImpl::removeDirectory(const std::string& path) {
|
|
233
|
+
requirePath(path);
|
|
234
|
+
if (rmdir(path.c_str()) != 0) throwSystemError(errno, "rmdir", path);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
void HybridNarsilFilesImpl::link(const std::string& existingPath, const std::string& newPath) {
|
|
238
|
+
requirePath(existingPath);
|
|
239
|
+
requirePath(newPath);
|
|
240
|
+
if (::link(existingPath.c_str(), newPath.c_str()) != 0) {
|
|
241
|
+
throwSystemError(errno, "link", existingPath + "' -> '" + newPath);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "HybridNarsilFilesSpec.hpp"
|
|
4
|
+
|
|
5
|
+
namespace margelo::nitro::narsil {
|
|
6
|
+
|
|
7
|
+
class HybridNarsilFilesImpl : public HybridNarsilFilesSpec {
|
|
8
|
+
public:
|
|
9
|
+
HybridNarsilFilesImpl() : HybridObject(TAG) {}
|
|
10
|
+
|
|
11
|
+
double open(const std::string& path, const std::string& flags) override;
|
|
12
|
+
void close(double descriptor) override;
|
|
13
|
+
double read(double descriptor, const std::shared_ptr<ArrayBuffer>& target, double byteOffset, double byteLength,
|
|
14
|
+
double position) override;
|
|
15
|
+
double write(double descriptor, const std::shared_ptr<ArrayBuffer>& source, double byteOffset, double byteLength,
|
|
16
|
+
double position) override;
|
|
17
|
+
void sync(double descriptor) override;
|
|
18
|
+
std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> readAsync(double descriptor, double byteLength,
|
|
19
|
+
double position) override;
|
|
20
|
+
std::shared_ptr<Promise<double>> writeAsync(double descriptor, const std::shared_ptr<ArrayBuffer>& source,
|
|
21
|
+
double byteOffset, double byteLength, double position) override;
|
|
22
|
+
std::shared_ptr<Promise<void>> syncAsync(double descriptor) override;
|
|
23
|
+
void truncate(double descriptor, double byteLength) override;
|
|
24
|
+
FileStatus descriptorStatus(double descriptor) override;
|
|
25
|
+
FileStatus pathStatus(const std::string& path) override;
|
|
26
|
+
void makeDirectory(const std::string& path) override;
|
|
27
|
+
std::vector<DirectoryEntry> readDirectory(const std::string& path) override;
|
|
28
|
+
void rename(const std::string& from, const std::string& to) override;
|
|
29
|
+
void unlink(const std::string& path) override;
|
|
30
|
+
void removeDirectory(const std::string& path) override;
|
|
31
|
+
void link(const std::string& existingPath, const std::string& newPath) override;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#include "HybridNarsilHostImpl.hpp"
|
|
2
|
+
#include "Compression.hpp"
|
|
3
|
+
#include "HostMemory.hpp"
|
|
4
|
+
#include "NativeAtomics.hpp"
|
|
5
|
+
#include "ProcessInfo.hpp"
|
|
6
|
+
#include "ThreadPriority.hpp"
|
|
7
|
+
#include "WorkletRuntimeDispatcher.hpp"
|
|
8
|
+
|
|
9
|
+
#include <cerrno>
|
|
10
|
+
#include <chrono>
|
|
11
|
+
#include <cmath>
|
|
12
|
+
#include <csignal>
|
|
13
|
+
#include <cstdint>
|
|
14
|
+
#include <cstdlib>
|
|
15
|
+
#include <jsi/instrumentation.h>
|
|
16
|
+
#include <unistd.h>
|
|
17
|
+
|
|
18
|
+
namespace margelo::nitro::narsil {
|
|
19
|
+
|
|
20
|
+
namespace {
|
|
21
|
+
|
|
22
|
+
double millisecondsSinceEpoch() {
|
|
23
|
+
auto now = std::chrono::system_clock::now().time_since_epoch();
|
|
24
|
+
return static_cast<double>(std::chrono::duration_cast<std::chrono::milliseconds>(now).count());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const double LIBRARY_LOADED_AT_MS = millisecondsSinceEpoch();
|
|
28
|
+
|
|
29
|
+
const char* const GARBAGE_COLLECTION_CAUSE = "narsil-memory-limit";
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
void HybridNarsilHostImpl::loadHybridMethods() {
|
|
34
|
+
HybridNarsilHostSpec::loadHybridMethods();
|
|
35
|
+
registerHybrids(this, [](Prototype& prototype) {
|
|
36
|
+
prototype.registerRawHybridMethod("collectGarbage", 0, &HybridNarsilHostImpl::collectGarbage);
|
|
37
|
+
prototype.registerRawHybridMethod("installWorkletDispatcher", 0, &HybridNarsilHostImpl::installWorkletDispatcher);
|
|
38
|
+
prototype.registerRawHybridMethod("threadPriority", 0, &HybridNarsilHostImpl::threadPriority);
|
|
39
|
+
prototype.registerRawHybridMethod("adoptAppThreadPriority", 1, &HybridNarsilHostImpl::adoptAppThreadPriority);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
jsi::Value HybridNarsilHostImpl::installWorkletDispatcher(jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*,
|
|
44
|
+
size_t) {
|
|
45
|
+
return jsi::Value(installWorkletRuntimeDispatcher(runtime));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
jsi::Value HybridNarsilHostImpl::threadPriority(jsi::Runtime&, const jsi::Value&, const jsi::Value*, size_t) {
|
|
49
|
+
return jsi::Value(priorityOfThisThread());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
jsi::Value HybridNarsilHostImpl::adoptAppThreadPriority(jsi::Runtime&, const jsi::Value&, const jsi::Value* arguments,
|
|
53
|
+
size_t count) {
|
|
54
|
+
if (count < 1 || !arguments[0].isNumber()) return jsi::Value(false);
|
|
55
|
+
return jsi::Value(margelo::nitro::narsil::adoptAppThreadPriority(arguments[0].getNumber()));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
jsi::Value HybridNarsilHostImpl::collectGarbage(jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*,
|
|
59
|
+
size_t) {
|
|
60
|
+
runtime.instrumentation().collectGarbage(GARBAGE_COLLECTION_CAUSE);
|
|
61
|
+
return jsi::Value(true);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
std::shared_ptr<ArrayBuffer> HybridNarsilHostImpl::reserveMemory(double bytes) { return reserveRegion(bytes); }
|
|
65
|
+
|
|
66
|
+
std::shared_ptr<ArrayBuffer> HybridNarsilHostImpl::allocateMemory(double bytes) { return allocateZeroed(bytes); }
|
|
67
|
+
|
|
68
|
+
bool HybridNarsilHostImpl::ownsMemory(const std::shared_ptr<ArrayBuffer>& buffer) { return isHostOwned(buffer); }
|
|
69
|
+
|
|
70
|
+
double HybridNarsilHostImpl::atomic(double operation, double elementKind, const std::shared_ptr<ArrayBuffer>& buffer,
|
|
71
|
+
double byteIndex, double value, double replacement) {
|
|
72
|
+
return atomicOnHostMemory(operation, elementKind, buffer, byteIndex, value, replacement);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
void HybridNarsilHostImpl::fillRandom(const std::shared_ptr<ArrayBuffer>& target, double byteOffset,
|
|
76
|
+
double byteLength) {
|
|
77
|
+
uint8_t* bytes = bytesWithin(target, byteOffset, byteLength, "The random byte target");
|
|
78
|
+
if (bytes != nullptr) arc4random_buf(bytes, static_cast<size_t>(byteLength));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
double HybridNarsilHostImpl::processId() { return static_cast<double>(getpid()); }
|
|
82
|
+
|
|
83
|
+
double HybridNarsilHostImpl::processStartedAtMs() { return LIBRARY_LOADED_AT_MS; }
|
|
84
|
+
|
|
85
|
+
bool HybridNarsilHostImpl::processIsAlive(double processId) {
|
|
86
|
+
if (!std::isfinite(processId) || processId <= 0 || std::floor(processId) != processId || processId > INT32_MAX) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
return kill(static_cast<pid_t>(processId), 0) == 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
ProcessMemory HybridNarsilHostImpl::processMemory() {
|
|
93
|
+
return ProcessMemory(residentBytesOfThisProcess(), availableBytesForThisProcess());
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
std::string HybridNarsilHostImpl::appStorageDirectory() { return privateStorageDirectory(); }
|
|
97
|
+
|
|
98
|
+
std::shared_ptr<ArrayBuffer> HybridNarsilHostImpl::deflateRaw(const std::shared_ptr<ArrayBuffer>& source,
|
|
99
|
+
double byteOffset, double byteLength) {
|
|
100
|
+
uint8_t* bytes = bytesWithin(source, byteOffset, byteLength, "The bytes to compress");
|
|
101
|
+
return compressBytes(bytes, static_cast<size_t>(byteLength), CompressionFormat::RawDeflate);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
std::shared_ptr<ArrayBuffer> HybridNarsilHostImpl::inflateRaw(const std::shared_ptr<ArrayBuffer>& source,
|
|
105
|
+
double byteOffset, double byteLength,
|
|
106
|
+
double rawByteLength) {
|
|
107
|
+
uint8_t* bytes = bytesWithin(source, byteOffset, byteLength, "The bytes to decompress");
|
|
108
|
+
size_t limit = requireByteCount(rawByteLength, "The decompressed length");
|
|
109
|
+
return inflateBytes(bytes, static_cast<size_t>(byteLength), CompressionFormat::RawDeflate, limit);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
std::shared_ptr<ArrayBuffer> HybridNarsilHostImpl::gzip(const std::shared_ptr<ArrayBuffer>& source,
|
|
113
|
+
double byteOffset, double byteLength) {
|
|
114
|
+
uint8_t* bytes = bytesWithin(source, byteOffset, byteLength, "The bytes to compress");
|
|
115
|
+
return compressBytes(bytes, static_cast<size_t>(byteLength), CompressionFormat::Gzip);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
std::shared_ptr<ArrayBuffer> HybridNarsilHostImpl::gunzip(const std::shared_ptr<ArrayBuffer>& source,
|
|
119
|
+
double byteOffset, double byteLength,
|
|
120
|
+
double maxByteLength) {
|
|
121
|
+
uint8_t* bytes = bytesWithin(source, byteOffset, byteLength, "The bytes to decompress");
|
|
122
|
+
size_t limit = requireByteCount(maxByteLength, "The decompressed length limit");
|
|
123
|
+
return inflateBytes(bytes, static_cast<size_t>(byteLength), CompressionFormat::Gzip, limit);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "HybridNarsilHostSpec.hpp"
|
|
4
|
+
|
|
5
|
+
namespace margelo::nitro::narsil {
|
|
6
|
+
|
|
7
|
+
class HybridNarsilHostImpl : public HybridNarsilHostSpec {
|
|
8
|
+
public:
|
|
9
|
+
HybridNarsilHostImpl() : HybridObject(TAG) {}
|
|
10
|
+
|
|
11
|
+
void loadHybridMethods() override;
|
|
12
|
+
jsi::Value collectGarbage(jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
|
|
13
|
+
size_t count);
|
|
14
|
+
jsi::Value installWorkletDispatcher(jsi::Runtime& runtime, const jsi::Value& thisValue,
|
|
15
|
+
const jsi::Value* arguments, size_t count);
|
|
16
|
+
jsi::Value threadPriority(jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
|
|
17
|
+
size_t count);
|
|
18
|
+
jsi::Value adoptAppThreadPriority(jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
|
|
19
|
+
size_t count);
|
|
20
|
+
|
|
21
|
+
std::shared_ptr<ArrayBuffer> reserveMemory(double bytes) override;
|
|
22
|
+
std::shared_ptr<ArrayBuffer> allocateMemory(double bytes) override;
|
|
23
|
+
bool ownsMemory(const std::shared_ptr<ArrayBuffer>& buffer) override;
|
|
24
|
+
double atomic(double operation, double elementKind, const std::shared_ptr<ArrayBuffer>& buffer, double byteIndex,
|
|
25
|
+
double value, double replacement) override;
|
|
26
|
+
void fillRandom(const std::shared_ptr<ArrayBuffer>& target, double byteOffset, double byteLength) override;
|
|
27
|
+
double processId() override;
|
|
28
|
+
double processStartedAtMs() override;
|
|
29
|
+
bool processIsAlive(double processId) override;
|
|
30
|
+
ProcessMemory processMemory() override;
|
|
31
|
+
std::string appStorageDirectory() override;
|
|
32
|
+
std::shared_ptr<ArrayBuffer> deflateRaw(const std::shared_ptr<ArrayBuffer>& source, double byteOffset,
|
|
33
|
+
double byteLength) override;
|
|
34
|
+
std::shared_ptr<ArrayBuffer> inflateRaw(const std::shared_ptr<ArrayBuffer>& source, double byteOffset,
|
|
35
|
+
double byteLength, double rawByteLength) override;
|
|
36
|
+
std::shared_ptr<ArrayBuffer> gzip(const std::shared_ptr<ArrayBuffer>& source, double byteOffset,
|
|
37
|
+
double byteLength) override;
|
|
38
|
+
std::shared_ptr<ArrayBuffer> gunzip(const std::shared_ptr<ArrayBuffer>& source, double byteOffset,
|
|
39
|
+
double byteLength, double maxByteLength) override;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#include "NativeAtomics.hpp"
|
|
2
|
+
#include "HostMemory.hpp"
|
|
3
|
+
|
|
4
|
+
#include <cmath>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
|
|
7
|
+
namespace margelo::nitro::narsil {
|
|
8
|
+
|
|
9
|
+
namespace {
|
|
10
|
+
|
|
11
|
+
enum AtomicOperation : int {
|
|
12
|
+
ATOMIC_LOAD = 0,
|
|
13
|
+
ATOMIC_STORE = 1,
|
|
14
|
+
ATOMIC_ADD = 2,
|
|
15
|
+
ATOMIC_SUB = 3,
|
|
16
|
+
ATOMIC_AND = 4,
|
|
17
|
+
ATOMIC_OR = 5,
|
|
18
|
+
ATOMIC_XOR = 6,
|
|
19
|
+
ATOMIC_EXCHANGE = 7,
|
|
20
|
+
ATOMIC_COMPARE_EXCHANGE = 8,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
enum AtomicElementKind : int {
|
|
24
|
+
ELEMENT_INT8 = 0,
|
|
25
|
+
ELEMENT_UINT8 = 1,
|
|
26
|
+
ELEMENT_INT16 = 2,
|
|
27
|
+
ELEMENT_UINT16 = 3,
|
|
28
|
+
ELEMENT_INT32 = 4,
|
|
29
|
+
ELEMENT_UINT32 = 5,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
constexpr double TWO_TO_THE_32 = 4294967296.0;
|
|
33
|
+
|
|
34
|
+
uint32_t wrappedToUint32(double value) {
|
|
35
|
+
if (!std::isfinite(value)) return 0;
|
|
36
|
+
double wrapped = std::fmod(std::trunc(value), TWO_TO_THE_32);
|
|
37
|
+
if (wrapped < 0) wrapped += TWO_TO_THE_32;
|
|
38
|
+
return static_cast<uint32_t>(wrapped);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
template <typename T>
|
|
42
|
+
T elementOf(double value) {
|
|
43
|
+
return static_cast<T>(wrappedToUint32(value));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
template <typename T>
|
|
47
|
+
double atomicOn(T* at, int operation, double value, double replacement) {
|
|
48
|
+
T operand = elementOf<T>(value);
|
|
49
|
+
switch (operation) {
|
|
50
|
+
case ATOMIC_LOAD:
|
|
51
|
+
return static_cast<double>(__atomic_load_n(at, __ATOMIC_SEQ_CST));
|
|
52
|
+
case ATOMIC_STORE:
|
|
53
|
+
__atomic_store_n(at, operand, __ATOMIC_SEQ_CST);
|
|
54
|
+
return static_cast<double>(operand);
|
|
55
|
+
case ATOMIC_ADD:
|
|
56
|
+
return static_cast<double>(__atomic_fetch_add(at, operand, __ATOMIC_SEQ_CST));
|
|
57
|
+
case ATOMIC_SUB:
|
|
58
|
+
return static_cast<double>(__atomic_fetch_sub(at, operand, __ATOMIC_SEQ_CST));
|
|
59
|
+
case ATOMIC_AND:
|
|
60
|
+
return static_cast<double>(__atomic_fetch_and(at, operand, __ATOMIC_SEQ_CST));
|
|
61
|
+
case ATOMIC_OR:
|
|
62
|
+
return static_cast<double>(__atomic_fetch_or(at, operand, __ATOMIC_SEQ_CST));
|
|
63
|
+
case ATOMIC_XOR:
|
|
64
|
+
return static_cast<double>(__atomic_fetch_xor(at, operand, __ATOMIC_SEQ_CST));
|
|
65
|
+
case ATOMIC_EXCHANGE:
|
|
66
|
+
return static_cast<double>(__atomic_exchange_n(at, operand, __ATOMIC_SEQ_CST));
|
|
67
|
+
case ATOMIC_COMPARE_EXCHANGE: {
|
|
68
|
+
T expected = operand;
|
|
69
|
+
__atomic_compare_exchange_n(at, &expected, elementOf<T>(replacement), false, __ATOMIC_SEQ_CST,
|
|
70
|
+
__ATOMIC_SEQ_CST);
|
|
71
|
+
return static_cast<double>(expected);
|
|
72
|
+
}
|
|
73
|
+
default:
|
|
74
|
+
throwInvalid("An atomic operation is a number from 0 to 8");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
template <typename T>
|
|
79
|
+
double atomicAt(const std::shared_ptr<ArrayBuffer>& buffer, double byteIndex, int operation, double value,
|
|
80
|
+
double replacement) {
|
|
81
|
+
uint8_t* bytes = bytesWithin(buffer, byteIndex, static_cast<double>(sizeof(T)), "The atomic element");
|
|
82
|
+
if (reinterpret_cast<uintptr_t>(bytes) % alignof(T) != 0) throwInvalid("The atomic element is not aligned");
|
|
83
|
+
return atomicOn(reinterpret_cast<T*>(bytes), operation, value, replacement);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
double atomicOnHostMemory(double operation, double elementKind, const std::shared_ptr<ArrayBuffer>& buffer,
|
|
89
|
+
double byteIndex, double value, double replacement) {
|
|
90
|
+
if (!isHostOwned(buffer)) throwInvalid("Atomic operations run only on memory that the native module allocated");
|
|
91
|
+
int op = static_cast<int>(operation);
|
|
92
|
+
switch (static_cast<int>(elementKind)) {
|
|
93
|
+
case ELEMENT_INT8:
|
|
94
|
+
return atomicAt<int8_t>(buffer, byteIndex, op, value, replacement);
|
|
95
|
+
case ELEMENT_UINT8:
|
|
96
|
+
return atomicAt<uint8_t>(buffer, byteIndex, op, value, replacement);
|
|
97
|
+
case ELEMENT_INT16:
|
|
98
|
+
return atomicAt<int16_t>(buffer, byteIndex, op, value, replacement);
|
|
99
|
+
case ELEMENT_UINT16:
|
|
100
|
+
return atomicAt<uint16_t>(buffer, byteIndex, op, value, replacement);
|
|
101
|
+
case ELEMENT_INT32:
|
|
102
|
+
return atomicAt<int32_t>(buffer, byteIndex, op, value, replacement);
|
|
103
|
+
case ELEMENT_UINT32:
|
|
104
|
+
return atomicAt<uint32_t>(buffer, byteIndex, op, value, replacement);
|
|
105
|
+
default:
|
|
106
|
+
throwInvalid("An atomic element kind is a number from 0 to 5");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <NitroModules/ArrayBuffer.hpp>
|
|
4
|
+
#include <memory>
|
|
5
|
+
|
|
6
|
+
namespace margelo::nitro::narsil {
|
|
7
|
+
|
|
8
|
+
double atomicOnHostMemory(double operation, double elementKind, const std::shared_ptr<ArrayBuffer>& buffer,
|
|
9
|
+
double byteIndex, double value, double replacement);
|
|
10
|
+
|
|
11
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#include "ProcessInfo.hpp"
|
|
2
|
+
#include "HostMemory.hpp"
|
|
3
|
+
|
|
4
|
+
#include <cerrno>
|
|
5
|
+
#include <cstdio>
|
|
6
|
+
#include <cstdlib>
|
|
7
|
+
#include <cstring>
|
|
8
|
+
#include <string>
|
|
9
|
+
#include <sys/stat.h>
|
|
10
|
+
#include <unistd.h>
|
|
11
|
+
|
|
12
|
+
#if defined(__APPLE__)
|
|
13
|
+
#include <mach/mach.h>
|
|
14
|
+
#include <os/proc.h>
|
|
15
|
+
#elif defined(__ANDROID__)
|
|
16
|
+
#include "AndroidEnvironment.hpp"
|
|
17
|
+
#include <fstream>
|
|
18
|
+
#endif
|
|
19
|
+
|
|
20
|
+
namespace margelo::nitro::narsil {
|
|
21
|
+
|
|
22
|
+
namespace {
|
|
23
|
+
|
|
24
|
+
constexpr double UNKNOWN_BYTES = -1;
|
|
25
|
+
|
|
26
|
+
void makeDirectoryIfMissing(const std::string& path) {
|
|
27
|
+
if (mkdir(path.c_str(), 0700) != 0 && errno != EEXIST) throwSystemError(errno, "create the directory", path);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#if defined(__APPLE__)
|
|
33
|
+
|
|
34
|
+
double residentBytesOfThisProcess() {
|
|
35
|
+
task_vm_info_data_t info{};
|
|
36
|
+
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
|
|
37
|
+
if (task_info(mach_task_self(), TASK_VM_INFO, reinterpret_cast<task_info_t>(&info), &count) != KERN_SUCCESS) {
|
|
38
|
+
return UNKNOWN_BYTES;
|
|
39
|
+
}
|
|
40
|
+
return static_cast<double>(info.phys_footprint);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
double availableBytesForThisProcess() { return static_cast<double>(os_proc_available_memory()); }
|
|
44
|
+
|
|
45
|
+
std::string privateStorageDirectory() {
|
|
46
|
+
const char* home = std::getenv("HOME");
|
|
47
|
+
if (home == nullptr || home[0] == '\0') throwSystemError(ENOENT, "find the app's home directory", "HOME");
|
|
48
|
+
std::string library = std::string(home) + "/Library";
|
|
49
|
+
std::string support = library + "/Application Support";
|
|
50
|
+
makeDirectoryIfMissing(library);
|
|
51
|
+
makeDirectoryIfMissing(support);
|
|
52
|
+
return support;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
#elif defined(__ANDROID__)
|
|
56
|
+
|
|
57
|
+
double residentBytesOfThisProcess() {
|
|
58
|
+
std::ifstream statm("/proc/self/statm");
|
|
59
|
+
double totalPages = 0;
|
|
60
|
+
double residentPages = 0;
|
|
61
|
+
if (!(statm >> totalPages >> residentPages)) return UNKNOWN_BYTES;
|
|
62
|
+
long page = sysconf(_SC_PAGESIZE);
|
|
63
|
+
return residentPages * static_cast<double>(page > 0 ? page : 4096);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
double availableBytesForThisProcess() { return androidAvailableBytes(); }
|
|
67
|
+
|
|
68
|
+
std::string privateStorageDirectory() {
|
|
69
|
+
std::string files = androidFilesDirectory();
|
|
70
|
+
if (files.empty()) throwSystemError(ENOENT, "find the app's private directory", "Context.getFilesDir()");
|
|
71
|
+
makeDirectoryIfMissing(files);
|
|
72
|
+
return files;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
#else
|
|
76
|
+
|
|
77
|
+
double residentBytesOfThisProcess() { return UNKNOWN_BYTES; }
|
|
78
|
+
double availableBytesForThisProcess() { return UNKNOWN_BYTES; }
|
|
79
|
+
std::string privateStorageDirectory() { throwSystemError(ENOTSUP, "find the app's private directory", ""); }
|
|
80
|
+
|
|
81
|
+
#endif
|
|
82
|
+
|
|
83
|
+
}
|