3497 lines
74 KiB
C
3497 lines
74 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#define _GNU_SOURCE
|
|
#include <asm/unistd.h>
|
|
#include <linux/time_types.h>
|
|
#include <poll.h>
|
|
#include <unistd.h>
|
|
#include <assert.h>
|
|
#include <signal.h>
|
|
#include <pthread.h>
|
|
#include <sys/epoll.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/eventfd.h>
|
|
#include "../../kselftest_harness.h"
|
|
|
|
struct epoll_mtcontext
|
|
{
|
|
int efd[3];
|
|
int sfd[4];
|
|
volatile int count;
|
|
|
|
pthread_t main;
|
|
pthread_t waiter;
|
|
};
|
|
|
|
#ifndef __NR_epoll_pwait2
|
|
#define __NR_epoll_pwait2 -1
|
|
#endif
|
|
|
|
static inline int sys_epoll_pwait2(int fd, struct epoll_event *events,
|
|
int maxevents,
|
|
const struct __kernel_timespec *timeout,
|
|
const sigset_t *sigset, size_t sigsetsize)
|
|
{
|
|
return syscall(__NR_epoll_pwait2, fd, events, maxevents, timeout,
|
|
sigset, sigsetsize);
|
|
}
|
|
|
|
static void signal_handler(int signum)
|
|
{
|
|
}
|
|
|
|
static void kill_timeout(struct epoll_mtcontext *ctx)
|
|
{
|
|
usleep(1000000);
|
|
pthread_kill(ctx->main, SIGUSR1);
|
|
pthread_kill(ctx->waiter, SIGUSR1);
|
|
}
|
|
|
|
static void *waiter_entry1a(void *data)
|
|
{
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext *ctx = data;
|
|
|
|
if (epoll_wait(ctx->efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx->count, 1);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void *waiter_entry1ap(void *data)
|
|
{
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext *ctx = data;
|
|
|
|
pfd.fd = ctx->efd[0];
|
|
pfd.events = POLLIN;
|
|
if (poll(&pfd, 1, -1) > 0) {
|
|
if (epoll_wait(ctx->efd[0], &e, 1, 0) > 0)
|
|
__sync_fetch_and_add(&ctx->count, 1);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void *waiter_entry1o(void *data)
|
|
{
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext *ctx = data;
|
|
|
|
if (epoll_wait(ctx->efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_or(&ctx->count, 1);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void *waiter_entry1op(void *data)
|
|
{
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext *ctx = data;
|
|
|
|
pfd.fd = ctx->efd[0];
|
|
pfd.events = POLLIN;
|
|
if (poll(&pfd, 1, -1) > 0) {
|
|
if (epoll_wait(ctx->efd[0], &e, 1, 0) > 0)
|
|
__sync_fetch_and_or(&ctx->count, 1);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void *waiter_entry2a(void *data)
|
|
{
|
|
struct epoll_event events[2];
|
|
struct epoll_mtcontext *ctx = data;
|
|
|
|
if (epoll_wait(ctx->efd[0], events, 2, -1) > 0)
|
|
__sync_fetch_and_add(&ctx->count, 1);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void *waiter_entry2ap(void *data)
|
|
{
|
|
struct pollfd pfd;
|
|
struct epoll_event events[2];
|
|
struct epoll_mtcontext *ctx = data;
|
|
|
|
pfd.fd = ctx->efd[0];
|
|
pfd.events = POLLIN;
|
|
if (poll(&pfd, 1, -1) > 0) {
|
|
if (epoll_wait(ctx->efd[0], events, 2, 0) > 0)
|
|
__sync_fetch_and_add(&ctx->count, 1);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void *emitter_entry1(void *data)
|
|
{
|
|
struct epoll_mtcontext *ctx = data;
|
|
|
|
usleep(100000);
|
|
write(ctx->sfd[1], "w", 1);
|
|
|
|
kill_timeout(ctx);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void *emitter_entry2(void *data)
|
|
{
|
|
struct epoll_mtcontext *ctx = data;
|
|
|
|
usleep(100000);
|
|
write(ctx->sfd[1], "w", 1);
|
|
write(ctx->sfd[3], "w", 1);
|
|
|
|
kill_timeout(ctx);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (ew)
|
|
* e0
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll1)
|
|
{
|
|
int efd;
|
|
int sfd[2];
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
|
|
|
|
efd = epoll_create(1);
|
|
ASSERT_GE(efd, 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
|
|
EXPECT_EQ(epoll_wait(efd, &e, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd, &e, 1, 0), 1);
|
|
|
|
close(efd);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (ew)
|
|
* e0
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll2)
|
|
{
|
|
int efd;
|
|
int sfd[2];
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
|
|
|
|
efd = epoll_create(1);
|
|
ASSERT_GE(efd, 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
|
|
EXPECT_EQ(epoll_wait(efd, &e, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd, &e, 1, 0), 0);
|
|
|
|
close(efd);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (ew)
|
|
* e0
|
|
* (lt) / \ (lt)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll3)
|
|
{
|
|
int efd;
|
|
int sfd[4];
|
|
struct epoll_event events[2];
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
|
|
|
|
efd = epoll_create(1);
|
|
ASSERT_GE(efd, 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], events), 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[2], events), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
ASSERT_EQ(write(sfd[3], "w", 1), 1);
|
|
|
|
EXPECT_EQ(epoll_wait(efd, events, 2, 0), 2);
|
|
EXPECT_EQ(epoll_wait(efd, events, 2, 0), 2);
|
|
|
|
close(efd);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
close(sfd[2]);
|
|
close(sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (ew)
|
|
* e0
|
|
* (et) / \ (et)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll4)
|
|
{
|
|
int efd;
|
|
int sfd[4];
|
|
struct epoll_event events[2];
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
|
|
|
|
efd = epoll_create(1);
|
|
ASSERT_GE(efd, 0);
|
|
|
|
events[0].events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], events), 0);
|
|
|
|
events[0].events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[2], events), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
ASSERT_EQ(write(sfd[3], "w", 1), 1);
|
|
|
|
EXPECT_EQ(epoll_wait(efd, events, 2, 0), 2);
|
|
EXPECT_EQ(epoll_wait(efd, events, 2, 0), 0);
|
|
|
|
close(efd);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
close(sfd[2]);
|
|
close(sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (p)
|
|
* e0
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll5)
|
|
{
|
|
int efd;
|
|
int sfd[2];
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
|
|
|
|
efd = epoll_create(1);
|
|
ASSERT_GE(efd, 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
|
|
pfd.fd = efd;
|
|
pfd.events = POLLIN;
|
|
ASSERT_EQ(poll(&pfd, 1, 0), 1);
|
|
ASSERT_EQ(epoll_wait(efd, &e, 1, 0), 1);
|
|
|
|
pfd.fd = efd;
|
|
pfd.events = POLLIN;
|
|
ASSERT_EQ(poll(&pfd, 1, 0), 1);
|
|
ASSERT_EQ(epoll_wait(efd, &e, 1, 0), 1);
|
|
|
|
close(efd);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (p)
|
|
* e0
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll6)
|
|
{
|
|
int efd;
|
|
int sfd[2];
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
|
|
|
|
efd = epoll_create(1);
|
|
ASSERT_GE(efd, 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
|
|
pfd.fd = efd;
|
|
pfd.events = POLLIN;
|
|
ASSERT_EQ(poll(&pfd, 1, 0), 1);
|
|
ASSERT_EQ(epoll_wait(efd, &e, 1, 0), 1);
|
|
|
|
pfd.fd = efd;
|
|
pfd.events = POLLIN;
|
|
ASSERT_EQ(poll(&pfd, 1, 0), 0);
|
|
ASSERT_EQ(epoll_wait(efd, &e, 1, 0), 0);
|
|
|
|
close(efd);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (p)
|
|
* e0
|
|
* (lt) / \ (lt)
|
|
* s0 s2
|
|
*/
|
|
|
|
TEST(epoll7)
|
|
{
|
|
int efd;
|
|
int sfd[4];
|
|
struct pollfd pfd;
|
|
struct epoll_event events[2];
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
|
|
|
|
efd = epoll_create(1);
|
|
ASSERT_GE(efd, 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], events), 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[2], events), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
ASSERT_EQ(write(sfd[3], "w", 1), 1);
|
|
|
|
pfd.fd = efd;
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd, events, 2, 0), 2);
|
|
|
|
pfd.fd = efd;
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd, events, 2, 0), 2);
|
|
|
|
close(efd);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
close(sfd[2]);
|
|
close(sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (p)
|
|
* e0
|
|
* (et) / \ (et)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll8)
|
|
{
|
|
int efd;
|
|
int sfd[4];
|
|
struct pollfd pfd;
|
|
struct epoll_event events[2];
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
|
|
|
|
efd = epoll_create(1);
|
|
ASSERT_GE(efd, 0);
|
|
|
|
events[0].events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], events), 0);
|
|
|
|
events[0].events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[2], events), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
ASSERT_EQ(write(sfd[3], "w", 1), 1);
|
|
|
|
pfd.fd = efd;
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd, events, 2, 0), 2);
|
|
|
|
pfd.fd = efd;
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 0);
|
|
EXPECT_EQ(epoll_wait(efd, events, 2, 0), 0);
|
|
|
|
close(efd);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
close(sfd[2]);
|
|
close(sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (ew)
|
|
* e0
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll9)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (ew)
|
|
* e0
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll10)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 1);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (ew)
|
|
* e0
|
|
* (lt) / \ (lt)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll11)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event events[2];
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], events), 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[2], events), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry2a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], events, 2, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
close(ctx.sfd[2]);
|
|
close(ctx.sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (ew)
|
|
* e0
|
|
* (et) / \ (et)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll12)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event events[2];
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
events[0].events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], events), 0);
|
|
|
|
events[0].events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[2], events), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], events, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
close(ctx.sfd[2]);
|
|
close(ctx.sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (p)
|
|
* e0
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll13)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (p)
|
|
* e0
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll14)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 1);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (p)
|
|
* e0
|
|
* (lt) / \ (lt)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll15)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event events[2];
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], events), 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[2], events), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry2ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], events, 2, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
close(ctx.sfd[2]);
|
|
close(ctx.sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (p)
|
|
* e0
|
|
* (et) / \ (et)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll16)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event events[2];
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
events[0].events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], events), 0);
|
|
|
|
events[0].events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[2], events), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], events, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
close(ctx.sfd[2]);
|
|
close(ctx.sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (ew)
|
|
* e0
|
|
* | (lt)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll17)
|
|
{
|
|
int efd[2];
|
|
int sfd[2];
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
|
|
|
|
efd[0] = epoll_create(1);
|
|
ASSERT_GE(efd[0], 0);
|
|
|
|
efd[1] = epoll_create(1);
|
|
ASSERT_GE(efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
|
|
|
|
close(efd[0]);
|
|
close(efd[1]);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (ew)
|
|
* e0
|
|
* | (lt)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll18)
|
|
{
|
|
int efd[2];
|
|
int sfd[2];
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
|
|
|
|
efd[0] = epoll_create(1);
|
|
ASSERT_GE(efd[0], 0);
|
|
|
|
efd[1] = epoll_create(1);
|
|
ASSERT_GE(efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
|
|
|
|
close(efd[0]);
|
|
close(efd[1]);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (ew)
|
|
* e0
|
|
* | (et)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll19)
|
|
{
|
|
int efd[2];
|
|
int sfd[2];
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
|
|
|
|
efd[0] = epoll_create(1);
|
|
ASSERT_GE(efd[0], 0);
|
|
|
|
efd[1] = epoll_create(1);
|
|
ASSERT_GE(efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 0);
|
|
|
|
close(efd[0]);
|
|
close(efd[1]);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (ew)
|
|
* e0
|
|
* | (et)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll20)
|
|
{
|
|
int efd[2];
|
|
int sfd[2];
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
|
|
|
|
efd[0] = epoll_create(1);
|
|
ASSERT_GE(efd[0], 0);
|
|
|
|
efd[1] = epoll_create(1);
|
|
ASSERT_GE(efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 0);
|
|
|
|
close(efd[0]);
|
|
close(efd[1]);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (p)
|
|
* e0
|
|
* | (lt)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll21)
|
|
{
|
|
int efd[2];
|
|
int sfd[2];
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
|
|
|
|
efd[0] = epoll_create(1);
|
|
ASSERT_GE(efd[0], 0);
|
|
|
|
efd[1] = epoll_create(1);
|
|
ASSERT_GE(efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
|
|
pfd.fd = efd[0];
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
|
|
|
|
pfd.fd = efd[0];
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
|
|
|
|
close(efd[0]);
|
|
close(efd[1]);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (p)
|
|
* e0
|
|
* | (lt)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll22)
|
|
{
|
|
int efd[2];
|
|
int sfd[2];
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
|
|
|
|
efd[0] = epoll_create(1);
|
|
ASSERT_GE(efd[0], 0);
|
|
|
|
efd[1] = epoll_create(1);
|
|
ASSERT_GE(efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
|
|
pfd.fd = efd[0];
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
|
|
|
|
pfd.fd = efd[0];
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
|
|
|
|
close(efd[0]);
|
|
close(efd[1]);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (p)
|
|
* e0
|
|
* | (et)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll23)
|
|
{
|
|
int efd[2];
|
|
int sfd[2];
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
|
|
|
|
efd[0] = epoll_create(1);
|
|
ASSERT_GE(efd[0], 0);
|
|
|
|
efd[1] = epoll_create(1);
|
|
ASSERT_GE(efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
|
|
pfd.fd = efd[0];
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
|
|
|
|
pfd.fd = efd[0];
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 0);
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 0);
|
|
|
|
close(efd[0]);
|
|
close(efd[1]);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (p)
|
|
* e0
|
|
* | (et)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll24)
|
|
{
|
|
int efd[2];
|
|
int sfd[2];
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
|
|
|
|
efd[0] = epoll_create(1);
|
|
ASSERT_GE(efd[0], 0);
|
|
|
|
efd[1] = epoll_create(1);
|
|
ASSERT_GE(efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], &e), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
|
|
pfd.fd = efd[0];
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 1);
|
|
|
|
pfd.fd = efd[0];
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 0);
|
|
EXPECT_EQ(epoll_wait(efd[0], &e, 1, 0), 0);
|
|
|
|
close(efd[0]);
|
|
close(efd[1]);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (ew)
|
|
* e0
|
|
* | (lt)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll25)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (ew)
|
|
* e0
|
|
* | (lt)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll26)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (ew)
|
|
* e0
|
|
* | (et)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll27)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 1);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (ew)
|
|
* e0
|
|
* | (et)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll28)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 1);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (p)
|
|
* e0
|
|
* | (lt)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll29)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (p)
|
|
* e0
|
|
* | (lt)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll30)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (p)
|
|
* e0
|
|
* | (et)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll31)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 1);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (p)
|
|
* e0
|
|
* | (et)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll32)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 1);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) | | (ew)
|
|
* | e0
|
|
* \ / (lt)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll33)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) | | (ew)
|
|
* | e0
|
|
* \ / (lt)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll34)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1o, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
|
|
__sync_fetch_and_or(&ctx.count, 2);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) | | (ew)
|
|
* | e0
|
|
* \ / (et)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll35)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) | | (ew)
|
|
* | e0
|
|
* \ / (et)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll36)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1o, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
|
|
__sync_fetch_and_or(&ctx.count, 2);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (p) | | (ew)
|
|
* | e0
|
|
* \ / (lt)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll37)
|
|
{
|
|
pthread_t emitter;
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
pfd.fd = ctx.efd[1];
|
|
pfd.events = POLLIN;
|
|
if (poll(&pfd, 1, -1) > 0) {
|
|
if (epoll_wait(ctx.efd[1], &e, 1, 0) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
}
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (p) | | (ew)
|
|
* | e0
|
|
* \ / (lt)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll38)
|
|
{
|
|
pthread_t emitter;
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1o, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
pfd.fd = ctx.efd[1];
|
|
pfd.events = POLLIN;
|
|
if (poll(&pfd, 1, -1) > 0) {
|
|
if (epoll_wait(ctx.efd[1], &e, 1, 0) > 0)
|
|
__sync_fetch_and_or(&ctx.count, 2);
|
|
}
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (p) | | (ew)
|
|
* | e0
|
|
* \ / (et)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll39)
|
|
{
|
|
pthread_t emitter;
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
pfd.fd = ctx.efd[1];
|
|
pfd.events = POLLIN;
|
|
if (poll(&pfd, 1, -1) > 0) {
|
|
if (epoll_wait(ctx.efd[1], &e, 1, 0) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
}
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (p) | | (ew)
|
|
* | e0
|
|
* \ / (et)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll40)
|
|
{
|
|
pthread_t emitter;
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1o, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
pfd.fd = ctx.efd[1];
|
|
pfd.events = POLLIN;
|
|
if (poll(&pfd, 1, -1) > 0) {
|
|
if (epoll_wait(ctx.efd[1], &e, 1, 0) > 0)
|
|
__sync_fetch_and_or(&ctx.count, 2);
|
|
}
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) | | (p)
|
|
* | e0
|
|
* \ / (lt)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll41)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) | | (p)
|
|
* | e0
|
|
* \ / (lt)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll42)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1op, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
|
|
__sync_fetch_and_or(&ctx.count, 2);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) | | (p)
|
|
* | e0
|
|
* \ / (et)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll43)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) | | (p)
|
|
* | e0
|
|
* \ / (et)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll44)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1op, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
|
|
__sync_fetch_and_or(&ctx.count, 2);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (p) | | (p)
|
|
* | e0
|
|
* \ / (lt)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll45)
|
|
{
|
|
pthread_t emitter;
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
pfd.fd = ctx.efd[1];
|
|
pfd.events = POLLIN;
|
|
if (poll(&pfd, 1, -1) > 0) {
|
|
if (epoll_wait(ctx.efd[1], &e, 1, 0) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
}
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (p) | | (p)
|
|
* | e0
|
|
* \ / (lt)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll46)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1op, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
|
|
__sync_fetch_and_or(&ctx.count, 2);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (p) | | (p)
|
|
* | e0
|
|
* \ / (et)
|
|
* e1
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll47)
|
|
{
|
|
pthread_t emitter;
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
pfd.fd = ctx.efd[1];
|
|
pfd.events = POLLIN;
|
|
if (poll(&pfd, 1, -1) > 0) {
|
|
if (epoll_wait(ctx.efd[1], &e, 1, 0) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
}
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (p) | | (p)
|
|
* | e0
|
|
* \ / (et)
|
|
* e1
|
|
* | (et)
|
|
* s0
|
|
*/
|
|
TEST(epoll48)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1op, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry1, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[1], &e, 1, -1) > 0)
|
|
__sync_fetch_and_or(&ctx.count, 2);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_TRUE((ctx.count == 2) || (ctx.count == 3));
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (ew)
|
|
* e0
|
|
* (lt) / \ (lt)
|
|
* e1 e2
|
|
* (lt) | | (lt)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll49)
|
|
{
|
|
int efd[3];
|
|
int sfd[4];
|
|
struct epoll_event events[2];
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
|
|
|
|
efd[0] = epoll_create(1);
|
|
ASSERT_GE(efd[0], 0);
|
|
|
|
efd[1] = epoll_create(1);
|
|
ASSERT_GE(efd[1], 0);
|
|
|
|
efd[2] = epoll_create(1);
|
|
ASSERT_GE(efd[2], 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], events), 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[2], EPOLL_CTL_ADD, sfd[2], events), 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], events), 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[2], events), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
ASSERT_EQ(write(sfd[3], "w", 1), 1);
|
|
|
|
EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 2);
|
|
EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 2);
|
|
|
|
close(efd[0]);
|
|
close(efd[1]);
|
|
close(efd[2]);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
close(sfd[2]);
|
|
close(sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (ew)
|
|
* e0
|
|
* (et) / \ (et)
|
|
* e1 e2
|
|
* (lt) | | (lt)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll50)
|
|
{
|
|
int efd[3];
|
|
int sfd[4];
|
|
struct epoll_event events[2];
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
|
|
|
|
efd[0] = epoll_create(1);
|
|
ASSERT_GE(efd[0], 0);
|
|
|
|
efd[1] = epoll_create(1);
|
|
ASSERT_GE(efd[1], 0);
|
|
|
|
efd[2] = epoll_create(1);
|
|
ASSERT_GE(efd[2], 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], events), 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[2], EPOLL_CTL_ADD, sfd[2], events), 0);
|
|
|
|
events[0].events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], events), 0);
|
|
|
|
events[0].events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[2], events), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
ASSERT_EQ(write(sfd[3], "w", 1), 1);
|
|
|
|
EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 2);
|
|
EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 0);
|
|
|
|
close(efd[0]);
|
|
close(efd[1]);
|
|
close(efd[2]);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
close(sfd[2]);
|
|
close(sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (p)
|
|
* e0
|
|
* (lt) / \ (lt)
|
|
* e1 e2
|
|
* (lt) | | (lt)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll51)
|
|
{
|
|
int efd[3];
|
|
int sfd[4];
|
|
struct pollfd pfd;
|
|
struct epoll_event events[2];
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
|
|
|
|
efd[0] = epoll_create(1);
|
|
ASSERT_GE(efd[0], 0);
|
|
|
|
efd[1] = epoll_create(1);
|
|
ASSERT_GE(efd[1], 0);
|
|
|
|
efd[2] = epoll_create(1);
|
|
ASSERT_GE(efd[2], 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], events), 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[2], EPOLL_CTL_ADD, sfd[2], events), 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], events), 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[2], events), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
ASSERT_EQ(write(sfd[3], "w", 1), 1);
|
|
|
|
pfd.fd = efd[0];
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 2);
|
|
|
|
pfd.fd = efd[0];
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 2);
|
|
|
|
close(efd[0]);
|
|
close(efd[1]);
|
|
close(efd[2]);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
close(sfd[2]);
|
|
close(sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* | (p)
|
|
* e0
|
|
* (et) / \ (et)
|
|
* e1 e2
|
|
* (lt) | | (lt)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll52)
|
|
{
|
|
int efd[3];
|
|
int sfd[4];
|
|
struct pollfd pfd;
|
|
struct epoll_event events[2];
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &sfd[2]), 0);
|
|
|
|
efd[0] = epoll_create(1);
|
|
ASSERT_GE(efd[0], 0);
|
|
|
|
efd[1] = epoll_create(1);
|
|
ASSERT_GE(efd[1], 0);
|
|
|
|
efd[2] = epoll_create(1);
|
|
ASSERT_GE(efd[2], 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[1], EPOLL_CTL_ADD, sfd[0], events), 0);
|
|
|
|
events[0].events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd[2], EPOLL_CTL_ADD, sfd[2], events), 0);
|
|
|
|
events[0].events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[1], events), 0);
|
|
|
|
events[0].events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(efd[0], EPOLL_CTL_ADD, efd[2], events), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
ASSERT_EQ(write(sfd[3], "w", 1), 1);
|
|
|
|
pfd.fd = efd[0];
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 1);
|
|
EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 2);
|
|
|
|
pfd.fd = efd[0];
|
|
pfd.events = POLLIN;
|
|
EXPECT_EQ(poll(&pfd, 1, 0), 0);
|
|
EXPECT_EQ(epoll_wait(efd[0], events, 2, 0), 0);
|
|
|
|
close(efd[0]);
|
|
close(efd[1]);
|
|
close(efd[2]);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
close(sfd[2]);
|
|
close(sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (ew)
|
|
* e0
|
|
* (lt) / \ (lt)
|
|
* e1 e2
|
|
* (lt) | | (lt)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll53)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
ctx.efd[2] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[2], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[2], EPOLL_CTL_ADD, ctx.sfd[2], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.efd[2]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
close(ctx.sfd[2]);
|
|
close(ctx.sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (ew)
|
|
* e0
|
|
* (et) / \ (et)
|
|
* e1 e2
|
|
* (lt) | | (lt)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll54)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
ctx.efd[2] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[2], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[2], EPOLL_CTL_ADD, ctx.sfd[2], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.efd[2]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
close(ctx.sfd[2]);
|
|
close(ctx.sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (p)
|
|
* e0
|
|
* (lt) / \ (lt)
|
|
* e1 e2
|
|
* (lt) | | (lt)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll55)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
ctx.efd[2] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[2], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[2], EPOLL_CTL_ADD, ctx.sfd[2], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.efd[2]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
close(ctx.sfd[2]);
|
|
close(ctx.sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (p)
|
|
* e0
|
|
* (et) / \ (et)
|
|
* e1 e2
|
|
* (lt) | | (lt)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll56)
|
|
{
|
|
pthread_t emitter;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
ctx.efd[2] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[2], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[2], EPOLL_CTL_ADD, ctx.sfd[2], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
|
|
|
|
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.efd[2]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
close(ctx.sfd[2]);
|
|
close(ctx.sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (p) \ / (p)
|
|
* e0
|
|
* (lt) / \ (lt)
|
|
* e1 e2
|
|
* (lt) | | (lt)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll57)
|
|
{
|
|
pthread_t emitter;
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
ctx.efd[2] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[2], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[2], EPOLL_CTL_ADD, ctx.sfd[2], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
|
|
|
|
pfd.fd = ctx.efd[0];
|
|
pfd.events = POLLIN;
|
|
if (poll(&pfd, 1, -1) > 0) {
|
|
if (epoll_wait(ctx.efd[0], &e, 1, 0) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
}
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.efd[2]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
close(ctx.sfd[2]);
|
|
close(ctx.sfd[3]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (p) \ / (p)
|
|
* e0
|
|
* (et) / \ (et)
|
|
* e1 e2
|
|
* (lt) | | (lt)
|
|
* s0 s2
|
|
*/
|
|
TEST(epoll58)
|
|
{
|
|
pthread_t emitter;
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[0]), 0);
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx.sfd[2]), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.efd[1] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[1], 0);
|
|
|
|
ctx.efd[2] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[2], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[1], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[2], EPOLL_CTL_ADD, ctx.sfd[2], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[1], &e), 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
|
|
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
|
|
|
|
pfd.fd = ctx.efd[0];
|
|
pfd.events = POLLIN;
|
|
if (poll(&pfd, 1, -1) > 0) {
|
|
if (epoll_wait(ctx.efd[0], &e, 1, 0) > 0)
|
|
__sync_fetch_and_add(&ctx.count, 1);
|
|
}
|
|
|
|
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.efd[1]);
|
|
close(ctx.efd[2]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
close(ctx.sfd[2]);
|
|
close(ctx.sfd[3]);
|
|
}
|
|
|
|
static void *epoll59_thread(void *ctx_)
|
|
{
|
|
struct epoll_mtcontext *ctx = ctx_;
|
|
struct epoll_event e;
|
|
int i;
|
|
|
|
for (i = 0; i < 100000; i++) {
|
|
while (ctx->count == 0)
|
|
;
|
|
|
|
e.events = EPOLLIN | EPOLLERR | EPOLLET;
|
|
epoll_ctl(ctx->efd[0], EPOLL_CTL_MOD, ctx->sfd[0], &e);
|
|
ctx->count = 0;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* t0
|
|
* (p) \
|
|
* e0
|
|
* (et) /
|
|
* e0
|
|
*
|
|
* Based on https://bugzilla.kernel.org/show_bug.cgi?id=205933
|
|
*/
|
|
TEST(epoll59)
|
|
{
|
|
pthread_t emitter;
|
|
struct pollfd pfd;
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
int i, ret;
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ctx.efd[0] = epoll_create1(0);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
ctx.sfd[0] = eventfd(1, 0);
|
|
ASSERT_GE(ctx.sfd[0], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLERR | EPOLLET;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
ASSERT_EQ(pthread_create(&emitter, NULL, epoll59_thread, &ctx), 0);
|
|
|
|
for (i = 0; i < 100000; i++) {
|
|
ret = epoll_wait(ctx.efd[0], &e, 1, 1000);
|
|
ASSERT_GT(ret, 0);
|
|
|
|
while (ctx.count != 0)
|
|
;
|
|
ctx.count = 1;
|
|
}
|
|
if (pthread_tryjoin_np(emitter, NULL) < 0) {
|
|
pthread_kill(emitter, SIGUSR1);
|
|
pthread_join(emitter, NULL);
|
|
}
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
}
|
|
|
|
enum {
|
|
EPOLL60_EVENTS_NR = 10,
|
|
};
|
|
|
|
struct epoll60_ctx {
|
|
volatile int stopped;
|
|
int ready;
|
|
int waiters;
|
|
int epfd;
|
|
int evfd[EPOLL60_EVENTS_NR];
|
|
};
|
|
|
|
static void *epoll60_wait_thread(void *ctx_)
|
|
{
|
|
struct epoll60_ctx *ctx = ctx_;
|
|
struct epoll_event e;
|
|
sigset_t sigmask;
|
|
uint64_t v;
|
|
int ret;
|
|
|
|
/* Block SIGUSR1 */
|
|
sigemptyset(&sigmask);
|
|
sigaddset(&sigmask, SIGUSR1);
|
|
sigprocmask(SIG_SETMASK, &sigmask, NULL);
|
|
|
|
/* Prepare empty mask for epoll_pwait() */
|
|
sigemptyset(&sigmask);
|
|
|
|
while (!ctx->stopped) {
|
|
/* Mark we are ready */
|
|
__atomic_fetch_add(&ctx->ready, 1, __ATOMIC_ACQUIRE);
|
|
|
|
/* Start when all are ready */
|
|
while (__atomic_load_n(&ctx->ready, __ATOMIC_ACQUIRE) &&
|
|
!ctx->stopped);
|
|
|
|
/* Account this waiter */
|
|
__atomic_fetch_add(&ctx->waiters, 1, __ATOMIC_ACQUIRE);
|
|
|
|
ret = epoll_pwait(ctx->epfd, &e, 1, 2000, &sigmask);
|
|
if (ret != 1) {
|
|
/* We expect only signal delivery on stop */
|
|
assert(ret < 0 && errno == EINTR && "Lost wakeup!\n");
|
|
assert(ctx->stopped);
|
|
break;
|
|
}
|
|
|
|
ret = read(e.data.fd, &v, sizeof(v));
|
|
/* Since we are on ET mode, thus each thread gets its own fd. */
|
|
assert(ret == sizeof(v));
|
|
|
|
__atomic_fetch_sub(&ctx->waiters, 1, __ATOMIC_RELEASE);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static inline unsigned long long msecs(void)
|
|
{
|
|
struct timespec ts;
|
|
unsigned long long msecs;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &ts);
|
|
msecs = ts.tv_sec * 1000ull;
|
|
msecs += ts.tv_nsec / 1000000ull;
|
|
|
|
return msecs;
|
|
}
|
|
|
|
static inline int count_waiters(struct epoll60_ctx *ctx)
|
|
{
|
|
return __atomic_load_n(&ctx->waiters, __ATOMIC_ACQUIRE);
|
|
}
|
|
|
|
TEST(epoll60)
|
|
{
|
|
struct epoll60_ctx ctx = { 0 };
|
|
pthread_t waiters[ARRAY_SIZE(ctx.evfd)];
|
|
struct epoll_event e;
|
|
int i, n, ret;
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ctx.epfd = epoll_create1(0);
|
|
ASSERT_GE(ctx.epfd, 0);
|
|
|
|
/* Create event fds */
|
|
for (i = 0; i < ARRAY_SIZE(ctx.evfd); i++) {
|
|
ctx.evfd[i] = eventfd(0, EFD_NONBLOCK);
|
|
ASSERT_GE(ctx.evfd[i], 0);
|
|
|
|
e.events = EPOLLIN | EPOLLET;
|
|
e.data.fd = ctx.evfd[i];
|
|
ASSERT_EQ(epoll_ctl(ctx.epfd, EPOLL_CTL_ADD, ctx.evfd[i], &e), 0);
|
|
}
|
|
|
|
/* Create waiter threads */
|
|
for (i = 0; i < ARRAY_SIZE(waiters); i++)
|
|
ASSERT_EQ(pthread_create(&waiters[i], NULL,
|
|
epoll60_wait_thread, &ctx), 0);
|
|
|
|
for (i = 0; i < 300; i++) {
|
|
uint64_t v = 1, ms;
|
|
|
|
/* Wait for all to be ready */
|
|
while (__atomic_load_n(&ctx.ready, __ATOMIC_ACQUIRE) !=
|
|
ARRAY_SIZE(ctx.evfd))
|
|
;
|
|
|
|
/* Steady, go */
|
|
__atomic_fetch_sub(&ctx.ready, ARRAY_SIZE(ctx.evfd),
|
|
__ATOMIC_ACQUIRE);
|
|
|
|
/* Wait all have gone to kernel */
|
|
while (count_waiters(&ctx) != ARRAY_SIZE(ctx.evfd))
|
|
;
|
|
|
|
/* 1ms should be enough to schedule away */
|
|
usleep(1000);
|
|
|
|
/* Quickly signal all handles at once */
|
|
for (n = 0; n < ARRAY_SIZE(ctx.evfd); n++) {
|
|
ret = write(ctx.evfd[n], &v, sizeof(v));
|
|
ASSERT_EQ(ret, sizeof(v));
|
|
}
|
|
|
|
/* Busy loop for 1s and wait for all waiters to wake up */
|
|
ms = msecs();
|
|
while (count_waiters(&ctx) && msecs() < ms + 1000)
|
|
;
|
|
|
|
ASSERT_EQ(count_waiters(&ctx), 0);
|
|
}
|
|
ctx.stopped = 1;
|
|
/* Stop waiters */
|
|
for (i = 0; i < ARRAY_SIZE(waiters); i++)
|
|
ret = pthread_kill(waiters[i], SIGUSR1);
|
|
for (i = 0; i < ARRAY_SIZE(waiters); i++)
|
|
pthread_join(waiters[i], NULL);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(waiters); i++)
|
|
close(ctx.evfd[i]);
|
|
close(ctx.epfd);
|
|
}
|
|
|
|
struct epoll61_ctx {
|
|
int epfd;
|
|
int evfd;
|
|
};
|
|
|
|
static void *epoll61_write_eventfd(void *ctx_)
|
|
{
|
|
struct epoll61_ctx *ctx = ctx_;
|
|
int64_t l = 1;
|
|
|
|
usleep(10950);
|
|
write(ctx->evfd, &l, sizeof(l));
|
|
return NULL;
|
|
}
|
|
|
|
static void *epoll61_epoll_with_timeout(void *ctx_)
|
|
{
|
|
struct epoll61_ctx *ctx = ctx_;
|
|
struct epoll_event events[1];
|
|
int n;
|
|
|
|
n = epoll_wait(ctx->epfd, events, 1, 11);
|
|
/*
|
|
* If epoll returned the eventfd, write on the eventfd to wake up the
|
|
* blocking poller.
|
|
*/
|
|
if (n == 1) {
|
|
int64_t l = 1;
|
|
|
|
write(ctx->evfd, &l, sizeof(l));
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void *epoll61_blocking_epoll(void *ctx_)
|
|
{
|
|
struct epoll61_ctx *ctx = ctx_;
|
|
struct epoll_event events[1];
|
|
|
|
epoll_wait(ctx->epfd, events, 1, -1);
|
|
return NULL;
|
|
}
|
|
|
|
TEST(epoll61)
|
|
{
|
|
struct epoll61_ctx ctx;
|
|
struct epoll_event ev;
|
|
int i, r;
|
|
|
|
ctx.epfd = epoll_create1(0);
|
|
ASSERT_GE(ctx.epfd, 0);
|
|
ctx.evfd = eventfd(0, EFD_NONBLOCK);
|
|
ASSERT_GE(ctx.evfd, 0);
|
|
|
|
ev.events = EPOLLIN | EPOLLET | EPOLLERR | EPOLLHUP;
|
|
ev.data.ptr = NULL;
|
|
r = epoll_ctl(ctx.epfd, EPOLL_CTL_ADD, ctx.evfd, &ev);
|
|
ASSERT_EQ(r, 0);
|
|
|
|
/*
|
|
* We are testing a race. Repeat the test case 1000 times to make it
|
|
* more likely to fail in case of a bug.
|
|
*/
|
|
for (i = 0; i < 1000; i++) {
|
|
pthread_t threads[3];
|
|
int n;
|
|
|
|
/*
|
|
* Start 3 threads:
|
|
* Thread 1 sleeps for 10.9ms and writes to the evenfd.
|
|
* Thread 2 calls epoll with a timeout of 11ms.
|
|
* Thread 3 calls epoll with a timeout of -1.
|
|
*
|
|
* The eventfd write by Thread 1 should either wakeup Thread 2
|
|
* or Thread 3. If it wakes up Thread 2, Thread 2 writes on the
|
|
* eventfd to wake up Thread 3.
|
|
*
|
|
* If no events are missed, all three threads should eventually
|
|
* be joinable.
|
|
*/
|
|
ASSERT_EQ(pthread_create(&threads[0], NULL,
|
|
epoll61_write_eventfd, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&threads[1], NULL,
|
|
epoll61_epoll_with_timeout, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&threads[2], NULL,
|
|
epoll61_blocking_epoll, &ctx), 0);
|
|
|
|
for (n = 0; n < ARRAY_SIZE(threads); ++n)
|
|
ASSERT_EQ(pthread_join(threads[n], NULL), 0);
|
|
}
|
|
|
|
close(ctx.epfd);
|
|
close(ctx.evfd);
|
|
}
|
|
|
|
/* Equivalent to basic test epoll1, but exercising epoll_pwait2. */
|
|
TEST(epoll62)
|
|
{
|
|
int efd;
|
|
int sfd[2];
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
|
|
|
|
efd = epoll_create(1);
|
|
ASSERT_GE(efd, 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
ASSERT_EQ(write(sfd[1], "w", 1), 1);
|
|
|
|
EXPECT_EQ(sys_epoll_pwait2(efd, &e, 1, NULL, NULL, 0), 1);
|
|
EXPECT_EQ(sys_epoll_pwait2(efd, &e, 1, NULL, NULL, 0), 1);
|
|
|
|
close(efd);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/* Epoll_pwait2 basic timeout test. */
|
|
TEST(epoll63)
|
|
{
|
|
const int cfg_delay_ms = 10;
|
|
unsigned long long tdiff;
|
|
struct __kernel_timespec ts;
|
|
int efd;
|
|
int sfd[2];
|
|
struct epoll_event e;
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0);
|
|
|
|
efd = epoll_create(1);
|
|
ASSERT_GE(efd, 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e), 0);
|
|
|
|
ts.tv_sec = 0;
|
|
ts.tv_nsec = cfg_delay_ms * 1000 * 1000;
|
|
|
|
tdiff = msecs();
|
|
EXPECT_EQ(sys_epoll_pwait2(efd, &e, 1, &ts, NULL, 0), 0);
|
|
tdiff = msecs() - tdiff;
|
|
|
|
EXPECT_GE(tdiff, cfg_delay_ms);
|
|
|
|
close(efd);
|
|
close(sfd[0]);
|
|
close(sfd[1]);
|
|
}
|
|
|
|
/*
|
|
* t0 t1
|
|
* (ew) \ / (ew)
|
|
* e0
|
|
* | (lt)
|
|
* s0
|
|
*/
|
|
TEST(epoll64)
|
|
{
|
|
pthread_t waiter[2];
|
|
struct epoll_event e;
|
|
struct epoll_mtcontext ctx = { 0 };
|
|
|
|
signal(SIGUSR1, signal_handler);
|
|
|
|
ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx.sfd), 0);
|
|
|
|
ctx.efd[0] = epoll_create(1);
|
|
ASSERT_GE(ctx.efd[0], 0);
|
|
|
|
e.events = EPOLLIN;
|
|
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[0], &e), 0);
|
|
|
|
/*
|
|
* main will act as the emitter once both waiter threads are
|
|
* blocked and expects to both be awoken upon the ready event.
|
|
*/
|
|
ctx.main = pthread_self();
|
|
ASSERT_EQ(pthread_create(&waiter[0], NULL, waiter_entry1a, &ctx), 0);
|
|
ASSERT_EQ(pthread_create(&waiter[1], NULL, waiter_entry1a, &ctx), 0);
|
|
|
|
usleep(100000);
|
|
ASSERT_EQ(write(ctx.sfd[1], "w", 1), 1);
|
|
|
|
ASSERT_EQ(pthread_join(waiter[0], NULL), 0);
|
|
ASSERT_EQ(pthread_join(waiter[1], NULL), 0);
|
|
|
|
EXPECT_EQ(ctx.count, 2);
|
|
|
|
close(ctx.efd[0]);
|
|
close(ctx.sfd[0]);
|
|
close(ctx.sfd[1]);
|
|
}
|
|
|
|
TEST_HARNESS_MAIN
|