2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-08-22 09:58:09 +00:00

zdtm: modify rseq01 to include a thread

Testing only the thread group leader is not enough and can hide bugs.

Signed-off-by: Michal Clapinski <mclapinski@google.com>
This commit is contained in:
Michal Clapinski 2023-03-30 17:47:38 +02:00 committed by Andrei Vagin
parent f8da250bb3
commit 6c728df1dc
2 changed files with 49 additions and 10 deletions

View File

@ -84,7 +84,9 @@ ptrace: LDFLAGS += -pthread
fork2: CFLAGS += -D FORK2 fork2: CFLAGS += -D FORK2
thread-bomb.o: CFLAGS += -pthread thread-bomb.o: CFLAGS += -pthread
thread-bomb: LDFLAGS += -pthread thread-bomb: LDFLAGS += -pthread
rseq01: LDLIBS += -pthread
rseq02: CFLAGS += -D NORESTART rseq02: CFLAGS += -D NORESTART
rseq02: LDLIBS += -pthread
%: %.sh %: %.sh
cp $< $@ cp $< $@

View File

@ -86,7 +86,7 @@ struct rseq {
#endif #endif
/* EOF */ /* EOF */
static volatile struct rseq *rseq_ptr; static __thread volatile struct rseq *rseq_ptr;
static __thread volatile struct rseq __rseq_abi; static __thread volatile struct rseq __rseq_abi;
static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len, int flags, uint32_t sig) static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len, int flags, uint32_t sig)
@ -119,7 +119,7 @@ static void check_thread(void)
#define rseq_after_asm_goto() asm volatile("" : : : "memory") #define rseq_after_asm_goto() asm volatile("" : : : "memory")
static int rseq_addv(intptr_t *v, intptr_t count, int cpu, bool ignore_abort) static int rseq_addv(intptr_t *v, intptr_t count, int cpu, bool ignore_abort, const char *id)
{ {
double a = 10000000000000000.0; double a = 10000000000000000.0;
double b = -1; double b = -1;
@ -177,7 +177,7 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu, bool ignore_abort)
); );
/* clang-format on */ /* clang-format on */
rseq_after_asm_goto(); rseq_after_asm_goto();
test_msg("exit %lx %lx %f %f\n", rseq_cs1, rseq_cs2, a, b); test_msg("exit %s, %lx %lx %f %f\n", id, rseq_cs1, rseq_cs2, a, b);
if (rseq_cs1 != rseq_cs2) { if (rseq_cs1 != rseq_cs2) {
/* /*
* It means that we finished critical section * It means that we finished critical section
@ -192,19 +192,45 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu, bool ignore_abort)
return 0; return 0;
abort: abort:
rseq_after_asm_goto(); rseq_after_asm_goto();
test_msg("abort %lx %lx %f %f\n", rseq_cs1, rseq_cs2, a, b); test_msg("abort %s, %lx %lx %f %f\n", id, rseq_cs1, rseq_cs2, a, b);
if (ignore_abort) if (ignore_abort)
return 0; return 0;
return -1; return -1;
} }
static task_waiter_t waiter;
static intptr_t *cpu_data;
bool ignore_abort = true;
int thread_ret;
void *thread_routine(void *args)
{
int cpu;
rseq_ptr = &__rseq_abi;
memset((void *)rseq_ptr, 0, sizeof(struct rseq));
register_thread();
task_waiter_complete(&waiter, 1);
task_waiter_wait4(&waiter, 2);
while (test_go()) {
cpu = RSEQ_ACCESS_ONCE(rseq_ptr->cpu_id_start);
thread_ret = rseq_addv(&cpu_data[cpu], 2, cpu, ignore_abort, "thread");
if (thread_ret)
break;
}
check_thread();
return NULL;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int cpu = 0; int cpu = 0;
int ret; int ret;
intptr_t *cpu_data;
long nr_cpus; long nr_cpus;
bool ignore_abort = true; pthread_t thread;
rseq_ptr = &__rseq_abi; rseq_ptr = &__rseq_abi;
memset((void *)rseq_ptr, 0, sizeof(struct rseq)); memset((void *)rseq_ptr, 0, sizeof(struct rseq));
@ -233,21 +259,32 @@ int main(int argc, char *argv[])
RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE; RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE;
#endif #endif
task_waiter_init(&waiter);
if (pthread_create(&thread, NULL, thread_routine, NULL)) {
fail("pthread_create");
exit(EXIT_FAILURE);
}
task_waiter_wait4(&waiter, 1);
test_daemon(); test_daemon();
task_waiter_complete(&waiter, 2);
while (test_go()) { while (test_go()) {
cpu = RSEQ_ACCESS_ONCE(rseq_ptr->cpu_id_start); cpu = RSEQ_ACCESS_ONCE(rseq_ptr->cpu_id_start);
ret = rseq_addv(&cpu_data[cpu], 2, cpu, ignore_abort); ret = rseq_addv(&cpu_data[cpu], 2, cpu, ignore_abort, "task");
if (ret) if (ret)
break; break;
} }
test_waitsig();
check_thread(); check_thread();
if (ret) if (pthread_join(thread, NULL)) {
fail("pthread_join");
exit(EXIT_FAILURE);
}
if (ret || thread_ret)
fail(); fail();
else else
pass(); pass();