Skip to content

Commit

Permalink
behavior tests passing on Linux
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewrk committed May 26, 2019
1 parent 44a049e commit 2b42e91
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 81 deletions.
9 changes: 6 additions & 3 deletions std/c.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
const builtin = @import("builtin");
const std = @import("std");
const page_size = std.mem.page_size;

pub use @import("os/bits.zig");

Expand Down Expand Up @@ -33,7 +35,7 @@ pub extern "c" fn close(fd: fd_t) c_int;
pub extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int;
pub extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *Stat) c_int;
pub extern "c" fn lseek(fd: fd_t, offset: isize, whence: c_int) isize;
pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int;
pub extern "c" fn open(path: [*]const u8, oflag: c_uint, ...) c_int;
pub extern "c" fn raise(sig: c_int) c_int;
pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize;
pub extern "c" fn pread(fd: fd_t, buf: [*]u8, nbyte: usize, offset: u64) isize;
Expand All @@ -42,8 +44,9 @@ pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec, iovcnt: c_int, offset:
pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int;
pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize;
pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64) isize;
pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: fd_t, offset: isize) usize;
pub extern "c" fn munmap(addr: ?*c_void, len: usize) c_int;
pub extern "c" fn mmap(addr: ?*align(page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: isize) *c_void;
pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int;
pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int;
pub extern "c" fn unlink(path: [*]const u8) c_int;
pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int;
Expand Down
7 changes: 3 additions & 4 deletions std/debug.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1011,7 +1011,7 @@ fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo {
S.self_exe_file = try fs.openSelfExe();
errdefer S.self_exe_file.close();

const self_exe_mmap_len = try S.self_exe_file.getEndPos();
const self_exe_mmap_len = mem.alignForward(try S.self_exe_file.getEndPos(), mem.page_size);
const self_exe_mmap = try os.mmap(
null,
self_exe_mmap_len,
Expand All @@ -1020,10 +1020,9 @@ fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo {
S.self_exe_file.handle,
0,
);
errdefer os.munmap(self_exe_mmap, self_exe_mmap_len);
errdefer os.munmap(self_exe_mmap);

const file_mmap_slice = @intToPtr([*]const u8, self_exe_mmap)[0..self_exe_mmap_len];
S.self_exe_mmap_seekable = io.SliceSeekableInStream.init(file_mmap_slice);
S.self_exe_mmap_seekable = io.SliceSeekableInStream.init(self_exe_mmap);

return openElfDebugInfo(
allocator,
Expand Down
4 changes: 2 additions & 2 deletions std/fs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -595,8 +595,8 @@ pub const Dir = struct {
}

while (true) {
const rc = os.system.getdents64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len);
switch (os.errno(rc)) {
const rc = os.linux.getdents64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len);
switch (os.linux.getErrno(rc)) {
0 => {},
os.EBADF => unreachable,
os.EFAULT => unreachable,
Expand Down
29 changes: 16 additions & 13 deletions std/heap.zig
Original file line number Diff line number Diff line change
Expand Up @@ -104,35 +104,36 @@ pub const DirectAllocator = struct {
}

const alloc_size = if (alignment <= mem.page_size) n else n + alignment;
const addr = os.mmap(
const slice = os.mmap(
null,
alloc_size,
mem.alignForward(alloc_size, mem.page_size),
os.PROT_READ | os.PROT_WRITE,
os.MAP_PRIVATE | os.MAP_ANONYMOUS,
-1,
0,
) catch return error.OutOfMemory;
if (alloc_size == n) return @intToPtr([*]u8, addr)[0..n];
if (alloc_size == n) return slice;

const aligned_addr = mem.alignForward(addr, alignment);
const aligned_addr = mem.alignForward(@ptrToInt(slice.ptr), alignment);

// Unmap the extra bytes that were only requested in order to guarantee
// that the range of memory we were provided had a proper alignment in
// it somewhere. The extra bytes could be at the beginning, or end, or both.
const unused_start_len = aligned_addr - addr;
const unused_start_len = aligned_addr - @ptrToInt(slice.ptr);
if (unused_start_len != 0) {
os.munmap(addr, unused_start_len);
os.munmap(slice[0..unused_start_len]);
}
const aligned_end_addr = std.mem.alignForward(aligned_addr + n, mem.page_size);
const unused_end_len = addr + alloc_size - aligned_end_addr;
const aligned_end_addr = mem.alignForward(aligned_addr + n, mem.page_size);
const unused_end_len = @ptrToInt(slice.ptr) + slice.len - aligned_end_addr;
if (unused_end_len != 0) {
os.munmap(aligned_end_addr, unused_end_len);
os.munmap(@intToPtr([*]align(mem.page_size) u8, aligned_end_addr)[0..unused_end_len]);
}

return @intToPtr([*]u8, aligned_addr)[0..n];
}

fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
fn shrink(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
const old_mem = @alignCast(mem.page_size, old_mem_unaligned);
if (os.windows.is_the_target) {
const w = os.windows;
if (new_size == 0) {
Expand Down Expand Up @@ -165,12 +166,14 @@ pub const DirectAllocator = struct {
const new_addr_end = base_addr + new_size;
const new_addr_end_rounded = mem.alignForward(new_addr_end, mem.page_size);
if (old_addr_end > new_addr_end_rounded) {
os.munmap(new_addr_end_rounded, old_addr_end - new_addr_end_rounded);
const ptr = @intToPtr([*]align(mem.page_size) u8, new_addr_end_rounded);
os.munmap(ptr[0 .. old_addr_end - new_addr_end_rounded]);
}
return old_mem[0..new_size];
}

fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
fn realloc(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
const old_mem = @alignCast(mem.page_size, old_mem_unaligned);
if (os.windows.is_the_target) {
if (old_mem.len == 0) {
return alloc(allocator, new_size, new_align);
Expand Down Expand Up @@ -231,7 +234,7 @@ pub const DirectAllocator = struct {
const result = try alloc(allocator, new_size, new_align);
if (old_mem.len != 0) {
@memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len));
os.munmap(@ptrToInt(old_mem.ptr), old_mem.len);
os.munmap(old_mem);
}
return result;
}
Expand Down
6 changes: 3 additions & 3 deletions std/io.zig
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const std = @import("std.zig");
const builtin = @import("builtin");
const Os = builtin.Os;
const c = std.c;

const math = std.math;
const debug = std.debug;
const assert = debug.assert;
const os = std.os;
const fs = std.fs;
const mem = std.mem;
const meta = std.meta;
const trait = meta.trait;
Expand Down Expand Up @@ -985,7 +985,7 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
}

pub const BufferedAtomicFile = struct {
atomic_file: os.AtomicFile,
atomic_file: fs.AtomicFile,
file_stream: File.OutStream,
buffered_stream: BufferedOutStream(File.WriteError),
allocator: *mem.Allocator,
Expand All @@ -1001,7 +1001,7 @@ pub const BufferedAtomicFile = struct {
};
errdefer allocator.destroy(self);

self.atomic_file = try os.AtomicFile.init(dest_path, File.default_mode);
self.atomic_file = try fs.AtomicFile.init(dest_path, File.default_mode);
errdefer self.atomic_file.deinit();

self.file_stream = self.atomic_file.file.outStream();
Expand Down
2 changes: 1 addition & 1 deletion std/io/c_out_stream.zig
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub const COutStream = struct {
os.ENOSPC => return error.NoSpaceLeft,
os.EPERM => return error.AccessDenied,
os.EPIPE => return error.BrokenPipe,
else => return os.unexpectedErrno(@intCast(usize, errno)),
else => |err| return os.unexpectedErrno(@intCast(usize, err)),
}
}
};
73 changes: 50 additions & 23 deletions std/mem.zig
Original file line number Diff line number Diff line change
Expand Up @@ -585,14 +585,14 @@ pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian)
test "comptime read/write int" {
comptime {
var bytes: [2]u8 = undefined;
std.mem.writeIntLittle(u16, &bytes, 0x1234);
const result = std.mem.readIntBig(u16, &bytes);
writeIntLittle(u16, &bytes, 0x1234);
const result = readIntBig(u16, &bytes);
testing.expect(result == 0x3412);
}
comptime {
var bytes: [2]u8 = undefined;
std.mem.writeIntBig(u16, &bytes, 0x1234);
const result = std.mem.readIntLittle(u16, &bytes);
writeIntBig(u16, &bytes, 0x1234);
const result = readIntLittle(u16, &bytes);
testing.expect(result == 0x3412);
}
}
Expand Down Expand Up @@ -1053,7 +1053,7 @@ fn testReadIntImpl() void {
}
}

test "std.mem.writeIntSlice" {
test "writeIntSlice" {
testWriteIntImpl();
comptime testWriteIntImpl();
}
Expand Down Expand Up @@ -1184,7 +1184,7 @@ pub fn reverse(comptime T: type, items: []T) void {
}
}

test "std.mem.reverse" {
test "reverse" {
var arr = []i32{
5,
3,
Expand All @@ -1211,7 +1211,7 @@ pub fn rotate(comptime T: type, items: []T, amount: usize) void {
reverse(T, items);
}

test "std.mem.rotate" {
test "rotate" {
var arr = []i32{
5,
3,
Expand Down Expand Up @@ -1296,14 +1296,14 @@ pub fn asBytes(ptr: var) AsBytesReturnType(@typeOf(ptr)) {
return @ptrCast(AsBytesReturnType(P), ptr);
}

test "std.mem.asBytes" {
test "asBytes" {
const deadbeef = u32(0xDEADBEEF);
const deadbeef_bytes = switch (builtin.endian) {
builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
builtin.Endian.Little => "\xEF\xBE\xAD\xDE",
};

testing.expect(std.mem.eql(u8, asBytes(&deadbeef), deadbeef_bytes));
testing.expect(eql(u8, asBytes(&deadbeef), deadbeef_bytes));

var codeface = u32(0xC0DEFACE);
for (asBytes(&codeface).*) |*b|
Expand All @@ -1323,25 +1323,25 @@ test "std.mem.asBytes" {
.c = 0xDE,
.d = 0xA1,
};
testing.expect(std.mem.eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1"));
testing.expect(eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1"));
}

///Given any value, returns a copy of its bytes in an array.
pub fn toBytes(value: var) [@sizeOf(@typeOf(value))]u8 {
return asBytes(&value).*;
}

test "std.mem.toBytes" {
test "toBytes" {
var my_bytes = toBytes(u32(0x12345678));
switch (builtin.endian) {
builtin.Endian.Big => testing.expect(std.mem.eql(u8, my_bytes, "\x12\x34\x56\x78")),
builtin.Endian.Little => testing.expect(std.mem.eql(u8, my_bytes, "\x78\x56\x34\x12")),
builtin.Endian.Big => testing.expect(eql(u8, my_bytes, "\x12\x34\x56\x78")),
builtin.Endian.Little => testing.expect(eql(u8, my_bytes, "\x78\x56\x34\x12")),
}

my_bytes[0] = '\x99';
switch (builtin.endian) {
builtin.Endian.Big => testing.expect(std.mem.eql(u8, my_bytes, "\x99\x34\x56\x78")),
builtin.Endian.Little => testing.expect(std.mem.eql(u8, my_bytes, "\x99\x56\x34\x12")),
builtin.Endian.Big => testing.expect(eql(u8, my_bytes, "\x99\x34\x56\x78")),
builtin.Endian.Little => testing.expect(eql(u8, my_bytes, "\x99\x56\x34\x12")),
}
}

Expand All @@ -1363,7 +1363,7 @@ pub fn bytesAsValue(comptime T: type, bytes: var) BytesAsValueReturnType(T, @typ
return @ptrCast(BytesAsValueReturnType(T, @typeOf(bytes)), bytes);
}

test "std.mem.bytesAsValue" {
test "bytesAsValue" {
const deadbeef = u32(0xDEADBEEF);
const deadbeef_bytes = switch (builtin.endian) {
builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
Expand Down Expand Up @@ -1405,7 +1405,7 @@ test "std.mem.bytesAsValue" {
pub fn bytesToValue(comptime T: type, bytes: var) T {
return bytesAsValue(T, &bytes).*;
}
test "std.mem.bytesToValue" {
test "bytesToValue" {
const deadbeef_bytes = switch (builtin.endian) {
builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
builtin.Endian.Little => "\xEF\xBE\xAD\xDE",
Expand All @@ -1430,25 +1430,25 @@ pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubA
return @ptrCast(ReturnType, &ptr[start]);
}

test "std.mem.subArrayPtr" {
test "subArrayPtr" {
const a1 = "abcdef";
const sub1 = subArrayPtr(&a1, 2, 3);
testing.expect(std.mem.eql(u8, sub1.*, "cde"));
testing.expect(eql(u8, sub1.*, "cde"));

var a2 = "abcdef";
var sub2 = subArrayPtr(&a2, 2, 3);

testing.expect(std.mem.eql(u8, sub2, "cde"));
testing.expect(eql(u8, sub2, "cde"));
sub2[1] = 'X';
testing.expect(std.mem.eql(u8, a2, "abcXef"));
testing.expect(eql(u8, a2, "abcXef"));
}

/// Round an address up to the nearest aligned address
pub fn alignForward(addr: usize, alignment: usize) usize {
return (addr + alignment - 1) & ~(alignment - 1);
return alignBackward(addr + (alignment - 1), alignment);
}

test "std.mem.alignForward" {
test "alignForward" {
testing.expect(alignForward(1, 1) == 1);
testing.expect(alignForward(2, 1) == 2);
testing.expect(alignForward(1, 2) == 2);
Expand All @@ -1462,3 +1462,30 @@ test "std.mem.alignForward" {
testing.expect(alignForward(16, 8) == 16);
testing.expect(alignForward(17, 8) == 24);
}

pub fn alignBackward(addr: usize, alignment: usize) usize {
// 000010000 // example addr
// 000001111 // subtract 1
// 111110000 // binary not
return addr & ~(alignment - 1);
}

pub fn isAligned(addr: usize, alignment: usize) bool {
return alignBackward(addr, alignment) == addr;
}

test "isAligned" {
testing.expect(isAligned(0, 4));
testing.expect(isAligned(1, 1));
testing.expect(isAligned(2, 1));
testing.expect(isAligned(2, 2));
testing.expect(!isAligned(2, 4));
testing.expect(isAligned(3, 1));
testing.expect(!isAligned(3, 2));
testing.expect(!isAligned(3, 4));
testing.expect(isAligned(4, 4));
testing.expect(isAligned(4, 2));
testing.expect(isAligned(4, 1));
testing.expect(!isAligned(4, 8));
testing.expect(!isAligned(4, 16));
}
Loading

0 comments on commit 2b42e91

Please sign in to comment.