2009-08-14 14:21:53 +04:00
# include "../perf.h"
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include "thread.h"
# include "util.h"
2009-08-18 19:04:03 +04:00
# include "debug.h"
2009-08-14 14:21:53 +04:00
static struct thread * thread__new ( pid_t pid )
{
2009-09-16 19:40:48 +04:00
struct thread * self = calloc ( 1 , sizeof ( * self ) ) ;
2009-08-14 14:21:53 +04:00
if ( self ! = NULL ) {
self - > pid = pid ;
self - > comm = malloc ( 32 ) ;
if ( self - > comm )
snprintf ( self - > comm , 32 , " :%d " , self - > pid ) ;
INIT_LIST_HEAD ( & self - > maps ) ;
}
return self ;
}
int thread__set_comm ( struct thread * self , const char * comm )
{
if ( self - > comm )
free ( self - > comm ) ;
self - > comm = strdup ( comm ) ;
return self - > comm ? 0 : - ENOMEM ;
}
static size_t thread__fprintf ( struct thread * self , FILE * fp )
{
struct map * pos ;
size_t ret = fprintf ( fp , " Thread %d %s \n " , self - > pid , self - > comm ) ;
list_for_each_entry ( pos , & self - > maps , node )
ret + = map__fprintf ( pos , fp ) ;
return ret ;
}
struct thread *
threads__findnew ( pid_t pid , struct rb_root * threads , struct thread * * last_match )
{
struct rb_node * * p = & threads - > rb_node ;
struct rb_node * parent = NULL ;
struct thread * th ;
/*
* Font - end cache - PID lookups come in blocks ,
* so most of the time we dont have to look up
* the full rbtree :
*/
if ( * last_match & & ( * last_match ) - > pid = = pid )
return * last_match ;
while ( * p ! = NULL ) {
parent = * p ;
th = rb_entry ( parent , struct thread , rb_node ) ;
if ( th - > pid = = pid ) {
* last_match = th ;
return th ;
}
if ( pid < th - > pid )
p = & ( * p ) - > rb_left ;
else
p = & ( * p ) - > rb_right ;
}
th = thread__new ( pid ) ;
if ( th ! = NULL ) {
rb_link_node ( & th - > rb_node , parent , p ) ;
rb_insert_color ( & th - > rb_node , threads ) ;
* last_match = th ;
}
return th ;
}
2009-08-31 08:45:18 +04:00
struct thread *
register_idle_thread ( struct rb_root * threads , struct thread * * last_match )
{
struct thread * thread = threads__findnew ( 0 , threads , last_match ) ;
2009-09-16 16:12:36 +04:00
if ( ! thread | | thread__set_comm ( thread , " swapper " ) ) {
2009-08-31 08:45:18 +04:00
fprintf ( stderr , " problem inserting idle task. \n " ) ;
exit ( - 1 ) ;
}
return thread ;
}
2009-08-14 14:21:53 +04:00
void thread__insert_map ( struct thread * self , struct map * map )
{
struct map * pos , * tmp ;
list_for_each_entry_safe ( pos , tmp , & self - > maps , node ) {
if ( map__overlap ( pos , map ) ) {
2009-08-18 19:04:03 +04:00
if ( verbose > = 2 ) {
printf ( " overlapping maps: \n " ) ;
map__fprintf ( map , stdout ) ;
map__fprintf ( pos , stdout ) ;
}
if ( map - > start < = pos - > start & & map - > end > pos - > start )
pos - > start = map - > end ;
if ( map - > end > = pos - > end & & map - > start < pos - > end )
pos - > end = map - > start ;
if ( verbose > = 2 ) {
printf ( " after collision: \n " ) ;
map__fprintf ( pos , stdout ) ;
}
if ( pos - > start > = pos - > end ) {
list_del_init ( & pos - > node ) ;
free ( pos ) ;
}
2009-08-14 14:21:53 +04:00
}
}
list_add_tail ( & map - > node , & self - > maps ) ;
}
int thread__fork ( struct thread * self , struct thread * parent )
{
struct map * map ;
if ( self - > comm )
free ( self - > comm ) ;
self - > comm = strdup ( parent - > comm ) ;
if ( ! self - > comm )
return - ENOMEM ;
list_for_each_entry ( map , & parent - > maps , node ) {
struct map * new = map__clone ( map ) ;
if ( ! new )
return - ENOMEM ;
thread__insert_map ( self , new ) ;
}
return 0 ;
}
struct map * thread__find_map ( struct thread * self , u64 ip )
{
struct map * pos ;
if ( self = = NULL )
return NULL ;
list_for_each_entry ( pos , & self - > maps , node )
if ( ip > = pos - > start & & ip < = pos - > end )
return pos ;
return NULL ;
}
size_t threads__fprintf ( FILE * fp , struct rb_root * threads )
{
size_t ret = 0 ;
struct rb_node * nd ;
for ( nd = rb_first ( threads ) ; nd ; nd = rb_next ( nd ) ) {
struct thread * pos = rb_entry ( nd , struct thread , rb_node ) ;
ret + = thread__fprintf ( pos , fp ) ;
}
return ret ;
}