I am using os.eventfd (new in Python 3.10) for IPC between a C process and a Python process. The Python process is run by fork-execv from C.
The eventfd and epoll are set up in C, and the eventfd file descriptor is passed to Python.
According to the Linux docs: "If EFD_SEMAPHORE was not specified and the eventfd counter has a nonzero value, then a read(2) returns 8 bytes containing that value, and the counter's value is reset to zero." So I would expect that a read would occur once, then not again, or subsequent reads should return 0 after the first read. But that's not what happens, it keeps returning the same value over and over again.
The C program sets up the eventfd and epoll:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/eventfd.h>
#include <sys/epoll.h>
int eventfd_initialize()
{
int efd = eventfd(0,0);
return efd;
}
int epoll_initialize(int efd, int64_t * output_array)
{
struct epoll_event ev;
int epoll_fd = epoll_create1(0);
if(epoll_fd == -1)
{
fprintf(stderr, "Failed to create epoll file descriptor\n");
return 1;
}
ev.events = EPOLLIN; //May also need to be or'ed with EPOLLOUT
ev.data.fd = efd; //was 0
if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, efd, &ev) == -1)
{
fprintf(stderr, "Failed to add file descriptor to epoll\n");
close(epoll_fd);
return 1;
}
output_array[0] = epoll_fd;
output_array[1] = (int64_t)&ev;
return 0;
}
ssize_t epoll_write(int epoll_fd, struct epoll_event * event_struc, int action_code)
{
char ewbuf[8];
sprintf(ewbuf, "%d", action_code);
int maxevents = 1;
int timeout = -1;
write(epoll_fd, &ewbuf, 8);
epoll_wait(epoll_fd, event_struc, maxevents, timeout);
return 0;
}
The C program writes to the eventfd before the Python script is initialized, then the Python script is called with fork-exec. The Python script is a simple while True loop:
#!/usr/bin/python3
import sys
import os
from multiprocessing import shared_memory
event_fd = int(sys.argv[3])
os.set_blocking(event_fd, False)
existing_shm = shared_memory.SharedMemory(name='shm_object_0_0',create=False)
while True:
print("Waiting in Python for event")
v = os.eventfd_read(event_fd)
print("found")
print(v)
if v != 99:
print("release semaphore")
os.eventfd_write(event_fd, v)
if v == 99:
print("finally")
os.close(event_fd)
So I would expect it to read once, then all subsequent reads would return zero before the C side has written more to the eventfd. But I get this continuous display:
Waiting in Python for event
found
13361
release semaphore
Waiting in Python for event
found
13361
release semaphore
Waiting in Python for event
found
13361
release semaphore
Waiting in Python for event
found
13361
release semaphore
With each new read it returns the same number, not 0. The docs say a read from the eventfd will set it back to zero. Adding time.sleep(1) to Python doesn't change the behavior.
Also, I don't see any way to call epoll_wait in the Python os docs.