-
Notifications
You must be signed in to change notification settings - Fork 423
Refactor socketpair tests to use utility functions for reading/writing #4770
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ use std::thread; | |
|
|
||
| #[path = "../../utils/libc.rs"] | ||
| mod libc_utils; | ||
| use libc_utils::{errno_check, errno_result, read_all_into_array, write_all_from_slice}; | ||
|
|
||
| fn main() { | ||
| test_socketpair(); | ||
|
|
@@ -21,23 +22,17 @@ fn main() { | |
|
|
||
| fn test_socketpair() { | ||
| let mut fds = [-1, -1]; | ||
| let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; | ||
| assert_eq!(res, 0); | ||
| errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); | ||
|
|
||
| // Read size == data available in buffer. | ||
| let data = "abcde".as_bytes().as_ptr(); | ||
| let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) }; | ||
| assert_eq!(res, 5); | ||
| let mut buf: [u8; 5] = [0; 5]; | ||
| let res = | ||
| unsafe { libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; | ||
| assert_eq!(res, 5); | ||
| assert_eq!(buf, "abcde".as_bytes()); | ||
| let data = b"abcde"; | ||
| write_all_from_slice(fds[0], data).unwrap(); | ||
| let buf = read_all_into_array::<5>(fds[1]).unwrap(); | ||
| assert_eq!(&buf, data); | ||
|
|
||
| // Read size > data available in buffer. | ||
| let data = "abc".as_bytes(); | ||
| let res = unsafe { libc_utils::write_all(fds[0], data.as_ptr() as *const libc::c_void, 3) }; | ||
| assert_eq!(res, 3); | ||
| let data = b"abc"; | ||
| write_all_from_slice(fds[0], data).unwrap(); | ||
| let mut buf2: [u8; 5] = [0; 5]; | ||
| let res = unsafe { libc::read(fds[1], buf2.as_mut_ptr().cast(), buf2.len() as libc::size_t) }; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to #4768, this should use helpers instead of directly invoking |
||
| assert!(res > 0 && res <= 3); | ||
|
|
@@ -51,20 +46,14 @@ fn test_socketpair() { | |
|
|
||
| // Test read and write from another direction. | ||
| // Read size == data available in buffer. | ||
| let data = "12345".as_bytes().as_ptr(); | ||
| let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) }; | ||
| assert_eq!(res, 5); | ||
| let mut buf3: [u8; 5] = [0; 5]; | ||
| let res = unsafe { | ||
| libc_utils::read_all(fds[0], buf3.as_mut_ptr().cast(), buf3.len() as libc::size_t) | ||
| }; | ||
| assert_eq!(res, 5); | ||
| assert_eq!(buf3, "12345".as_bytes()); | ||
| let data = b"12345"; | ||
| write_all_from_slice(fds[1], data).unwrap(); | ||
| let buf3 = read_all_into_array::<5>(fds[0]).unwrap(); | ||
| assert_eq!(&buf3, data); | ||
|
|
||
| // Read size > data available in buffer. | ||
| let data = "123".as_bytes(); | ||
| let res = unsafe { libc_utils::write_all(fds[1], data.as_ptr() as *const libc::c_void, 3) }; | ||
| assert_eq!(res, 3); | ||
| let data = b"123"; | ||
| write_all_from_slice(fds[1], data).unwrap(); | ||
| let mut buf4: [u8; 5] = [0; 5]; | ||
| let res = unsafe { libc::read(fds[0], buf4.as_mut_ptr().cast(), buf4.len() as libc::size_t) }; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another place that should use a helper. |
||
| assert!(res > 0 && res <= 3); | ||
|
|
@@ -77,15 +66,14 @@ fn test_socketpair() { | |
| } | ||
|
|
||
| // Test when happens when we close one end, with some data in the buffer. | ||
| let res = unsafe { libc_utils::write_all(fds[0], data.as_ptr() as *const libc::c_void, 3) }; | ||
| assert_eq!(res, 3); | ||
| unsafe { libc::close(fds[0]) }; | ||
| write_all_from_slice(fds[0], data).unwrap(); | ||
| errno_check(unsafe { libc::close(fds[0]) }); | ||
| // Reading the other end should return that data, then EOF. | ||
| let mut buf: [u8; 5] = [0; 5]; | ||
| let res = | ||
| unsafe { libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another helper candidate. |
||
| assert_eq!(res, 3); | ||
| assert_eq!(&buf[0..3], "123".as_bytes()); | ||
| assert_eq!(&buf[0..3], b"123"); | ||
| let res = | ||
| unsafe { libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And another one |
||
| assert_eq!(res, 0); // 0-sized read: EOF. | ||
|
|
@@ -97,86 +85,60 @@ fn test_socketpair() { | |
|
|
||
| fn test_socketpair_threaded() { | ||
| let mut fds = [-1, -1]; | ||
| let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; | ||
| assert_eq!(res, 0); | ||
| errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); | ||
|
|
||
| let thread1 = thread::spawn(move || { | ||
| let mut buf: [u8; 5] = [0; 5]; | ||
| let res: i64 = unsafe { | ||
| libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) | ||
| .try_into() | ||
| .unwrap() | ||
| }; | ||
| assert_eq!(res, 5); | ||
| assert_eq!(buf, "abcde".as_bytes()); | ||
| let buf = read_all_into_array::<5>(fds[1]).unwrap(); | ||
| assert_eq!(&buf, b"abcde"); | ||
| }); | ||
| thread::yield_now(); | ||
| let data = "abcde".as_bytes().as_ptr(); | ||
| let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) }; | ||
| assert_eq!(res, 5); | ||
| let data = b"abcde"; | ||
| write_all_from_slice(fds[0], data).unwrap(); | ||
| thread1.join().unwrap(); | ||
|
|
||
| // Read and write from different direction | ||
| let thread2 = thread::spawn(move || { | ||
| thread::yield_now(); | ||
| let data = "12345".as_bytes().as_ptr(); | ||
| let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) }; | ||
| assert_eq!(res, 5); | ||
| let data = b"12345"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This variable seems to be used only once, please inline it. (Same everywhere else in this PR, and in your other PRs as well.) |
||
| write_all_from_slice(fds[1], data).unwrap(); | ||
| }); | ||
| let mut buf: [u8; 5] = [0; 5]; | ||
| let res = | ||
| unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; | ||
| assert_eq!(res, 5); | ||
| assert_eq!(buf, "12345".as_bytes()); | ||
| let buf = read_all_into_array::<5>(fds[0]).unwrap(); | ||
| assert_eq!(&buf, b"12345"); | ||
| thread2.join().unwrap(); | ||
| } | ||
|
|
||
| fn test_race() { | ||
| static mut VAL: u8 = 0; | ||
| let mut fds = [-1, -1]; | ||
| let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; | ||
| assert_eq!(res, 0); | ||
| errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); | ||
| let thread1 = thread::spawn(move || { | ||
| let mut buf: [u8; 1] = [0; 1]; | ||
| // write() from the main thread will occur before the read() here | ||
| // because preemption is disabled and the main thread yields after write(). | ||
| let res: i32 = unsafe { | ||
| libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) | ||
| .try_into() | ||
| .unwrap() | ||
| }; | ||
| assert_eq!(res, 1); | ||
| assert_eq!(buf, "a".as_bytes()); | ||
| let buf = read_all_into_array::<1>(fds[1]).unwrap(); | ||
| assert_eq!(&buf, b"a"); | ||
| // The read above establishes a happens-before so it is now safe to access this global variable. | ||
| unsafe { assert_eq!(VAL, 1) }; | ||
| }); | ||
| unsafe { VAL = 1 }; | ||
| let data = "a".as_bytes().as_ptr(); | ||
| let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 1) }; | ||
| assert_eq!(res, 1); | ||
| let data = b"a"; | ||
| write_all_from_slice(fds[0], data).unwrap(); | ||
| thread::yield_now(); | ||
| thread1.join().unwrap(); | ||
| } | ||
|
|
||
| // Test the behaviour of a socketpair getting blocked on read and subsequently unblocked. | ||
| fn test_blocking_read() { | ||
| let mut fds = [-1, -1]; | ||
| let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; | ||
| assert_eq!(res, 0); | ||
| errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); | ||
| let thread1 = thread::spawn(move || { | ||
| // Let this thread block on read. | ||
| let mut buf: [u8; 3] = [0; 3]; | ||
| let res = unsafe { | ||
| libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) | ||
| }; | ||
| assert_eq!(res, 3); | ||
| assert_eq!(&buf, "abc".as_bytes()); | ||
| let buf = read_all_into_array::<3>(fds[1]).unwrap(); | ||
| assert_eq!(&buf, b"abc"); | ||
| }); | ||
| let thread2 = thread::spawn(move || { | ||
| // Unblock thread1 by doing writing something. | ||
| let data = "abc".as_bytes().as_ptr(); | ||
| let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 3) }; | ||
| assert_eq!(res, 3); | ||
| let data = b"abc"; | ||
| write_all_from_slice(fds[0], data).unwrap(); | ||
| }); | ||
| thread1.join().unwrap(); | ||
| thread2.join().unwrap(); | ||
|
|
@@ -185,26 +147,18 @@ fn test_blocking_read() { | |
| // Test the behaviour of a socketpair getting blocked on write and subsequently unblocked. | ||
| fn test_blocking_write() { | ||
| let mut fds = [-1, -1]; | ||
| let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; | ||
| assert_eq!(res, 0); | ||
| errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); | ||
| let arr1: [u8; 0x34000] = [1; 0x34000]; | ||
| // Exhaust the space in the buffer so the subsequent write will block. | ||
| let res = | ||
| unsafe { libc_utils::write_all(fds[0], arr1.as_ptr() as *const libc::c_void, arr1.len()) }; | ||
| assert_eq!(res, 0x34000); | ||
| write_all_from_slice(fds[0], &arr1).unwrap(); | ||
| let thread1 = thread::spawn(move || { | ||
| let data = "abc".as_bytes().as_ptr(); | ||
| let data = b"abc"; | ||
| // The write below will be blocked because the buffer is already full. | ||
| let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 3) }; | ||
| assert_eq!(res, 3); | ||
| write_all_from_slice(fds[0], data).unwrap(); | ||
| }); | ||
| let thread2 = thread::spawn(move || { | ||
| // Unblock thread1 by freeing up some space. | ||
| let mut buf: [u8; 3] = [0; 3]; | ||
| let res = unsafe { | ||
| libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) | ||
| }; | ||
| assert_eq!(res, 3); | ||
| let buf = read_all_into_array::<3>(fds[1]).unwrap(); | ||
| assert_eq!(buf, [1, 1, 1]); | ||
| }); | ||
| thread1.join().unwrap(); | ||
|
|
@@ -215,30 +169,25 @@ fn test_blocking_write() { | |
| fn test_socketpair_setfl_getfl() { | ||
| // Initialise socketpair fds. | ||
| let mut fds = [-1, -1]; | ||
| let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; | ||
| assert_eq!(res, 0); | ||
| errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); | ||
|
|
||
| // Test if both sides have O_RDWR. | ||
| let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) }; | ||
| assert_eq!(res, libc::O_RDWR); | ||
| let res = unsafe { libc::fcntl(fds[1], libc::F_GETFL) }; | ||
| assert_eq!(res, libc::O_RDWR); | ||
| assert_eq!(errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), libc::O_RDWR); | ||
| assert_eq!(errno_result(unsafe { libc::fcntl(fds[1], libc::F_GETFL) }).unwrap(), libc::O_RDWR); | ||
|
|
||
| // Add the O_NONBLOCK flag with F_SETFL. | ||
| let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) }; | ||
| assert_eq!(res, 0); | ||
| errno_check(unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) }); | ||
|
|
||
| // Test if the O_NONBLOCK flag is successfully added. | ||
| let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) }; | ||
| assert_eq!(res, libc::O_RDWR | libc::O_NONBLOCK); | ||
| assert_eq!( | ||
| errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), | ||
| libc::O_RDWR | libc::O_NONBLOCK | ||
| ); | ||
|
|
||
| // The other side remains unchanged. | ||
| let res = unsafe { libc::fcntl(fds[1], libc::F_GETFL) }; | ||
| assert_eq!(res, libc::O_RDWR); | ||
| assert_eq!(errno_result(unsafe { libc::fcntl(fds[1], libc::F_GETFL) }).unwrap(), libc::O_RDWR); | ||
|
|
||
| // Test if O_NONBLOCK flag can be unset. | ||
| let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, 0) }; | ||
| assert_eq!(res, 0); | ||
| let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) }; | ||
| assert_eq!(res, libc::O_RDWR); | ||
| errno_check(unsafe { libc::fcntl(fds[0], libc::F_SETFL, 0) }); | ||
| assert_eq!(errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), libc::O_RDWR); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.