On 20/10/2025 03:43, David Gibson wrote:
On Fri, Oct 17, 2025 at 12:31:29PM +0200, Laurent Vivier wrote:
Extract the epoll event processing logic from main() into a separate passt_worker() function. This refactoring prepares the code for future threading support where passt_worker() will be called as a worker thread callback.
The new function handles: - Processing epoll events and dispatching to protocol handlers - Event statistics tracking and printing - Post-handler periodic tasks (timers, deferred work) - Migration handling
No functional changes, purely a code restructuring.
Signed-off-by: Laurent Vivier
Looks good as far as it goes, and I've though often in the past that it would make more sense for the "engine" to go in its own function.
Wondering if it would make more sense to include the epoll_wait() itself and the loop in this function, rather than leaving that outside.
When I introduce the multithreading and the multiqueue, as the thread is driven by the epollfd, the events are managed by the multiqueue part and the epollfd by the multithread part. The "threading" worker is: static void *threading_worker(void *opaque) { struct threading_context *tc = opaque; while (true) { struct epoll_event events[NUM_EPOLL_EVENTS]; int nfds; nfds = epoll_wait(tc->epollfd, events, NUM_EPOLL_EVENTS, TIMER_INTERVAL); if (nfds == -1 && errno != EINTR) die_perror("epoll_wait() failed"); tc->worker(tc->opaque, nfds, events); } return NULL; } And the passt worker is registered with: threading_worker_set(0, passt_worker, NULL, &c); where: int threading_worker_set(unsigned int threadnb, void (*worker)(void *, int, struct epoll_event *), bool (*is_valid)(void *, unsigned int criteria), void *opaque) { struct threading_context *tc; if (threadnb >= ARRAY_SIZE(threads)) return -1; tc = &threads[threadnb]; tc->worker = worker; tc->is_valid = is_valid; tc->opaque = opaque; return 0; } Thanks, Laurent