|
5 | 5 | use std::convert::TryInto; |
6 | 6 | use std::thread; |
7 | 7 |
|
| 8 | +#[path = "../../utils/libc.rs"] |
| 9 | +mod libc_utils; |
| 10 | + |
8 | 11 | // Using `as` cast since `EPOLLET` wraps around |
9 | 12 | const EPOLL_IN_OUT_ET: u32 = (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _; |
10 | 13 |
|
@@ -47,37 +50,36 @@ fn main() { |
47 | 50 | let epfd = unsafe { libc::epoll_create1(0) }; |
48 | 51 | assert_ne!(epfd, -1); |
49 | 52 |
|
50 | | - // Create a socketpair instance. |
51 | | - let mut fds = [-1, -1]; |
52 | | - let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; |
53 | | - assert_eq!(res, 0); |
| 53 | + // Create an eventfd instance. |
| 54 | + let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC; |
| 55 | + let fd1 = unsafe { libc::eventfd(0, flags) }; |
| 56 | + // Make a duplicate so that we have two file descriptors for the same file description. |
| 57 | + let fd2 = unsafe { libc::dup(fd1) }; |
54 | 58 |
|
55 | | - // Register one side of the socketpair with epoll. |
56 | | - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 }; |
57 | | - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) }; |
| 59 | + // Register both with epoll. |
| 60 | + let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd1 as u64 }; |
| 61 | + let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd1, &mut ev) }; |
| 62 | + assert_eq!(res, 0); |
| 63 | + let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd2 as u64 }; |
| 64 | + let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd2, &mut ev) }; |
58 | 65 | assert_eq!(res, 0); |
59 | 66 |
|
60 | | - // epoll_wait to clear notification. |
61 | | - let expected_event = u32::try_from(libc::EPOLLOUT).unwrap(); |
62 | | - let expected_value = fds[0] as u64; |
63 | | - check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 0); |
| 67 | + // Consume the initial events. |
| 68 | + let expected = [(libc::EPOLLOUT as u32, fd1 as u64), (libc::EPOLLOUT as u32, fd2 as u64)]; |
| 69 | + check_epoll_wait::<8>(epfd, &expected, -1); |
64 | 70 |
|
65 | | - let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap(); |
66 | | - let expected_value = fds[0] as u64; |
67 | 71 | let thread1 = thread::spawn(move || { |
68 | | - check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], -1); |
| 72 | + check_epoll_wait::<2>(epfd, &expected, -1); |
69 | 73 | }); |
70 | 74 | let thread2 = thread::spawn(move || { |
71 | | - check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], -1); |
| 75 | + check_epoll_wait::<2>(epfd, &expected, -1); |
72 | 76 | //~^ERROR: deadlocked |
73 | 77 | }); |
74 | 78 | // Yield so the threads are both blocked. |
75 | 79 | thread::yield_now(); |
76 | 80 |
|
77 | | - // Just a single write, so we only wake up one of them. |
78 | | - let data = "abcde".as_bytes().as_ptr(); |
79 | | - let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) }; |
80 | | - assert!(res > 0 && res <= 5); |
| 81 | + // Create two events at once. |
| 82 | + libc_utils::write_all_from_slice(fd1, &0_u64.to_ne_bytes()).unwrap(); |
81 | 83 |
|
82 | 84 | thread1.join().unwrap(); |
83 | 85 | thread2.join().unwrap(); |
|
0 commit comments