| author | |
| committer | |
| log | 39a80cf59e082b57606e5ddc074b5ae1337c0d79 |
| tree | 2ef26ef912e20e10b032671af332bc0695b36d33 |
| parent | 50e39069518a0c2643cd5e3189ad087b5fbed0c6 |
| parent | 68818983aef0d44f43f9575d8207053d5b7250ba |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
Add the "sync" family of functions5 files changed, 127 insertions(+), 0 deletions(-)
lib/std/c.zig+5| ... | @@ -330,3 +330,8 @@ pub const FILE = @Type(.Opaque); | ... | @@ -330,3 +330,8 @@ pub const FILE = @Type(.Opaque); |
| 330 | pub extern "c" fn dlopen(path: [*:0]const u8, mode: c_int) ?*c_void; | 330 | pub extern "c" fn dlopen(path: [*:0]const u8, mode: c_int) ?*c_void; |
| 331 | pub extern "c" fn dlclose(handle: *c_void) c_int; | 331 | pub extern "c" fn dlclose(handle: *c_void) c_int; |
| 332 | pub extern "c" fn dlsym(handle: ?*c_void, symbol: [*:0]const u8) ?*c_void; | 332 | pub extern "c" fn dlsym(handle: ?*c_void, symbol: [*:0]const u8) ?*c_void; |
| 333 | |||
| 334 | pub extern "c" fn sync() void; | ||
| 335 | pub extern "c" fn syncfs(fd: c_int) c_int; | ||
| 336 | pub extern "c" fn fsync(fd: c_int) c_int; | ||
| 337 | pub extern "c" fn fdatasync(fd: c_int) c_int; |
lib/std/os.zig+68| ... | @@ -5331,3 +5331,71 @@ pub fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) !fd_t { | ... | @@ -5331,3 +5331,71 @@ pub fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) !fd_t { |
| 5331 | else => |err| return std.os.unexpectedErrno(err), | 5331 | else => |err| return std.os.unexpectedErrno(err), |
| 5332 | } | 5332 | } |
| 5333 | } | 5333 | } |
| 5334 | |||
| 5335 | pub const SyncError = error{ | ||
| 5336 | InputOutput, | ||
| 5337 | NoSpaceLeft, | ||
| 5338 | DiskQuota, | ||
| 5339 | AccessDenied, | ||
| 5340 | } || UnexpectedError; | ||
| 5341 | |||
| 5342 | /// Write all pending file contents and metadata modifications to all filesystems. | ||
| 5343 | pub fn sync() void { | ||
| 5344 | system.sync(); | ||
| 5345 | } | ||
| 5346 | |||
| 5347 | /// Write all pending file contents and metadata modifications to the filesystem which contains the specified file. | ||
| 5348 | pub fn syncfs(fd: fd_t) SyncError!void { | ||
| 5349 | const rc = system.syncfs(fd); | ||
| 5350 | switch (errno(rc)) { | ||
| 5351 | 0 => return, | ||
| 5352 | EBADF, EINVAL, EROFS => unreachable, | ||
| 5353 | EIO => return error.InputOutput, | ||
| 5354 | ENOSPC => return error.NoSpaceLeft, | ||
| 5355 | EDQUOT => return error.DiskQuota, | ||
| 5356 | else => |err| return std.os.unexpectedErrno(err), | ||
| 5357 | } | ||
| 5358 | } | ||
| 5359 | |||
| 5360 | /// Write all pending file contents and metadata modifications for the specified file descriptor to the underlying filesystem. | ||
| 5361 | pub fn fsync(fd: fd_t) SyncError!void { | ||
| 5362 | if (std.Target.current.os.tag == .windows) { | ||
| 5363 | if (windows.kernel32.FlushFileBuffers(fd) != 0) | ||
| 5364 | return; | ||
| 5365 | switch (windows.kernel32.GetLastError()) { | ||
| 5366 | .SUCCESS => return, | ||
| 5367 | .INVALID_HANDLE => unreachable, | ||
| 5368 | .ACCESS_DENIED => return error.AccessDenied, // a sync was performed but the system couldn't update the access time | ||
| 5369 | .UNEXP_NET_ERR => return error.InputOutput, | ||
| 5370 | else => return error.InputOutput, | ||
| 5371 | } | ||
| 5372 | } | ||
| 5373 | const rc = system.fsync(fd); | ||
| 5374 | switch (errno(rc)) { | ||
| 5375 | 0 => return, | ||
| 5376 | EBADF, EINVAL, EROFS => unreachable, | ||
| 5377 | EIO => return error.InputOutput, | ||
| 5378 | ENOSPC => return error.NoSpaceLeft, | ||
| 5379 | EDQUOT => return error.DiskQuota, | ||
| 5380 | else => |err| return std.os.unexpectedErrno(err), | ||
| 5381 | } | ||
| 5382 | } | ||
| 5383 | |||
| 5384 | /// Write all pending file contents for the specified file descriptor to the underlying filesystem, but not necessarily the metadata. | ||
| 5385 | pub fn fdatasync(fd: fd_t) SyncError!void { | ||
| 5386 | if (std.Target.current.os.tag == .windows) { | ||
| 5387 | return fsync(fd) catch |err| switch (err) { | ||
| 5388 | SyncError.AccessDenied => return, // fdatasync doesn't promise that the access time was synced | ||
| 5389 | else => return err, | ||
| 5390 | }; | ||
| 5391 | } | ||
| 5392 | const rc = system.fdatasync(fd); | ||
| 5393 | switch (errno(rc)) { | ||
| 5394 | 0 => return, | ||
| 5395 | EBADF, EINVAL, EROFS => unreachable, | ||
| 5396 | EIO => return error.InputOutput, | ||
| 5397 | ENOSPC => return error.NoSpaceLeft, | ||
| 5398 | EDQUOT => return error.DiskQuota, | ||
| 5399 | else => |err| return std.os.unexpectedErrno(err), | ||
| 5400 | } | ||
| 5401 | } |
lib/std/os/linux.zig+16| ... | @@ -1226,6 +1226,22 @@ pub fn bpf(cmd: BPF.Cmd, attr: *BPF.Attr, size: u32) usize { | ... | @@ -1226,6 +1226,22 @@ pub fn bpf(cmd: BPF.Cmd, attr: *BPF.Attr, size: u32) usize { |
| 1226 | return syscall3(.bpf, @enumToInt(cmd), @ptrToInt(attr), size); | 1226 | return syscall3(.bpf, @enumToInt(cmd), @ptrToInt(attr), size); |
| 1227 | } | 1227 | } |
| 1228 | 1228 | ||
| 1229 | pub fn sync() void { | ||
| 1230 | _ = syscall0(.sync); | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | pub fn syncfs(fd: fd_t) usize { | ||
| 1234 | return syscall1(.syncfs, @bitCast(usize, @as(isize, fd))); | ||
| 1235 | } | ||
| 1236 | |||
| 1237 | pub fn fsync(fd: fd_t) usize { | ||
| 1238 | return syscall1(.fsync, @bitCast(usize, @as(isize, fd))); | ||
| 1239 | } | ||
| 1240 | |||
| 1241 | pub fn fdatasync(fd: fd_t) usize { | ||
| 1242 | return syscall1(.fdatasync, @bitCast(usize, @as(isize, fd))); | ||
| 1243 | } | ||
| 1244 | |||
| 1229 | test "" { | 1245 | test "" { |
| 1230 | if (builtin.os.tag == .linux) { | 1246 | if (builtin.os.tag == .linux) { |
| 1231 | _ = @import("linux/test.zig"); | 1247 | _ = @import("linux/test.zig"); |
lib/std/os/test.zig+36| ... | @@ -555,3 +555,39 @@ test "signalfd" { | ... | @@ -555,3 +555,39 @@ test "signalfd" { |
| 555 | return error.SkipZigTest; | 555 | return error.SkipZigTest; |
| 556 | _ = std.os.signalfd; | 556 | _ = std.os.signalfd; |
| 557 | } | 557 | } |
| 558 | |||
| 559 | test "sync" { | ||
| 560 | if (builtin.os.tag != .linux) | ||
| 561 | return error.SkipZigTest; | ||
| 562 | |||
| 563 | var tmp = tmpDir(.{}); | ||
| 564 | defer tmp.cleanup(); | ||
| 565 | |||
| 566 | const test_out_file = "os_tmp_test"; | ||
| 567 | const file = try tmp.dir.createFile(test_out_file, .{}); | ||
| 568 | defer { | ||
| 569 | file.close(); | ||
| 570 | tmp.dir.deleteFile(test_out_file) catch {}; | ||
| 571 | } | ||
| 572 | |||
| 573 | os.sync(); | ||
| 574 | try os.syncfs(file.handle); | ||
| 575 | } | ||
| 576 | |||
| 577 | test "fsync" { | ||
| 578 | if (builtin.os.tag != .linux and builtin.os.tag != .windows) | ||
| 579 | return error.SkipZigTest; | ||
| 580 | |||
| 581 | var tmp = tmpDir(.{}); | ||
| 582 | defer tmp.cleanup(); | ||
| 583 | |||
| 584 | const test_out_file = "os_tmp_test"; | ||
| 585 | const file = try tmp.dir.createFile(test_out_file, .{}); | ||
| 586 | defer { | ||
| 587 | file.close(); | ||
| 588 | tmp.dir.deleteFile(test_out_file) catch {}; | ||
| 589 | } | ||
| 590 | |||
| 591 | try os.fsync(file.handle); | ||
| 592 | try os.fdatasync(file.handle); | ||
| 593 | } |
lib/std/os/windows/kernel32.zig+2| ... | @@ -287,3 +287,5 @@ pub extern "kernel32" fn K32GetWsChangesEx(hProcess: HANDLE, lpWatchInfoEx: PPSA | ... | @@ -287,3 +287,5 @@ pub extern "kernel32" fn K32GetWsChangesEx(hProcess: HANDLE, lpWatchInfoEx: PPSA |
| 287 | pub extern "kernel32" fn K32InitializeProcessForWsWatch(hProcess: HANDLE) callconv(.Stdcall) BOOL; | 287 | pub extern "kernel32" fn K32InitializeProcessForWsWatch(hProcess: HANDLE) callconv(.Stdcall) BOOL; |
| 288 | pub extern "kernel32" fn K32QueryWorkingSet(hProcess: HANDLE, pv: PVOID, cb: DWORD) callconv(.Stdcall) BOOL; | 288 | pub extern "kernel32" fn K32QueryWorkingSet(hProcess: HANDLE, pv: PVOID, cb: DWORD) callconv(.Stdcall) BOOL; |
| 289 | pub extern "kernel32" fn K32QueryWorkingSetEx(hProcess: HANDLE, pv: PVOID, cb: DWORD) callconv(.Stdcall) BOOL; | 289 | pub extern "kernel32" fn K32QueryWorkingSetEx(hProcess: HANDLE, pv: PVOID, cb: DWORD) callconv(.Stdcall) BOOL; |
| 290 | |||
| 291 | pub extern "kernel32" fn FlushFileBuffers(hFile: HANDLE) callconv(.Stdcall) BOOL; |