On 03/21/2014 12:31 AM, Pavel Emelyanov wrote: > On 03/20/2014 01:39 PM, Janani Venkataraman wrote: >> Getting number of threads and their respective IDs through /proc/pid/stat and >> /proc/pid/task. >> >> The threads are then seized and interrupted. After the dump is taken they are >> detached. >> >> Signed-off-by: Janani Venkataraman >> --- >> +/* Gets the Thread IDS and siezes them */ >> +int seize_threads(int pid) >> +{ >> + char filename[40]; >> + DIR *dir; >> + int ct = 0, ret = 0, tmp_tid; >> + struct dirent *entry; >> + char state; >> + >> + ret = get_thread_count(pid); >> + if (ret == -1) >> + return -1; >> + >> + cp.thread_count = ret; >> + cp.t_id = calloc(cp.thread_count, sizeof(int)); >> + if (!cp.t_id) { >> + status = errno; >> + gencore_log("Could not allocate memory for thread_ids.\n"); >> + return -1; >> + } >> + >> + snprintf(filename, 40, "/proc/%d/task", pid); >> + dir = opendir(filename); >> + >> + while ((entry = readdir(dir))) { > This simple loop is not enough -- threads may appear and disappear while > you do the readdir and seize, so you should scan it several times to > make sure you caught all the threads. > > You can look at how this is done in CRIU in cr-dump,c:collect_threads(). > If there are any new threads generated after the process is issued a gencore, we need to ensure even those threads are captured and seized. Hence we read the /proc/pid/task, till no new threads are created. We do a readdir again and again, till we find no new threads. If a new thread is found, it is inserted in the right position. This process is repeated till readdir reads no new threads. Signed-off-by: Suzuki K. Poulose Signed-off-by: Janani Venkataraman --- src/coredump.c | 161 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 117 insertions(+), 44 deletions(-) diff --git a/src/coredump.c b/src/coredump.c index 49af7b3..2247ba2 100644 --- a/src/coredump.c +++ b/src/coredump.c @@ -93,68 +93,141 @@ void init_core(void) memset(&cp, 0, sizeof(struct core_proc)); } -/* Gets the Thread IDS and siezes them */ -int seize_threads(int pid) +/* Check if a particular TID is already added to cp.t_id */ +int search(int pid, int n) { - char filename[40]; - DIR *dir; - int ct = 0, ret = 0, tmp_tid; - struct dirent *entry; - char state; + int first, last, middle; + + first = 0; + last = n - 1; + + while( first <= last ) { + + middle = (first + last)/2; + + if ( cp.t_id[middle] < pid ) + first = middle + 1; + else if ( cp.t_id[middle] == pid ) + return 1; + else + last = middle - 1; + } - ret = get_thread_count(pid); - if (ret == -1) - return -1; + return 0; +} - cp.thread_count = ret; - cp.t_id = calloc(cp.thread_count, sizeof(int)); - if (!cp.t_id) { - status = errno; - gencore_log("Could not allocate memory for thread_ids.\n"); - return -1; +/* Insert a TID to cp.t_id */ +void insert (int tid, int n) +{ + int i, j, flag = 0; + + for (i = 0; (i < n) && (tid > cp.t_id[i]); i++); + + j = i; + while (j < n) { + cp.t_id[j + 1] = cp.t_id[j]; + j++; } + cp.t_id[i] = tid; +} + +/* + * Read the directory /proc/pid/task again and again + * till we find no new threads. + */ +int scan_threads(int pid) +{ + DIR *dir; + struct dirent *entry; + int tmp_tid, ret = 0, k = 0; + char state; + char filename[40]; + snprintf(filename, 40, "/proc/%d/task", pid); + dir = opendir(filename); while ((entry = readdir(dir))) { if (entry->d_type == DT_DIR && entry->d_name[0] != '.') { tmp_tid = atoi(entry->d_name); - ret = ptrace(PTRACE_SEIZE, tmp_tid, 0, 0); - if (ret) { - state = get_thread_status(tmp_tid); - if (state == 'Z') - goto assign; - status = errno; - gencore_log("Could not seize thread: %d\n", - tmp_tid); - break; - } - ret = ptrace(PTRACE_INTERRUPT, tmp_tid, 0, 0); - if (ret) { - state = get_thread_status(tmp_tid); - if (state == 'Z') - goto assign; - status = errno; - gencore_log("Could not interrupt thread: %d\n", - tmp_tid); - break; - } -assign: - /* If a new thread, is created after we fetch the thread_count, - * we may encounter a buffer overflow situation in the cp_tid. - * Hence we check this case and re-allocate memory if required. + /* + * Search for the thread, if not present, seize, interrupt + * and insert it in cp.t_id. */ - cp.t_id[ct++] = tmp_tid; + if (!search(tmp_tid, cp.thread_count)) { + + k++; + + ret = ptrace(PTRACE_SEIZE, tmp_tid, 0, 0); + if (ret) { + state = get_thread_status(tmp_tid); + if (state == 'Z') + goto assign; + status = errno; + gencore_log("Could not seize thread: %d\n", + tmp_tid); + break; + } + + ret = ptrace(PTRACE_INTERRUPT, tmp_tid, 0, 0); + if (ret) { + state = get_thread_status(tmp_tid); + if (state == 'Z') + goto assign; + status = errno; + gencore_log("Could not interrupt thread: %d\n", + tmp_tid); + break; + } +assign: + cp.t_id = (char *) realloc(cp.t_id, (cp.thread_count + 1) * sizeof(int)); + if (!cp.t_id) { + status = errno; + gencore_log("Could not allocate memory for thread_ids.\n"); + return -1; + } + + insert(tmp_tid, cp.thread_count); + cp.thread_count ++; + } } } - /* Reassigning based on successful seizes */ - cp.thread_count = ct; - closedir(dir); + if (!k) + return 1; + + return ret; +} + +/* Gets the Thread IDS and siezes them */ +int seize_threads(int pid) +{ + int ret = 0; + + cp.thread_count = 0; + cp.t_id = calloc(cp.thread_count, sizeof(int)); + if (!cp.t_id) { + status = errno; + gencore_log("Could not allocate memory for thread_ids.\n"); + return -1; + } + + /* + * Read the directory /proc/pid/task again and again + * till we find no new threads. + */ + + do { + ret = scan_threads(pid); + } while (ret == 0); + /* Successful seize and interrupt on all threads makes ret = 0 */ + if (ret == 1) + return 0; + return ret; } Thanks. Janani