Skip to content

Instantly share code, notes, and snippets.

@franz1981
Created May 30, 2025 20:08
Show Gist options
  • Save franz1981/4f507a4a07c790745cdbffae1669de94 to your computer and use it in GitHub Desktop.
Save franz1981/4f507a4a07c790745cdbffae1669de94 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
void* writer_thread(void* arg) {
int efd = *((int*)arg);
printf("[Writer] Sleeping 3 seconds before writing to eventfd %d...\n", efd);
sleep(3);
uint64_t val = 1;
printf("[Writer] Writing to eventfd %d\n", efd);
if (write(efd, &val, sizeof(val)) != sizeof(val)) {
perror("write failed");
}
return NULL;
}
int main() {
// Create eventfd
int efd = eventfd(0, EFD_NONBLOCK);
if (efd == -1) {
perror("eventfd creation failed");
return 1;
}
printf("Created eventFd = %d\n", efd);
// Create first epoll instance (A)
int epollA = epoll_create1(0);
if (epollA == -1) {
perror("epoll_create1(A) failed");
return 1;
}
printf("Created epollA fd = %d\n", epollA);
// Add eventfd to epollA
struct epoll_event eventA;
eventA.events = EPOLLIN;
eventA.data.fd = efd;
if (epoll_ctl(epollA, EPOLL_CTL_ADD, efd, &eventA) == -1) {
perror("epoll_ctl(A) failed");
return 1;
}
// Create second epoll instance (B)
int epollB = epoll_create1(0);
if (epollB == -1) {
perror("epoll_create1(B) failed");
return 1;
}
printf("Created epollB fd = %d\n", epollB);
// Try to add epollA to epollB - THIS IS INVALID!
struct epoll_event eventB;
eventB.events = EPOLLIN | EPOLLONESHOT;
eventB.data.fd = epollA;
printf("Attempting to add epollA (%d) to epollB (%d)...\n", epollA, epollB);
if (epoll_ctl(epollB, EPOLL_CTL_ADD, epollA, &eventB) == -1) {
perror("epoll_ctl(B) failed (expected)");
printf("Kernel error: %s\n", strerror(errno));
printf("\nERROR: Cannot add an epoll instance to another epoll set!\n");
} else {
printf("\nKernel allowed epoll-in-epoll!\n");
// Start writer thread
pthread_t thread;
pthread_create(&thread, NULL, writer_thread, &efd);
// Wait on epollB
struct epoll_event events[1];
printf("[Main] Waiting on epollB (%d) for events...\n", epollB);
int num_events = epoll_wait(epollB, events, 1, 10000);
if (num_events > 0) {
printf("[Main] epollB returned event for fd %d\n", events[0].data.fd);
} else if (num_events == 0) {
printf("[Main] epollB timed out (no events)\n");
} else {
perror("epoll_wait failed");
}
num_events = epoll_wait(epollA, events, 1, 0);
if (num_events > 0) {
printf("[Main] epollA returned event for fd %d\n", events[0].data.fd);
} else if (num_events == 0) {
printf("[Main] epollB timed out (no events)\n");
} else {
perror("epoll_wait failed");
}
pthread_join(thread, NULL);
}
close(efd);
close(epollA);
close(epollB);
return 0;
}
@franz1981
Copy link
Author

This need to be compiled with:

$ gcc epoll_test.c -o epoll_test -pthread

and running it via:

$ ./epoll_test 
Created eventFd = 3
Created epollA fd = 4
Created epollB fd = 5
Attempting to add epollA (4) to epollB (5)...

Kernel allowed epoll-in-epoll!
[Main] Waiting on epollB (5) for events...
[Writer] Sleeping 3 seconds before writing to eventfd 3...
[Writer] Writing to eventfd 3
[Main] epollB returned event for fd 4
[Main] epollA returned event for fd 3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment