static int handshake_with_thread() { udi_errmsg errmsg; errmsg.size = ERRMSG_SIZE; errmsg.msg[ERRMSG_SIZE-1] = '\0'; unsigned char trigger = 0; if ( read(thread_barrier.read_handle, &trigger, 1) != 1 ) { udi_log("failed to read trigger from pipe: %e", errno); return RESULT_ERROR; } if ( trigger != sentinel ) { udi_abort(); return RESULT_ERROR; } thread *request_thr = NULL; int result = wait_and_execute_command(&errmsg, &request_thr); if (result == RESULT_ERROR) { udi_log("failed to handle command after thread create"); udi_abort(); } release_other_threads(); return result; }
static void report_thread_death() { // block signals while reporting the thread death sigset_t block_set; sigset_t original_set; sigfillset(&block_set); if (setsigmask(SIG_SETMASK, &block_set, &original_set) == -1) { udi_abort(); } udi_log("thread %a dying", get_user_thread_id()); thread *thr = get_current_thread(); thr->stack_event_pending = 1; int block_result = block_other_threads(); if (block_result < 0) { udi_log("failed to block other threads"); udi_abort(); return; } if (block_result > 0) { // the thread should always eventually be the control thread udi_abort(); } else { thr->stack_event_pending = 0; int death_result = handle_thread_death(); if (death_result != RESULT_SUCCESS) { udi_log("failed to handle thread death"); udi_abort(); return; } udi_errmsg errmsg; errmsg.size = ERRMSG_SIZE; errmsg.msg[ERRMSG_SIZE-1] = '\0'; thread *request_thr = NULL; int request_result = wait_and_execute_command(&errmsg, &request_thr); if (request_result == RESULT_ERROR) { udi_log("failed to handle command after thread death"); udi_abort(); } release_other_threads(); } setsigmask(SIG_SETMASK, &original_set, NULL); }
/** * Gets the specified register from the context * * @param reg the register to retrieve * @param context the context * * @return the value from the register */ unsigned long get_register_ud_type(ud_type_t reg, const void *context) { const ucontext_t *u_context = (const ucontext_t *)context; int offset = get_reg_context_offset(reg); if ( offset == -1 ) { udi_abort(__FILE__, __LINE__); } return u_context->uc_mcontext.gregs[offset]; }
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { udi_log("thread %a creating a new thread", get_user_thread_id()); int block_result = block_other_threads(); if (block_result < 0) { udi_log("failed to block other threads"); udi_abort(); return ENOMEM; } struct wrapped_thread_context *context = (struct wrapped_thread_context *)udi_malloc(sizeof(struct wrapped_thread_context)); context->start_routine = start_routine; context->arg = arg; context->creator_tid = get_user_thread_id(); int control_pipe[2]; if ( init_control_pipe(control_pipe) != 0 ) { return ENOMEM; } int create_result = real_pthread_create(thread, attr, wrapped_start_routine, context); if (create_result == 0) { int handshake_result = handshake_with_thread(); if (handshake_result != RESULT_SUCCESS) { return ENOMEM; } } else { if (get_multithread_capable()) { close(control_pipe[0]); close(control_pipe[1]); } } return create_result; }
static void *wrapped_start_routine(void *arg) { struct wrapped_thread_context *context = (struct wrapped_thread_context *)arg; void *ret_value = NULL; do { int create_result = handle_thread_create(context->creator_tid); if (create_result != RESULT_SUCCESS) { udi_log("failed to handle thread creation"); udi_abort(); break; } ret_value = context->start_routine(context->arg); report_thread_death(); }while(0); udi_free(context); return ret_value; }
static int handle_thread_create(uint64_t creator_thr) { int result; uint64_t tid; udi_errmsg errmsg; errmsg.size = ERRMSG_SIZE; errmsg.msg[ERRMSG_SIZE-1] = '\0'; do { tid = get_user_thread_id(); udi_log("thread create event for %a", tid); thread *thr = create_thread(tid); if (thr == NULL) { result = RESULT_ERROR; break; } if ( thread_create_callback(thr, &errmsg) != 0 ) { result = RESULT_ERROR; break; } result = handle_thread_create_event(creator_thr, tid, &errmsg); if (result != RESULT_SUCCESS) { break; } result = thread_create_handshake(thr, &errmsg); if (result != RESULT_SUCCESS) { break; } if ( write(thread_barrier.write_handle, &sentinel, 1) != 1 ) { udi_log("failed to write trigger to pipe: %e", errno); result = RESULT_ERROR; break; } unsigned char trigger = 0; while (trigger == 0) { int trigger_read_result = read(thr->control_read, &trigger, 1); if (trigger_read_result == -1) { if (errno == EINTR) { continue; } udi_log("failed to read control trigger from pipe: %e", errno); result = RESULT_ERROR; break; } result = RESULT_SUCCESS; } if (result != RESULT_SUCCESS) { break; } if ( trigger != sentinel ) { udi_abort(); } }while(0); if ( result != RESULT_SUCCESS ) { udi_log("failed to report thread create of %a: %s", tid, errmsg.msg); } return result; }