occlum/test/eventfd/main.c
2020-05-27 07:09:18 +00:00

262 lines
6.7 KiB
C

#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <spawn.h>
#include <string.h>
#include "test.h"
#define MAXEVENTS 1
// ============================================================================
// Test cases
// ============================================================================
int test_fcntl_get_flags() {
int event_fd = eventfd(0, 0);
if (event_fd < 0) {
THROW_ERROR("failed to create an eventfd");
}
if ((fcntl(event_fd, F_GETFL, 0) != O_RDWR)) {
close(event_fd);
THROW_ERROR("fcntl get flags failed");
}
close(event_fd);
return 0;
}
int test_fcntl_set_flags() {
int event_fd = eventfd(0, 0);
if (event_fd < 0) {
THROW_ERROR("failed to create an eventfd");
}
fcntl(event_fd, F_SETFL, O_NONBLOCK);
if ((fcntl(event_fd, F_GETFL, 0) != (O_NONBLOCK | O_RDWR))) {
close(event_fd);
THROW_ERROR("fcntl set flags failed");
}
close(event_fd);
return 0;
}
int test_create_with_flags() {
int event_fd = eventfd(0, EFD_NONBLOCK);
if (event_fd < 0) {
THROW_ERROR("failed to create an eventfd");
}
if ((fcntl(event_fd, F_GETFL, 0) != (O_NONBLOCK | O_RDWR))) {
close(event_fd);
THROW_ERROR("create flags failed\n");
}
close(event_fd);
return 0;
}
struct thread_arg {
pthread_t tid;
int fd;
uint64_t data;
};
#define TEST_DATA 678
#define CHILD_NUM 16
static void *thread_child(void *arg) {
struct thread_arg *child_arg = arg;
write(child_arg->fd, &(child_arg->data), sizeof(child_arg->data));
return NULL;
}
int create_child(struct thread_arg *arg) {
pthread_attr_t attr;
if (pthread_attr_init(&attr) != 0) {
THROW_ERROR("failed to initialize attribute");
}
if (pthread_create(&(arg->tid), &attr, &thread_child, arg) != 0) {
if (pthread_attr_destroy(&attr) != 0) {
THROW_ERROR("failed to destroy attr");
}
THROW_ERROR("failed to create the thread");
}
if (pthread_attr_destroy(&attr) != 0) {
THROW_ERROR("failed to destroy attr");
}
return 0;
}
int test_read_write() {
int event_fd = eventfd(0, 0);
if (event_fd < 0) {
THROW_ERROR("failed to create an eventfd");
}
struct thread_arg child_arg[CHILD_NUM] = {0};
// Create child threads and send eventfd and data
for (int i = 0; i < CHILD_NUM; i++) {
child_arg[i].fd = event_fd;
child_arg[i].data = TEST_DATA;
if (create_child(&child_arg[i]) != 0) {
close(event_fd);
THROW_ERROR("failed to create children");
}
}
// Check the data sent from children
uint64_t data_recv = 0;
do {
uint64_t cur_data = 0;
ssize_t len_recv = read(event_fd, &cur_data, sizeof(uint64_t));
if (len_recv != sizeof(uint64_t)) {
close(event_fd);
THROW_ERROR("received length is not as expected");
}
data_recv += cur_data;
} while (data_recv != TEST_DATA * CHILD_NUM);
close(event_fd);
for (int i = 0; i < CHILD_NUM; i++) {
if (pthread_join(child_arg[i].tid, NULL) != 0) {
THROW_ERROR("pthread_join");
}
}
return 0;
}
int test_select_with_socket() {
fd_set rfds, wfds;
int ret = 0;
struct timeval tv = { .tv_sec = 60, .tv_usec = 0 };
int sock = socket(AF_INET, SOCK_STREAM, 0);
int event_fd = eventfd(0, 0);
if (event_fd < 0 || sock < 0) {
THROW_ERROR("failed to create files");
}
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(sock, &rfds);
FD_SET(sock, &wfds);
FD_SET(event_fd, &rfds);
FD_SET(event_fd, &wfds);
ret = select(sock > event_fd ? sock + 1 : event_fd + 1, &rfds, &wfds, NULL, &tv);
if (ret != 3) {
close_files(2, sock, event_fd);
THROW_ERROR("select failed");
}
if (FD_ISSET(event_fd, &rfds) == 1 || FD_ISSET(event_fd, &wfds) == 0 ||
FD_ISSET(sock, &rfds) == 0 || FD_ISSET(sock, &wfds) == 0) {
close_files(2, sock, event_fd);
THROW_ERROR("bad select return");
}
close_files(2, sock, event_fd);
return 0;
}
int test_poll_with_socket() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
int event_fd = eventfd(0, 0);
if (event_fd < 0 || sock < 0) {
THROW_ERROR("failed to create files");
}
struct pollfd pollfds[] = {
{ .fd = sock, .events = POLLIN, .revents = 0, },
{ .fd = event_fd, .events = POLLOUT, .revents = 0 },
};
int ret = poll(pollfds, 2, -1);
if (ret <= 0) {
close_files(2, event_fd, sock);
THROW_ERROR("poll error");
}
close_files(2, event_fd, sock);
return 0;
}
int test_epoll_with_socket() {
int event_fd = eventfd(0, EFD_NONBLOCK);
int sock = socket(AF_INET, SOCK_STREAM, 0);
int epfd = epoll_create1(0);
if (event_fd < 0 || sock < 0 || epfd < 0) {
THROW_ERROR("failed to create files");
}
struct epoll_event ctl_events[2] = {0};
// Add eventfd to the interest list
ctl_events[0].data.fd = event_fd;
ctl_events[0].events = EPOLLIN | EPOLLET;
// Add socket to the interest list
ctl_events[1].data.fd = sock;
ctl_events[1].events = EPOLLIN | EPOLLET;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, event_fd, &ctl_events[0]) == -1 ||
epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ctl_events[1]) == -1) {
close_files(3, event_fd, sock, epfd);
THROW_ERROR("epoll_ctl");
}
struct thread_arg child_arg = { .tid = 0, .fd = event_fd, .data = TEST_DATA };
if (create_child(&child_arg) != 0) {
close_files(3, event_fd, sock, epfd);
THROW_ERROR("failed to create child");
}
struct epoll_event events[MAXEVENTS] = {0};
if (epoll_pwait(epfd, events, MAXEVENTS, -1, NULL) <= 0) {
close_files(3, event_fd, sock, epfd);
THROW_ERROR("epoll failed");
}
close_files(3, event_fd, sock, epfd);
if (pthread_join(child_arg.tid, NULL) != 0) {
THROW_ERROR("pthread_join");
}
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),
TEST_CASE(test_epoll_with_socket),
TEST_CASE(test_poll_with_socket),
TEST_CASE(test_select_with_socket),
};
int main(int argc, const char *argv[]) {
return test_suite_run(test_cases, ARRAY_SIZE(test_cases));
}