Can not join ev loop thread since it is hanging in epoll_wait
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
If an event loop thread is sitting in epoll_wait, that does not automatically mean it is broken. On Linux, that is often the normal idle state of a loop waiting for file-descriptor activity. The real reason join() hangs is usually that the loop was never told to stop, or it was told in a way that did not wake the loop thread safely.
Why epoll_wait Appears in Stack Traces
Event loops spend much of their life waiting for I/O readiness. Under the hood, that wait often maps to epoll_wait on Linux. So a blocked stack frame there usually means:
- the loop is alive
- it is waiting for work
- no stop signal has completed the shutdown path yet
That is a different problem from a deadlock. An idle event loop is expected to sleep until new work or a wake-up event arrives.
join() Does Not Stop a Thread
This is the key mistake. thread.join() only waits for the thread to finish. It does not request shutdown.
If your code looks like this, it can wait forever:
The event loop thread must first receive a stop request and a wake-up event so it can exit its run loop.
Use a Thread-Safe Stop Path
For an asyncio loop running in another thread, the normal pattern is:
call_soon_threadsafe matters because it schedules the stop request from another thread and wakes the loop correctly. That gives the loop a chance to leave run_forever, clean up, and let join() complete.
Clean Up Pending Tasks Before Closing
A second shutdown issue comes from pending tasks that keep the loop busy or leave resources half-open. A more complete pattern is:
This is useful when your loop owns long-lived coroutines. The stop request exits the main wait, and the cleanup phase drains outstanding work.
Why the Loop May Not Wake Up
If you modify shared state from another thread without using the event loop's thread-safe APIs, the loop can remain parked in epoll_wait because nothing notified it that shutdown work exists.
That is why direct cross-thread mutation is risky. The event loop needs a wake-up mechanism, not just a boolean flag in memory.
Debug the Shutdown Contract, Not Only the Stack Frame
When shutdown hangs, ask:
- who owns the loop
- who requests stop
- is the stop request thread-safe
- are there pending tasks or open transports
- does the thread exit after the loop stops
These questions usually find the issue faster than treating epoll_wait itself as the bug.
Common Pitfalls
- Calling
join()and expecting it to stop the event loop thread. - Setting a shared flag from another thread without waking the loop.
- Closing the loop before pending tasks have been cancelled or awaited.
- Interpreting an idle
epoll_waitframe as proof of a deadlock. - Mixing thread ownership rules and calling loop methods from the wrong thread.
Summary
- '
epoll_waitis often the normal idle state of an event loop on Linux.' - A hanging
join()usually means the loop was never stopped correctly. - Use thread-safe APIs such as
loop.call_soon_threadsafe(loop.stop)to request shutdown. - Clean up pending tasks before closing the loop.
- Treat loop shutdown as a protocol with wake-up, stop, cleanup, and then join.
Related reading
- Can Powershell Run Commands in Parallel?
- Can ruby exceptions be handled asynchronously outside of a Threadhandle_interrupt block?
- Can someone explain to me what is an event-driven, asynchronous, non-blocking I/O
- Can Spring Boot application handle multiple requests simultaneously?
- Can Numba be used with Tensorflow?
- Can one use the Django database layer outside of Django?
- Can tensorflow sess.run really release GIL global interpreter look of python?
- Can thread trying to stdlock_unique an stdshared_mutex be starved by threads calling stdlock_shared?
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseNo course covers this one yet
Basis Lab writes one for you from a sentence about what you want to be able to do, then teaches it and checks you understood. Your first course is free.
Build my courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.