/** * Registers a new thread to the runtime system. This includes * initialization of the hardware performance counters */ void rec_sched_register_thread(pid_t parent, pid_t child, int flags) { struct tasklist_entry* entry = sys_malloc_zero(sizeof(*entry)); struct task* t = &entry->t; assert(child > 0 && child < MAX_TID); t->status = 0; t->rec_tid = t->tid = child; t->child_mem_fd = sys_open_child_mem(child); push_placeholder_event(t); if (parent) { struct task* parent_t = get_task(parent); struct sighandlers* parent_handlers = parent_t->sighandlers; t->syscallbuf_lib_start = parent_t->syscallbuf_lib_start; t->syscallbuf_lib_end = parent_t->syscallbuf_lib_end; t->task_group = (SHARE_TASK_GROUP & flags) ? task_group_add_and_ref(parent_t->task_group, t) : task_group_new_and_add(t); t->sighandlers = (SHARE_SIGHANDLERS & flags) ? sighandlers_ref(parent_handlers) : sighandlers_copy(parent_handlers); } else { /* After the first task is forked, we always need to * know the parent in order to initialize some task * state. */ static int is_first_task = 1; assert(is_first_task); is_first_task = 0; t->task_group = task_group_new_and_add(t); /* The very first task we fork inherits our * sighandlers (which should all be default at this * point, but ...). From there on, new tasks will * transitively inherit from this first task. */ t->sighandlers = sighandlers_new(); sighandlers_init_from_current_process(t->sighandlers); } /* These will be initialized when the syscall buffer is. */ t->desched_fd = t->desched_fd_child = -1; sys_ptrace_setup(child); init_hpc(t); start_hpc(t, rr_flags()->max_rbc); CIRCLEQ_INSERT_TAIL(&head, entry, entries); num_active_threads++; tid_to_entry[child] = entry; }
/** * main replayer method */ static void start(int option, int argc, char* argv[], char** envp) { pid_t pid; int status, fake_argc; if (option == RECORD) { copy_executable(argv[2]); if (access(__executable, X_OK)) { printf("The specified file '%s' does not exist or is not executable\n", __executable); return; } /* create directory for trace files */ setup_trace_dir(0); /* initialize trace files */ open_trace_files(); init_trace_files(); copy_argv(argc, argv); copy_envp(envp); record_argv_envp(argc, __argv, __envp); close_trace_files(); pid = sys_fork(); /* child process */ if (pid == 0) { sys_start_trace(__executable, __argv, __envp); /* parent process */ } else { child = pid; /* make sure that the child process dies when the master process gets interrupted */ install_signal_handler(); /* sync with the child process */ sys_waitpid(pid, &status); /* configure the child process to get a message upon a thread start, fork(), etc. */ sys_ptrace_setup(pid); /* initialize stuff */ init_libpfm(); /* initialize the trace file here -- we need to record argc and envp */ open_trace_files(); /* register thread at the scheduler and start the HPC */ rec_sched_register_thread(0, pid); /* perform the action recording */ fprintf(stderr, "start recording...\n"); start_recording(); fprintf(stderr, "done recording -- cleaning up\n"); /* cleanup all initialized data-structures */ close_trace_files(); close_libpfm(); } /* replayer code comes here */ } else if (option == REPLAY) { init_environment(argv[2], &fake_argc, __argv, __envp); copy_executable(__argv[0]); if (access(__executable, X_OK)) { printf("The specified file '%s' does not exist or is not executable\n", __executable); return; } pid = sys_fork(); //child process if (pid == 0) { sys_start_trace(__executable, __argv, __envp); /* parent process */ } else { child = pid; /* make sure that the child process dies when the master process gets interrupted */ install_signal_handler(); sys_waitpid(pid, &status); sys_ptrace_setup(pid); /* initialize stuff */ init_libpfm(); rep_sched_init(); /* sets the file pointer to the first trace entry */ read_trace_init(argv[2]); pid_t rec_main_thread = get_recorded_main_thread(); rep_sched_register_thread(pid, rec_main_thread); /* main loop */ replay(); /* thread wants to exit*/ close_libpfm(); read_trace_close(); rep_sched_close(); } } }