-
-
Notifications
You must be signed in to change notification settings - Fork 345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
monitoring arbitrary kevents #579
Conversation
So this is one of those classic weird and subtle Unix things. You've heard of "zombie processes"? On Unix when a process exits, the kernel cleans up most of it (the address space, the threads, etc.), but it keeps around a little bit of metadata (the process name, the return value) – this is a "zombie process". This metadata stays in the process table under the original process's PID, until someone calls So after you fork a child process, the pid you get back is guaranteed to keep referring to that exact process – or at least, its undead remains – until you call This does mean that you have to be careful that for each child process, you call |
|
||
|
||
async def test_kqueue_monitor_proc_event(): | ||
p = subprocess.Popen(['sleep', '0.1']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So all that stuff about zombies means you don't need this process to sleep. Maybe true
and false
and then you can also check the exit code?
I started writing more high-level review, but realized it was so high-level it wasn't really about this specific PR at all, so I posted it on the issue instead :-): #578 (comment) |
Not sure if Popen does something I don't understand compared to a naked fork/exec, but I cannot register a kevent for a child process pid after that process has terminated. I will definitely look further into it, because I too expected it to provide some way to deal with zombies. Now that I think of it, I was so confused by this that I forgot to reap the child :) Thanks for the review and the excellent write-up! I will follow up on that later. |
Codecov Report
@@ Coverage Diff @@
## master #579 +/- ##
=========================================
- Coverage 99.27% 97.3% -1.98%
=========================================
Files 89 92 +3
Lines 10628 12943 +2315
Branches 747 1191 +444
=========================================
+ Hits 10551 12594 +2043
- Misses 59 325 +266
- Partials 18 24 +6
Continue to review full report at Codecov.
|
I guess It's also possible that kqueue simple doesn't let you register a filter for a process that's already dead. Maybe you're expected to take the error message as your notification that the process is finished and you should call |
A couple notes on monitoring process termination. First, it seems this is the correct case:
As I said above, my code totally forgets the reaping part. You have to do Another note: some platforms differ on the way they report the exit status of the exited process. On FreeBSD it's included whenever you register |
We should probably still do a pass over the low-level kqueue APIs to clean them up, but this PR has stalled and the discussion is way out of date (e.g. trio mainline is now actually using kqueue to monitor process termination). So I'm gonna close it, and we can always re-open if that turns out to be useful. |
So, this is just to start thinking how we can implement support for arbitrary kevent events (#578). I'm not a kqueue expert at all, I just happen to run macOS. @njsmith is this similar to what you had in mind?
I think there are weird interactions between flags that are not apparent from the documentation. For example it appears that waiting for process exit will get an event with EV_ONESHOT which makes sense (you can't wait for an event from a pid that doesn't exist anymore). So maybe making it actually arbitrary involves some more tricks that I haven't explored yet.
But it seems to work ok to wait for a child process to terminate. I'm afraid I might be missing something for that use case too, though, because there is a race condition between process creation and opening a monitor. If the process has already terminated we get an exception, or we might even monitor the wrong process. I'm not sure this is relevant to this issue. Maybe the API should be changed for the bigger picture but right now I cannot suggest how.