Skip to content

Commit

Permalink
perf session: Remove threads from tree on PERF_RECORD_EXIT
Browse files Browse the repository at this point in the history
Move them to a session->dead_threads list just like we do with maps that
are replaced, because we may have hist_entries pointing to them.

This fixes a bug when inserting maps for a new thread that reused the
TID, mixing maps for two different threads, causing an endless loop.

The code for insering maps should be made more robust but for .35 this
is the minimalistic patch.

Reported-by: Ingo Molnar <mingo@elte.hu>
Cc: David S. Miller <davem@davemloft.net>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Arnaldo Carvalho de Melo committed Jun 17, 2010
1 parent 174787c commit 720a3ae
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 2 deletions.
4 changes: 3 additions & 1 deletion tools/perf/util/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -538,8 +538,10 @@ int event__process_task(event_t *self, struct perf_session *session)
dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
self->fork.ppid, self->fork.ptid);

if (self->header.type == PERF_RECORD_EXIT)
if (self->header.type == PERF_RECORD_EXIT) {
perf_session__remove_thread(session, thread);
return 0;
}

if (thread == NULL || parent == NULL ||
thread__fork(thread, parent) < 0) {
Expand Down
11 changes: 11 additions & 0 deletions tools/perf/util/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc

memcpy(self->filename, filename, len);
self->threads = RB_ROOT;
INIT_LIST_HEAD(&self->dead_threads);
self->hists_tree = RB_ROOT;
self->last_match = NULL;
self->mmap_window = 32;
Expand Down Expand Up @@ -131,6 +132,16 @@ void perf_session__delete(struct perf_session *self)
free(self);
}

void perf_session__remove_thread(struct perf_session *self, struct thread *th)
{
rb_erase(&th->rb_node, &self->threads);
/*
* We may have references to this thread, for instance in some hist_entry
* instances, so just move them to a separate list.
*/
list_add_tail(&th->node, &self->dead_threads);
}

static bool symbol__match_parent_regex(struct symbol *sym)
{
if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
Expand Down
2 changes: 2 additions & 0 deletions tools/perf/util/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct perf_session {
unsigned long size;
unsigned long mmap_window;
struct rb_root threads;
struct list_head dead_threads;
struct thread *last_match;
struct machine host_machine;
struct rb_root machines;
Expand Down Expand Up @@ -99,6 +100,7 @@ int perf_session__create_kernel_maps(struct perf_session *self);

int do_read(int fd, void *buf, size_t size);
void perf_session__update_sample_type(struct perf_session *self);
void perf_session__remove_thread(struct perf_session *self, struct thread *th);

static inline
struct machine *perf_session__find_host_machine(struct perf_session *self)
Expand Down
5 changes: 4 additions & 1 deletion tools/perf/util/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
#include "symbol.h"

struct thread {
struct rb_node rb_node;
union {
struct rb_node rb_node;
struct list_head node;
};
struct map_groups mg;
pid_t pid;
char shortname[3];
Expand Down

0 comments on commit 720a3ae

Please sign in to comment.