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 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));
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user