authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-11 00:09:58-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-11 00:09:58-04:00
log33371ab55c01d896b91df13eafe6e5c601400a07
tree879666e7729aaef2273e8c336b425909df3d2022
parentd504318f2e0f3054c772abbd34f938f2cefa6ccc
parent34a22a85ca8d4371fe9b8f921cce858ab4351cca
signature Commit is signed but in an unrecognized format.

Merge remote-tracking branch 'origin/master' into copy-elision-3


22 files changed, 548 insertions(+), 46 deletions(-)

README.md+1-1
......@@ -53,7 +53,7 @@ brew install cmake llvm@8
5353brew outdated llvm@8 || brew upgrade llvm@8
5454mkdir build
5555cd build
56cmake .. -DCMAKE_PREFIX_PATH=/usr/local/Cellar/llvm/8.0.0
56cmake .. -DCMAKE_PREFIX_PATH=/usr/local/Cellar/llvm/8.0.0_1
5757make install
5858```
5959
src-self-hosted/compilation.zig+1-1
......@@ -160,7 +160,7 @@ pub const Compilation = struct {
160160 /// it uses an optional pointer so that tombstone removals are possible
161161 fn_link_set: event.Locked(FnLinkSet),
162162
163 pub const FnLinkSet = std.LinkedList(?*Value.Fn);
163 pub const FnLinkSet = std.TailQueue(?*Value.Fn);
164164
165165 windows_subsystem_windows: bool,
166166 windows_subsystem_console: bool,
src-self-hosted/value.zig+1-1
......@@ -186,7 +186,7 @@ pub const Value = struct {
186186 /// Path to the object file that contains this function
187187 containing_object: Buffer,
188188
189 link_set_node: *std.LinkedList(?*Value.Fn).Node,
189 link_set_node: *std.TailQueue(?*Value.Fn).Node,
190190
191191 /// Creates a Fn value with 1 ref
192192 /// Takes ownership of symbol_name
src/parser.cpp+15
......@@ -890,6 +890,11 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) {
890890 body = ast_parse_assign_expr(pc);
891891 }
892892
893 if (body == nullptr) {
894 Token *tok = eat_token(pc);
895 ast_error(pc, tok, "expected if body, found '%s'", token_name(tok->id));
896 }
897
893898 Token *err_payload = nullptr;
894899 AstNode *else_body = nullptr;
895900 if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) {
......@@ -994,6 +999,11 @@ static AstNode *ast_parse_for_statement(ParseContext *pc) {
994999 body = ast_parse_assign_expr(pc);
9951000 }
9961001
1002 if (body == nullptr) {
1003 Token *tok = eat_token(pc);
1004 ast_error(pc, tok, "expected loop body, found '%s'", token_name(tok->id));
1005 }
1006
9971007 AstNode *else_body = nullptr;
9981008 if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) {
9991009 else_body = ast_expect(pc, ast_parse_statement);
......@@ -1023,6 +1033,11 @@ static AstNode *ast_parse_while_statement(ParseContext *pc) {
10231033 body = ast_parse_assign_expr(pc);
10241034 }
10251035
1036 if (body == nullptr) {
1037 Token *tok = eat_token(pc);
1038 ast_error(pc, tok, "expected loop body, found '%s'", token_name(tok->id));
1039 }
1040
10261041 Token *err_payload = nullptr;
10271042 AstNode *else_body = nullptr;
10281043 if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) {
std/atomic/queue.zig+1-1
......@@ -14,7 +14,7 @@ pub fn Queue(comptime T: type) type {
1414 mutex: std.Mutex,
1515
1616 pub const Self = @This();
17 pub const Node = std.LinkedList(T).Node;
17 pub const Node = std.TailQueue(T).Node;
1818
1919 pub fn init() Self {
2020 return Self{
std/child_process.zig+3-3
......@@ -13,7 +13,7 @@ const BufMap = std.BufMap;
1313const Buffer = std.Buffer;
1414const builtin = @import("builtin");
1515const Os = builtin.Os;
16const LinkedList = std.LinkedList;
16const TailQueue = std.TailQueue;
1717const maxInt = std.math.maxInt;
1818
1919pub const ChildProcess = struct {
......@@ -48,7 +48,7 @@ pub const ChildProcess = struct {
4848 pub cwd: ?[]const u8,
4949
5050 err_pipe: if (os.windows.is_the_target) void else [2]os.fd_t,
51 llnode: if (os.windows.is_the_target) void else LinkedList(*ChildProcess).Node,
51 llnode: if (os.windows.is_the_target) void else TailQueue(*ChildProcess).Node,
5252
5353 pub const SpawnError = error{OutOfMemory} || os.ExecveError || os.SetIdError ||
5454 os.ChangeCurDirError || windows.CreateProcessError;
......@@ -388,7 +388,7 @@ pub const ChildProcess = struct {
388388
389389 self.pid = pid;
390390 self.err_pipe = err_pipe;
391 self.llnode = LinkedList(*ChildProcess).Node.init(self);
391 self.llnode = TailQueue(*ChildProcess).Node.init(self);
392392 self.term = null;
393393
394394 if (self.stdin_behavior == StdIo.Pipe) {
std/debug.zig+3-2
......@@ -2224,8 +2224,9 @@ fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
22242224
22252225fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {
22262226 // TODO https://github.com/ziglang/zig/issues/863
2227 const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian);
2228 ptr.* += @sizeOf(T);
2227 const size = (T.bit_count + 7) / 8;
2228 const result = mem.readIntSlice(T, ptr.*[0..size], endian);
2229 ptr.* += size;
22292230 return result;
22302231}
22312232
std/event/fs.zig+1-1
......@@ -887,7 +887,7 @@ pub fn Watch(comptime V: type) type {
887887 }
888888
889889 async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
890 const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [][]const u8{file_path});
890 const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [_][]const u8{file_path});
891891 var resolved_path_consumed = false;
892892 defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
893893
std/event/net.zig+1-1
......@@ -19,7 +19,7 @@ pub const Server = struct {
1919 waiting_for_emfile_node: PromiseNode,
2020 listen_resume_node: event.Loop.ResumeNode,
2121
22 const PromiseNode = std.LinkedList(promise).Node;
22 const PromiseNode = std.TailQueue(promise).Node;
2323
2424 pub fn init(loop: *Loop) Server {
2525 // TODO can't initialize handler coroutine here because we need well defined copy elision
std/hash_map.zig+1-2
......@@ -157,8 +157,7 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3
157157 fn ensureCapacityExact(self: *Self, new_capacity: usize) !void {
158158 // capacity must always be a power of two to allow for modulo
159159 // optimization in the constrainIndex fn
160 const is_power_of_two = new_capacity & (new_capacity - 1) == 0;
161 assert(is_power_of_two);
160 assert(math.isPowerOfTwo(new_capacity));
162161
163162 if (new_capacity <= self.entries.len) {
164163 return;
std/heap.zig+5-6
......@@ -347,10 +347,10 @@ pub const ArenaAllocator = struct {
347347 pub allocator: Allocator,
348348
349349 child_allocator: *Allocator,
350 buffer_list: std.LinkedList([]u8),
350 buffer_list: std.SinglyLinkedList([]u8),
351351 end_index: usize,
352352
353 const BufNode = std.LinkedList([]u8).Node;
353 const BufNode = std.SinglyLinkedList([]u8).Node;
354354
355355 pub fn init(child_allocator: *Allocator) ArenaAllocator {
356356 return ArenaAllocator{
......@@ -359,7 +359,7 @@ pub const ArenaAllocator = struct {
359359 .shrinkFn = shrink,
360360 },
361361 .child_allocator = child_allocator,
362 .buffer_list = std.LinkedList([]u8).init(),
362 .buffer_list = std.SinglyLinkedList([]u8).init(),
363363 .end_index = 0,
364364 };
365365 }
......@@ -387,10 +387,9 @@ pub const ArenaAllocator = struct {
387387 const buf_node = &buf_node_slice[0];
388388 buf_node.* = BufNode{
389389 .data = buf,
390 .prev = null,
391390 .next = null,
392391 };
393 self.buffer_list.append(buf_node);
392 self.buffer_list.prepend(buf_node);
394393 self.end_index = 0;
395394 return buf_node;
396395 }
......@@ -398,7 +397,7 @@ pub const ArenaAllocator = struct {
398397 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
399398 const self = @fieldParentPtr(ArenaAllocator, "allocator", allocator);
400399
401 var cur_node = if (self.buffer_list.last) |last_node| last_node else try self.createNode(0, n + alignment);
400 var cur_node = if (self.buffer_list.first) |first_node| first_node else try self.createNode(0, n + alignment);
402401 while (true) {
403402 const cur_buf = cur_node.data[@sizeOf(BufNode)..];
404403 const addr = @ptrToInt(cur_buf.ptr) + self.end_index;
std/io.zig+10-10
......@@ -164,32 +164,32 @@ pub fn InStream(comptime ReadError: type) type {
164164
165165 /// Reads a native-endian integer
166166 pub fn readIntNative(self: *Self, comptime T: type) !T {
167 var bytes: [@sizeOf(T)]u8 = undefined;
167 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
168168 try self.readNoEof(bytes[0..]);
169169 return mem.readIntNative(T, &bytes);
170170 }
171171
172172 /// Reads a foreign-endian integer
173173 pub fn readIntForeign(self: *Self, comptime T: type) !T {
174 var bytes: [@sizeOf(T)]u8 = undefined;
174 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
175175 try self.readNoEof(bytes[0..]);
176176 return mem.readIntForeign(T, &bytes);
177177 }
178178
179179 pub fn readIntLittle(self: *Self, comptime T: type) !T {
180 var bytes: [@sizeOf(T)]u8 = undefined;
180 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
181181 try self.readNoEof(bytes[0..]);
182182 return mem.readIntLittle(T, &bytes);
183183 }
184184
185185 pub fn readIntBig(self: *Self, comptime T: type) !T {
186 var bytes: [@sizeOf(T)]u8 = undefined;
186 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
187187 try self.readNoEof(bytes[0..]);
188188 return mem.readIntBig(T, &bytes);
189189 }
190190
191191 pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
192 var bytes: [@sizeOf(T)]u8 = undefined;
192 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
193193 try self.readNoEof(bytes[0..]);
194194 return mem.readInt(T, &bytes, endian);
195195 }
......@@ -249,32 +249,32 @@ pub fn OutStream(comptime WriteError: type) type {
249249
250250 /// Write a native-endian integer.
251251 pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void {
252 var bytes: [@sizeOf(T)]u8 = undefined;
252 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
253253 mem.writeIntNative(T, &bytes, value);
254254 return self.writeFn(self, bytes);
255255 }
256256
257257 /// Write a foreign-endian integer.
258258 pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void {
259 var bytes: [@sizeOf(T)]u8 = undefined;
259 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
260260 mem.writeIntForeign(T, &bytes, value);
261261 return self.writeFn(self, bytes);
262262 }
263263
264264 pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void {
265 var bytes: [@sizeOf(T)]u8 = undefined;
265 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
266266 mem.writeIntLittle(T, &bytes, value);
267267 return self.writeFn(self, bytes);
268268 }
269269
270270 pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void {
271 var bytes: [@sizeOf(T)]u8 = undefined;
271 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
272272 mem.writeIntBig(T, &bytes, value);
273273 return self.writeFn(self, bytes);
274274 }
275275
276276 pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {
277 var bytes: [@sizeOf(T)]u8 = undefined;
277 var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
278278 mem.writeInt(T, &bytes, value, endian);
279279 return self.writeFn(self, bytes);
280280 }
std/linked_list.zig+191-7
......@@ -5,8 +5,192 @@ const testing = std.testing;
55const mem = std.mem;
66const Allocator = mem.Allocator;
77
8/// Generic doubly linked list.
9pub fn LinkedList(comptime T: type) type {
8/// A singly-linked list is headed by a single forward pointer. The elements
9/// are singly linked for minimum space and pointer manipulation overhead at
10/// the expense of O(n) removal for arbitrary elements. New elements can be
11/// added to the list after an existing element or at the head of the list.
12/// A singly-linked list may only be traversed in the forward direction.
13/// Singly-linked lists are ideal for applications with large datasets and
14/// few or no removals or for implementing a LIFO queue.
15pub fn SinglyLinkedList(comptime T: type) type {
16 return struct {
17 const Self = @This();
18
19 /// Node inside the linked list wrapping the actual data.
20 pub const Node = struct {
21 next: ?*Node,
22 data: T,
23
24 pub fn init(data: T) Node {
25 return Node{
26 .next = null,
27 .data = data,
28 };
29 }
30
31 /// Insert a new node after the current one.
32 ///
33 /// Arguments:
34 /// new_node: Pointer to the new node to insert.
35 pub fn insertAfter(node: *Node, new_node: *Node) void {
36 new_node.next = node.next;
37 node.next = new_node;
38 }
39
40 /// Remove a node from the list.
41 ///
42 /// Arguments:
43 /// node: Pointer to the node to be removed.
44 /// Returns:
45 /// node removed
46 pub fn removeNext(node: *Node) ?*Node {
47 const next_node = node.next orelse return null;
48 node.next = next_node.next;
49 return next_node;
50 }
51 };
52
53 first: ?*Node,
54
55 /// Initialize a linked list.
56 ///
57 /// Returns:
58 /// An empty linked list.
59 pub fn init() Self {
60 return Self{
61 .first = null,
62 };
63 }
64
65 /// Insert a new node after an existing one.
66 ///
67 /// Arguments:
68 /// node: Pointer to a node in the list.
69 /// new_node: Pointer to the new node to insert.
70 pub fn insertAfter(list: *Self, node: *Node, new_node: *Node) void {
71 node.insertAfter(new_node);
72 }
73
74 /// Insert a new node at the head.
75 ///
76 /// Arguments:
77 /// new_node: Pointer to the new node to insert.
78 pub fn prepend(list: *Self, new_node: *Node) void {
79 new_node.next = list.first;
80 list.first = new_node;
81 }
82
83 /// Remove a node from the list.
84 ///
85 /// Arguments:
86 /// node: Pointer to the node to be removed.
87 pub fn remove(list: *Self, node: *Node) void {
88 if (list.first == node) {
89 list.first = node.next;
90 } else {
91 var current_elm = list.first.?;
92 while (current_elm.next != node) {
93 current_elm = current_elm.next.?;
94 }
95 current_elm.next = node.next;
96 }
97 }
98
99 /// Remove and return the first node in the list.
100 ///
101 /// Returns:
102 /// A pointer to the first node in the list.
103 pub fn popFirst(list: *Self) ?*Node {
104 const first = list.first orelse return null;
105 list.first = first.next;
106 return first;
107 }
108
109 /// Allocate a new node.
110 ///
111 /// Arguments:
112 /// allocator: Dynamic memory allocator.
113 ///
114 /// Returns:
115 /// A pointer to the new node.
116 pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node {
117 return allocator.create(Node);
118 }
119
120 /// Deallocate a node.
121 ///
122 /// Arguments:
123 /// node: Pointer to the node to deallocate.
124 /// allocator: Dynamic memory allocator.
125 pub fn destroyNode(list: *Self, node: *Node, allocator: *Allocator) void {
126 allocator.destroy(node);
127 }
128
129 /// Allocate and initialize a node and its data.
130 ///
131 /// Arguments:
132 /// data: The data to put inside the node.
133 /// allocator: Dynamic memory allocator.
134 ///
135 /// Returns:
136 /// A pointer to the new node.
137 pub fn createNode(list: *Self, data: T, allocator: *Allocator) !*Node {
138 var node = try list.allocateNode(allocator);
139 node.* = Node.init(data);
140 return node;
141 }
142 };
143}
144
145test "basic SinglyLinkedList test" {
146 const allocator = debug.global_allocator;
147 var list = SinglyLinkedList(u32).init();
148
149 var one = try list.createNode(1, allocator);
150 var two = try list.createNode(2, allocator);
151 var three = try list.createNode(3, allocator);
152 var four = try list.createNode(4, allocator);
153 var five = try list.createNode(5, allocator);
154 defer {
155 list.destroyNode(one, allocator);
156 list.destroyNode(two, allocator);
157 list.destroyNode(three, allocator);
158 list.destroyNode(four, allocator);
159 list.destroyNode(five, allocator);
160 }
161
162 list.prepend(two); // {2}
163 list.insertAfter(two, five); // {2, 5}
164 list.prepend(one); // {1, 2, 5}
165 list.insertAfter(two, three); // {1, 2, 3, 5}
166 list.insertAfter(three, four); // {1, 2, 3, 4, 5}
167
168 // Traverse forwards.
169 {
170 var it = list.first;
171 var index: u32 = 1;
172 while (it) |node| : (it = node.next) {
173 testing.expect(node.data == index);
174 index += 1;
175 }
176 }
177
178 _ = list.popFirst(); // {2, 3, 4, 5}
179 _ = list.remove(five); // {2, 3, 4}
180 _ = two.removeNext(); // {2, 4}
181
182 testing.expect(list.first.?.data == 2);
183 testing.expect(list.first.?.next.?.data == 4);
184 testing.expect(list.first.?.next.?.next == null);
185}
186
187/// A tail queue is headed by a pair of pointers, one to the head of the
188/// list and the other to the tail of the list. The elements are doubly
189/// linked so that an arbitrary element can be removed without a need to
190/// traverse the list. New elements can be added to the list before or
191/// after an existing element, at the head of the list, or at the end of
192/// the list. A tail queue may be traversed in either direction.
193pub fn TailQueue(comptime T: type) type {
10194 return struct {
11195 const Self = @This();
12196
......@@ -219,9 +403,9 @@ pub fn LinkedList(comptime T: type) type {
219403 };
220404}
221405
222test "basic linked list test" {
406test "basic TailQueue test" {
223407 const allocator = debug.global_allocator;
224 var list = LinkedList(u32).init();
408 var list = TailQueue(u32).init();
225409
226410 var one = try list.createNode(1, allocator);
227411 var two = try list.createNode(2, allocator);
......@@ -271,10 +455,10 @@ test "basic linked list test" {
271455 testing.expect(list.len == 2);
272456}
273457
274test "linked list concatenation" {
458test "TailQueue concatenation" {
275459 const allocator = debug.global_allocator;
276 var list1 = LinkedList(u32).init();
277 var list2 = LinkedList(u32).init();
460 var list1 = TailQueue(u32).init();
461 var list2 = TailQueue(u32).init();
278462
279463 var one = try list1.createNode(1, allocator);
280464 defer list1.destroyNode(one, allocator);
std/math.zig+16-5
......@@ -288,10 +288,8 @@ pub fn shl(comptime T: type, a: T, shift_amt: var) T {
288288 const abs_shift_amt = absCast(shift_amt);
289289 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
290290
291 if (@typeOf(shift_amt).is_signed) {
292 if (shift_amt >= 0) {
293 return a << casted_shift_amt;
294 } else {
291 if (@typeOf(shift_amt) == comptime_int or @typeOf(shift_amt).is_signed) {
292 if (shift_amt < 0) {
295293 return a >> casted_shift_amt;
296294 }
297295 }
......@@ -304,6 +302,10 @@ test "math.shl" {
304302 testing.expect(shl(u8, 0b11111111, usize(8)) == 0);
305303 testing.expect(shl(u8, 0b11111111, usize(9)) == 0);
306304 testing.expect(shl(u8, 0b11111111, isize(-2)) == 0b00111111);
305 testing.expect(shl(u8, 0b11111111, 3) == 0b11111000);
306 testing.expect(shl(u8, 0b11111111, 8) == 0);
307 testing.expect(shl(u8, 0b11111111, 9) == 0);
308 testing.expect(shl(u8, 0b11111111, -2) == 0b00111111);
307309}
308310
309311/// Shifts right. Overflowed bits are truncated.
......@@ -312,7 +314,7 @@ pub fn shr(comptime T: type, a: T, shift_amt: var) T {
312314 const abs_shift_amt = absCast(shift_amt);
313315 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
314316
315 if (@typeOf(shift_amt).is_signed) {
317 if (@typeOf(shift_amt) == comptime_int or @typeOf(shift_amt).is_signed) {
316318 if (shift_amt >= 0) {
317319 return a >> casted_shift_amt;
318320 } else {
......@@ -328,6 +330,10 @@ test "math.shr" {
328330 testing.expect(shr(u8, 0b11111111, usize(8)) == 0);
329331 testing.expect(shr(u8, 0b11111111, usize(9)) == 0);
330332 testing.expect(shr(u8, 0b11111111, isize(-2)) == 0b11111100);
333 testing.expect(shr(u8, 0b11111111, 3) == 0b00011111);
334 testing.expect(shr(u8, 0b11111111, 8) == 0);
335 testing.expect(shr(u8, 0b11111111, 9) == 0);
336 testing.expect(shr(u8, 0b11111111, -2) == 0b11111100);
331337}
332338
333339/// Rotates right. Only unsigned values can be rotated.
......@@ -680,6 +686,11 @@ pub fn alignCast(comptime alignment: u29, ptr: var) AlignCastError!@typeOf(@alig
680686 return @alignCast(alignment, ptr);
681687}
682688
689pub fn isPowerOfTwo(v: var) bool {
690 assert(v != 0);
691 return (v & (v - 1)) == 0;
692}
693
683694pub fn floorPowerOfTwo(comptime T: type, value: T) T {
684695 var x = value;
685696
std/math/big/int.zig+1-1
......@@ -447,7 +447,7 @@ pub const Int = struct {
447447 }
448448
449449 // Power of two: can do a single pass and use masks to extract digits.
450 if (base & (base - 1) == 0) {
450 if (math.isPowerOfTwo(base)) {
451451 const base_shift = math.log2_int(Limb, base);
452452
453453 for (self.limbs[0..self.len()]) |limb| {
std/os/bits/linux.zig+143
......@@ -119,6 +119,23 @@ pub const O_RDONLY = 0o0;
119119pub const O_WRONLY = 0o1;
120120pub const O_RDWR = 0o2;
121121
122pub const kernel_rwf = u32;
123
124/// high priority request, poll if possible
125pub const RWF_HIPRI = kernel_rwf(0x00000001);
126
127/// per-IO O_DSYNC
128pub const RWF_DSYNC = kernel_rwf(0x00000002);
129
130/// per-IO O_SYNC
131pub const RWF_SYNC = kernel_rwf(0x00000004);
132
133/// per-IO, return -EAGAIN if operation would block
134pub const RWF_NOWAIT = kernel_rwf(0x00000008);
135
136/// per-IO O_APPEND
137pub const RWF_APPEND = kernel_rwf(0x00000010);
138
122139pub const SEEK_SET = 0;
123140pub const SEEK_CUR = 1;
124141pub const SEEK_END = 2;
......@@ -950,3 +967,129 @@ pub const stack_t = extern struct {
950967 ss_flags: i32,
951968 ss_size: isize,
952969};
970
971pub const io_uring_params = extern struct {
972 sq_entries: u32,
973 cq_entries: u32,
974 flags: u32,
975 sq_thread_cpu: u32,
976 sq_thread_idle: u32,
977 resv: [5]u32,
978 sq_off: io_sqring_offsets,
979 cq_off: io_cqring_offsets,
980};
981
982// io_uring_params.flags
983
984/// io_context is polled
985pub const IORING_SETUP_IOPOLL = (1 << 0);
986
987/// SQ poll thread
988pub const IORING_SETUP_SQPOLL = (1 << 1);
989
990/// sq_thread_cpu is valid
991pub const IORING_SETUP_SQ_AFF = (1 << 2);
992
993pub const io_sqring_offsets = extern struct {
994 /// offset of ring head
995 head: u32,
996
997 /// offset of ring tail
998 tail: u32,
999
1000 /// ring mask value
1001 ring_mask: u32,
1002
1003 /// entries in ring
1004 ring_entries: u32,
1005
1006 /// ring flags
1007 flags: u32,
1008
1009 /// number of sqes not submitted
1010 dropped: u32,
1011
1012 /// sqe index array
1013 array: u32,
1014
1015 resv1: u32,
1016 resv2: u64,
1017};
1018
1019// io_sqring_offsets.flags
1020
1021/// needs io_uring_enter wakeup
1022pub const IORING_SQ_NEED_WAKEUP = 1 << 0;
1023
1024pub const io_cqring_offsets = extern struct {
1025 head: u32,
1026 tail: u32,
1027 ring_mask: u32,
1028 ring_entries: u32,
1029 overflow: u32,
1030 cqes: u32,
1031 resv: [2]u64,
1032};
1033
1034pub const io_uring_sqe = extern struct {
1035 opcode: u8,
1036 flags: u8,
1037 ioprio: u16,
1038 fd: i32,
1039 off: u64,
1040 addr: u64,
1041 len: u32,
1042 pub const union1 = extern union {
1043 rw_flags: kernel_rwf,
1044 fsync_flags: u32,
1045 poll_event: u16,
1046 };
1047 union1: union1,
1048 user_data: u64,
1049 pub const union2 = extern union {
1050 buf_index: u16,
1051 __pad2: [3]u64,
1052 };
1053 union2: union2,
1054};
1055
1056// io_uring_sqe.flags
1057
1058/// use fixed fileset
1059pub const IOSQE_FIXED_FILE = (1 << 0);
1060
1061pub const IORING_OP_NOP = 0;
1062pub const IORING_OP_READV = 1;
1063pub const IORING_OP_WRITEV = 2;
1064pub const IORING_OP_FSYNC = 3;
1065pub const IORING_OP_READ_FIXED = 4;
1066pub const IORING_OP_WRITE_FIXED = 5;
1067pub const IORING_OP_POLL_ADD = 6;
1068pub const IORING_OP_POLL_REMOVE = 7;
1069
1070// io_uring_sqe.fsync_flags
1071pub const IORING_FSYNC_DATASYNC = (1 << 0);
1072
1073// IO completion data structure (Completion Queue Entry)
1074pub const io_uring_cqe = extern struct {
1075 /// io_uring_sqe.data submission passed back
1076 user_data: u64,
1077
1078 /// result code for this event
1079 res: i32,
1080 flags: u32,
1081};
1082
1083pub const IORING_OFF_SQ_RING = 0;
1084pub const IORING_OFF_CQ_RING = 0x8000000;
1085pub const IORING_OFF_SQES = 0x10000000;
1086
1087// io_uring_enter flags
1088pub const IORING_ENTER_GETEVENTS = (1 << 0);
1089pub const IORING_ENTER_SQ_WAKEUP = (1 << 1);
1090
1091// io_uring_register opcodes and arguments
1092pub const IORING_REGISTER_BUFFERS = 0;
1093pub const IORING_UNREGISTER_BUFFERS = 1;
1094pub const IORING_REGISTER_FILES = 2;
1095pub const IORING_UNREGISTER_FILES = 3;
std/os/linux.zig+20
......@@ -189,6 +189,10 @@ pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {
189189 return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
190190}
191191
192pub fn preadv2(fd: i32, iov: [*]const iovec, count: usize, offset: u64, flags: kernel_rwf) usize {
193 return syscall5(SYS_preadv2, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset, flags);
194}
195
192196pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize {
193197 return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
194198}
......@@ -201,6 +205,10 @@ pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) us
201205 return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
202206}
203207
208pub fn pwritev2(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64, flags: kernel_rwf) usize {
209 return syscall5(SYS_pwritev2, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset, flags);
210}
211
204212// TODO https://github.com/ziglang/zig/issues/265
205213pub fn rmdir(path: [*]const u8) usize {
206214 if (@hasDecl(@This(), "SYS_rmdir")) {
......@@ -887,6 +895,18 @@ pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_inf
887895 return last_r;
888896}
889897
898pub fn io_uring_setup(entries: u32, p: *io_uring_params) usize {
899 return syscall2(SYS_io_uring_setup, entries, @ptrToInt(p));
900}
901
902pub fn io_uring_enter(fd: i32, to_submit: u32, min_complete: u32, flags: u32, sig: ?*sigset_t) usize {
903 return syscall6(SYS_io_uring_enter, @bitCast(usize, isize(fd)), to_submit, min_complete, flags, @ptrToInt(sig), NSIG / 8);
904}
905
906pub fn io_uring_register(fd: i32, opcode: u32, arg: ?*const c_void, nr_args: u32) usize {
907 return syscall4(SYS_io_uring_register, @bitCast(usize, isize(fd)), opcode, @ptrToInt(arg), nr_args);
908}
909
890910test "" {
891911 if (is_the_target) {
892912 _ = @import("linux/test.zig");
std/rand.zig+100
......@@ -18,6 +18,7 @@ const std = @import("std.zig");
1818const builtin = @import("builtin");
1919const assert = std.debug.assert;
2020const expect = std.testing.expect;
21const expectEqual = std.testing.expectEqual;
2122const mem = std.mem;
2223const math = std.math;
2324const ziggurat = @import("rand/ziggurat.zig");
......@@ -935,6 +936,105 @@ test "isaac64 sequence" {
935936 }
936937}
937938
939/// Sfc64 pseudo-random number generator from Practically Random.
940/// Fastest engine of pracrand and smallest footprint.
941/// See http://pracrand.sourceforge.net/
942pub const Sfc64 = struct {
943 random: Random,
944
945 a: u64 = undefined,
946 b: u64 = undefined,
947 c: u64 = undefined,
948 counter: u64 = undefined,
949
950 const Rotation = 24;
951 const RightShift = 11;
952 const LeftShift = 3;
953
954 pub fn init(init_s: u64) Sfc64 {
955 var x = Sfc64{
956 .random = Random{ .fillFn = fill },
957 };
958
959 x.seed(init_s);
960 return x;
961 }
962
963 fn next(self: *Sfc64) u64 {
964 const tmp = self.a +% self.b +% self.counter;
965 self.counter += 1;
966 self.a = self.b ^ (self.b >> RightShift);
967 self.b = self.c +% (self.c << LeftShift);
968 self.c = math.rotl(u64, self.c, Rotation) +% tmp;
969 return tmp;
970 }
971
972 fn seed(self: *Sfc64, init_s: u64) void {
973 self.a = init_s;
974 self.b = init_s;
975 self.c = init_s;
976 self.counter = 1;
977 var i: u32 = 0;
978 while (i < 12) : (i += 1) {
979 _ = self.next();
980 }
981 }
982
983 fn fill(r: *Random, buf: []u8) void {
984 const self = @fieldParentPtr(Sfc64, "random", r);
985
986 var i: usize = 0;
987 const aligned_len = buf.len - (buf.len & 7);
988
989 // Complete 8 byte segments.
990 while (i < aligned_len) : (i += 8) {
991 var n = self.next();
992 comptime var j: usize = 0;
993 inline while (j < 8) : (j += 1) {
994 buf[i + j] = @truncate(u8, n);
995 n >>= 8;
996 }
997 }
998
999 // Remaining. (cuts the stream)
1000 if (i != buf.len) {
1001 var n = self.next();
1002 while (i < buf.len) : (i += 1) {
1003 buf[i] = @truncate(u8, n);
1004 n >>= 8;
1005 }
1006 }
1007 }
1008};
1009
1010test "Sfc64 sequence" {
1011 // Unfortunately there does not seem to be an official test sequence.
1012 var r = Sfc64.init(0);
1013
1014 const seq = [_]u64{
1015 0x3acfa029e3cc6041,
1016 0xf5b6515bf2ee419c,
1017 0x1259635894a29b61,
1018 0xb6ae75395f8ebd6,
1019 0x225622285ce302e2,
1020 0x520d28611395cb21,
1021 0xdb909c818901599d,
1022 0x8ffd195365216f57,
1023 0xe8c4ad5e258ac04a,
1024 0x8f8ef2c89fdb63ca,
1025 0xf9865b01d98d8e2f,
1026 0x46555871a65d08ba,
1027 0x66868677c6298fcd,
1028 0x2ce15a7e6329f57d,
1029 0xb2f1833ca91ca79,
1030 0x4b0890ac9bf453ca,
1031 };
1032
1033 for (seq) |s| {
1034 expectEqual(s, r.next());
1035 }
1036}
1037
9381038// Actual Random helper function tests, pcg engine is assumed correct.
9391039test "Random float" {
9401040 var prng = DefaultPrng.init(0);
std/segmented_list.zig+1-1
......@@ -80,9 +80,9 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
8080 const prealloc_exp = blk: {
8181 // we don't use the prealloc_exp constant when prealloc_item_count is 0.
8282 assert(prealloc_item_count != 0);
83 assert(std.math.isPowerOfTwo(prealloc_item_count));
8384
8485 const value = std.math.log2_int(usize, prealloc_item_count);
85 assert((1 << value) == prealloc_item_count); // prealloc_item_count must be a power of 2
8686 break :blk @typeOf(1)(value);
8787 };
8888 const ShelfIndex = std.math.Log2Int(usize);
std/std.zig+2-1
......@@ -7,17 +7,18 @@ pub const Buffer = @import("buffer.zig").Buffer;
77pub const BufferOutStream = @import("io.zig").BufferOutStream;
88pub const DynLib = @import("dynamic_library.zig").DynLib;
99pub const HashMap = @import("hash_map.zig").HashMap;
10pub const LinkedList = @import("linked_list.zig").LinkedList;
1110pub const Mutex = @import("mutex.zig").Mutex;
1211pub const PackedIntArrayEndian = @import("packed_int_array.zig").PackedIntArrayEndian;
1312pub const PackedIntArray = @import("packed_int_array.zig").PackedIntArray;
1413pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian;
1514pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice;
1615pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
16pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList;
1717pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;
1818pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
1919pub const SpinLock = @import("spinlock.zig").SpinLock;
2020pub const ChildProcess = @import("child_process.zig").ChildProcess;
21pub const TailQueue = @import("linked_list.zig").TailQueue;
2122pub const Thread = @import("thread.zig").Thread;
2223
2324pub const atomic = @import("atomic.zig");
std/testing.zig+4-2
......@@ -78,8 +78,10 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
7878
7979 TypeId.Array => |array| expectEqualSlices(array.child, &expected, &actual),
8080
81 TypeId.Struct => {
82 @compileError("TODO implement testing.expectEqual for structs");
81 TypeId.Struct => |structType| {
82 inline for (structType.fields) |field| {
83 expectEqual(@field(expected, field.name), @field(actual, field.name));
84 }
8385 },
8486
8587 TypeId.Union => |union_info| {
test/compile_errors.zig+27
......@@ -230,6 +230,33 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
230230 "tmp.zig:10:25: error: expression value is ignored",
231231 );
232232
233 cases.add(
234 "empty while loop body",
235 \\export fn a() void {
236 \\ while(true);
237 \\}
238 ,
239 "tmp.zig:2:16: error: expected loop body, found ';'",
240 );
241
242 cases.add(
243 "empty for loop body",
244 \\export fn a() void {
245 \\ for(undefined) |x|;
246 \\}
247 ,
248 "tmp.zig:2:23: error: expected loop body, found ';'",
249 );
250
251 cases.add(
252 "empty if body",
253 \\export fn a() void {
254 \\ if(true);
255 \\}
256 ,
257 "tmp.zig:2:13: error: expected if body, found ';'",
258 );
259
233260 cases.add(
234261 "import outside package path",
235262 \\comptime{