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:
Vladimir Prus 2010-01-12 21:40:25 +00:00
parent 837504c42d
commit dc146f7c09
25 changed files with 1334 additions and 133 deletions

View file

@ -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