diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 0d9b174e..9161fb0c 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -243,7 +243,7 @@ pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2]> { let creation_flags = CreationFlags::from_bits_truncate(flags); let current_ref = process::get_current(); let current = current_ref.lock().unwrap(); - let pipe = Pipe::new()?; + let pipe = Pipe::new(StatusFlags::from_bits_truncate(flags))?; let file_table_ref = current.get_files(); let mut file_table = file_table_ref.lock().unwrap(); diff --git a/src/libos/src/fs/pipe.rs b/src/libos/src/fs/pipe.rs index b5b1d6c8..50a9c949 100644 --- a/src/libos/src/fs/pipe.rs +++ b/src/libos/src/fs/pipe.rs @@ -12,14 +12,18 @@ pub struct Pipe { } impl Pipe { - pub fn new() -> Result { + pub fn new(flags: StatusFlags) -> Result { let mut ring_buf = RingBuf::new(PIPE_BUF_SIZE); + // Only O_NONBLOCK and O_DIRECT can be applied during pipe creation + let valid_flags = flags & (StatusFlags::O_NONBLOCK | StatusFlags::O_DIRECT); Ok(Pipe { reader: PipeReader { inner: SgxMutex::new(ring_buf.reader), + status_flags: SgxRwLock::new(valid_flags), }, writer: PipeWriter { inner: SgxMutex::new(ring_buf.writer), + status_flags: SgxRwLock::new(valid_flags), }, }) } @@ -28,6 +32,7 @@ impl Pipe { #[derive(Debug)] pub struct PipeReader { inner: SgxMutex, + status_flags: SgxRwLock, } impl File for PipeReader { @@ -60,6 +65,23 @@ impl File for PipeReader { Ok(total_bytes) } + fn get_access_mode(&self) -> Result { + Ok(AccessMode::O_RDONLY) + } + + fn get_status_flags(&self) -> Result { + let status_flags = self.status_flags.read().unwrap(); + Ok(status_flags.clone()) + } + + fn set_status_flags(&self, new_status_flags: StatusFlags) -> Result<()> { + let mut status_flags = self.status_flags.write().unwrap(); + // Only O_NONBLOCK, O_ASYNC and O_DIRECT can be set + *status_flags = new_status_flags + & (StatusFlags::O_NONBLOCK | StatusFlags::O_ASYNC | StatusFlags::O_DIRECT); + Ok(()) + } + fn as_any(&self) -> &dyn Any { self } @@ -71,6 +93,7 @@ unsafe impl Sync for PipeReader {} #[derive(Debug)] pub struct PipeWriter { inner: SgxMutex, + status_flags: SgxRwLock, } impl File for PipeWriter { @@ -107,6 +130,23 @@ impl File for PipeWriter { return_errno!(ESPIPE, "Pipe does not support seek") } + fn get_access_mode(&self) -> Result { + Ok(AccessMode::O_WRONLY) + } + + fn get_status_flags(&self) -> Result { + let status_flags = self.status_flags.read().unwrap(); + Ok(status_flags.clone()) + } + + fn set_status_flags(&self, new_status_flags: StatusFlags) -> Result<()> { + let mut status_flags = self.status_flags.write().unwrap(); + // Only O_NONBLOCK, O_ASYNC and O_DIRECT can be set + *status_flags = new_status_flags + & (StatusFlags::O_NONBLOCK | StatusFlags::O_ASYNC | StatusFlags::O_DIRECT); + Ok(()) + } + fn as_any(&self) -> &dyn Any { self } diff --git a/test/pipe/main.c b/test/pipe/main.c index 5c98d37b..1ecc41c3 100644 --- a/test/pipe/main.c +++ b/test/pipe/main.c @@ -1,21 +1,80 @@ #include #include +#include #include #include #include #include #include -int main(int argc, const char* argv[]) { - // XXX: this is a hack! remove this in the future - void* ptr = malloc(64); - free(ptr); +#include "test.h" +// ============================================================================ +// Helper function +// ============================================================================ +static void free_pipe(int *pipe) { + close(pipe[0]); + close(pipe[1]); +} + +// ============================================================================ +// Test cases +// ============================================================================ +int test_fcntl_get_flags() { int pipe_fds[2]; if (pipe(pipe_fds) < 0) { - printf("ERROR: failed to create a pipe\n"); - return -1; + THROW_ERROR("failed to create a pipe"); } + + if ((fcntl(pipe_fds[0], F_GETFL, 0) != O_RDONLY) || + (fcntl(pipe_fds[1], F_GETFL, 0) != O_WRONLY)) { + free_pipe(pipe_fds); + THROW_ERROR("fcntl get flags failed"); + } + + free_pipe(pipe_fds); + return 0; +} + +int test_fcntl_set_flags() { + int pipe_fds[2]; + if (pipe(pipe_fds) < 0) { + THROW_ERROR("failed to create a pipe"); + } + + fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK); + if ((fcntl(pipe_fds[0], F_GETFL, 0) != (O_NONBLOCK | O_RDONLY)) || + (fcntl(pipe_fds[1], F_GETFL, 0) != O_WRONLY)) { + free_pipe(pipe_fds); + THROW_ERROR("fcntl set flags failed"); + } + + free_pipe(pipe_fds); + return 0; +} + +int test_create_with_flags() { + int pipe_fds[2]; + if (pipe2(pipe_fds, O_NONBLOCK) < 0) { + THROW_ERROR("failed to create a pipe"); + } + + if ((fcntl(pipe_fds[0], F_GETFL, 0) != (O_NONBLOCK | O_RDONLY)) || + (fcntl(pipe_fds[1], F_GETFL, 0) != (O_NONBLOCK | O_WRONLY))) { + free_pipe(pipe_fds); + THROW_ERROR("create flags failed\n"); + } + + free_pipe(pipe_fds); + return 0; +} + +int test_read_write() { + int pipe_fds[2]; + if (pipe(pipe_fds) < 0) { + THROW_ERROR("failed to create a pipe"); + } + int pipe_rd_fd = pipe_fds[0]; int pipe_wr_fd = pipe_fds[1]; @@ -30,8 +89,7 @@ int main(int argc, const char* argv[]) { int child_pid; if (posix_spawn(&child_pid, child_prog, &file_actions, NULL, (char*const *)child_argv, NULL) < 0) { - printf("ERROR: failed to spawn a child process\n"); - return -1; + THROW_ERROR("failed to spawn a child process"); } close(pipe_wr_fd); @@ -43,14 +101,28 @@ int main(int argc, const char* argv[]) { actual_len = read(pipe_rd_fd, actual_str, sizeof(actual_str) - 1); } while (actual_len == 0); if (strncmp(expected_str, actual_str, expected_len) != 0) { - printf("ERROR: received string is not as expected\n"); - return -1; + THROW_ERROR("received string is not as expected"); } + close(pipe_rd_fd); + int status = 0; if (wait4(child_pid, &status, 0, NULL) < 0) { - printf("ERROR: failed to wait4 the child process\n"); - return -1; + THROW_ERROR("failed to wait4 the child process"); } return 0; } + +// ============================================================================ +// Test suite +// ============================================================================ +static test_case_t test_cases[] = { + TEST_CASE(test_fcntl_get_flags), + TEST_CASE(test_fcntl_set_flags), + TEST_CASE(test_create_with_flags), + TEST_CASE(test_read_write), +}; + +int main(int argc, const char* argv[]) { + return test_suite_run(test_cases, ARRAY_SIZE(test_cases)); +}