Skip to content

Commit af9ae48

Browse files
authored
Merge pull request #4290 from flysand7/pipe-has-data
[os2/process]: Implement `process_exec`, and `pipe_has_data`
2 parents 9f813a6 + ca9cfc7 commit af9ae48

File tree

7 files changed

+321
-125
lines changed

7 files changed

+321
-125
lines changed

core/os/os2/errors_windows.odin

+3-1
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,15 @@ _get_platform_error :: proc() -> Error {
5555
case win32.ERROR_NEGATIVE_SEEK:
5656
return .Invalid_Offset
5757

58+
case win32.ERROR_BROKEN_PIPE:
59+
return .Broken_Pipe
60+
5861
case
5962
win32.ERROR_BAD_ARGUMENTS,
6063
win32.ERROR_INVALID_PARAMETER,
6164
win32.ERROR_NOT_ENOUGH_MEMORY,
6265
win32.ERROR_NO_MORE_FILES,
6366
win32.ERROR_LOCK_VIOLATION,
64-
win32.ERROR_BROKEN_PIPE,
6567
win32.ERROR_CALL_NOT_IMPLEMENTED,
6668
win32.ERROR_INSUFFICIENT_BUFFER,
6769
win32.ERROR_INVALID_NAME,

core/os/os2/pipe.odin

+37
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,43 @@
11
package os2
22

3+
/*
4+
Create an anonymous pipe.
5+
6+
This procedure creates an anonymous pipe, returning two ends of the pipe, `r`
7+
and `w`. The file `r` is the readable end of the pipe. The file `w` is a
8+
writeable end of the pipe.
9+
10+
Pipes are used as an inter-process communication mechanism, to communicate
11+
between a parent and a child process. The child uses one end of the pipe to
12+
write data, and the parent uses the other end to read from the pipe
13+
(or vice-versa). When a parent passes one of the ends of the pipe to the child
14+
process, that end of the pipe needs to be closed by the parent, before any data
15+
is attempted to be read.
16+
17+
Although pipes look like files and is compatible with most file APIs in package
18+
os2, the way it's meant to be read is different. Due to asynchronous nature of
19+
the communication channel, the data may not be present at the time of a read
20+
request. The other scenario is when a pipe has no data because the other end
21+
of the pipe was closed by the child process.
22+
*/
323
@(require_results)
424
pipe :: proc() -> (r, w: ^File, err: Error) {
525
return _pipe()
626
}
27+
28+
/*
29+
Check if the pipe has any data.
30+
31+
This procedure checks whether a read-end of the pipe has data that can be
32+
read, and returns `true`, if the pipe has readable data, and `false` if the
33+
pipe is empty. This procedure does not block the execution of the current
34+
thread.
35+
36+
**Note**: If the other end of the pipe was closed by the child process, the
37+
`.Broken_Pipe`
38+
can be returned by this procedure. Handle these errors accordingly.
39+
*/
40+
@(require_results)
41+
pipe_has_data :: proc(r: ^File) -> (ok: bool, err: Error) {
42+
return _pipe_has_data(r)
43+
}

core/os/os2/pipe_linux.odin

+26
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,29 @@ _pipe :: proc() -> (r, w: ^File, err: Error) {
1515

1616
return
1717
}
18+
19+
@(require_results)
20+
_pipe_has_data :: proc(r: ^File) -> (ok: bool, err: Error) {
21+
if r == nil || r.impl == nil {
22+
return false, nil
23+
}
24+
fd := linux.Fd((^File_Impl)(r.impl).fd)
25+
poll_fds := []linux.Poll_Fd {
26+
linux.Poll_Fd {
27+
fd = fd,
28+
events = {.IN, .HUP},
29+
},
30+
}
31+
n, errno := linux.poll(poll_fds, 0)
32+
if n != 1 || errno != nil {
33+
return false, _get_platform_error(errno)
34+
}
35+
pipe_events := poll_fds[0].revents
36+
if pipe_events >= {.IN} {
37+
return true, nil
38+
}
39+
if pipe_events >= {.HUP} {
40+
return false, .Broken_Pipe
41+
}
42+
return false, nil
43+
}

core/os/os2/pipe_posix.odin

+25
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,28 @@ _pipe :: proc() -> (r, w: ^File, err: Error) {
4444
return
4545
}
4646

47+
@(require_results)
48+
_pipe_has_data :: proc(r: ^File) -> (ok: bool, err: Error) {
49+
if r == nil || r.impl == nil {
50+
return false, nil
51+
}
52+
fd := posix.FD((^File_Impl)(r.impl).fd)
53+
poll_fds := []posix.pollfd {
54+
posix.pollfd {
55+
fd = fd,
56+
events = {.IN, .HUP},
57+
},
58+
}
59+
n := posix.poll(raw_data(poll_fds), u32(len(poll_fds)), 0)
60+
if n != 1 {
61+
return false, _get_platform_error()
62+
}
63+
pipe_events := poll_fds[0].revents
64+
if pipe_events >= {.IN} {
65+
return true, nil
66+
}
67+
if pipe_events >= {.HUP} {
68+
return false, .Broken_Pipe
69+
}
70+
return false, nil
71+
}

core/os/os2/pipe_windows.odin

+12
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,15 @@ _pipe :: proc() -> (r, w: ^File, err: Error) {
1515
return new_file(uintptr(p[0]), ""), new_file(uintptr(p[1]), ""), nil
1616
}
1717

18+
@(require_results)
19+
_pipe_has_data :: proc(r: ^File) -> (ok: bool, err: Error) {
20+
if r == nil || r.impl == nil {
21+
return false, nil
22+
}
23+
handle := win32.HANDLE((^File_Impl)(r.impl).fd)
24+
bytes_available: u32
25+
if !win32.PeekNamedPipe(handle, nil, 0, nil, &bytes_available, nil) {
26+
return false, _get_platform_error()
27+
}
28+
return bytes_available > 0, nil
29+
}

0 commit comments

Comments
 (0)