diff --git a/criu/timer.c b/criu/timer.c index 856501be6b..b8c0e32f45 100644 --- a/criu/timer.c +++ b/criu/timer.c @@ -306,6 +306,16 @@ static int encode_notify_thread_id(pid_t rtid, struct pstree_item *item, PosixTi 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; + } + pte->notify_thread_id = rtid; pte->has_notify_thread_id = true; return 0; @@ -326,8 +336,8 @@ static int encode_notify_thread_id(pid_t rtid, struct pstree_item *item, PosixTi } 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; } pte->notify_thread_id = vtid; @@ -351,10 +361,7 @@ static int encode_posix_timer(struct pstree_item *item, struct posix_timer *v, s pte->vsec = v->val.it_value.tv_sec; pte->vnsec = v->val.it_value.tv_nsec; - if (encode_notify_thread_id(vp->spt.notify_thread_id, item, pte)) - return -1; - - return 0; + return encode_notify_thread_id(vp->spt.notify_thread_id, item, pte); } int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, struct parasite_ctl *ctl, @@ -367,7 +374,7 @@ int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, struct parasite_dump_posix_timers_args *args; int ret, exit_code = -1; int args_size; - int i; + int i, j; if (core_alloc_posix_timers(tte, proc_args->timer_n, &pte)) return -1; @@ -386,14 +393,28 @@ int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args, if (ret < 0) goto end_posix; + /* + * i advances every iteration (indexes parasite-filled args->timer[]); + * j advances only for timers we keep, both the next output slot + * and the final count. Timers whose notify thread has exited are + * skipped (i.e., j <= i). + */ i = 0; + j = 0; list_for_each_entry(temp, &proc_args->timers, list) { - posix_timer_entry__init(&pte[i]); - if (encode_posix_timer(item, &args->timer[i], temp, &pte[i])) + posix_timer_entry__init(&pte[j]); + ret = encode_posix_timer(item, &args->timer[i], temp, &pte[j]); + if (ret < 0) goto end_posix; - tte->posix[i] = &pte[i]; + if (ret == 1) { + i++; + continue; + } + tte->posix[j] = &pte[j]; i++; + j++; } + tte->n_posix = j; exit_code = 0; end_posix: diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 947cafd37b..47a5fdc7b4 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -76,6 +76,7 @@ TST_NOFILE := \ pthread_timers \ pthread_timers_h \ leader_posix_timer \ + dead_thread_posix_timer \ rseq00 \ membarrier \ vdso00 \ @@ -618,6 +619,7 @@ pthread02: LDLIBS += -pthread pthread_timers: LDLIBS += -lrt -pthread pthread_timers_h: LDLIBS += -lrt -pthread leader_posix_timer: LDLIBS += -lrt -pthread +dead_thread_posix_timer: LDLIBS += -lrt -pthread different_creds: LDLIBS += -pthread sigpending: LDLIBS += -pthread sigaltstack: LDLIBS += -pthread diff --git a/test/zdtm/static/dead_thread_posix_timer.c b/test/zdtm/static/dead_thread_posix_timer.c new file mode 100644 index 0000000000..afd973ebaf --- /dev/null +++ b/test/zdtm/static/dead_thread_posix_timer.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +#ifndef SIGEV_THREAD_ID +#define SIGEV_THREAD_ID 4 +#endif + +const char *test_doc = "Check that a SIGEV_THREAD_ID timer targeting a dead thread doesn't break dump"; +const char *test_author = "Felicitas Pojtinger "; + +static timer_t timerid; + +static void *worker(void *arg) +{ + pid_t tid; + struct sigevent evp = {}; + + tid = syscall(SYS_gettid); + + evp.sigev_notify = SIGEV_THREAD_ID; +#ifdef __GLIBC__ + evp._sigev_un._tid = tid; +#else + evp.sigev_notify_thread_id = tid; +#endif + evp.sigev_signo = SIGRTMIN; + + if (timer_create(CLOCK_MONOTONIC, &evp, &timerid)) { + pr_perror("timer_create"); + return (void *)1; + } + + return NULL; +} + +int main(int argc, char **argv) +{ + pthread_t thr; + void *ret; + + test_init(argc, argv); + + if (pthread_create(&thr, NULL, worker, NULL)) { + pr_perror("pthread_create"); + return 1; + } + + if (pthread_join(thr, &ret)) { + pr_perror("pthread_join"); + return 1; + } + + if (ret != NULL) { + fail("Timer creation thread failed"); + return 1; + } + + test_daemon(); + test_waitsig(); + + pass(); + + timer_delete(timerid); + return 0; +} \ No newline at end of file diff --git a/test/zdtm/static/dead_thread_posix_timer.desc b/test/zdtm/static/dead_thread_posix_timer.desc new file mode 100644 index 0000000000..c0a31e06bd --- /dev/null +++ b/test/zdtm/static/dead_thread_posix_timer.desc @@ -0,0 +1 @@ +{'feature': 'ns_pid'}