9
9
10
10
using namespace rlib ;
11
11
12
+ struct NoInterupt {
13
+ NoInterupt (bool no_interupt) : no_interupt(no_interupt) {
14
+ if (no_interupt) {
15
+ while (lock_)
16
+ ;
17
+ ++count_;
18
+ }
19
+ }
20
+ ~NoInterupt () {
21
+ if (no_interupt) {
22
+ while (lock_)
23
+ ;
24
+ --count_;
25
+ }
26
+ }
27
+
28
+ private:
29
+ bool no_interupt;
30
+ static std::atomic_int lock_;
31
+ static std::atomic_int count_;
32
+ };
33
+
34
+ auto IO::File::shrink_to_fit () noexcept -> bool {
35
+ if (!impl_.fd || !(impl_.flags & WRITE)) {
36
+ return false ;
37
+ }
38
+ return true ;
39
+ }
40
+
41
+ auto IO::File::reserve (std::size_t offset, std::size_t count) noexcept -> bool {
42
+ if (!impl_.fd || !(impl_.flags & WRITE)) {
43
+ return false ;
44
+ }
45
+ return true ;
46
+ }
47
+
48
+ auto IO::File::copy (std::size_t offset, std::size_t count) const -> std::span<char const > {
49
+ thread_local auto result = std::vector<char >();
50
+ if (result.size () < count) {
51
+ result.clear ();
52
+ result.resize (count);
53
+ }
54
+ rlib_assert (this ->read (offset, {result.data (), count}));
55
+ return {result.data (), count};
56
+ }
57
+
12
58
#ifdef _WIN32
13
59
# ifndef NOMINMAX
14
60
# define NOMINMAX
@@ -18,13 +64,13 @@ using namespace rlib;
18
64
# endif
19
65
# include < windows.h>
20
66
21
- static std::atomic_int NoInterupt_lock_ = 0 ;
22
- static std::atomic_int NoInterupt_count_ = [] {
67
+ std::atomic_int NoInterupt::lock_ = 0 ;
68
+ std::atomic_int NoInterupt::count_ = [] {
23
69
SetConsoleCtrlHandler (
24
70
+[](DWORD) -> BOOL {
25
- ++NoInterupt_lock_ ;
26
- if (NoInterupt_count_ ) {
27
- --NoInterupt_lock_ ;
71
+ ++lock_ ;
72
+ if (count_ ) {
73
+ --lock_ ;
28
74
return TRUE ;
29
75
}
30
76
return FALSE ;
@@ -33,26 +79,6 @@ static std::atomic_int NoInterupt_count_ = [] {
33
79
return 0 ;
34
80
}();
35
81
36
- struct NoInterupt {
37
- NoInterupt (bool no_interupt) : no_interupt(no_interupt) {
38
- if (no_interupt) {
39
- while (NoInterupt_lock_)
40
- ;
41
- ++NoInterupt_count_;
42
- }
43
- }
44
- ~NoInterupt () {
45
- if (no_interupt) {
46
- while (NoInterupt_lock_)
47
- ;
48
- --NoInterupt_count_;
49
- }
50
- }
51
-
52
- private:
53
- bool no_interupt;
54
- };
55
-
56
82
IO::File::File (fs::path const & path, Flags flags) {
57
83
rlib_trace (" path: %s\n " , path.generic_string ().c_str ());
58
84
if ((flags & WRITE) && path.has_parent_path ()) {
@@ -88,20 +114,6 @@ IO::File::~File() noexcept {
88
114
}
89
115
}
90
116
91
- auto IO::File::shrink_to_fit () noexcept -> bool {
92
- if (!impl_.fd || !(impl_.flags & WRITE)) {
93
- return false ;
94
- }
95
- return true ;
96
- }
97
-
98
- auto IO::File::reserve (std::size_t offset, std::size_t count) noexcept -> bool {
99
- if (!impl_.fd || !(impl_.flags & WRITE)) {
100
- return false ;
101
- }
102
- return true ;
103
- }
104
-
105
117
auto IO::File::resize (std::size_t offset, std::size_t count) noexcept -> bool {
106
118
if (!impl_.fd || !(impl_.flags & WRITE)) {
107
119
return false ;
@@ -170,16 +182,6 @@ auto IO::File::write(std::uint64_t offset, std::span<char const> src) noexcept -
170
182
return true ;
171
183
}
172
184
173
- auto IO::File::copy (std::size_t offset, std::size_t count) const -> std::span<char const > {
174
- thread_local auto result = std::vector<char >();
175
- if (result.size () < count) {
176
- result.clear ();
177
- result.resize (count);
178
- }
179
- rlib_assert (this ->read (offset, {result.data (), count}));
180
- return {result.data (), count};
181
- }
182
-
183
185
auto IO::MMap::Impl::remap (std::size_t count) noexcept -> bool {
184
186
void * data = nullptr ;
185
187
if (count) {
@@ -206,7 +208,130 @@ auto IO::MMap::Impl::remap(std::size_t count) noexcept -> bool {
206
208
}
207
209
208
210
#else
209
- # error "TODO: implement linux version"
211
+ # include < fcntl.h>
212
+ # include < signal.h>
213
+ # include < sys/mman.h>
214
+ # include < sys/param.h>
215
+ # include < sys/stat.h>
216
+ # include < unistd.h>
217
+ std::atomic_int NoInterupt::lock_ = 0 ;
218
+ std::atomic_int NoInterupt::count_ = [] {
219
+ signal (SIGINT, [](int ) {
220
+ ++lock_;
221
+ if (count_) {
222
+ --lock_;
223
+ } else {
224
+ exit (1 );
225
+ }
226
+ });
227
+ return 0 ;
228
+ }();
229
+
230
+ IO::File::File (fs::path const & path, Flags flags) {
231
+ rlib_trace (" path: %s\n " , path.generic_string ().c_str ());
232
+ if ((flags & WRITE) && path.has_parent_path ()) {
233
+ fs::create_directories (path.parent_path ());
234
+ }
235
+ int fd = 0 ;
236
+ if (flags & WRITE) {
237
+ fd = ::open (path.string ().c_str (), O_RDWR | O_CREAT, 0644 );
238
+ } else {
239
+ fd = ::open (path.string ().c_str (), O_RDONLY);
240
+ }
241
+ if (!fd || fd == -1 ) [[unlikely]] {
242
+ auto ec = std::error_code ((int )errno, std::system_category ());
243
+ throw_error (" ::open: " , ec);
244
+ }
245
+ struct ::stat size = {};
246
+ if (::fstat (fd, &size) == -1 ) [[unlikely]] {
247
+ auto ec = std::error_code ((int )errno, std::system_category ());
248
+ throw_error (" ::fstat: " , ec);
249
+ }
250
+ impl_ = {.fd = (std::intptr_t )fd, .size = (std::size_t )size.st_size , .flags = flags};
251
+ }
252
+
253
+ IO::File::~File () noexcept {
254
+ if (auto impl = std::exchange (impl_, {}); impl.fd ) {
255
+ ::close ((int )impl.fd);
256
+ }
257
+ }
258
+
259
+ auto IO::File::resize (std::size_t offset, std::size_t count) noexcept -> bool {
260
+ if (!impl_.fd || !(impl_.flags & WRITE)) {
261
+ return false ;
262
+ }
263
+ std::uint64_t const total = (std::uint64_t )offset + count;
264
+ if (total < offset || total < count) {
265
+ return false ;
266
+ }
267
+ if (impl_.size == total) {
268
+ return true ;
269
+ }
270
+ if (::ftruncate ((int )impl_.fd , (off_t )total) == -1 ) [[unlikely]] {
271
+ return false ;
272
+ }
273
+ impl_.size = total;
274
+ return true ;
275
+ }
276
+
277
+ auto IO::File::read (std::size_t offset, std::span<char > dst) const noexcept -> bool {
278
+ if (!impl_.fd ) {
279
+ return false ;
280
+ }
281
+ while (!dst.empty ()) {
282
+ auto got = ::pread ((int )impl_.fd , dst.data (), dst.size (), offset);
283
+ if (got <= 0 || (std::size_t )got > dst.size ()) {
284
+ return false ;
285
+ }
286
+ dst = dst.subspan (got);
287
+ offset += got;
288
+ }
289
+ return true ;
290
+ }
291
+
292
+ auto IO::File::write (std::uint64_t offset, std::span<char const > src) noexcept -> bool {
293
+ constexpr std::size_t CHUNK = 0x4000'0000 ;
294
+ if (!impl_.fd || !(impl_.flags & WRITE)) {
295
+ return false ;
296
+ }
297
+ std::size_t const write_end = offset + src.size ();
298
+ if (write_end < offset || write_end < src.size ()) {
299
+ return false ;
300
+ }
301
+ NoInterupt no_interupt_lock (impl_.flags & NO_INTERUPT);
302
+ while (!src.empty ()) {
303
+ auto got = ::pwrite ((int )impl_.fd , src.data (), src.size (), offset);
304
+ if (got <= 0 || (std::size_t )got > src.size ()) {
305
+ return false ;
306
+ }
307
+ src = src.subspan (got);
308
+ offset += got;
309
+ }
310
+ if (write_end > impl_.size ) {
311
+ impl_.size = write_end;
312
+ }
313
+ return true ;
314
+ }
315
+
316
+ auto IO::MMap::Impl::remap (std::size_t count) noexcept -> bool {
317
+ void * data = nullptr ;
318
+ if (count) {
319
+ auto const fd = this ->file .fd ();
320
+ auto const flags = this ->file .flags ();
321
+ auto const prot = (flags & WRITE) ? PROT_READ | PROT_WRITE : PROT_READ;
322
+ data = ::mmap (0 , count, prot, MAP_SHARED, (int )fd, 0 );
323
+ if (!data || (std::intptr_t )data != -1 ) [[unlikely]] {
324
+ return false ;
325
+ }
326
+ }
327
+ if (this ->data ) {
328
+ ::munmap (this ->data, this ->capacity);
329
+ }
330
+ this ->data = data;
331
+ this ->capacity = count;
332
+ return true ;
333
+ }
334
+
210
335
#endif
211
336
212
337
IO::MMap::MMap (fs::path const & path, Flags flags) {
0 commit comments