tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c
Extension
.c
Size
76907 bytes
Lines
3542
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

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);

Annotation

Implementation Notes