tigerbeetle-node 0.4.2 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -5
- package/dist/benchmark.js.map +1 -1
- package/dist/index.d.ts +18 -16
- package/dist/index.js +35 -13
- package/dist/index.js.map +1 -1
- package/dist/test.js +12 -0
- package/dist/test.js.map +1 -1
- package/package.json +2 -2
- package/scripts/postinstall.sh +2 -2
- package/src/benchmark.ts +2 -2
- package/src/index.ts +29 -4
- package/src/node.zig +120 -17
- package/src/test.ts +14 -0
- package/src/tigerbeetle/scripts/install.sh +1 -1
- package/src/tigerbeetle/scripts/install_zig.bat +109 -0
- package/src/tigerbeetle/scripts/install_zig.sh +4 -2
- package/src/tigerbeetle/scripts/lint.zig +8 -2
- package/src/tigerbeetle/scripts/vopr.bat +48 -0
- package/src/tigerbeetle/src/benchmark.zig +10 -8
- package/src/tigerbeetle/src/cli.zig +6 -4
- package/src/tigerbeetle/src/config.zig +2 -2
- package/src/tigerbeetle/src/demo.zig +119 -89
- package/src/tigerbeetle/src/demo_01_create_accounts.zig +5 -3
- package/src/tigerbeetle/src/demo_02_lookup_accounts.zig +2 -3
- package/src/tigerbeetle/src/demo_03_create_transfers.zig +5 -3
- package/src/tigerbeetle/src/demo_04_create_transfers_two_phase_commit.zig +5 -3
- package/src/tigerbeetle/src/demo_05_accept_transfers.zig +5 -3
- package/src/tigerbeetle/src/demo_06_reject_transfers.zig +5 -3
- package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +7 -0
- package/src/tigerbeetle/src/io/benchmark.zig +238 -0
- package/src/tigerbeetle/src/{io_darwin.zig → io/darwin.zig} +89 -124
- package/src/tigerbeetle/src/io/linux.zig +933 -0
- package/src/tigerbeetle/src/io/test.zig +621 -0
- package/src/tigerbeetle/src/io.zig +7 -1328
- package/src/tigerbeetle/src/main.zig +18 -10
- package/src/tigerbeetle/src/message_bus.zig +43 -60
- package/src/tigerbeetle/src/message_pool.zig +3 -2
- package/src/tigerbeetle/src/ring_buffer.zig +135 -68
- package/src/tigerbeetle/src/simulator.zig +41 -37
- package/src/tigerbeetle/src/state_machine.zig +851 -26
- package/src/tigerbeetle/src/storage.zig +49 -46
- package/src/tigerbeetle/src/test/cluster.zig +2 -2
- package/src/tigerbeetle/src/test/message_bus.zig +6 -6
- package/src/tigerbeetle/src/test/network.zig +3 -3
- package/src/tigerbeetle/src/test/packet_simulator.zig +32 -29
- package/src/tigerbeetle/src/test/state_checker.zig +2 -2
- package/src/tigerbeetle/src/test/state_machine.zig +4 -0
- package/src/tigerbeetle/src/test/storage.zig +39 -19
- package/src/tigerbeetle/src/test/time.zig +2 -2
- package/src/tigerbeetle/src/tigerbeetle.zig +6 -129
- package/src/tigerbeetle/src/time.zig +6 -5
- package/src/tigerbeetle/src/vsr/client.zig +11 -11
- package/src/tigerbeetle/src/vsr/clock.zig +26 -43
- package/src/tigerbeetle/src/vsr/journal.zig +7 -6
- package/src/tigerbeetle/src/vsr/marzullo.zig +6 -3
- package/src/tigerbeetle/src/vsr/replica.zig +51 -48
- package/src/tigerbeetle/src/vsr.zig +24 -20
- package/src/translate.zig +55 -55
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
const std = @import("std");
|
|
2
2
|
const os = std.os;
|
|
3
|
+
const mem = std.mem;
|
|
3
4
|
const assert = std.debug.assert;
|
|
4
5
|
|
|
5
|
-
const FIFO = @import("fifo.zig").FIFO;
|
|
6
|
-
const Time = @import("time.zig").Time;
|
|
7
|
-
const buffer_limit = @import("io.zig").buffer_limit;
|
|
6
|
+
const FIFO = @import("../fifo.zig").FIFO;
|
|
7
|
+
const Time = @import("../time.zig").Time;
|
|
8
|
+
const buffer_limit = @import("../io.zig").buffer_limit;
|
|
8
9
|
|
|
9
10
|
pub const IO = struct {
|
|
10
11
|
kq: os.fd_t,
|
|
11
12
|
time: Time = .{},
|
|
13
|
+
io_inflight: usize = 0,
|
|
12
14
|
timeouts: FIFO(Completion) = .{},
|
|
13
15
|
completed: FIFO(Completion) = .{},
|
|
14
16
|
io_pending: FIFO(Completion) = .{},
|
|
15
17
|
|
|
16
18
|
pub fn init(entries: u12, flags: u32) !IO {
|
|
19
|
+
_ = entries;
|
|
20
|
+
_ = flags;
|
|
21
|
+
|
|
17
22
|
const kq = try os.kqueue();
|
|
18
23
|
assert(kq > -1);
|
|
19
24
|
return IO{ .kq = kq };
|
|
@@ -27,9 +32,7 @@ pub const IO = struct {
|
|
|
27
32
|
|
|
28
33
|
/// Pass all queued submissions to the kernel and peek for completions.
|
|
29
34
|
pub fn tick(self: *IO) !void {
|
|
30
|
-
|
|
31
|
-
// What we're seeing for the tigerbeetle-node client is that recv() syscalls never complete.
|
|
32
|
-
return self.run_for_ns(std.time.ns_per_ms);
|
|
35
|
+
return self.flush(false);
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
/// Pass all queued submissions to the kernel and run for `nanoseconds`.
|
|
@@ -42,8 +45,11 @@ pub const IO = struct {
|
|
|
42
45
|
fn callback(
|
|
43
46
|
timed_out_ptr: *bool,
|
|
44
47
|
_completion: *Completion,
|
|
45
|
-
|
|
48
|
+
result: TimeoutError!void,
|
|
46
49
|
) void {
|
|
50
|
+
_ = _completion;
|
|
51
|
+
_ = result catch unreachable;
|
|
52
|
+
|
|
47
53
|
timed_out_ptr.* = true;
|
|
48
54
|
}
|
|
49
55
|
}.callback;
|
|
@@ -84,10 +90,13 @@ pub const IO = struct {
|
|
|
84
90
|
// - tick() is non-blocking (wait_for_completions = false)
|
|
85
91
|
// - run_for_ns() always submits a timeout
|
|
86
92
|
if (change_events == 0 and self.completed.peek() == null) {
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
93
|
+
if (wait_for_completions) {
|
|
94
|
+
const timeout_ns = next_timeout orelse @panic("kevent() blocking forever");
|
|
95
|
+
ts.tv_nsec = @intCast(@TypeOf(ts.tv_nsec), timeout_ns % std.time.ns_per_s);
|
|
96
|
+
ts.tv_sec = @intCast(@TypeOf(ts.tv_sec), timeout_ns / std.time.ns_per_s);
|
|
97
|
+
} else if (self.io_inflight == 0) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
91
100
|
}
|
|
92
101
|
|
|
93
102
|
const new_events = try os.kevent(
|
|
@@ -103,8 +112,12 @@ pub const IO = struct {
|
|
|
103
112
|
self.io_pending.in = null;
|
|
104
113
|
}
|
|
105
114
|
|
|
115
|
+
self.io_inflight += change_events;
|
|
116
|
+
self.io_inflight -= new_events;
|
|
117
|
+
|
|
106
118
|
for (events[0..new_events]) |event| {
|
|
107
119
|
const completion = @intToPtr(*Completion, event.udata);
|
|
120
|
+
completion.next = null;
|
|
108
121
|
self.completed.push(completion);
|
|
109
122
|
}
|
|
110
123
|
}
|
|
@@ -116,25 +129,25 @@ pub const IO = struct {
|
|
|
116
129
|
}
|
|
117
130
|
}
|
|
118
131
|
|
|
119
|
-
fn flush_io(
|
|
132
|
+
fn flush_io(_: *IO, events: []os.Kevent, io_pending_top: *?*Completion) usize {
|
|
120
133
|
for (events) |*event, flushed| {
|
|
121
134
|
const completion = io_pending_top.* orelse return flushed;
|
|
122
135
|
io_pending_top.* = completion.next;
|
|
123
136
|
|
|
124
137
|
const event_info = switch (completion.operation) {
|
|
125
|
-
.accept => |op| [2]c_int{ op.socket, os.EVFILT_READ },
|
|
126
|
-
.connect => |op| [2]c_int{ op.socket, os.EVFILT_WRITE },
|
|
127
|
-
.read => |op| [2]c_int{ op.fd, os.EVFILT_READ },
|
|
128
|
-
.write => |op| [2]c_int{ op.fd, os.EVFILT_WRITE },
|
|
129
|
-
.recv => |op| [2]c_int{ op.socket, os.EVFILT_READ },
|
|
130
|
-
.send => |op| [2]c_int{ op.socket, os.EVFILT_WRITE },
|
|
138
|
+
.accept => |op| [2]c_int{ op.socket, os.system.EVFILT_READ },
|
|
139
|
+
.connect => |op| [2]c_int{ op.socket, os.system.EVFILT_WRITE },
|
|
140
|
+
.read => |op| [2]c_int{ op.fd, os.system.EVFILT_READ },
|
|
141
|
+
.write => |op| [2]c_int{ op.fd, os.system.EVFILT_WRITE },
|
|
142
|
+
.recv => |op| [2]c_int{ op.socket, os.system.EVFILT_READ },
|
|
143
|
+
.send => |op| [2]c_int{ op.socket, os.system.EVFILT_WRITE },
|
|
131
144
|
else => @panic("invalid completion operation queued for io"),
|
|
132
145
|
};
|
|
133
146
|
|
|
134
147
|
event.* = .{
|
|
135
148
|
.ident = @intCast(u32, event_info[0]),
|
|
136
149
|
.filter = @intCast(i16, event_info[1]),
|
|
137
|
-
.flags = os.EV_ADD | os.EV_ENABLE | os.EV_ONESHOT,
|
|
150
|
+
.flags = os.system.EV_ADD | os.system.EV_ENABLE | os.system.EV_ONESHOT,
|
|
138
151
|
.fflags = 0,
|
|
139
152
|
.data = 0,
|
|
140
153
|
.udata = @ptrToInt(completion),
|
|
@@ -174,7 +187,7 @@ pub const IO = struct {
|
|
|
174
187
|
/// This struct holds the data needed for a single IO operation
|
|
175
188
|
pub const Completion = struct {
|
|
176
189
|
next: ?*Completion,
|
|
177
|
-
context: ?*
|
|
190
|
+
context: ?*anyopaque,
|
|
178
191
|
callback: fn (*IO, *Completion) void,
|
|
179
192
|
operation: Operation,
|
|
180
193
|
};
|
|
@@ -182,7 +195,6 @@ pub const IO = struct {
|
|
|
182
195
|
const Operation = union(enum) {
|
|
183
196
|
accept: struct {
|
|
184
197
|
socket: os.socket_t,
|
|
185
|
-
flags: u32,
|
|
186
198
|
},
|
|
187
199
|
close: struct {
|
|
188
200
|
fd: os.fd_t,
|
|
@@ -194,13 +206,6 @@ pub const IO = struct {
|
|
|
194
206
|
},
|
|
195
207
|
fsync: struct {
|
|
196
208
|
fd: os.fd_t,
|
|
197
|
-
flags: u32,
|
|
198
|
-
},
|
|
199
|
-
openat: struct {
|
|
200
|
-
fd: os.fd_t,
|
|
201
|
-
path: [*:0]const u8,
|
|
202
|
-
flags: u32,
|
|
203
|
-
mode: os.mode_t,
|
|
204
209
|
},
|
|
205
210
|
read: struct {
|
|
206
211
|
fd: os.fd_t,
|
|
@@ -212,13 +217,11 @@ pub const IO = struct {
|
|
|
212
217
|
socket: os.socket_t,
|
|
213
218
|
buf: [*]u8,
|
|
214
219
|
len: u32,
|
|
215
|
-
flags: u32,
|
|
216
220
|
},
|
|
217
221
|
send: struct {
|
|
218
222
|
socket: os.socket_t,
|
|
219
223
|
buf: [*]const u8,
|
|
220
224
|
len: u32,
|
|
221
|
-
flags: u32,
|
|
222
225
|
},
|
|
223
226
|
timeout: struct {
|
|
224
227
|
expires: u64,
|
|
@@ -284,7 +287,7 @@ pub const IO = struct {
|
|
|
284
287
|
}
|
|
285
288
|
}
|
|
286
289
|
|
|
287
|
-
pub const AcceptError = os.AcceptError;
|
|
290
|
+
pub const AcceptError = os.AcceptError || os.SetSockOptError;
|
|
288
291
|
|
|
289
292
|
pub fn accept(
|
|
290
293
|
self: *IO,
|
|
@@ -297,7 +300,6 @@ pub const IO = struct {
|
|
|
297
300
|
) void,
|
|
298
301
|
completion: *Completion,
|
|
299
302
|
socket: os.socket_t,
|
|
300
|
-
flags: u32,
|
|
301
303
|
) void {
|
|
302
304
|
self.submit(
|
|
303
305
|
context,
|
|
@@ -306,11 +308,33 @@ pub const IO = struct {
|
|
|
306
308
|
.accept,
|
|
307
309
|
.{
|
|
308
310
|
.socket = socket,
|
|
309
|
-
.flags = flags,
|
|
310
311
|
},
|
|
311
312
|
struct {
|
|
312
313
|
fn doOperation(op: anytype) AcceptError!os.socket_t {
|
|
313
|
-
|
|
314
|
+
const fd = try os.accept(
|
|
315
|
+
op.socket,
|
|
316
|
+
null,
|
|
317
|
+
null,
|
|
318
|
+
os.SOCK.NONBLOCK | os.SOCK.CLOEXEC,
|
|
319
|
+
);
|
|
320
|
+
errdefer os.close(fd);
|
|
321
|
+
|
|
322
|
+
// Darwin doesn't support os.MSG_NOSIGNAL to avoid getting SIGPIPE on socket send().
|
|
323
|
+
// Instead, it uses the SO_NOSIGPIPE socket option which does the same for all send()s.
|
|
324
|
+
os.setsockopt(
|
|
325
|
+
fd,
|
|
326
|
+
os.SOL.SOCKET,
|
|
327
|
+
os.SO.NOSIGPIPE,
|
|
328
|
+
&mem.toBytes(@as(c_int, 1)),
|
|
329
|
+
) catch |err| return switch (err) {
|
|
330
|
+
error.TimeoutTooBig => unreachable,
|
|
331
|
+
error.PermissionDenied => error.NetworkSubsystemFailed,
|
|
332
|
+
error.AlreadyConnected => error.NetworkSubsystemFailed,
|
|
333
|
+
error.InvalidProtocolOption => error.ProtocolFailure,
|
|
334
|
+
else => |e| e,
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
return fd;
|
|
314
338
|
}
|
|
315
339
|
},
|
|
316
340
|
);
|
|
@@ -346,10 +370,10 @@ pub const IO = struct {
|
|
|
346
370
|
struct {
|
|
347
371
|
fn doOperation(op: anytype) CloseError!void {
|
|
348
372
|
return switch (os.errno(os.system.close(op.fd))) {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
373
|
+
.SUCCESS => {},
|
|
374
|
+
.BADF => error.FileDescriptorInvalid,
|
|
375
|
+
.INTR => {}, // A success, see https://github.com/ziglang/zig/issues/2425
|
|
376
|
+
.IO => error.InputOutput,
|
|
353
377
|
else => |errno| os.unexpectedErrno(errno),
|
|
354
378
|
};
|
|
355
379
|
}
|
|
@@ -398,14 +422,7 @@ pub const IO = struct {
|
|
|
398
422
|
);
|
|
399
423
|
}
|
|
400
424
|
|
|
401
|
-
pub const FsyncError =
|
|
402
|
-
FileDescriptorInvalid,
|
|
403
|
-
DiskQuota,
|
|
404
|
-
ArgumentsInvalid,
|
|
405
|
-
InputOutput,
|
|
406
|
-
NoSpaceLeft,
|
|
407
|
-
ReadOnlyFileSystem,
|
|
408
|
-
} || os.UnexpectedError;
|
|
425
|
+
pub const FsyncError = os.SyncError;
|
|
409
426
|
|
|
410
427
|
pub fn fsync(
|
|
411
428
|
self: *IO,
|
|
@@ -418,7 +435,6 @@ pub const IO = struct {
|
|
|
418
435
|
) void,
|
|
419
436
|
completion: *Completion,
|
|
420
437
|
fd: os.fd_t,
|
|
421
|
-
flags: u32,
|
|
422
438
|
) void {
|
|
423
439
|
self.submit(
|
|
424
440
|
context,
|
|
@@ -427,66 +443,10 @@ pub const IO = struct {
|
|
|
427
443
|
.fsync,
|
|
428
444
|
.{
|
|
429
445
|
.fd = fd,
|
|
430
|
-
.flags = flags,
|
|
431
446
|
},
|
|
432
447
|
struct {
|
|
433
448
|
fn doOperation(op: anytype) FsyncError!void {
|
|
434
|
-
_ = os.fcntl(op.fd, os.
|
|
435
|
-
}
|
|
436
|
-
},
|
|
437
|
-
);
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
pub const OpenatError = error{
|
|
441
|
-
AccessDenied,
|
|
442
|
-
FileDescriptorInvalid,
|
|
443
|
-
DeviceBusy,
|
|
444
|
-
PathAlreadyExists,
|
|
445
|
-
FileTooBig,
|
|
446
|
-
ArgumentsInvalid,
|
|
447
|
-
IsDir,
|
|
448
|
-
SymLinkLoop,
|
|
449
|
-
ProcessFdQuotaExceeded,
|
|
450
|
-
NameTooLong,
|
|
451
|
-
SystemFdQuotaExceeded,
|
|
452
|
-
NoDevice,
|
|
453
|
-
FileNotFound,
|
|
454
|
-
SystemResources,
|
|
455
|
-
NoSpaceLeft,
|
|
456
|
-
NotDir,
|
|
457
|
-
FileLocksNotSupported,
|
|
458
|
-
WouldBlock,
|
|
459
|
-
} || os.UnexpectedError;
|
|
460
|
-
|
|
461
|
-
pub fn openat(
|
|
462
|
-
self: *IO,
|
|
463
|
-
comptime Context: type,
|
|
464
|
-
context: Context,
|
|
465
|
-
comptime callback: fn (
|
|
466
|
-
context: Context,
|
|
467
|
-
completion: *Completion,
|
|
468
|
-
result: OpenatError!os.fd_t,
|
|
469
|
-
) void,
|
|
470
|
-
completion: *Completion,
|
|
471
|
-
fd: os.fd_t,
|
|
472
|
-
path: [*:0]const u8,
|
|
473
|
-
flags: u32,
|
|
474
|
-
mode: os.mode_t,
|
|
475
|
-
) void {
|
|
476
|
-
self.submit(
|
|
477
|
-
context,
|
|
478
|
-
callback,
|
|
479
|
-
completion,
|
|
480
|
-
.openat,
|
|
481
|
-
.{
|
|
482
|
-
.fd = fd,
|
|
483
|
-
.path = path,
|
|
484
|
-
.mode = mode,
|
|
485
|
-
.flags = flags,
|
|
486
|
-
},
|
|
487
|
-
struct {
|
|
488
|
-
fn doOperation(op: anytype) OpenatError!os.fd_t {
|
|
489
|
-
return os.openatZ(op.fd, op.path, op.flags, op.mode);
|
|
449
|
+
_ = os.fcntl(op.fd, os.F.FULLFSYNC, 1) catch return os.fsync(op.fd);
|
|
490
450
|
}
|
|
491
451
|
},
|
|
492
452
|
);
|
|
@@ -538,20 +498,20 @@ pub const IO = struct {
|
|
|
538
498
|
@bitCast(isize, op.offset),
|
|
539
499
|
);
|
|
540
500
|
return switch (os.errno(rc)) {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
501
|
+
.SUCCESS => @intCast(usize, rc),
|
|
502
|
+
.INTR => continue,
|
|
503
|
+
.AGAIN => error.WouldBlock,
|
|
504
|
+
.BADF => error.NotOpenForReading,
|
|
505
|
+
.CONNRESET => error.ConnectionResetByPeer,
|
|
506
|
+
.FAULT => unreachable,
|
|
507
|
+
.INVAL => error.Alignment,
|
|
508
|
+
.IO => error.InputOutput,
|
|
509
|
+
.ISDIR => error.IsDir,
|
|
510
|
+
.NOBUFS => error.SystemResources,
|
|
511
|
+
.NOMEM => error.SystemResources,
|
|
512
|
+
.NXIO => error.Unseekable,
|
|
513
|
+
.OVERFLOW => error.Unseekable,
|
|
514
|
+
.SPIPE => error.Unseekable,
|
|
555
515
|
else => |err| os.unexpectedErrno(err),
|
|
556
516
|
};
|
|
557
517
|
}
|
|
@@ -574,7 +534,6 @@ pub const IO = struct {
|
|
|
574
534
|
completion: *Completion,
|
|
575
535
|
socket: os.socket_t,
|
|
576
536
|
buffer: []u8,
|
|
577
|
-
flags: u32,
|
|
578
537
|
) void {
|
|
579
538
|
self.submit(
|
|
580
539
|
context,
|
|
@@ -585,11 +544,10 @@ pub const IO = struct {
|
|
|
585
544
|
.socket = socket,
|
|
586
545
|
.buf = buffer.ptr,
|
|
587
546
|
.len = @intCast(u32, buffer_limit(buffer.len)),
|
|
588
|
-
.flags = flags,
|
|
589
547
|
},
|
|
590
548
|
struct {
|
|
591
549
|
fn doOperation(op: anytype) RecvError!usize {
|
|
592
|
-
return os.recv(op.socket, op.buf[0..op.len],
|
|
550
|
+
return os.recv(op.socket, op.buf[0..op.len], 0);
|
|
593
551
|
}
|
|
594
552
|
},
|
|
595
553
|
);
|
|
@@ -609,7 +567,6 @@ pub const IO = struct {
|
|
|
609
567
|
completion: *Completion,
|
|
610
568
|
socket: os.socket_t,
|
|
611
569
|
buffer: []const u8,
|
|
612
|
-
flags: u32,
|
|
613
570
|
) void {
|
|
614
571
|
self.submit(
|
|
615
572
|
context,
|
|
@@ -620,11 +577,10 @@ pub const IO = struct {
|
|
|
620
577
|
.socket = socket,
|
|
621
578
|
.buf = buffer.ptr,
|
|
622
579
|
.len = @intCast(u32, buffer_limit(buffer.len)),
|
|
623
|
-
.flags = flags,
|
|
624
580
|
},
|
|
625
581
|
struct {
|
|
626
582
|
fn doOperation(op: anytype) SendError!usize {
|
|
627
|
-
return os.send(op.socket, op.buf[0..op.len],
|
|
583
|
+
return os.send(op.socket, op.buf[0..op.len], 0);
|
|
628
584
|
}
|
|
629
585
|
},
|
|
630
586
|
);
|
|
@@ -694,4 +650,13 @@ pub const IO = struct {
|
|
|
694
650
|
},
|
|
695
651
|
);
|
|
696
652
|
}
|
|
653
|
+
|
|
654
|
+
pub fn openSocket(family: u32, sock_type: u32, protocol: u32) !os.socket_t {
|
|
655
|
+
const fd = try os.socket(family, sock_type | os.SOCK.NONBLOCK, protocol);
|
|
656
|
+
errdefer os.close(fd);
|
|
657
|
+
|
|
658
|
+
// darwin doesn't support os.MSG_NOSIGNAL, but instead a socket option to avoid SIGPIPE.
|
|
659
|
+
try os.setsockopt(fd, os.SOL.SOCKET, os.SO.NOSIGPIPE, &mem.toBytes(@as(c_int, 1)));
|
|
660
|
+
return fd;
|
|
661
|
+
}
|
|
697
662
|
};
|