From a8060f0b2471376913412f9ed14940e8c03f8324 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 12 Apr 2019 15:14:11 +0800 Subject: [PATCH] add simple epoll test. fix epoll_wait, accept4 --- src/libos/src/fs/io_multiplexing.rs | 9 +- src/libos/src/syscall/mod.rs | 12 +- test/Makefile | 2 +- test/server_epoll/Makefile | 5 + test/server_epoll/main.c | 186 ++++++++++++++++++++++++++++ 5 files changed, 202 insertions(+), 12 deletions(-) create mode 100644 test/server_epoll/Makefile create mode 100644 test/server_epoll/main.c diff --git a/src/libos/src/fs/io_multiplexing.rs b/src/libos/src/fs/io_multiplexing.rs index a998ecd6..214f369f 100644 --- a/src/libos/src/fs/io_multiplexing.rs +++ b/src/libos/src/fs/io_multiplexing.rs @@ -313,14 +313,7 @@ impl EpollFileInner { if ret < 0 { return Err(Error::new(Errno::from_retval(ret as i32), "")); } - // convert host fd to libos - let count = ret as usize; - for event in events[0..count].iter_mut() { - let host_fd = event.u64 as FileDesc; - let fd = self.fd_to_libos[&host_fd]; - event.u64 = fd as u64; - } - Ok(count) + Ok(ret as usize) } } diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 7a9cf0f2..3c843f06 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -198,7 +198,13 @@ pub extern "C" fn dispatch_syscall( arg1 as *const libc::sockaddr, arg2 as libc::socklen_t, ), - SYS_ACCEPT => do_accept( + SYS_ACCEPT => do_accept4( + arg0 as c_int, + arg1 as *mut libc::sockaddr, + arg2 as *mut libc::socklen_t, + 0, + ), + SYS_ACCEPT4 => do_accept4( arg0 as c_int, arg1 as *mut libc::sockaddr, arg2 as *mut libc::socklen_t, @@ -882,14 +888,14 @@ fn do_connect( Ok(ret as isize) } -fn do_accept( +fn do_accept4( fd: c_int, addr: *mut libc::sockaddr, addr_len: *mut libc::socklen_t, flags: c_int, ) -> Result { info!( - "accept: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}", + "accept4: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}", fd, addr, addr_len, flags ); let current_ref = process::get_current(); diff --git a/test/Makefile b/test/Makefile index e9181d9e..4d4ca4cb 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../) # Dependencies: need to be compiled but not to run by any Makefile target TEST_DEPS := dev_null # Tests: need to be compiled and run by test-% target -TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server +TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server server_epoll # Benchmarks: need to be compiled and run by bench-% target BENCHES := spawn_and_exit_latency pipe_throughput diff --git a/test/server_epoll/Makefile b/test/server_epoll/Makefile new file mode 100644 index 00000000..9e1b6dec --- /dev/null +++ b/test/server_epoll/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/server_epoll/main.c b/test/server_epoll/main.c new file mode 100644 index 00000000..22f8867c --- /dev/null +++ b/test/server_epoll/main.c @@ -0,0 +1,186 @@ +// Modified from https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/epoll-example.c +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXEVENTS 64 + +static int +create_and_bind() { + int listenfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + if (listenfd < 0) { + printf("create socket error: %s(errno: %d)\n", strerror(errno), errno); + return -1; + } + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(6666); + + int ret = bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); + if (ret < 0) { + printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno); + return -1; + } + return listenfd; +} + +int +main(int argc, char *argv[]) { + int sfd = create_and_bind(); + + int s = listen(sfd, SOMAXCONN); + if (s == -1) { + perror("listen"); + return -1; + } + + int efd = epoll_create1(0); + if (efd == -1) { + perror("epoll_create"); + return -1; + } + + struct epoll_event event; + event.data.fd = sfd; + event.events = EPOLLIN | EPOLLET; + s = epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &event); + if (s == -1) { + perror("epoll_ctl"); + return -1; + } + + /* Buffer where events are returned */ + struct epoll_event *events = calloc(MAXEVENTS, sizeof event); + + // spawn clients + int client_pid; + char* client_argv[] = {"client", "127.0.0.1"}; + for(int i=0; i<3; ++i) { + int ret = posix_spawn(&client_pid, "client", NULL, NULL, client_argv, NULL); + if (ret < 0) { + printf("spawn client process error: %s(errno: %d)\n", strerror(errno), errno); + return -1; + } + } + + /* The event loop */ + int done_count = 0; + while (done_count < 3) { + int n = epoll_wait(efd, events, MAXEVENTS, -1); + for (int i = 0; i < n; i++) { + if ((events[i].events & EPOLLERR) || + (events[i].events & EPOLLHUP) || + (!(events[i].events & EPOLLIN))) { + /* An error has occured on this fd, or the socket is not + ready for reading (why were we notified then?) */ + fprintf(stderr, "epoll error\n"); + close(events[i].data.fd); + continue; + } else if (sfd == events[i].data.fd) { + /* We have a notification on the listening socket, which + means one or more incoming connections. */ + while (1) { + struct sockaddr in_addr; + socklen_t in_len; + int infd; + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + + in_len = sizeof in_addr; + infd = accept4(sfd, &in_addr, &in_len, SOCK_NONBLOCK); + if (infd == -1) { + if ((errno == EAGAIN) || + (errno == EWOULDBLOCK)) { + /* We have processed all incoming + connections. */ + break; + } else { + perror("accept"); + break; + } + } + + s = getnameinfo(&in_addr, in_len, + hbuf, sizeof hbuf, + sbuf, sizeof sbuf, + NI_NUMERICHOST | NI_NUMERICSERV); + if (s == 0) { + printf("Accepted connection on descriptor %d " + "(host=%s, port=%s)\n", infd, hbuf, sbuf); + } + + // add it to the list of fds to monitor + event.data.fd = infd; + event.events = EPOLLIN | EPOLLET; + s = epoll_ctl(efd, EPOLL_CTL_ADD, infd, &event); + if (s == -1) { + perror("epoll_ctl"); + return -1; + } + } + continue; + } else { + /* We have data on the fd waiting to be read. Read and + display it. We must read whatever data is available + completely, as we are running in edge-triggered mode + and won't get a notification again for the same + data. */ + int done = 0; + + while (1) { + ssize_t count; + char buf[512]; + + count = read(events[i].data.fd, buf, sizeof buf); + if (count == -1) { + /* If errno == EAGAIN, that means we have read all + data. So go back to the main loop. */ + if (errno != EAGAIN) { + perror("read"); + done = 1; + } + break; + } else if (count == 0) { + /* End of file. The remote has closed the + connection. */ + done = 1; + break; + } + + /* Write the buffer to standard output */ + s = write(1, buf, count); + if (s == -1) { + perror("write"); + return -1; + } + } + + if (done) { + printf("Closed connection on descriptor %d\n", + events[i].data.fd); + + /* Closing the descriptor will make epoll remove it + from the set of descriptors which are monitored. */ + close(events[i].data.fd); + + done_count ++; + } + } + } + } + + free(events); + + close(sfd); + + return EXIT_SUCCESS; +}