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 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();

@ -12,14 +12,18 @@ pub struct Pipe {
}
impl Pipe {
pub fn new() -> Result<Pipe> {
pub fn new(flags: StatusFlags) -> Result<Pipe> {
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<RingBufReader>,
status_flags: SgxRwLock<StatusFlags>,
}
impl File for PipeReader {
@ -60,6 +65,23 @@ impl File for PipeReader {
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 {
self
}
@ -71,6 +93,7 @@ unsafe impl Sync for PipeReader {}
#[derive(Debug)]
pub struct PipeWriter {
inner: SgxMutex<RingBufWriter>,
status_flags: SgxRwLock<StatusFlags>,
}
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<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 {
self
}

@ -1,21 +1,80 @@
#include <sys/syscall.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <spawn.h>
#include <string.h>
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));
}