2019-03-02 21:46:04 +00:00
|
|
|
const std = @import("../std.zig");
|
2018-03-05 05:57:02 +00:00
|
|
|
const os = std.os;
|
2019-05-24 22:27:18 +00:00
|
|
|
const testing = std.testing;
|
2019-02-08 23:18:47 +00:00
|
|
|
const expect = std.testing.expect;
|
2018-03-05 05:57:02 +00:00
|
|
|
const io = std.io;
|
2019-05-26 17:17:34 +00:00
|
|
|
const fs = std.fs;
|
2018-10-01 17:43:25 +00:00
|
|
|
const mem = std.mem;
|
2019-05-29 08:30:30 +00:00
|
|
|
const elf = std.elf;
|
2019-05-25 02:52:07 +00:00
|
|
|
const File = std.fs.File;
|
2019-05-25 17:07:44 +00:00
|
|
|
const Thread = std.Thread;
|
2018-03-05 05:57:02 +00:00
|
|
|
|
|
|
|
const a = std.debug.global_allocator;
|
|
|
|
|
2018-04-04 04:08:10 +00:00
|
|
|
const builtin = @import("builtin");
|
2018-04-14 06:12:19 +00:00
|
|
|
const AtomicRmwOp = builtin.AtomicRmwOp;
|
|
|
|
const AtomicOrder = builtin.AtomicOrder;
|
2018-04-04 04:08:10 +00:00
|
|
|
|
2018-03-05 05:57:02 +00:00
|
|
|
test "makePath, put some files in it, deleteTree" {
|
2019-05-27 03:35:26 +00:00
|
|
|
try fs.makePath(a, "os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c");
|
2019-05-26 17:17:34 +00: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-05-27 03:35:26 +00:00
|
|
|
try fs.deleteTree(a, "os_test_tmp");
|
|
|
|
if (fs.Dir.open(a, "os_test_tmp")) |dir| {
|
2018-04-04 04:08:10 +00:00
|
|
|
@panic("expected error");
|
2018-03-29 08:23:44 +00:00
|
|
|
} else |err| {
|
2019-02-08 23:18:47 +00:00
|
|
|
expect(err == error.FileNotFound);
|
2018-03-29 08:23:44 +00:00
|
|
|
}
|
2018-03-05 05:57:02 +00:00
|
|
|
}
|
2018-04-13 09:27:09 +00:00
|
|
|
|
|
|
|
test "access file" {
|
2019-05-27 03:35:26 +00:00
|
|
|
try fs.makePath(a, "os_test_tmp");
|
2019-05-26 17:17:34 +00:00
|
|
|
if (File.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt")) |ok| {
|
2018-07-23 04:35:53 +00:00
|
|
|
@panic("expected error");
|
2018-04-13 09:27:09 +00:00
|
|
|
} else |err| {
|
2019-02-08 23:18:47 +00:00
|
|
|
expect(err == error.FileNotFound);
|
2018-04-13 09:27:09 +00:00
|
|
|
}
|
|
|
|
|
2019-05-26 17:17:34 +00:00
|
|
|
try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", "");
|
2019-05-27 03:35:26 +00:00
|
|
|
try os.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", os.F_OK);
|
|
|
|
try fs.deleteTree(a, "os_test_tmp");
|
2018-04-13 09:27:09 +00:00
|
|
|
}
|
2018-04-14 06:12:19 +00:00
|
|
|
|
2019-05-25 17:07:44 +00:00
|
|
|
fn testThreadIdFn(thread_id: *Thread.Id) void {
|
|
|
|
thread_id.* = Thread.getCurrentId();
|
2018-08-02 21:44:20 +00:00
|
|
|
}
|
|
|
|
|
2019-05-25 17:07:44 +00:00
|
|
|
test "std.Thread.getCurrentId" {
|
2019-02-01 22:49:29 +00:00
|
|
|
if (builtin.single_threaded) return error.SkipZigTest;
|
|
|
|
|
2019-05-25 17:07:44 +00:00
|
|
|
var thread_current_id: Thread.Id = undefined;
|
|
|
|
const thread = try Thread.spawn(&thread_current_id, testThreadIdFn);
|
2018-08-06 21:30:55 +00:00
|
|
|
const thread_id = thread.handle();
|
2018-08-02 21:44:20 +00:00
|
|
|
thread.wait();
|
2019-05-25 17:07:44 +00:00
|
|
|
if (Thread.use_pthreads) {
|
2019-04-05 22:12:46 +00:00
|
|
|
expect(thread_current_id == thread_id);
|
2019-05-27 03:35:26 +00:00
|
|
|
} else if (os.windows.is_the_target) {
|
|
|
|
expect(Thread.getCurrentId() != thread_current_id);
|
2019-04-05 22:12:46 +00:00
|
|
|
} else {
|
2019-05-27 03:35:26 +00: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 21:25:24 +00:00
|
|
|
}
|
2018-08-02 21:44:20 +00:00
|
|
|
}
|
|
|
|
|
2018-04-14 06:12:19 +00:00
|
|
|
test "spawn threads" {
|
2019-02-01 22:49:29 +00:00
|
|
|
if (builtin.single_threaded) return error.SkipZigTest;
|
|
|
|
|
2018-04-14 06:12:19 +00:00
|
|
|
var shared_ctx: i32 = 1;
|
|
|
|
|
2019-05-25 17:07:44 +00: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-14 06:12:19 +00:00
|
|
|
|
|
|
|
thread1.wait();
|
|
|
|
thread2.wait();
|
|
|
|
thread3.wait();
|
|
|
|
thread4.wait();
|
|
|
|
|
2019-02-08 23:18:47 +00:00
|
|
|
expect(shared_ctx == 4);
|
2018-04-14 06:12:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn start1(ctx: void) u8 {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-31 14:56:59 +00:00
|
|
|
fn start2(ctx: *i32) u8 {
|
2018-04-14 06:12:19 +00:00
|
|
|
_ = @atomicRmw(i32, ctx, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
|
|
|
|
return 0;
|
|
|
|
}
|
2018-07-07 05:23:18 +00:00
|
|
|
|
|
|
|
test "cpu count" {
|
2019-05-27 03:35:26 +00:00
|
|
|
const cpu_count = try Thread.cpuCount();
|
2019-02-08 23:18:47 +00:00
|
|
|
expect(cpu_count >= 1);
|
2018-07-07 05:23:18 +00:00
|
|
|
}
|
2018-10-01 17:43:25 +00:00
|
|
|
|
|
|
|
test "AtomicFile" {
|
|
|
|
var buffer: [1024]u8 = undefined;
|
|
|
|
const allocator = &std.heap.FixedBufferAllocator.init(buffer[0..]).allocator;
|
|
|
|
const test_out_file = "tmp_atomic_file_test_dest.txt";
|
|
|
|
const test_content =
|
|
|
|
\\ hello!
|
|
|
|
\\ this is a test file
|
|
|
|
;
|
|
|
|
{
|
2019-05-27 03:35:26 +00:00
|
|
|
var af = try fs.AtomicFile.init(test_out_file, File.default_mode);
|
2018-10-01 17:43:25 +00:00
|
|
|
defer af.deinit();
|
|
|
|
try af.file.write(test_content);
|
|
|
|
try af.finish();
|
|
|
|
}
|
|
|
|
const content = try io.readFileAlloc(allocator, test_out_file);
|
2019-02-08 23:18:47 +00:00
|
|
|
expect(mem.eql(u8, content, test_content));
|
2018-10-01 17:43:25 +00:00
|
|
|
|
2019-05-27 03:35:26 +00:00
|
|
|
try fs.deleteFile(test_out_file);
|
2018-10-01 17:43:25 +00:00
|
|
|
}
|
2019-02-06 18:48:04 +00:00
|
|
|
|
|
|
|
test "thread local storage" {
|
|
|
|
if (builtin.single_threaded) return error.SkipZigTest;
|
2019-05-25 17:07:44 +00:00
|
|
|
const thread1 = try Thread.spawn({}, testTls);
|
|
|
|
const thread2 = try Thread.spawn({}, testTls);
|
2019-02-06 18:48:04 +00: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 22:27:18 +00: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.
|
|
|
|
expect(!mem.eql(u8, buf_a, buf_b));
|
|
|
|
}
|
|
|
|
|
|
|
|
test "getcwd" {
|
|
|
|
// at least call it so it gets compiled
|
|
|
|
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
2019-05-27 03:35:26 +00:00
|
|
|
_ = os.getcwd(&buf) catch undefined;
|
2019-05-24 22:27:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
test "realpath" {
|
|
|
|
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
2019-05-27 03:35:26 +00:00
|
|
|
testing.expectError(error.FileNotFound, fs.realpath("definitely_bogus_does_not_exist1234", &buf));
|
2019-05-24 22:27:18 +00:00
|
|
|
}
|
2019-05-29 07:43:39 +00:00
|
|
|
|
|
|
|
test "sigaltstack" {
|
|
|
|
if (builtin.os == .windows or builtin.os == .wasi) return error.SkipZigTest;
|
|
|
|
|
|
|
|
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 08:30:30 +00: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;
|
|
|
|
|
|
|
|
export fn iter_fn(info: *dl_phdr_info, size: usize, data: ?*usize) i32 {
|
|
|
|
if (builtin.os == .windows or builtin.os == .wasi or builtin.os == .macosx)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
var counter = data.?;
|
|
|
|
// Count how many libraries are loaded
|
|
|
|
counter.* += usize(1);
|
|
|
|
|
|
|
|
// The image should contain at least a PT_LOAD segment
|
|
|
|
if (info.dlpi_phnum < 1) return -1;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
// Find the ELF header
|
|
|
|
const elf_header = @intToPtr(*elf.Ehdr, phdr.p_vaddr - phdr.p_offset);
|
|
|
|
// Validate the magic
|
|
|
|
if (!mem.eql(u8, elf_header.e_ident[0..4], "\x7fELF")) return -1;
|
|
|
|
// Consistency check
|
|
|
|
if (elf_header.e_phnum != info.dlpi_phnum) return -1;
|
|
|
|
|
|
|
|
found_load = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found_load) return -1;
|
|
|
|
|
|
|
|
return 42;
|
|
|
|
}
|
|
|
|
|
|
|
|
test "dl_iterate_phdr" {
|
|
|
|
if (builtin.os == .windows or builtin.os == .wasi or builtin.os == .macosx)
|
|
|
|
return error.SkipZigTest;
|
|
|
|
|
|
|
|
var counter: usize = 0;
|
|
|
|
expect(os.dl_iterate_phdr(usize, iter_fn, &counter) != 0);
|
|
|
|
expect(counter != 0);
|
|
|
|
}
|