Add pipe support for fcntl's F_GETFL and F_SETFL commands

This commit is contained in:
He Sun 2020-01-16 15:53:52 +08:00 committed by Tate, Hongliang Tian
parent 343c19391a
commit 295d52fbe8
3 changed files with 126 additions and 14 deletions

@ -243,7 +243,7 @@ pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2]> {
let creation_flags = CreationFlags::from_bits_truncate(flags); let creation_flags = CreationFlags::from_bits_truncate(flags);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current = current_ref.lock().unwrap(); 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 file_table_ref = current.get_files();
let mut file_table = file_table_ref.lock().unwrap(); let mut file_table = file_table_ref.lock().unwrap();

@ -12,14 +12,18 @@ pub struct Pipe {
} }
impl Pipe { impl Pipe {
pub fn new() -> Result<Pipe> { pub fn new(flags: StatusFlags) -> Result<Pipe> {
let mut ring_buf = RingBuf::new(PIPE_BUF_SIZE); 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 { Ok(Pipe {
reader: PipeReader { reader: PipeReader {
inner: SgxMutex::new(ring_buf.reader), inner: SgxMutex::new(ring_buf.reader),
status_flags: SgxRwLock::new(valid_flags),
}, },
writer: PipeWriter { writer: PipeWriter {
inner: SgxMutex::new(ring_buf.writer), inner: SgxMutex::new(ring_buf.writer),
status_flags: SgxRwLock::new(valid_flags),
}, },
}) })
} }
@ -28,6 +32,7 @@ impl Pipe {
#[derive(Debug)] #[derive(Debug)]
pub struct PipeReader { pub struct PipeReader {
inner: SgxMutex<RingBufReader>, inner: SgxMutex<RingBufReader>,
status_flags: SgxRwLock<StatusFlags>,
} }
impl File for PipeReader { impl File for PipeReader {
@ -60,6 +65,23 @@ impl File for PipeReader {
Ok(total_bytes) Ok(total_bytes)
} }
fn get_access_mode(&self) -> Result<AccessMode> {
Ok(AccessMode::O_RDONLY)
}
fn get_status_flags(&self) -> Result<StatusFlags> {
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 { fn as_any(&self) -> &dyn Any {
self self
} }
@ -71,6 +93,7 @@ unsafe impl Sync for PipeReader {}
#[derive(Debug)] #[derive(Debug)]
pub struct PipeWriter { pub struct PipeWriter {
inner: SgxMutex<RingBufWriter>, inner: SgxMutex<RingBufWriter>,
status_flags: SgxRwLock<StatusFlags>,
} }
impl File for PipeWriter { impl File for PipeWriter {
@ -107,6 +130,23 @@ impl File for PipeWriter {
return_errno!(ESPIPE, "Pipe does not support seek") return_errno!(ESPIPE, "Pipe does not support seek")
} }
fn get_access_mode(&self) -> Result<AccessMode> {
Ok(AccessMode::O_WRONLY)
}
fn get_status_flags(&self) -> Result<StatusFlags> {
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 { fn as_any(&self) -> &dyn Any {
self self
} }

@ -1,21 +1,80 @@
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <spawn.h> #include <spawn.h>
#include <string.h> #include <string.h>
int main(int argc, const char* argv[]) { #include "test.h"
// XXX: this is a hack! remove this in the future
void* ptr = malloc(64);
free(ptr);
// ============================================================================
// 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]; int pipe_fds[2];
if (pipe(pipe_fds) < 0) { if (pipe(pipe_fds) < 0) {
printf("ERROR: failed to create a pipe\n"); THROW_ERROR("failed to create a pipe");
return -1;
} }
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_rd_fd = pipe_fds[0];
int pipe_wr_fd = pipe_fds[1]; int pipe_wr_fd = pipe_fds[1];
@ -30,8 +89,7 @@ int main(int argc, const char* argv[]) {
int child_pid; int child_pid;
if (posix_spawn(&child_pid, child_prog, &file_actions, if (posix_spawn(&child_pid, child_prog, &file_actions,
NULL, (char*const *)child_argv, NULL) < 0) { NULL, (char*const *)child_argv, NULL) < 0) {
printf("ERROR: failed to spawn a child process\n"); THROW_ERROR("failed to spawn a child process");
return -1;
} }
close(pipe_wr_fd); 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); actual_len = read(pipe_rd_fd, actual_str, sizeof(actual_str) - 1);
} while (actual_len == 0); } while (actual_len == 0);
if (strncmp(expected_str, actual_str, expected_len) != 0) { if (strncmp(expected_str, actual_str, expected_len) != 0) {
printf("ERROR: received string is not as expected\n"); THROW_ERROR("received string is not as expected");
return -1;
} }
close(pipe_rd_fd);
int status = 0; int status = 0;
if (wait4(child_pid, &status, 0, NULL) < 0) { if (wait4(child_pid, &status, 0, NULL) < 0) {
printf("ERROR: failed to wait4 the child process\n"); THROW_ERROR("failed to wait4 the child process");
return -1;
} }
return 0; 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));
}