2011-05-20 Luis Machado * linux-low.c (set_resume_kind_stop): New function. (linux_attach): Scan for existing threads when attaching to a process. --- .pc/stop_threads.diff/gdb/gdbserver/linux-low.c 2011-05-20 10:37:41.915272001 -0300 +++ gdb/gdbserver/linux-low.c 2011-05-20 14:25:59.019272001 -0300 @@ -561,6 +561,16 @@ linux_create_inferior (char *program, ch return pid; } +/* Set a threads's last_resume_kind to RESUME_STOP. */ + +static void +set_resume_kind_stop (struct inferior_list_entry *entry) +{ + struct thread_info *thread= (struct thread_info *) entry; + + thread->last_resume_kind = resume_stop; +} + /* Attach to an inferior process. */ static void @@ -646,22 +656,100 @@ linux_attach_lwp (unsigned long lwpid) linux_attach_lwp_1 (lwpid, 0); } +/* Attach to PID. If PID is the tgdi, attach to it and stop + all of its threads. */ + int linux_attach (unsigned long pid) { + DIR *dir; + char pathname[128]; + int is_tgid = 0; + FILE *fd; + + /* Attach to PID. We will check for other threads + soon. */ linux_attach_lwp_1 (pid, 1); - linux_add_process (pid, 1); - if (!non_stop) + /* Find out what is the tgid of this lwp. */ + sprintf (pathname, "/proc/%ld/stat", pid); + + fd = fopen (pathname, "r"); + + if (fd != NULL) { - struct thread_info *thread; + int proc_id, ppid, pgrp; + char comm[NAME_MAX + 1], state; - /* Don't ignore the initial SIGSTOP if we just attached to this - process. It will be collected by wait shortly. */ - thread = find_thread_ptid (ptid_build (pid, pid, 0)); - thread->last_resume_kind = resume_stop; + fscanf (fd, "%d %s %c %d %d", &proc_id, comm, &state, &ppid, &pgrp); + fclose (fd); + + if (pgrp == pid) + is_tgid = 1; + } + else + { + fprintf (stderr, "Could not open /proc/%ld/stat.\n", pid); + fflush (stderr); } + sprintf (pathname, "/proc/%ld/task", pid); + + dir = opendir (pathname); + + if (!dir) + { + fprintf (stderr, "Could not open /proc/%ld/task.\n", pid); + fflush (stderr); + } + else if (is_tgid) + { + /* At this point we attached to the tgid. Scan the task for + existing threads. */ + unsigned long lwp; + int new_threads_found; + int iterations = 0; + struct dirent *dp; + + while (iterations < 2) + { + new_threads_found = 0; + /* Add all the other threads. While we go through the + threads, new threads may be spawned. Cycle through + the list of threads until we have done two iterations without + finding new threads. */ + while ((dp = readdir (dir)) != NULL) + { + /* Fetch one lwp. */ + lwp = strtoul (dp->d_name, NULL, 10); + + /* Is this a new thread? */ + if (lwp && find_thread_ptid (ptid_build (pid, lwp, 0)) == NULL) + { + linux_attach_lwp_1 (lwp, 0); + new_threads_found++; + + if (debug_threads) + fprintf (stderr, "Found and attached to new lwp %ld\n", lwp); + } + } + + if (!new_threads_found) + iterations++; + else + iterations = 0; + + rewinddir (dir); + } + closedir (dir); + } + + linux_add_process (pid, 1); + + /* Mark the threads as stopped. */ + if (!non_stop) + for_each_inferior (&all_threads, set_resume_kind_stop); + return 0; }