/* * Threads restoration via sigreturn. Note it's locked * routine and calls for unlock at the end. */ long __export_restore_thread(struct thread_restore_args *args) { struct rt_sigframe *rt_sigframe; k_rtsigset_t to_block; unsigned long new_sp; int my_pid = sys_gettid(); int ret; if (my_pid != args->pid) { pr_err("Thread pid mismatch %d/%d\n", my_pid, args->pid); goto core_restore_end; } /* All signals must be handled by thread leader */ ksigfillset(&to_block); ret = sys_sigprocmask(SIG_SETMASK, &to_block, NULL, sizeof(k_rtsigset_t)); if (ret) { pr_err("Unable to block signals %d", ret); goto core_restore_end; } rt_sigframe = (void *)args->mem_zone.rt_sigframe; if (restore_thread_common(rt_sigframe, args)) goto core_restore_end; ret = restore_creds(&args->ta->creds); if (ret) goto core_restore_end; ret = restore_dumpable_flag(&args->ta->mm); if (ret) goto core_restore_end; pr_info("%ld: Restored\n", sys_gettid()); restore_finish_stage(CR_STATE_RESTORE); if (restore_signals(args->siginfo, args->siginfo_nr, false)) goto core_restore_end; restore_finish_stage(CR_STATE_RESTORE_SIGCHLD); restore_pdeath_sig(args); restore_finish_stage(CR_STATE_RESTORE_CREDS); futex_dec_and_wake(&thread_inprogress); new_sp = (long)rt_sigframe + SIGFRAME_OFFSET; rst_sigreturn(new_sp); core_restore_end: pr_err("Restorer abnormal termination for %ld\n", sys_getpid()); futex_abort_and_wake(&task_entries->nr_in_progress); sys_exit_group(1); return -1; }
void xmutex_unlock(struct xmutex * lock, sigset_t sigset) { TRACE(MUTEX, "thread %d:%d is unlocking %p\n", sys_getpid(), sys_gettid(), lock); /* atomic_dec(&lock->val) != 1 */ if (!atomic_dec_and_test(&lock->val)) { atomic_set(&lock->val, 0); futex_wake(&lock->val, 1); } restore_signals(sigset); TRACE(MUTEX, "thread %d:%d unlocked %p\n", sys_getpid(), sys_gettid(), lock); }
int main(int argc, char** argv) { int num_syscalls; int child; int i; bad_breakpoint(); test_assert(argc == 2); num_syscalls = atoi(argv[1]); atomic_printf("%d: running %d syscalls ...\n", getpid(), num_syscalls); for (i = 0; i < num_syscalls; ++i) { sys_gettid(); } if (0 == (child = fork())) { good_breakpoint(); exit(0); } atomic_printf("child %d\n", child); waitpid(child, NULL, 0); atomic_puts("EXIT-SUCCESS"); return 0; }
static int open_counter(size_t nr_switches) { struct perf_event_attr attr; int fd; struct f_owner_ex own; memset(&attr, 0, sizeof(attr)); attr.size = sizeof(attr); attr.type = PERF_TYPE_SOFTWARE; attr.config = PERF_COUNT_SW_CONTEXT_SWITCHES; attr.disabled = 1; attr.sample_period = nr_switches; fd = sys_perf_event_open(&attr, 0/*self*/, -1/*any cpu*/, -1, 0); if (0 > fd) err(1, "perf_event_open(cs, period=%u)", nr_switches); if (fcntl(fd, F_SETFL, O_ASYNC)) err(1, "fcntl(O_ASYNC)"); own.type = F_OWNER_TID; own.pid = sys_gettid(); if (fcntl(fd, F_SETOWN_EX, &own)) err(1, "fcntl(SETOWN_EX)"); if (fcntl(fd, F_SETSIG, SIGIO)) err(1, "fcntl(SETSIG, SIGIO)"); return fd; }
int main(void) { signal(SIGUSR1, sighandler); signal(SIGUSR2, sighandler); tgkill(getpid(), sys_gettid(), SIGUSR1); tgkill(getpid(), sys_gettid(), SIGUSR2); test_assert(2 == num_signals_caught); syscall(SYS_tkill, sys_gettid(), SIGUSR1); syscall(SYS_tkill, sys_gettid(), SIGUSR2); test_assert(4 == num_signals_caught); atomic_puts("EXIT-SUCCESS"); return 0; }
static int in_dirlist(char *path, char *dirs) { char *p; int match = 0; while (*dirs && !match) { p = path; match = 1; while ( *dirs != '\0' && *dirs != ':' ) { if (*p != *dirs) match = 0; if (*p) p++; dirs++; } if (*p != '/') match = 0; if (*dirs != '\0') dirs++; } if (match) sys_gettid(); return match; }
static int restore_signals(siginfo_t *ptr, int nr, bool group) { int ret, i; k_rtsigset_t to_block; ksigfillset(&to_block); ret = sys_sigprocmask(SIG_SETMASK, &to_block, NULL, sizeof(k_rtsigset_t)); if (ret) { pr_err("Unable to block signals %d", ret); return -1; } for (i = 0; i < nr; i++) { siginfo_t *info = ptr + i; pr_info("Restore signal %d group %d\n", info->si_signo, group); if (group) ret = sys_rt_sigqueueinfo(sys_getpid(), info->si_signo, info); else ret = sys_rt_tgsigqueueinfo(sys_getpid(), sys_gettid(), info->si_signo, info); if (ret) { pr_err("Unable to send siginfo %d %x with code %d\n", info->si_signo, info->si_code, ret); return -1;; } } return 0; }
static void* reader_thread(void* dontcare) { char token = start_token; struct sigaction act; int readsock = sockfds[1]; char c = sentinel_token; int flags = 0; reader_tid = sys_gettid(); flags = SA_RESTART; memset(&act, 0, sizeof(act)); act.sa_handler = sighandler; act.sa_flags = flags; sigaction(SIGUSR1, &act, NULL); memset(&act, 0, sizeof(act)); act.sa_handler = sighandler2; act.sa_flags = flags; sigaction(SIGUSR2, &act, NULL); pthread_barrier_wait(&barrier); atomic_puts("r: blocking on read, awaiting signal ..."); test_assert(1 == read(readsock, &c, sizeof(c))); test_assert(2 == reader_caught_signal); token += reader_caught_signal; atomic_printf("r: ... read level 0 '%c'\n", c); test_assert(c == token); return NULL; }
int main(int argc, char *argv[]) { const size_t stack_size = 1 << 20; void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); int pid; sigset_t set; sys_gettid(); /* NB: no syscalls in between the sys_gettid() above and this * clone(). */ breakpoint(); /* Warning: strace gets the parameter order wrong and will print child_tidptr as 0 here. */ pid = clone(child, stack + stack_size, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | CLONE_SIGHAND | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID, NULL, &child_tid, NULL, &child_tid); atomic_printf("clone()d pid: %d\n", pid); test_assert(pid > 0); futex(&child_tid, FUTEX_WAIT, pid, NULL, NULL, 0); test_assert(child_tid_copy == pid); /* clone() should have cleared child_tid now */ test_assert(child_tid == 0); sys_gettid(); sigfillset(&set); test_assert(0 == sigprocmask(SIG_BLOCK, &set, NULL)); /* NB: no syscalls in between the sys_gettid() above and this * clone(). */ breakpoint(); pid = clone(child, stack + stack_size, CLONE_SIGHAND /*must also have CLONE_VM*/, NULL, NULL, NULL); atomic_printf("clone(CLONE_SIGHAND)'d pid: %d\n", pid); test_assert(-1 == pid); atomic_puts("EXIT-SUCCESS"); return 0; }
long hio_gettid(void) { if (!syscall_isset(__NR_gettid, current->aspace->hio_syscall_mask)) return sys_gettid(); return hio_format_and_exec_syscall(__NR_gettid, 0); }
static void sighandler(int sig) { test_assert(sys_gettid() == reader_tid); ++reader_caught_signal; atomic_puts("r: in sighandler level 1 ..."); cond_wait(1); atomic_puts("r: ... wait done"); }
static void *child_thread_func(void *arg) { child_tid = sys_gettid(); TST_CHECKPOINT_WAKE_AND_WAIT(0); return arg; }
sigset_t xmutex_lock(struct xmutex * lock) { TRACE(MUTEX, "thread %d:%d is locking %p\n", sys_getpid(), sys_gettid(), lock); int c; sigset_t sigset = block_signals(); if ((c = atomic_cmpxchg(&lock->val, 0, 1)) != 0) { do { if (c == 2 || atomic_cmpxchg(&lock->val, 1, 2) != 0) futex_wait(&lock->val, 2); } while ((c = atomic_cmpxchg(&lock->val, 0, 2)) != 0); } TRACE(MUTEX, "thread %d:%d gained lock %p\n", sys_getpid(), sys_gettid(), lock); return sigset; }
/* * Threads restoration via sigreturn. Note it's locked * routine and calls for unlock at the end. */ long __export_restore_thread(struct thread_restore_args *args) { struct rt_sigframe *rt_sigframe; unsigned long new_sp; int my_pid = sys_gettid(); int ret; if (my_pid != args->pid) { pr_err("Thread pid mismatch %d/%d\n", my_pid, args->pid); goto core_restore_end; } rt_sigframe = (void *)args->mem_zone.rt_sigframe + 8; if (restore_thread_common(rt_sigframe, args)) goto core_restore_end; mutex_unlock(&args->ta->rst_lock); ret = restore_creds(&args->ta->creds); if (ret) goto core_restore_end; pr_info("%ld: Restored\n", sys_gettid()); restore_finish_stage(CR_STATE_RESTORE); if (restore_signals(args->siginfo, args->siginfo_nr, false)) goto core_restore_end; restore_finish_stage(CR_STATE_RESTORE_SIGCHLD); restore_finish_stage(CR_STATE_RESTORE_CREDS); futex_dec_and_wake(&thread_inprogress); new_sp = (long)rt_sigframe + SIGFRAME_OFFSET; ARCH_RT_SIGRETURN(new_sp); core_restore_end: pr_err("Restorer abnormal termination for %ld\n", sys_getpid()); futex_abort_and_wake(&task_entries->nr_in_progress); sys_exit_group(1); return -1; }
static int dump_tid_info(struct parasite_dump_tid_info *args) { int ret; ret = sys_prctl(PR_GET_TID_ADDRESS, (unsigned long) &args->tid_addr, 0, 0, 0); if (ret) return ret; args->tid = sys_gettid(); return 0; }
static void sighandler2(int sig) { char c = sentinel_token; test_assert(sys_gettid() == reader_tid); ++reader_caught_signal; atomic_puts("r: in sighandler level 2 ..."); test_assert(1 == read(sockfds[1], &c, sizeof(c))); atomic_printf("r: ... read level 2 '%c'\n", c); test_assert(c == start_token); }
static int fini_thread(void) { struct tid_state_s *s; s = find_thread_state(sys_gettid()); if (!s) return -ENOENT; if (s->use_sig_blocked) return sys_sigprocmask(SIG_SETMASK, &s->sig_blocked, NULL, sizeof(k_rtsigset_t)); return 0; }
static void* child_thread(void* num_syscallsp) { int num_syscalls = (uintptr_t)num_syscallsp; int i; first_breakpoint(); /* NB: this test assumes that gettid() produces at least one * trace event per syscall. */ atomic_printf("%d: running %d syscalls ...\n", getpid(), num_syscalls); for (i = 0; i < num_syscalls; ++i) { (void)sys_gettid(); } second_breakpoint(); return NULL; }
static void setup(void) { sigset_t sigusr1; pthread_t defunct_thread; sigemptyset(&sigusr1); sigaddset(&sigusr1, SIGUSR1); pthread_sigmask(SIG_BLOCK, &sigusr1, NULL); parent_tgid = getpid(); parent_tid = sys_gettid(); SAFE_PTHREAD_CREATE(&child_thread, NULL, child_thread_func, NULL); TST_CHECKPOINT_WAIT(0); SAFE_PTHREAD_CREATE(&defunct_thread, NULL, defunct_thread_func, NULL); SAFE_PTHREAD_JOIN(defunct_thread, NULL); }
static int init_thread(void) { k_rtsigset_t to_block; int ret; if (next_tid_state >= nr_tid_state) return -ENOMEM; ksigfillset(&to_block); ret = sys_sigprocmask(SIG_SETMASK, &to_block, &tid_state[next_tid_state].sig_blocked, sizeof(k_rtsigset_t)); if (ret >= 0) tid_state[next_tid_state].use_sig_blocked = true; tid_state[next_tid_state].tid = sys_gettid(); next_tid_state++; return ret; }
static int restore_signals(siginfo_t *ptr, int nr, bool group) { int ret, i; for (i = 0; i < nr; i++) { siginfo_t *info = ptr + i; pr_info("Restore signal %d group %d\n", info->si_signo, group); if (group) ret = sys_rt_sigqueueinfo(sys_getpid(), info->si_signo, info); else ret = sys_rt_tgsigqueueinfo(sys_getpid(), sys_gettid(), info->si_signo, info); if (ret) { pr_err("Unable to send siginfo %d %x with code %d\n", info->si_signo, info->si_code, ret); return -1;; } } return 0; }
static int dump_thread(struct parasite_dump_thread *args) { pid_t tid = sys_gettid(); struct tid_state_s *s; int ret; s = find_thread_state(tid); if (!s) return -ENOENT; if (!s->use_sig_blocked) return -EINVAL; ret = sys_prctl(PR_GET_TID_ADDRESS, (unsigned long) &args->tid_addr, 0, 0, 0); if (ret) return ret; args->blocked = s->sig_blocked; args->tid = tid; args->tls = arch_get_tls(); return 0; }
static void unblock_signals(void) { sigset_t set; sigfillset(&set); test_assert(0 == pthread_sigmask(SIG_UNBLOCK, &set, NULL)); atomic_printf(" %d: unblocked all sigs\n", sys_gettid()); }
static int sockfds[2]; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; static void cond_wait(int secs) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += secs; test_assert(ETIMEDOUT == pthread_cond_timedwait(&cond, &lock, &ts)); } static void sighandler(__attribute__((unused)) int sig) { test_assert(sys_gettid() == reader_tid); ++reader_caught_signal; atomic_puts("r: in sighandler level 1 ..."); cond_wait(1); atomic_puts("r: ... wait done"); } static void* reader_thread(__attribute__((unused)) void* dontcare) { char token = start_token; struct sigaction act; int readsock = sockfds[1]; char c = sentinel_token; int flags = 0; pthread_mutex_lock(&lock);
static void fin_sleep(int secs) { struct timespec req = {.tv_sec = secs }; struct timespec rem = {.tv_sec = -1, .tv_nsec = -1 }; test_assert(0 == nanosleep(&req, &rem)); test_assert(-1 == rem.tv_sec && -1 == rem.tv_nsec); } static void sighandler(__attribute__((unused)) int sig) { test_assert(sys_gettid() == reader_tid); ++reader_caught_signal; atomic_puts("r: in sighandler level 1 ..."); intr_sleep(2); } static void sighandler2(__attribute__((unused)) int sig) { test_assert(sys_gettid() == reader_tid); ++reader_caught_signal; atomic_puts("r: in sighandler level 2 ..."); fin_sleep(1); } static void* reader_thread(__attribute__((unused)) void* dontcare) { struct sigaction act; int flags = 0; reader_tid = sys_gettid(); act.sa_handler = sighandler; sigemptyset(&act.sa_mask); act.sa_flags = flags; sigaction(SIGUSR1, &act, NULL); act.sa_handler = sighandler2; sigemptyset(&act.sa_mask); act.sa_flags = flags; sigaction(SIGUSR2, &act, NULL); pthread_barrier_wait(&barrier); atomic_puts("r: blocking on sleep, awaiting signal ..."); intr_sleep(3); return NULL; } int main(void) { struct timeval ts; /* (Kick on the syscallbuf if it's enabled.) */ gettimeofday(&ts, NULL); pthread_barrier_init(&barrier, NULL, 2); pthread_create(&reader, NULL, reader_thread, NULL); pthread_barrier_wait(&barrier); /* Force a blocked read() that's interrupted by a SIGUSR1, * which then itself blocks on read() and succeeds. */ atomic_puts("M: sleeping ..."); usleep(500000); atomic_puts("M: killing reader ..."); pthread_kill(reader, SIGUSR1); atomic_puts("M: (quick nap)"); usleep(100000); atomic_puts("M: killing reader again ..."); pthread_kill(reader, SIGUSR2); atomic_puts("M: ... done"); pthread_join(reader, NULL); atomic_puts("EXIT-SUCCESS"); return 0; }
static void *defunct_thread_func(void *arg) { defunct_tid = sys_gettid(); return arg; }
static void write_tid(void) { pid_t tid = sys_gettid(); test_assert(sizeof(tid) == write(tid_pipe[1], &tid, sizeof(tid))); }
/* -*- Mode: C; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */ #include "rrutil.h" static int v; static int* p; static int pipe_fds[2]; static void* run_thread(__attribute__((unused)) void* p) { char ch; test_assert(1 == read(pipe_fds[0], &ch, 1)); test_assert(sys_gettid() == syscall(SYS_set_tid_address, &v)); return NULL; } static void* run_thread2(__attribute__((unused)) void* q) { test_assert(sys_gettid() == syscall(SYS_set_tid_address, p)); test_assert(1 == write(pipe_fds[1], "x", 1)); return NULL; } int main(void) { pthread_t thread; char ch; test_assert(0 == pipe(pipe_fds)); v = 1; pthread_create(&thread, NULL, run_thread, NULL); test_assert(1 == write(pipe_fds[1], "x", 1)); int ret = syscall(SYS_futex, &v, FUTEX_WAIT, 1, NULL, NULL, 0);
void task_waiter_complete_current(task_waiter_t *t) { return task_waiter_complete(t, (int)sys_gettid()); }
static void sighandler(int sig) { atomic_printf("Task %d got signal %d\n", sys_gettid(), sig); ++num_signals_caught; }