add epoll.c tests
This commit is contained in:
parent
a649f55195
commit
c46f6ac022
|
@ -0,0 +1,183 @@
|
|||
#ifdef __APPLE__
|
||||
#include "eok.h"
|
||||
#else
|
||||
#include <sys/epoll.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#define D(fmt, ...) fprintf(stderr, "%s[%d]%s(): " fmt "\n", basename(__FILE__), __LINE__, __func__, ##__VA_ARGS__)
|
||||
#define A(statement, fmt, ...) do { \
|
||||
if (statement) break; \
|
||||
fprintf(stderr, "%s[%d]%s(): assert [%s] failed: %d[%s]: " fmt "\n", \
|
||||
basename(__FILE__), __LINE__, __func__, \
|
||||
#statement, errno, strerror(errno), \
|
||||
##__VA_ARGS__); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
|
||||
#define E(fmt, ...) do { \
|
||||
fprintf(stderr, "%s[%d]%s(): %d[%s]: " fmt "\n", \
|
||||
basename(__FILE__), __LINE__, __func__, \
|
||||
errno, strerror(errno), \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
typedef struct ep_s ep_t;
|
||||
struct ep_s {
|
||||
int ep;
|
||||
|
||||
pthread_mutex_t lock;
|
||||
int sv[2]; // 0 for read, 1 for write;
|
||||
pthread_t thread;
|
||||
|
||||
volatile unsigned int stopping:1;
|
||||
volatile unsigned int waiting:1;
|
||||
volatile unsigned int wakenup:1;
|
||||
};
|
||||
|
||||
static int ep_dummy = 0;
|
||||
|
||||
static ep_t* ep_create(void);
|
||||
static void ep_destroy(ep_t *ep);
|
||||
static void* routine(void* arg);
|
||||
static int open_connect(unsigned short port);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
ep_t* ep = ep_create();
|
||||
A(ep, "failed");
|
||||
int skt = open_connect(6789);
|
||||
if (skt!=-1) {
|
||||
struct epoll_event ev = {0};
|
||||
ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLRDHUP;
|
||||
ev.data.ptr = &skt;
|
||||
A(0==epoll_ctl(ep->ep, EPOLL_CTL_ADD, skt, &ev), "");
|
||||
}
|
||||
getchar();
|
||||
ep_destroy(ep);
|
||||
D("");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ep_t* ep_create(void) {
|
||||
ep_t *ep = (ep_t*)calloc(1, sizeof(*ep));
|
||||
A(ep, "out of memory");
|
||||
A(-1!=(ep->ep = epoll_create(1)), "");
|
||||
ep->sv[0] = -1;
|
||||
ep->sv[1] = -1;
|
||||
A(0==socketpair(AF_LOCAL, SOCK_STREAM, 0, ep->sv), "");
|
||||
A(0==pthread_mutex_init(&ep->lock, NULL), "");
|
||||
A(0==pthread_mutex_lock(&ep->lock), "");
|
||||
struct epoll_event ev = {0};
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.ptr = &ep_dummy;
|
||||
A(0==epoll_ctl(ep->ep, EPOLL_CTL_ADD, ep->sv[0], &ev), "");
|
||||
A(0==pthread_create(&ep->thread, NULL, routine, ep), "");
|
||||
A(0==pthread_mutex_unlock(&ep->lock), "");
|
||||
return ep;
|
||||
}
|
||||
|
||||
static void ep_destroy(ep_t *ep) {
|
||||
A(ep, "invalid argument");
|
||||
ep->stopping = 1;
|
||||
A(1==send(ep->sv[1], "1", 1, 0), "");
|
||||
A(0==pthread_join(ep->thread, NULL), "");
|
||||
A(0==pthread_mutex_destroy(&ep->lock), "");
|
||||
A(0==close(ep->sv[0]), "");
|
||||
A(0==close(ep->sv[1]), "");
|
||||
A(0==close(ep->ep), "");
|
||||
free(ep);
|
||||
}
|
||||
|
||||
static void* routine(void* arg) {
|
||||
A(arg, "invalid argument");
|
||||
ep_t *ep = (ep_t*)arg;
|
||||
|
||||
while (!ep->stopping) {
|
||||
struct epoll_event evs[10] = {0};
|
||||
|
||||
A(0==pthread_mutex_lock(&ep->lock), "");
|
||||
A(ep->waiting==0, "internal logic error");
|
||||
ep->waiting = 1;
|
||||
A(0==pthread_mutex_unlock(&ep->lock), "");
|
||||
|
||||
int r = epoll_wait(ep->ep, evs, sizeof(evs)/sizeof(evs[0]), -1);
|
||||
A(r>0, "indefinite epoll_wait shall not timeout");
|
||||
|
||||
A(0==pthread_mutex_lock(&ep->lock), "");
|
||||
A(ep->waiting==1, "internal logic error");
|
||||
ep->waiting = 0;
|
||||
A(0==pthread_mutex_unlock(&ep->lock), "");
|
||||
|
||||
for (int i=0; i<r; ++i) {
|
||||
struct epoll_event *ev = evs + i;
|
||||
if (ev->data.ptr == &ep_dummy) {
|
||||
char c = '\0';
|
||||
A(1==recv(ep->sv[0], &c, 1, 0), "internal logic error");
|
||||
A(0==pthread_mutex_lock(&ep->lock), "");
|
||||
ep->wakenup = 0;
|
||||
A(0==pthread_mutex_unlock(&ep->lock), "");
|
||||
D("........");
|
||||
continue;
|
||||
}
|
||||
A(ev->data.ptr, "internal logic error");
|
||||
int skt = *(int*)ev->data.ptr;
|
||||
if (ev->events & EPOLLIN) {
|
||||
char buf[4];
|
||||
int n = recv(skt, buf, sizeof(buf)-1, 0);
|
||||
A(n>=0 && n<sizeof(buf), "internal logic error");
|
||||
buf[n] = '\0';
|
||||
fprintf(stderr, "events[%x]:%s\n", ev->events, buf);
|
||||
}
|
||||
if (ev->events & EPOLLRDHUP) {
|
||||
A(0==epoll_ctl(ep->ep, EPOLL_CTL_DEL, skt, NULL), "");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int open_connect(unsigned short port) {
|
||||
int r = 0;
|
||||
int skt = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (skt==-1) {
|
||||
E("socket() failed");
|
||||
return -1;
|
||||
}
|
||||
do {
|
||||
struct sockaddr_in si = {0};
|
||||
si.sin_family = AF_INET;
|
||||
si.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
si.sin_port = htons(port);
|
||||
r = connect(skt, (struct sockaddr*)&si, sizeof(si));
|
||||
if (r) {
|
||||
E("connect(%u) failed", port);
|
||||
break;
|
||||
}
|
||||
memset(&si, 0, sizeof(si));
|
||||
socklen_t len = sizeof(si);
|
||||
r = getsockname(skt, (struct sockaddr *)&si, &len);
|
||||
if (r) {
|
||||
E("getsockname() failed");
|
||||
}
|
||||
A(len==sizeof(si), "internal logic error");
|
||||
D("connected: %d", ntohs(si.sin_port));
|
||||
return skt;
|
||||
} while (0);
|
||||
close(skt);
|
||||
return -1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue