Implement core awareness.
* bcache.c (compare_ints): Remove (print_percentage): Use compare_positive_ints. * defs.h (compare_positive_ints): Declare. * linux-nat.h (struct lin_lwp): New field core. (linux_nat_core_of_thread_1): Declare. * linux-nat.c (add_lwp): Init the 'core' field. (linux_nat_wait_1): Record the core. (linux_nat_core_of_thread_1, linux_nat_core_of_thread): New. (linux_nat_add_target): Register the above. * linux-thread-db.c (update_thread_core): New. (thread_db_find_new_threads): Update core information for every thread. * remote.c (struct private_thread_info): New. (free_private_thread_info, demand_private_info): New. (PACKET_qXfer_threads, use_osdata_threads): New. (struct thread_item, threads_parsing_context (start_thread, end_thread, thread_attributes) (thread_children, threads_children, threads_elements): New. (remote_threads_info): Try qXfer:threads before anything else. (remote_protocol_packets): Register qXfer:threads. (remote_open_1): Init use_osdata_threads. (struct stop_reply): New field 'core'. (remote_parse_stop_reply): Parse core number. (process_stop_reply): Record core number. (remote_xfer_partial): Handle qXfer:threads. (remote_core_of_thread): New. (init_remote_ops): Register remote_core_of_thread. (_initialize_remote): Register qXfer:read. * target.c (target_core_of_thread): New * target.h (enum target_object): New value TARGET_OBJECT_THREADS. (struct target_ops): New field to_core_of_threads. (target_core_of_thread): Declare. * gdbthread.h (struct thread_info): New field private_dtor. * thread.c (print_thread_info): Report the core. * ui-out.c (MAX_UI_OUT_LEVELS): Increase. * utils.c (compare_positive_ints): New. * features/threads.dtd: New. * mi/mi-interp.c (mi_on_normal_stop): Report the core. * mi/mi-main.c (struct collect_cores_data, collect_cores) (do_nothing, free_vector_of_osdata_items) (splay_tree_int_comparator, free_splay_tree): New. (print_one_inferior_data): Implemented printing of selected inferiors. Collect and print cores. (output_cores): New. (mi_cmd_list_thread_groups): Support --recurse. Permit specifying thread groups together with --available.
This commit is contained in:
parent
837504c42d
commit
dc146f7c09
25 changed files with 1334 additions and 133 deletions
|
@ -140,6 +140,7 @@ static int check_removed_breakpoint (struct lwp_info *event_child);
|
|||
static void *add_lwp (ptid_t ptid);
|
||||
static int linux_stopped_by_watchpoint (void);
|
||||
static void mark_lwp_dead (struct lwp_info *lwp, int wstat);
|
||||
static int linux_core_of_thread (ptid_t ptid);
|
||||
|
||||
struct pending_signals
|
||||
{
|
||||
|
@ -2801,6 +2802,175 @@ linux_read_offsets (CORE_ADDR *text_p, CORE_ADDR *data_p)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
compare_ints (const void *xa, const void *xb)
|
||||
{
|
||||
int a = *(const int *)xa;
|
||||
int b = *(const int *)xb;
|
||||
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static int *
|
||||
unique (int *b, int *e)
|
||||
{
|
||||
int *d = b;
|
||||
while (++b != e)
|
||||
if (*d != *b)
|
||||
*++d = *b;
|
||||
return ++d;
|
||||
}
|
||||
|
||||
/* Given PID, iterates over all threads in that process.
|
||||
|
||||
Information about each thread, in a format suitable for qXfer:osdata:thread
|
||||
is printed to BUFFER, if it's not NULL. BUFFER is assumed to be already
|
||||
initialized, and the caller is responsible for finishing and appending '\0'
|
||||
to it.
|
||||
|
||||
The list of cores that threads are running on is assigned to *CORES, if it
|
||||
is not NULL. If no cores are found, *CORES will be set to NULL. Caller
|
||||
should free *CORES. */
|
||||
|
||||
static void
|
||||
list_threads (int pid, struct buffer *buffer, char **cores)
|
||||
{
|
||||
int count = 0;
|
||||
int allocated = 10;
|
||||
int *core_numbers = xmalloc (sizeof (int) * allocated);
|
||||
char pathname[128];
|
||||
DIR *dir;
|
||||
struct dirent *dp;
|
||||
struct stat statbuf;
|
||||
|
||||
sprintf (pathname, "/proc/%d/task", pid);
|
||||
if (stat (pathname, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
|
||||
{
|
||||
dir = opendir (pathname);
|
||||
if (!dir)
|
||||
{
|
||||
free (core_numbers);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((dp = readdir (dir)) != NULL)
|
||||
{
|
||||
unsigned long lwp = strtoul (dp->d_name, NULL, 10);
|
||||
|
||||
if (lwp != 0)
|
||||
{
|
||||
unsigned core = linux_core_of_thread (ptid_build (pid, lwp, 0));
|
||||
|
||||
if (core != -1)
|
||||
{
|
||||
char s[sizeof ("4294967295")];
|
||||
sprintf (s, "%u", core);
|
||||
|
||||
if (count == allocated)
|
||||
{
|
||||
allocated *= 2;
|
||||
core_numbers = realloc (core_numbers,
|
||||
sizeof (int) * allocated);
|
||||
}
|
||||
core_numbers[count++] = core;
|
||||
if (buffer)
|
||||
buffer_xml_printf (buffer,
|
||||
"<item>"
|
||||
"<column name=\"pid\">%d</column>"
|
||||
"<column name=\"tid\">%s</column>"
|
||||
"<column name=\"core\">%s</column>"
|
||||
"</item>", pid, dp->d_name, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buffer)
|
||||
buffer_xml_printf (buffer,
|
||||
"<item>"
|
||||
"<column name=\"pid\">%d</column>"
|
||||
"<column name=\"tid\">%s</column>"
|
||||
"</item>", pid, dp->d_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cores)
|
||||
{
|
||||
*cores = NULL;
|
||||
if (count > 0)
|
||||
{
|
||||
struct buffer buffer2;
|
||||
int *b;
|
||||
int *e;
|
||||
qsort (core_numbers, count, sizeof (int), compare_ints);
|
||||
|
||||
/* Remove duplicates. */
|
||||
b = core_numbers;
|
||||
e = unique (b, core_numbers + count);
|
||||
|
||||
buffer_init (&buffer2);
|
||||
|
||||
for (b = core_numbers; b != e; ++b)
|
||||
{
|
||||
char number[sizeof ("4294967295")];
|
||||
sprintf (number, "%u", *b);
|
||||
buffer_xml_printf (&buffer2, "%s%s",
|
||||
(b == core_numbers) ? "" : ",", number);
|
||||
}
|
||||
buffer_grow_str0 (&buffer2, "");
|
||||
|
||||
*cores = buffer_finish (&buffer2);
|
||||
}
|
||||
}
|
||||
free (core_numbers);
|
||||
}
|
||||
|
||||
static void
|
||||
show_process (int pid, const char *username, struct buffer *buffer)
|
||||
{
|
||||
char pathname[128];
|
||||
FILE *f;
|
||||
char cmd[MAXPATHLEN + 1];
|
||||
|
||||
sprintf (pathname, "/proc/%d/cmdline", pid);
|
||||
|
||||
if ((f = fopen (pathname, "r")) != NULL)
|
||||
{
|
||||
size_t len = fread (cmd, 1, sizeof (cmd) - 1, f);
|
||||
if (len > 0)
|
||||
{
|
||||
char *cores = 0;
|
||||
int i;
|
||||
for (i = 0; i < len; i++)
|
||||
if (cmd[i] == '\0')
|
||||
cmd[i] = ' ';
|
||||
cmd[len] = '\0';
|
||||
|
||||
buffer_xml_printf (buffer,
|
||||
"<item>"
|
||||
"<column name=\"pid\">%d</column>"
|
||||
"<column name=\"user\">%s</column>"
|
||||
"<column name=\"command\">%s</column>",
|
||||
pid,
|
||||
username,
|
||||
cmd);
|
||||
|
||||
/* This only collects core numbers, and does not print threads. */
|
||||
list_threads (pid, NULL, &cores);
|
||||
|
||||
if (cores)
|
||||
{
|
||||
buffer_xml_printf (buffer,
|
||||
"<column name=\"cores\">%s</column>", cores);
|
||||
free (cores);
|
||||
}
|
||||
|
||||
buffer_xml_printf (buffer, "</item>");
|
||||
}
|
||||
fclose (f);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
linux_qxfer_osdata (const char *annex,
|
||||
unsigned char *readbuf, unsigned const char *writebuf,
|
||||
|
@ -2811,10 +2981,16 @@ linux_qxfer_osdata (const char *annex,
|
|||
static const char *buf;
|
||||
static long len_avail = -1;
|
||||
static struct buffer buffer;
|
||||
int processes = 0;
|
||||
int threads = 0;
|
||||
|
||||
DIR *dirp;
|
||||
|
||||
if (strcmp (annex, "processes") != 0)
|
||||
if (strcmp (annex, "processes") == 0)
|
||||
processes = 1;
|
||||
else if (strcmp (annex, "threads") == 0)
|
||||
threads = 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (!readbuf || writebuf)
|
||||
|
@ -2827,7 +3003,10 @@ linux_qxfer_osdata (const char *annex,
|
|||
len_avail = 0;
|
||||
buf = NULL;
|
||||
buffer_init (&buffer);
|
||||
buffer_grow_str (&buffer, "<osdata type=\"processes\">");
|
||||
if (processes)
|
||||
buffer_grow_str (&buffer, "<osdata type=\"processes\">");
|
||||
else if (threads)
|
||||
buffer_grow_str (&buffer, "<osdata type=\"threads\">");
|
||||
|
||||
dirp = opendir ("/proc");
|
||||
if (dirp)
|
||||
|
@ -2846,37 +3025,16 @@ linux_qxfer_osdata (const char *annex,
|
|||
if (stat (procentry, &statbuf) == 0
|
||||
&& S_ISDIR (statbuf.st_mode))
|
||||
{
|
||||
char pathname[128];
|
||||
FILE *f;
|
||||
char cmd[MAXPATHLEN + 1];
|
||||
struct passwd *entry;
|
||||
int pid = (int) strtoul (dp->d_name, NULL, 10);
|
||||
|
||||
sprintf (pathname, "/proc/%s/cmdline", dp->d_name);
|
||||
entry = getpwuid (statbuf.st_uid);
|
||||
|
||||
if ((f = fopen (pathname, "r")) != NULL)
|
||||
if (processes)
|
||||
{
|
||||
size_t len = fread (cmd, 1, sizeof (cmd) - 1, f);
|
||||
if (len > 0)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len; i++)
|
||||
if (cmd[i] == '\0')
|
||||
cmd[i] = ' ';
|
||||
cmd[len] = '\0';
|
||||
|
||||
buffer_xml_printf (
|
||||
&buffer,
|
||||
"<item>"
|
||||
"<column name=\"pid\">%s</column>"
|
||||
"<column name=\"user\">%s</column>"
|
||||
"<column name=\"command\">%s</column>"
|
||||
"</item>",
|
||||
dp->d_name,
|
||||
entry ? entry->pw_name : "?",
|
||||
cmd);
|
||||
}
|
||||
fclose (f);
|
||||
struct passwd *entry = getpwuid (statbuf.st_uid);
|
||||
show_process (pid, entry ? entry->pw_name : "?", &buffer);
|
||||
}
|
||||
else if (threads)
|
||||
{
|
||||
list_threads (pid, &buffer, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3152,6 +3310,55 @@ linux_qxfer_spu (const char *annex, unsigned char *readbuf,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
linux_core_of_thread (ptid_t ptid)
|
||||
{
|
||||
char filename[sizeof ("/proc//task//stat")
|
||||
+ 2 * 20 /* decimal digits for 2 numbers, max 2^64 bit each */
|
||||
+ 1];
|
||||
FILE *f;
|
||||
char *content = NULL;
|
||||
char *p;
|
||||
char *ts = 0;
|
||||
int content_read = 0;
|
||||
int i;
|
||||
int core;
|
||||
|
||||
sprintf (filename, "/proc/%d/task/%ld/stat",
|
||||
ptid_get_pid (ptid), ptid_get_lwp (ptid));
|
||||
f = fopen (filename, "r");
|
||||
if (!f)
|
||||
return -1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int n;
|
||||
content = realloc (content, content_read + 1024);
|
||||
n = fread (content + content_read, 1, 1024, f);
|
||||
content_read += n;
|
||||
if (n < 1024)
|
||||
{
|
||||
content[content_read] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p = strchr (content, '(');
|
||||
p = strchr (p, ')') + 2; /* skip ")" and a whitespace. */
|
||||
|
||||
p = strtok_r (p, " ", &ts);
|
||||
for (i = 0; i != 36; ++i)
|
||||
p = strtok_r (NULL, " ", &ts);
|
||||
|
||||
if (sscanf (p, "%d", &core) == 0)
|
||||
core = -1;
|
||||
|
||||
free (content);
|
||||
fclose (f);
|
||||
|
||||
return core;
|
||||
}
|
||||
|
||||
static struct target_ops linux_target_ops = {
|
||||
linux_create_inferior,
|
||||
linux_attach,
|
||||
|
@ -3191,10 +3398,11 @@ static struct target_ops linux_target_ops = {
|
|||
linux_start_non_stop,
|
||||
linux_supports_multi_process,
|
||||
#ifdef USE_THREAD_DB
|
||||
thread_db_handle_monitor_command
|
||||
thread_db_handle_monitor_command,
|
||||
#else
|
||||
NULL
|
||||
NULL,
|
||||
#endif
|
||||
linux_core_of_thread
|
||||
};
|
||||
|
||||
static void
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue