1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
| #![no_std]
#![no_main]
#[macro_use]
#[path = "ulib.rs"]
mod ulib;
extern crate alloc;
use ulib::*;
const FIONBIO: u64 = 0x5421;
fn main() -> i64 {
let mut c = Checks::new("nbtest");
let mut buf = [0u8; 4096];
let (r, w) = pipe2(O_NONBLOCK).unwrap();
c.check(read(r, &mut buf) == -EAGAIN, "pipe: read with nothing there: EAGAIN");
let mut p = [PollFd { fd: r as i32, events: POLLIN, revents: 0 }];
c.check(poll(&mut p, 0) == 0, "pipe: poll says not readable");
let mut total = 0;
loop {
let n = write(w, &buf);
if n < 0 {
c.check(n == -EAGAIN, "pipe: write to a full pipe: EAGAIN");
break;
}
total += n;
}
println!("nbtest: the pipe took {} bytes before it was full", total);
c.check(total == 65536, "pipe: holds 64 KiB, like Linux");
let mut p = [PollFd { fd: w as i32, events: POLLOUT, revents: 0 }];
c.check(poll(&mut p, 0) == 0, "pipe: poll says a full pipe isn't writable");
c.check(read(r, &mut buf) == 4096, "pipe: then reading works");
c.check(poll(&mut p, 0) == 1 && p[0].revents & POLLOUT != 0, "pipe: room again -> POLLOUT");
close(w);
while read(r, &mut buf) > 0 {}
c.check(read(r, &mut buf) == 0, "pipe: writer gone -> end of file, not EAGAIN");
close(r);
let (r, w) = pipe().unwrap();
c.check(fcntl(r, F_GETFL, 0) as u64 & O_NONBLOCK == 0, "fcntl F_GETFL: blocking by default");
set_nonblocking(r, true);
c.check(fcntl(r, F_GETFL, 0) as u64 & O_NONBLOCK != 0, "fcntl F_SETFL O_NONBLOCK sticks");
c.check(read(r, &mut buf) == -EAGAIN, "fcntl-made nonblocking pipe: EAGAIN");
let off = 0i32;
ioctl(r, FIONBIO, &off as *const i32 as u64);
c.check(fcntl(r, F_GETFL, 0) as u64 & O_NONBLOCK == 0, "ioctl FIONBIO 0 turns it off");
close(r);
close(w);
let l = socket(SOCK_STREAM, 0);
bind(l, 7080);
listen(l, 2);
set_nonblocking(l, true);
c.check(accept(l).0 == -EAGAIN, "socket: accept with nobody calling: EAGAIN");
let s = socket(SOCK_STREAM | O_NONBLOCK, 0);
let r = connect(s, Ip([127, 0, 0, 1]), 7080);
c.check(r == 0 || r == -EINPROGRESS, "socket: nonblocking connect: EINPROGRESS (or done at once)");
let mut p = [PollFd { fd: s as i32, events: POLLOUT, revents: 0 }];
c.check(poll(&mut p, 2000) == 1 && p[0].revents & POLLOUT != 0, "socket: poll POLLOUT = connected");
let mut p = [PollFd { fd: l as i32, events: POLLIN, revents: 0 }];
c.check(poll(&mut p, 2000) == 1, "socket: listener POLLIN = a connection to accept");
let (a, _) = accept(l);
c.check(a >= 0, "socket: accept it");
c.check(read(s, &mut buf) == -EAGAIN, "socket: recv with no data: EAGAIN");
write(a, b"hi");
let mut p = [PollFd { fd: s as i32, events: POLLIN, revents: 0 }];
poll(&mut p, 2000);
c.check(read(s, &mut buf) == 2, "socket: data after POLLIN");
close(a);
close(s);
close(l);
if let Ok((m, n)) = openpty() {
let slave = open(&alloc::format!("/dev/pts/{}", n), O_RDWR | O_NOCTTY | O_NONBLOCK);
c.check(read(slave, &mut buf) == -EAGAIN, "tty: read with no line typed: EAGAIN");
close(slave);
close(m);
} else {
c.check(false, "openpty");
}
let fd = open("/tmp/nbtest.txt", O_CREAT | O_TRUNC | O_RDWR);
writev(fd, &[b"hello ", b"vectored ", b"world"]);
pwrite(fd, b"HELLO", 0);
let n = pread(fd, &mut buf, 6);
c.check(&buf[..n.max(0) as usize] == b"vectored world", "writev + pread at an offset");
c.check(lseek(fd, 0, SEEK_CUR) == 20, "pread/pwrite leave the file position alone");
lseek(fd, 0, SEEK_SET);
let n = read(fd, &mut buf);
c.check(&buf[..n.max(0) as usize] == b"HELLO vectored world", "pwrite overwrote the start");
close(fd);
unlink("/tmp/nbtest.txt");
let fd = open("/tmp/nbtest.txt", O_CREAT | O_TRUNC | O_RDWR);
write(fd, b"abcdefgh");
lseek(fd, 0, SEEK_SET);
let (mut a, mut b) = ([0u8; 3], [0u8; 5]);
let n = readv(fd, &mut [&mut a, &mut b]);
c.check(n == 8 && &a == b"abc" && &b == b"defgh", "readv fills the buffers in order");
close(fd);
unlink("/tmp/nbtest.txt");
let (r, w) = pipe2(0).unwrap();
let (mut rs, mut ws) = ([0u64; 16], [0u64; 16]);
fd_set(&mut rs, r);
let t0 = now_us();
c.check(select(r + 1, &mut rs, &mut ws, 20_000) == 0 && now_us() - t0 >= 20_000, "select: times out after 20 ms on an empty pipe");
write(w, b"!");
let (mut rs, mut ws) = ([0u64; 16], [0u64; 16]);
fd_set(&mut rs, r);
fd_set(&mut ws, w);
c.check(select(w.max(r) + 1, &mut rs, &mut ws, 0) == 2 && fd_isset(&rs, r) && fd_isset(&ws, w), "select: pipe readable + writable");
let mut p = [PollFd { fd: r as i32, events: POLLIN, revents: 0 }];
c.check(ppoll_us(&mut p, 0) == 1 && p[0].revents & POLLIN != 0, "ppoll: POLLIN");
close(r);
close(w);
let mut cwd = [0u8; 64];
let n = getcwd(&mut cwd);
c.check(n > 0 && cwd[0] == b'/', "getcwd gives an absolute path");
let mut ub = [0u8; 6 * 65];
let u = uname(&mut ub);
c.check(u[0] == "Rustbelt" && u[3].starts_with("stage 18"), "uname: Rustbelt, stage 18");
let (secs, _) = clock_gettime(0);
c.check(secs > 1_600_000_000, "CLOCK_REALTIME is a real date (after 2020)");
let t0 = now_us();
nanosleep_us(30_000);
c.check(now_us() - t0 >= 25_000, "nanosleep 30 ms");
let mut link = [0u8; 64];
let n = readlink("/proc/self/exe", &mut link);
c.check(n > 0 && link[..n as usize].ends_with(b"nbtest"), "readlink /proc/self/exe = this program");
c.done()
}
|