2019-03-02 13:46:04 -08:00
|
|
|
const std = @import("../std.zig");
|
2018-03-04 21:57:02 -08:00
|
|
|
const os = std.os;
|
2019-05-24 15:27:18 -07:00
|
|
|
const testing = std.testing;
|
2019-02-08 15:18:47 -08:00
|
|
|
const expect = std.testing.expect;
|
2018-03-04 21:57:02 -08:00
|
|
|
const io = std.io;
|
2019-05-26 10:17:34 -07:00
|
|
|
const fs = std.fs;
|
2018-10-01 10:43:25 -07:00
|
|
|
const mem = std.mem;
|
2019-05-29 01:30:30 -07:00
|
|
|
const elf = std.elf;
|
2019-05-24 19:52:07 -07:00
|
|
|
const File = std.fs.File;
|
2019-05-25 10:07:44 -07:00
|
|
|
const Thread = std.Thread;
|
2018-03-04 21:57:02 -08:00
|
|
|
|
2020-01-29 19:22:01 -08:00
|
|
|
const a = std.testing.allocator;
|
2018-03-04 21:57:02 -08:00
|
|
|
|
2018-04-03 21:08:10 -07:00
|
|
|
const builtin = @import("builtin");
|
2018-04-13 23:12:19 -07:00
|
|
|
const AtomicRmwOp = builtin.AtomicRmwOp;
|
|
|
|
const AtomicOrder = builtin.AtomicOrder;
|
2018-04-03 21:08:10 -07:00
|
|
|
|
2018-03-04 21:57:02 -08:00
|
|
|
test "makePath, put some files in it, deleteTree" {
|
2019-05-26 20:35:26 -07:00
|
|
|
try fs.makePath(a, "os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c");
|
2019-05-26 10:17:34 -07:00
|
|
|
try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense");
|
|
|
|
try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah");
|
2019-09-18 23:56:45 -07:00
|
|
|
try fs.deleteTree("os_test_tmp");
|
2019-11-30 12:14:04 -08:00
|
|
|
if (fs.cwd().openDirTraverse("os_test_tmp")) |dir| {
|
2018-04-03 21:08:10 -07:00
|
|
|
@panic("expected error");
|
2018-03-29 01:23:44 -07:00
|
|
|
} else |err| {
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(err == error.FileNotFound);
|
2018-03-29 01:23:44 -07:00
|
|
|
}
|
2018-03-04 21:57:02 -08:00
|
|
|
}
|
2018-04-13 02:27:09 -07:00
|
|
|
|
|
|
|
test "access file" {
|
2019-05-26 20:35:26 -07:00
|
|
|
try fs.makePath(a, "os_test_tmp");
|
2020-02-16 10:25:30 -08:00
|
|
|
if (fs.cwd().access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", .{})) |ok| {
|
2018-07-22 21:35:53 -07:00
|
|
|
@panic("expected error");
|
2018-04-13 02:27:09 -07:00
|
|
|
} else |err| {
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(err == error.FileNotFound);
|
2018-04-13 02:27:09 -07:00
|
|
|
}
|
|
|
|
|
2019-05-26 10:17:34 -07:00
|
|
|
try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", "");
|
2019-05-26 20:35:26 -07:00
|
|
|
try os.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", os.F_OK);
|
2019-09-18 23:56:45 -07:00
|
|
|
try fs.deleteTree("os_test_tmp");
|
2018-04-13 02:27:09 -07:00
|
|
|
}
|
2018-04-13 23:12:19 -07:00
|
|
|
|
2019-05-25 10:07:44 -07:00
|
|
|
fn testThreadIdFn(thread_id: *Thread.Id) void {
|
|
|
|
thread_id.* = Thread.getCurrentId();
|
2018-08-02 14:44:20 -07:00
|
|
|
}
|
|
|
|
|
2020-03-02 23:03:22 -08:00
|
|
|
test "sendfile" {
|
|
|
|
try fs.makePath(a, "os_test_tmp");
|
|
|
|
defer fs.deleteTree("os_test_tmp") catch {};
|
|
|
|
|
|
|
|
var dir = try fs.cwd().openDirList("os_test_tmp");
|
|
|
|
defer dir.close();
|
|
|
|
|
|
|
|
const line1 = "line1\n";
|
|
|
|
const line2 = "second line\n";
|
|
|
|
var vecs = [_]os.iovec_const{
|
|
|
|
.{
|
|
|
|
.iov_base = line1,
|
|
|
|
.iov_len = line1.len,
|
|
|
|
},
|
|
|
|
.{
|
|
|
|
.iov_base = line2,
|
|
|
|
.iov_len = line2.len,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
var src_file = try dir.createFileC("sendfile1.txt", .{ .read = true });
|
|
|
|
defer src_file.close();
|
|
|
|
|
|
|
|
try src_file.writevAll(&vecs);
|
|
|
|
|
|
|
|
var dest_file = try dir.createFileC("sendfile2.txt", .{ .read = true });
|
|
|
|
defer dest_file.close();
|
|
|
|
|
|
|
|
const header1 = "header1\n";
|
|
|
|
const header2 = "second header\n";
|
|
|
|
var headers = [_]os.iovec_const{
|
|
|
|
.{
|
|
|
|
.iov_base = header1,
|
|
|
|
.iov_len = header1.len,
|
|
|
|
},
|
|
|
|
.{
|
|
|
|
.iov_base = header2,
|
|
|
|
.iov_len = header2.len,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const trailer1 = "trailer1\n";
|
|
|
|
const trailer2 = "second trailer\n";
|
|
|
|
var trailers = [_]os.iovec_const{
|
|
|
|
.{
|
|
|
|
.iov_base = trailer1,
|
|
|
|
.iov_len = trailer1.len,
|
|
|
|
},
|
|
|
|
.{
|
|
|
|
.iov_base = trailer2,
|
|
|
|
.iov_len = trailer2.len,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
var written_buf: [header1.len + header2.len + 10 + trailer1.len + trailer2.len]u8 = undefined;
|
|
|
|
try sendfileAll(dest_file.handle, src_file.handle, 1, 10, &headers, &trailers, 0);
|
|
|
|
|
|
|
|
try dest_file.preadAll(&written_buf, 0);
|
|
|
|
expect(mem.eql(u8, &written_buf, "header1\nsecond header\nine1\nsecontrailer1\nsecond trailer\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sendfileAll(
|
|
|
|
out_fd: os.fd_t,
|
|
|
|
in_fd: os.fd_t,
|
|
|
|
offset: u64,
|
|
|
|
count: usize,
|
|
|
|
headers: []os.iovec_const,
|
|
|
|
trailers: []os.iovec_const,
|
|
|
|
flags: u32,
|
|
|
|
) os.SendFileError!void {
|
|
|
|
var amt: usize = undefined;
|
|
|
|
hdrs: {
|
|
|
|
var i: usize = 0;
|
|
|
|
while (i < headers.len) {
|
|
|
|
amt = try os.sendfile(out_fd, in_fd, offset, count, headers[i..], trailers, flags);
|
|
|
|
while (amt >= headers[i].iov_len) {
|
|
|
|
amt -= headers[i].iov_len;
|
|
|
|
i += 1;
|
|
|
|
if (i >= headers.len) break :hdrs;
|
|
|
|
}
|
|
|
|
headers[i].iov_base += amt;
|
|
|
|
headers[i].iov_len -= amt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var off = amt;
|
|
|
|
while (off < count) {
|
|
|
|
amt = try os.sendfile(out_fd, in_fd, offset + off, count - off, &[0]os.iovec_const{}, trailers, flags);
|
|
|
|
off += amt;
|
|
|
|
}
|
|
|
|
amt = off - count;
|
|
|
|
var i: usize = 0;
|
|
|
|
while (i < trailers.len) {
|
|
|
|
while (amt >= headers[i].iov_len) {
|
|
|
|
amt -= trailers[i].iov_len;
|
|
|
|
i += 1;
|
|
|
|
if (i >= trailers.len) return;
|
|
|
|
}
|
|
|
|
trailers[i].iov_base += amt;
|
|
|
|
trailers[i].iov_len -= amt;
|
|
|
|
if (std.Target.current.os.tag == .windows) {
|
|
|
|
amt = try os.writev(out_fd, trailers[i..]);
|
|
|
|
} else {
|
|
|
|
// Here we must use send because it's the only way to give the flags.
|
|
|
|
amt = try os.send(out_fd, trailers[i].iov_base[0..trailers[i].iov_len], flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-25 10:07:44 -07:00
|
|
|
test "std.Thread.getCurrentId" {
|
2019-02-01 14:49:29 -08:00
|
|
|
if (builtin.single_threaded) return error.SkipZigTest;
|
|
|
|
|
2019-05-25 10:07:44 -07:00
|
|
|
var thread_current_id: Thread.Id = undefined;
|
|
|
|
const thread = try Thread.spawn(&thread_current_id, testThreadIdFn);
|
2018-08-06 14:30:55 -07:00
|
|
|
const thread_id = thread.handle();
|
2018-08-02 14:44:20 -07:00
|
|
|
thread.wait();
|
2019-05-25 10:07:44 -07:00
|
|
|
if (Thread.use_pthreads) {
|
2019-04-05 15:12:46 -07:00
|
|
|
expect(thread_current_id == thread_id);
|
2020-02-24 22:52:27 -08:00
|
|
|
} else if (builtin.os.tag == .windows) {
|
2019-05-26 20:35:26 -07:00
|
|
|
expect(Thread.getCurrentId() != thread_current_id);
|
2019-04-05 15:12:46 -07:00
|
|
|
} else {
|
2019-05-26 20:35:26 -07:00
|
|
|
// If the thread completes very quickly, then thread_id can be 0. See the
|
|
|
|
// documentation comments for `std.Thread.handle`.
|
|
|
|
expect(thread_id == 0 or thread_current_id == thread_id);
|
2018-08-06 14:25:24 -07:00
|
|
|
}
|
2018-08-02 14:44:20 -07:00
|
|
|
}
|
|
|
|
|
2018-04-13 23:12:19 -07:00
|
|
|
test "spawn threads" {
|
2019-02-01 14:49:29 -08:00
|
|
|
if (builtin.single_threaded) return error.SkipZigTest;
|
|
|
|
|
2018-04-13 23:12:19 -07:00
|
|
|
var shared_ctx: i32 = 1;
|
|
|
|
|
2019-05-25 10:07:44 -07:00
|
|
|
const thread1 = try Thread.spawn({}, start1);
|
|
|
|
const thread2 = try Thread.spawn(&shared_ctx, start2);
|
|
|
|
const thread3 = try Thread.spawn(&shared_ctx, start2);
|
|
|
|
const thread4 = try Thread.spawn(&shared_ctx, start2);
|
2018-04-13 23:12:19 -07:00
|
|
|
|
|
|
|
thread1.wait();
|
|
|
|
thread2.wait();
|
|
|
|
thread3.wait();
|
|
|
|
thread4.wait();
|
|
|
|
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(shared_ctx == 4);
|
2018-04-13 23:12:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn start1(ctx: void) u8 {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-31 07:56:59 -07:00
|
|
|
fn start2(ctx: *i32) u8 {
|
2018-04-13 23:12:19 -07:00
|
|
|
_ = @atomicRmw(i32, ctx, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
|
|
|
|
return 0;
|
|
|
|
}
|
2018-07-06 22:23:18 -07:00
|
|
|
|
|
|
|
test "cpu count" {
|
2019-05-26 20:35:26 -07:00
|
|
|
const cpu_count = try Thread.cpuCount();
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(cpu_count >= 1);
|
2018-07-06 22:23:18 -07:00
|
|
|
}
|
2018-10-01 10:43:25 -07:00
|
|
|
|
|
|
|
test "AtomicFile" {
|
|
|
|
const test_out_file = "tmp_atomic_file_test_dest.txt";
|
|
|
|
const test_content =
|
|
|
|
\\ hello!
|
|
|
|
\\ this is a test file
|
|
|
|
;
|
|
|
|
{
|
2019-05-26 20:35:26 -07:00
|
|
|
var af = try fs.AtomicFile.init(test_out_file, File.default_mode);
|
2018-10-01 10:43:25 -07:00
|
|
|
defer af.deinit();
|
2020-03-02 23:03:22 -08:00
|
|
|
try af.file.writeAll(test_content);
|
2018-10-01 10:43:25 -07:00
|
|
|
try af.finish();
|
|
|
|
}
|
2020-01-31 17:06:50 -08:00
|
|
|
const content = try io.readFileAlloc(testing.allocator, test_out_file);
|
|
|
|
defer testing.allocator.free(content);
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(mem.eql(u8, content, test_content));
|
2018-10-01 10:43:25 -07:00
|
|
|
|
2019-11-30 12:14:04 -08:00
|
|
|
try fs.cwd().deleteFile(test_out_file);
|
2018-10-01 10:43:25 -07:00
|
|
|
}
|
2019-02-06 10:48:04 -08:00
|
|
|
|
|
|
|
test "thread local storage" {
|
|
|
|
if (builtin.single_threaded) return error.SkipZigTest;
|
2019-05-25 10:07:44 -07:00
|
|
|
const thread1 = try Thread.spawn({}, testTls);
|
|
|
|
const thread2 = try Thread.spawn({}, testTls);
|
2019-02-06 10:48:04 -08:00
|
|
|
testTls({});
|
|
|
|
thread1.wait();
|
|
|
|
thread2.wait();
|
|
|
|
}
|
|
|
|
|
|
|
|
threadlocal var x: i32 = 1234;
|
|
|
|
fn testTls(context: void) void {
|
|
|
|
if (x != 1234) @panic("bad start value");
|
|
|
|
x += 1;
|
|
|
|
if (x != 1235) @panic("bad end value");
|
|
|
|
}
|
2019-05-24 15:27:18 -07:00
|
|
|
|
|
|
|
test "getrandom" {
|
|
|
|
var buf_a: [50]u8 = undefined;
|
|
|
|
var buf_b: [50]u8 = undefined;
|
|
|
|
try os.getrandom(&buf_a);
|
|
|
|
try os.getrandom(&buf_b);
|
|
|
|
// If this test fails the chance is significantly higher that there is a bug than
|
|
|
|
// that two sets of 50 bytes were equal.
|
2019-11-27 00:30:39 -08:00
|
|
|
expect(!mem.eql(u8, &buf_a, &buf_b));
|
2019-05-24 15:27:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
test "getcwd" {
|
|
|
|
// at least call it so it gets compiled
|
|
|
|
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
2019-05-26 20:35:26 -07:00
|
|
|
_ = os.getcwd(&buf) catch undefined;
|
2019-05-24 15:27:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
test "realpath" {
|
|
|
|
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
2019-05-26 20:35:26 -07:00
|
|
|
testing.expectError(error.FileNotFound, fs.realpath("definitely_bogus_does_not_exist1234", &buf));
|
2019-05-24 15:27:18 -07:00
|
|
|
}
|
2019-05-29 00:43:39 -07:00
|
|
|
|
|
|
|
test "sigaltstack" {
|
2020-02-24 22:52:27 -08:00
|
|
|
if (builtin.os.tag == .windows or builtin.os.tag == .wasi) return error.SkipZigTest;
|
2019-05-29 00:43:39 -07:00
|
|
|
|
|
|
|
var st: os.stack_t = undefined;
|
|
|
|
try os.sigaltstack(null, &st);
|
|
|
|
// Setting a stack size less than MINSIGSTKSZ returns ENOMEM
|
|
|
|
st.ss_flags = 0;
|
|
|
|
st.ss_size = 1;
|
|
|
|
testing.expectError(error.SizeTooSmall, os.sigaltstack(&st, null));
|
|
|
|
}
|
2019-05-29 01:30:30 -07:00
|
|
|
|
|
|
|
// If the type is not available use void to avoid erroring out when `iter_fn` is
|
|
|
|
// analyzed
|
|
|
|
const dl_phdr_info = if (@hasDecl(os, "dl_phdr_info")) os.dl_phdr_info else c_void;
|
|
|
|
|
2020-02-17 14:22:32 -08:00
|
|
|
const IterFnError = error{
|
|
|
|
MissingPtLoadSegment,
|
|
|
|
MissingLoad,
|
|
|
|
BadElfMagic,
|
|
|
|
FailedConsistencyCheck,
|
|
|
|
};
|
|
|
|
|
|
|
|
fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
|
2019-05-29 01:30:30 -07:00
|
|
|
// Count how many libraries are loaded
|
2019-11-06 20:25:57 -08:00
|
|
|
counter.* += @as(usize, 1);
|
2019-05-29 01:30:30 -07:00
|
|
|
|
|
|
|
// The image should contain at least a PT_LOAD segment
|
2020-02-17 14:22:32 -08:00
|
|
|
if (info.dlpi_phnum < 1) return error.MissingPtLoadSegment;
|
2019-05-29 01:30:30 -07:00
|
|
|
|
|
|
|
// Quick & dirty validation of the phdr pointers, make sure we're not
|
|
|
|
// pointing to some random gibberish
|
|
|
|
var i: usize = 0;
|
|
|
|
var found_load = false;
|
|
|
|
while (i < info.dlpi_phnum) : (i += 1) {
|
|
|
|
const phdr = info.dlpi_phdr[i];
|
|
|
|
|
|
|
|
if (phdr.p_type != elf.PT_LOAD) continue;
|
|
|
|
|
2020-01-28 15:08:01 -08:00
|
|
|
const reloc_addr = info.dlpi_addr + phdr.p_vaddr;
|
2019-05-29 01:30:30 -07:00
|
|
|
// Find the ELF header
|
2020-01-28 15:08:01 -08:00
|
|
|
const elf_header = @intToPtr(*elf.Ehdr, reloc_addr - phdr.p_offset);
|
2019-05-29 01:30:30 -07:00
|
|
|
// Validate the magic
|
2020-02-17 14:22:32 -08:00
|
|
|
if (!mem.eql(u8, elf_header.e_ident[0..4], "\x7fELF")) return error.BadElfMagic;
|
2019-05-29 01:30:30 -07:00
|
|
|
// Consistency check
|
2020-02-17 14:22:32 -08:00
|
|
|
if (elf_header.e_phnum != info.dlpi_phnum) return error.FailedConsistencyCheck;
|
2019-05-29 01:30:30 -07:00
|
|
|
|
|
|
|
found_load = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-02-17 14:22:32 -08:00
|
|
|
if (!found_load) return error.MissingLoad;
|
2019-05-29 01:30:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
test "dl_iterate_phdr" {
|
2020-02-24 22:52:27 -08:00
|
|
|
if (builtin.os.tag == .windows or builtin.os.tag == .wasi or builtin.os.tag == .macosx)
|
2019-05-29 01:30:30 -07:00
|
|
|
return error.SkipZigTest;
|
|
|
|
|
|
|
|
var counter: usize = 0;
|
2020-02-17 14:22:32 -08:00
|
|
|
try os.dl_iterate_phdr(&counter, IterFnError, iter_fn);
|
2019-05-29 01:30:30 -07:00
|
|
|
expect(counter != 0);
|
|
|
|
}
|
2019-09-22 12:36:11 -07:00
|
|
|
|
|
|
|
test "gethostname" {
|
2020-02-24 22:52:27 -08:00
|
|
|
if (builtin.os.tag == .windows)
|
2019-09-22 12:36:11 -07:00
|
|
|
return error.SkipZigTest;
|
|
|
|
|
|
|
|
var buf: [os.HOST_NAME_MAX]u8 = undefined;
|
|
|
|
const hostname = try os.gethostname(&buf);
|
|
|
|
expect(hostname.len != 0);
|
|
|
|
}
|
2019-10-03 06:32:47 -07:00
|
|
|
|
|
|
|
test "pipe" {
|
2020-02-24 22:52:27 -08:00
|
|
|
if (builtin.os.tag == .windows)
|
2019-10-03 06:32:47 -07:00
|
|
|
return error.SkipZigTest;
|
|
|
|
|
|
|
|
var fds = try os.pipe();
|
2020-03-02 23:03:22 -08:00
|
|
|
expect((try os.write(fds[1], "hello")) == 5);
|
2019-10-03 06:32:47 -07:00
|
|
|
var buf: [16]u8 = undefined;
|
|
|
|
expect((try os.read(fds[0], buf[0..])) == 5);
|
|
|
|
testing.expectEqualSlices(u8, buf[0..5], "hello");
|
|
|
|
os.close(fds[1]);
|
|
|
|
os.close(fds[0]);
|
|
|
|
}
|
2019-10-10 20:22:18 -07:00
|
|
|
|
|
|
|
test "argsAlloc" {
|
2020-01-29 20:06:26 -08:00
|
|
|
var args = try std.process.argsAlloc(std.testing.allocator);
|
|
|
|
std.process.argsFree(std.testing.allocator, args);
|
2019-10-10 20:22:18 -07:00
|
|
|
}
|
2019-12-31 13:34:14 -08:00
|
|
|
|
|
|
|
test "memfd_create" {
|
|
|
|
// memfd_create is linux specific.
|
2020-02-24 22:52:27 -08:00
|
|
|
if (builtin.os.tag != .linux) return error.SkipZigTest;
|
2019-12-31 14:57:20 -08:00
|
|
|
const fd = std.os.memfd_create("test", 0) catch |err| switch (err) {
|
|
|
|
// Related: https://github.com/ziglang/zig/issues/4019
|
|
|
|
error.SystemOutdated => return error.SkipZigTest,
|
|
|
|
else => |e| return e,
|
|
|
|
};
|
2019-12-31 13:34:14 -08:00
|
|
|
defer std.os.close(fd);
|
2020-03-02 23:03:22 -08:00
|
|
|
expect((try std.os.write(fd, "test")) == 4);
|
2019-12-31 13:34:14 -08:00
|
|
|
try std.os.lseek_SET(fd, 0);
|
|
|
|
|
|
|
|
var buf: [10]u8 = undefined;
|
|
|
|
const bytes_read = try std.os.read(fd, &buf);
|
|
|
|
expect(bytes_read == 4);
|
|
|
|
expect(mem.eql(u8, buf[0..4], "test"));
|
|
|
|
}
|
2020-02-07 07:07:12 -08:00
|
|
|
|
|
|
|
test "mmap" {
|
2020-02-24 22:52:27 -08:00
|
|
|
if (builtin.os.tag == .windows)
|
2020-02-07 07:07:12 -08:00
|
|
|
return error.SkipZigTest;
|
|
|
|
|
|
|
|
// Simple mmap() call with non page-aligned size
|
|
|
|
{
|
|
|
|
const data = try os.mmap(
|
|
|
|
null,
|
|
|
|
1234,
|
|
|
|
os.PROT_READ | os.PROT_WRITE,
|
|
|
|
os.MAP_ANONYMOUS | os.MAP_PRIVATE,
|
|
|
|
-1,
|
|
|
|
0,
|
|
|
|
);
|
|
|
|
defer os.munmap(data);
|
|
|
|
|
|
|
|
testing.expectEqual(@as(usize, 1234), data.len);
|
|
|
|
|
|
|
|
// By definition the data returned by mmap is zero-filled
|
2020-02-12 15:49:42 -08:00
|
|
|
testing.expect(mem.eql(u8, data, &[_]u8{0x00} ** 1234));
|
|
|
|
|
|
|
|
// Make sure the memory is writeable as requested
|
|
|
|
std.mem.set(u8, data, 0x55);
|
|
|
|
testing.expect(mem.eql(u8, data, &[_]u8{0x55} ** 1234));
|
2020-02-07 07:07:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
const test_out_file = "os_tmp_test";
|
|
|
|
// Must be a multiple of 4096 so that the test works with mmap2
|
|
|
|
const alloc_size = 8 * 4096;
|
|
|
|
|
|
|
|
// Create a file used for testing mmap() calls with a file descriptor
|
|
|
|
{
|
|
|
|
const file = try fs.cwd().createFile(test_out_file, .{});
|
|
|
|
defer file.close();
|
|
|
|
|
|
|
|
var out_stream = file.outStream();
|
|
|
|
const stream = &out_stream.stream;
|
|
|
|
|
|
|
|
var i: u32 = 0;
|
|
|
|
while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
|
|
|
|
try stream.writeIntNative(u32, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Map the whole file
|
|
|
|
{
|
2020-02-12 15:49:42 -08:00
|
|
|
const file = try fs.cwd().openFile(test_out_file, .{});
|
2020-02-07 07:07:12 -08:00
|
|
|
defer file.close();
|
|
|
|
|
|
|
|
const data = try os.mmap(
|
|
|
|
null,
|
|
|
|
alloc_size,
|
|
|
|
os.PROT_READ,
|
|
|
|
os.MAP_PRIVATE,
|
|
|
|
file.handle,
|
|
|
|
0,
|
|
|
|
);
|
|
|
|
defer os.munmap(data);
|
|
|
|
|
|
|
|
var mem_stream = io.SliceInStream.init(data);
|
|
|
|
const stream = &mem_stream.stream;
|
|
|
|
|
|
|
|
var i: u32 = 0;
|
|
|
|
while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
|
|
|
|
testing.expectEqual(i, try stream.readIntNative(u32));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Map the upper half of the file
|
|
|
|
{
|
2020-02-12 15:49:42 -08:00
|
|
|
const file = try fs.cwd().openFile(test_out_file, .{});
|
2020-02-07 07:07:12 -08:00
|
|
|
defer file.close();
|
|
|
|
|
|
|
|
const data = try os.mmap(
|
|
|
|
null,
|
2020-02-12 15:49:42 -08:00
|
|
|
alloc_size / 2,
|
2020-02-07 07:07:12 -08:00
|
|
|
os.PROT_READ,
|
|
|
|
os.MAP_PRIVATE,
|
|
|
|
file.handle,
|
|
|
|
alloc_size / 2,
|
|
|
|
);
|
|
|
|
defer os.munmap(data);
|
|
|
|
|
|
|
|
var mem_stream = io.SliceInStream.init(data);
|
|
|
|
const stream = &mem_stream.stream;
|
|
|
|
|
|
|
|
var i: u32 = alloc_size / 2 / @sizeOf(u32);
|
|
|
|
while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
|
|
|
|
testing.expectEqual(i, try stream.readIntNative(u32));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
try fs.cwd().deleteFile(test_out_file);
|
|
|
|
}
|
2020-02-22 14:35:36 -08:00
|
|
|
|
|
|
|
test "getenv" {
|
2020-02-24 22:52:27 -08:00
|
|
|
if (builtin.os.tag == .windows) {
|
2020-02-22 14:35:36 -08:00
|
|
|
expect(os.getenvW(&[_:0]u16{ 'B', 'O', 'G', 'U', 'S', 0x11, 0x22, 0x33, 0x44, 0x55 }) == null);
|
|
|
|
} else {
|
|
|
|
expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null);
|
|
|
|
}
|
|
|
|
}
|