Add pipe support for fcntl's F_GETFL and F_SETFL commands
This commit is contained in:
parent
343c19391a
commit
295d52fbe8
@ -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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user