dump: skip POSIX timers targeting dead threads#2996
Conversation
…t/dead threads from checkpoint Signed-off-by: Felicitas Pojtinger <felicitas@pojtinger.com>
There was a problem hiding this comment.
Pull request overview
This PR adjusts CRIU’s POSIX timer dump logic to tolerate SIGEV_THREAD_ID timers whose notify thread has already exited, avoiding dump/restore failures seen in PID-namespace vs host-mode scenarios, and adds ZDTM coverage for both modes.
Changes:
- Skip POSIX timers during dump when their
SIGEV_THREAD_IDnotify thread is detected as dead (instead of failing the dump). - Update the POSIX timer dump loop to compact the encoded timer list after skips (
tte->n_posixreflects only kept timers). - Add two ZDTM static tests (
dead_thread_posix_timerand_hhost-flavor variant) and wire them into the static test Makefile.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
criu/timer.c |
Detects dead notify threads and skips affected timers; compacts dumped timer entries. |
test/zdtm/static/dead_thread_posix_timer.c |
New ZDTM test creating a SIGEV_THREAD_ID timer targeting a thread that exits. |
test/zdtm/static/dead_thread_posix_timer_h.c |
Host-flavor variant of the same test scenario. |
test/zdtm/static/dead_thread_posix_timer.desc |
Runs the test with ns_pid feature enabled. |
test/zdtm/static/dead_thread_posix_timer_h.desc |
Runs the test in host flavor ({'flavor': 'h'}). |
test/zdtm/static/Makefile |
Registers the new tests and links them with -lrt -pthread. |
| for (i = 0; i < item->nr_threads; i++) { | ||
| if (item->threads[i].real != rtid) | ||
| continue; | ||
|
|
||
| vtid = item->threads[i].ns[0].virt; | ||
| break; | ||
| } | ||
|
|
||
| if (vtid == 0) { | ||
| pr_err("Unable to convert the notify thread id %d\n", rtid); | ||
| return -1; | ||
| pr_warn("Skipping timer because notify thread %d is dead\n", rtid); | ||
| return 1; | ||
| } |
There was a problem hiding this comment.
In the pid-namespace path, vtid==0 is treated as “notify thread is dead” and the timer is skipped. That also covers the case where the thread is found but its ns virt tid is unexpectedly 0 (e.g., a regression in thread nsid collection), which would silently drop a valid timer and hide the underlying bug. Consider tracking whether the thread was found separately: only skip when the notify thread isn’t present in item->threads, and keep vtid==0 as a hard error if the thread was found but conversion failed.
| static int encode_notify_thread_id(pid_t rtid, struct pstree_item *item, PosixTimerEntry *pte) | ||
| { | ||
| pid_t vtid = 0; | ||
| int i; | ||
|
|
||
| if (rtid == 0) | ||
| return 0; | ||
|
|
||
| if (!(root_ns_mask & CLONE_NEWPID)) { | ||
| /* Non-pid-namespace case */ | ||
| for (i = 0; i < item->nr_threads; i++) { | ||
| if (item->threads[i].real == rtid) | ||
| break; | ||
| } | ||
|
|
||
| if (i == item->nr_threads) { | ||
| pr_warn("Skipping timer because notify thread %d is dead\n", rtid); | ||
| return 1; | ||
| } |
There was a problem hiding this comment.
encode_notify_thread_id now uses return value 1 to signal “skip this timer”, while -1 still means error. Since this is a new non-obvious contract, it’s easy for future callers to mishandle. Consider introducing a named constant/enum for the skip return code and documenting it in the function comment (or using a more conventional negative errno for “skip”).
| pthread_timers_h \ | ||
| leader_posix_timer \ | ||
| dead_thread_posix_timer \ | ||
| dead_thread_posix_timer_nons \ |
There was a problem hiding this comment.
It isn't required. The previous test will be executed in non-ns, ns and uns envs.
There was a problem hiding this comment.
I think this was a review on an older commit pushed as part of this PR? From the PR description:
I added dead_thread_posix_timer_h since I wanted to specifically trigger the restore failure case, which needs host mode. I followed the convention that pthread_timers.c and pthread_timers_h.c uses.
I'll remove it regardless, it was mostly used as a reproducer initially. Resolved via c245960
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## criu-dev #2996 +/- ##
============================================
+ Coverage 57.21% 57.23% +0.01%
============================================
Files 154 154
Lines 40400 40413 +13
Branches 8857 8859 +2
============================================
+ Hits 23115 23130 +15
+ Misses 17021 17019 -2
Partials 264 264 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
@pojntfx Would it be possible to add commit messages? |
3526179 to
f4e3b56
Compare
|
@rst0git @avagin Thank you for your reviews. I collapsed it into a single commit and rebased on the latest
When collapsing them into a single new commit I also added a body based on the PR description. Let me know if I should make any further changes :) |
@pojntfx Thank you! Could you please separate this into two commits? The PR currently squashes the core fix and the ZDTM test into a single commit. According to the Contribution Guidelines, each logical change should be separated into a distinct patch. |
When a POSIX timer uses SIGEV_THREAD_ID and the target thread has
exited, dump fails in PID namespaces ("Unable to convert the notify
thread id") and restore fails without PID namespaces (EINVAL from
timer_create()). We noticed this when an application switched from
Java 8 to Java 21.
Detect dead notify threads during dump and skip the timer instead
of failing. The kernel already silently drops signals from these
timers, so skipping them during dump is safe.
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Felicitas Pojtinger <felicitas@pojtinger.com>
Add a test that creates a SIGEV_THREAD_ID POSIX timer pointing at a thread which then exits before checkpoint. Dump and restore must succeed by skipping the timer rather than failing. Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Felicitas Pojtinger <felicitas@pojtinger.com>
f4e3b56 to
5b30f6d
Compare
|
@3idey Done! |

What:
When a POSIX timer uses SIGEV_THREAD_ID and the target thread has exited, dump fails in PID namespaces (
Unable to convert the notify thread id) and restore fails without PID namespaces (EINVALfrom timer_create()). We noticed this when an application switched from Java 8 to Java 21.How:
To fix this, this PR detects dead notify threads during dump and skips the timer instead of failing. The kernel already silently drops signals from these timers, so skipping them during dump is safe.
Tests:
zdtm/static/dead_thread_posix_timer-zdtm/static/dead_thread_posix_timer_hI addeddead_thread_posix_timer_hsince I wanted to specifically trigger the restore failure case, which needs host mode. I followed the convention thatpthread_timers.candpthread_timers_h.cuses.