|
@@ -30,7 +30,21 @@ static void dsos__init(struct dsos *dsos)
|
|
{
|
|
{
|
|
INIT_LIST_HEAD(&dsos->head);
|
|
INIT_LIST_HEAD(&dsos->head);
|
|
dsos->root = RB_ROOT;
|
|
dsos->root = RB_ROOT;
|
|
- pthread_rwlock_init(&dsos->lock, NULL);
|
|
|
|
|
|
+ init_rwsem(&dsos->lock);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void machine__threads_init(struct machine *machine)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < THREADS__TABLE_SIZE; i++) {
|
|
|
|
+ struct threads *threads = &machine->threads[i];
|
|
|
|
+ threads->entries = RB_ROOT;
|
|
|
|
+ init_rwsem(&threads->lock);
|
|
|
|
+ threads->nr = 0;
|
|
|
|
+ INIT_LIST_HEAD(&threads->dead);
|
|
|
|
+ threads->last_match = NULL;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
|
|
int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
|
|
@@ -40,11 +54,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
|
|
RB_CLEAR_NODE(&machine->rb_node);
|
|
RB_CLEAR_NODE(&machine->rb_node);
|
|
dsos__init(&machine->dsos);
|
|
dsos__init(&machine->dsos);
|
|
|
|
|
|
- machine->threads = RB_ROOT;
|
|
|
|
- pthread_rwlock_init(&machine->threads_lock, NULL);
|
|
|
|
- machine->nr_threads = 0;
|
|
|
|
- INIT_LIST_HEAD(&machine->dead_threads);
|
|
|
|
- machine->last_match = NULL;
|
|
|
|
|
|
+ machine__threads_init(machine);
|
|
|
|
|
|
machine->vdso_info = NULL;
|
|
machine->vdso_info = NULL;
|
|
machine->env = NULL;
|
|
machine->env = NULL;
|
|
@@ -120,7 +130,7 @@ static void dsos__purge(struct dsos *dsos)
|
|
{
|
|
{
|
|
struct dso *pos, *n;
|
|
struct dso *pos, *n;
|
|
|
|
|
|
- pthread_rwlock_wrlock(&dsos->lock);
|
|
|
|
|
|
+ down_write(&dsos->lock);
|
|
|
|
|
|
list_for_each_entry_safe(pos, n, &dsos->head, node) {
|
|
list_for_each_entry_safe(pos, n, &dsos->head, node) {
|
|
RB_CLEAR_NODE(&pos->rb_node);
|
|
RB_CLEAR_NODE(&pos->rb_node);
|
|
@@ -129,39 +139,49 @@ static void dsos__purge(struct dsos *dsos)
|
|
dso__put(pos);
|
|
dso__put(pos);
|
|
}
|
|
}
|
|
|
|
|
|
- pthread_rwlock_unlock(&dsos->lock);
|
|
|
|
|
|
+ up_write(&dsos->lock);
|
|
}
|
|
}
|
|
|
|
|
|
static void dsos__exit(struct dsos *dsos)
|
|
static void dsos__exit(struct dsos *dsos)
|
|
{
|
|
{
|
|
dsos__purge(dsos);
|
|
dsos__purge(dsos);
|
|
- pthread_rwlock_destroy(&dsos->lock);
|
|
|
|
|
|
+ exit_rwsem(&dsos->lock);
|
|
}
|
|
}
|
|
|
|
|
|
void machine__delete_threads(struct machine *machine)
|
|
void machine__delete_threads(struct machine *machine)
|
|
{
|
|
{
|
|
struct rb_node *nd;
|
|
struct rb_node *nd;
|
|
|
|
+ int i;
|
|
|
|
|
|
- pthread_rwlock_wrlock(&machine->threads_lock);
|
|
|
|
- nd = rb_first(&machine->threads);
|
|
|
|
- while (nd) {
|
|
|
|
- struct thread *t = rb_entry(nd, struct thread, rb_node);
|
|
|
|
|
|
+ for (i = 0; i < THREADS__TABLE_SIZE; i++) {
|
|
|
|
+ struct threads *threads = &machine->threads[i];
|
|
|
|
+ down_write(&threads->lock);
|
|
|
|
+ nd = rb_first(&threads->entries);
|
|
|
|
+ while (nd) {
|
|
|
|
+ struct thread *t = rb_entry(nd, struct thread, rb_node);
|
|
|
|
|
|
- nd = rb_next(nd);
|
|
|
|
- __machine__remove_thread(machine, t, false);
|
|
|
|
|
|
+ nd = rb_next(nd);
|
|
|
|
+ __machine__remove_thread(machine, t, false);
|
|
|
|
+ }
|
|
|
|
+ up_write(&threads->lock);
|
|
}
|
|
}
|
|
- pthread_rwlock_unlock(&machine->threads_lock);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void machine__exit(struct machine *machine)
|
|
void machine__exit(struct machine *machine)
|
|
{
|
|
{
|
|
|
|
+ int i;
|
|
|
|
+
|
|
machine__destroy_kernel_maps(machine);
|
|
machine__destroy_kernel_maps(machine);
|
|
map_groups__exit(&machine->kmaps);
|
|
map_groups__exit(&machine->kmaps);
|
|
dsos__exit(&machine->dsos);
|
|
dsos__exit(&machine->dsos);
|
|
machine__exit_vdso(machine);
|
|
machine__exit_vdso(machine);
|
|
zfree(&machine->root_dir);
|
|
zfree(&machine->root_dir);
|
|
zfree(&machine->current_tid);
|
|
zfree(&machine->current_tid);
|
|
- pthread_rwlock_destroy(&machine->threads_lock);
|
|
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < THREADS__TABLE_SIZE; i++) {
|
|
|
|
+ struct threads *threads = &machine->threads[i];
|
|
|
|
+ exit_rwsem(&threads->lock);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
void machine__delete(struct machine *machine)
|
|
void machine__delete(struct machine *machine)
|
|
@@ -379,10 +399,11 @@ out_err:
|
|
* lookup/new thread inserted.
|
|
* lookup/new thread inserted.
|
|
*/
|
|
*/
|
|
static struct thread *____machine__findnew_thread(struct machine *machine,
|
|
static struct thread *____machine__findnew_thread(struct machine *machine,
|
|
|
|
+ struct threads *threads,
|
|
pid_t pid, pid_t tid,
|
|
pid_t pid, pid_t tid,
|
|
bool create)
|
|
bool create)
|
|
{
|
|
{
|
|
- struct rb_node **p = &machine->threads.rb_node;
|
|
|
|
|
|
+ struct rb_node **p = &threads->entries.rb_node;
|
|
struct rb_node *parent = NULL;
|
|
struct rb_node *parent = NULL;
|
|
struct thread *th;
|
|
struct thread *th;
|
|
|
|
|
|
@@ -391,14 +412,14 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
|
|
* so most of the time we dont have to look up
|
|
* so most of the time we dont have to look up
|
|
* the full rbtree:
|
|
* the full rbtree:
|
|
*/
|
|
*/
|
|
- th = machine->last_match;
|
|
|
|
|
|
+ th = threads->last_match;
|
|
if (th != NULL) {
|
|
if (th != NULL) {
|
|
if (th->tid == tid) {
|
|
if (th->tid == tid) {
|
|
machine__update_thread_pid(machine, th, pid);
|
|
machine__update_thread_pid(machine, th, pid);
|
|
return thread__get(th);
|
|
return thread__get(th);
|
|
}
|
|
}
|
|
|
|
|
|
- machine->last_match = NULL;
|
|
|
|
|
|
+ threads->last_match = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
while (*p != NULL) {
|
|
while (*p != NULL) {
|
|
@@ -406,7 +427,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
|
|
th = rb_entry(parent, struct thread, rb_node);
|
|
th = rb_entry(parent, struct thread, rb_node);
|
|
|
|
|
|
if (th->tid == tid) {
|
|
if (th->tid == tid) {
|
|
- machine->last_match = th;
|
|
|
|
|
|
+ threads->last_match = th;
|
|
machine__update_thread_pid(machine, th, pid);
|
|
machine__update_thread_pid(machine, th, pid);
|
|
return thread__get(th);
|
|
return thread__get(th);
|
|
}
|
|
}
|
|
@@ -423,7 +444,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
|
|
th = thread__new(pid, tid);
|
|
th = thread__new(pid, tid);
|
|
if (th != NULL) {
|
|
if (th != NULL) {
|
|
rb_link_node(&th->rb_node, parent, p);
|
|
rb_link_node(&th->rb_node, parent, p);
|
|
- rb_insert_color(&th->rb_node, &machine->threads);
|
|
|
|
|
|
+ rb_insert_color(&th->rb_node, &threads->entries);
|
|
|
|
|
|
/*
|
|
/*
|
|
* We have to initialize map_groups separately
|
|
* We have to initialize map_groups separately
|
|
@@ -434,7 +455,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
|
|
* leader and that would screwed the rb tree.
|
|
* leader and that would screwed the rb tree.
|
|
*/
|
|
*/
|
|
if (thread__init_map_groups(th, machine)) {
|
|
if (thread__init_map_groups(th, machine)) {
|
|
- rb_erase_init(&th->rb_node, &machine->threads);
|
|
|
|
|
|
+ rb_erase_init(&th->rb_node, &threads->entries);
|
|
RB_CLEAR_NODE(&th->rb_node);
|
|
RB_CLEAR_NODE(&th->rb_node);
|
|
thread__put(th);
|
|
thread__put(th);
|
|
return NULL;
|
|
return NULL;
|
|
@@ -443,8 +464,8 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
|
|
* It is now in the rbtree, get a ref
|
|
* It is now in the rbtree, get a ref
|
|
*/
|
|
*/
|
|
thread__get(th);
|
|
thread__get(th);
|
|
- machine->last_match = th;
|
|
|
|
- ++machine->nr_threads;
|
|
|
|
|
|
+ threads->last_match = th;
|
|
|
|
+ ++threads->nr;
|
|
}
|
|
}
|
|
|
|
|
|
return th;
|
|
return th;
|
|
@@ -452,27 +473,30 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
|
|
|
|
|
|
struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid)
|
|
struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid)
|
|
{
|
|
{
|
|
- return ____machine__findnew_thread(machine, pid, tid, true);
|
|
|
|
|
|
+ return ____machine__findnew_thread(machine, machine__threads(machine, tid), pid, tid, true);
|
|
}
|
|
}
|
|
|
|
|
|
struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
|
|
struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
|
|
pid_t tid)
|
|
pid_t tid)
|
|
{
|
|
{
|
|
|
|
+ struct threads *threads = machine__threads(machine, tid);
|
|
struct thread *th;
|
|
struct thread *th;
|
|
|
|
|
|
- pthread_rwlock_wrlock(&machine->threads_lock);
|
|
|
|
|
|
+ down_write(&threads->lock);
|
|
th = __machine__findnew_thread(machine, pid, tid);
|
|
th = __machine__findnew_thread(machine, pid, tid);
|
|
- pthread_rwlock_unlock(&machine->threads_lock);
|
|
|
|
|
|
+ up_write(&threads->lock);
|
|
return th;
|
|
return th;
|
|
}
|
|
}
|
|
|
|
|
|
struct thread *machine__find_thread(struct machine *machine, pid_t pid,
|
|
struct thread *machine__find_thread(struct machine *machine, pid_t pid,
|
|
pid_t tid)
|
|
pid_t tid)
|
|
{
|
|
{
|
|
|
|
+ struct threads *threads = machine__threads(machine, tid);
|
|
struct thread *th;
|
|
struct thread *th;
|
|
- pthread_rwlock_rdlock(&machine->threads_lock);
|
|
|
|
- th = ____machine__findnew_thread(machine, pid, tid, false);
|
|
|
|
- pthread_rwlock_unlock(&machine->threads_lock);
|
|
|
|
|
|
+
|
|
|
|
+ down_read(&threads->lock);
|
|
|
|
+ th = ____machine__findnew_thread(machine, threads, pid, tid, false);
|
|
|
|
+ up_read(&threads->lock);
|
|
return th;
|
|
return th;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -564,7 +588,7 @@ static struct dso *machine__findnew_module_dso(struct machine *machine,
|
|
{
|
|
{
|
|
struct dso *dso;
|
|
struct dso *dso;
|
|
|
|
|
|
- pthread_rwlock_wrlock(&machine->dsos.lock);
|
|
|
|
|
|
+ down_write(&machine->dsos.lock);
|
|
|
|
|
|
dso = __dsos__find(&machine->dsos, m->name, true);
|
|
dso = __dsos__find(&machine->dsos, m->name, true);
|
|
if (!dso) {
|
|
if (!dso) {
|
|
@@ -578,7 +602,7 @@ static struct dso *machine__findnew_module_dso(struct machine *machine,
|
|
|
|
|
|
dso__get(dso);
|
|
dso__get(dso);
|
|
out_unlock:
|
|
out_unlock:
|
|
- pthread_rwlock_unlock(&machine->dsos.lock);
|
|
|
|
|
|
+ up_write(&machine->dsos.lock);
|
|
return dso;
|
|
return dso;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -719,21 +743,25 @@ size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
|
|
|
|
|
|
size_t machine__fprintf(struct machine *machine, FILE *fp)
|
|
size_t machine__fprintf(struct machine *machine, FILE *fp)
|
|
{
|
|
{
|
|
- size_t ret;
|
|
|
|
struct rb_node *nd;
|
|
struct rb_node *nd;
|
|
|
|
+ size_t ret;
|
|
|
|
+ int i;
|
|
|
|
|
|
- pthread_rwlock_rdlock(&machine->threads_lock);
|
|
|
|
|
|
+ for (i = 0; i < THREADS__TABLE_SIZE; i++) {
|
|
|
|
+ struct threads *threads = &machine->threads[i];
|
|
|
|
|
|
- ret = fprintf(fp, "Threads: %u\n", machine->nr_threads);
|
|
|
|
|
|
+ down_read(&threads->lock);
|
|
|
|
|
|
- for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
|
|
|
|
- struct thread *pos = rb_entry(nd, struct thread, rb_node);
|
|
|
|
|
|
+ ret = fprintf(fp, "Threads: %u\n", threads->nr);
|
|
|
|
|
|
- ret += thread__fprintf(pos, fp);
|
|
|
|
- }
|
|
|
|
|
|
+ for (nd = rb_first(&threads->entries); nd; nd = rb_next(nd)) {
|
|
|
|
+ struct thread *pos = rb_entry(nd, struct thread, rb_node);
|
|
|
|
|
|
- pthread_rwlock_unlock(&machine->threads_lock);
|
|
|
|
|
|
+ ret += thread__fprintf(pos, fp);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ up_read(&threads->lock);
|
|
|
|
+ }
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1292,7 +1320,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
|
|
struct dso *kernel = NULL;
|
|
struct dso *kernel = NULL;
|
|
struct dso *dso;
|
|
struct dso *dso;
|
|
|
|
|
|
- pthread_rwlock_rdlock(&machine->dsos.lock);
|
|
|
|
|
|
+ down_read(&machine->dsos.lock);
|
|
|
|
|
|
list_for_each_entry(dso, &machine->dsos.head, node) {
|
|
list_for_each_entry(dso, &machine->dsos.head, node) {
|
|
|
|
|
|
@@ -1322,7 +1350,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
- pthread_rwlock_unlock(&machine->dsos.lock);
|
|
|
|
|
|
+ up_read(&machine->dsos.lock);
|
|
|
|
|
|
if (kernel == NULL)
|
|
if (kernel == NULL)
|
|
kernel = machine__findnew_dso(machine, kmmap_prefix);
|
|
kernel = machine__findnew_dso(machine, kmmap_prefix);
|
|
@@ -1479,23 +1507,25 @@ out_problem:
|
|
|
|
|
|
static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock)
|
|
static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock)
|
|
{
|
|
{
|
|
- if (machine->last_match == th)
|
|
|
|
- machine->last_match = NULL;
|
|
|
|
|
|
+ struct threads *threads = machine__threads(machine, th->tid);
|
|
|
|
+
|
|
|
|
+ if (threads->last_match == th)
|
|
|
|
+ threads->last_match = NULL;
|
|
|
|
|
|
BUG_ON(refcount_read(&th->refcnt) == 0);
|
|
BUG_ON(refcount_read(&th->refcnt) == 0);
|
|
if (lock)
|
|
if (lock)
|
|
- pthread_rwlock_wrlock(&machine->threads_lock);
|
|
|
|
- rb_erase_init(&th->rb_node, &machine->threads);
|
|
|
|
|
|
+ down_write(&threads->lock);
|
|
|
|
+ rb_erase_init(&th->rb_node, &threads->entries);
|
|
RB_CLEAR_NODE(&th->rb_node);
|
|
RB_CLEAR_NODE(&th->rb_node);
|
|
- --machine->nr_threads;
|
|
|
|
|
|
+ --threads->nr;
|
|
/*
|
|
/*
|
|
* Move it first to the dead_threads list, then drop the reference,
|
|
* Move it first to the dead_threads list, then drop the reference,
|
|
* if this is the last reference, then the thread__delete destructor
|
|
* if this is the last reference, then the thread__delete destructor
|
|
* will be called and we will remove it from the dead_threads list.
|
|
* will be called and we will remove it from the dead_threads list.
|
|
*/
|
|
*/
|
|
- list_add_tail(&th->node, &machine->dead_threads);
|
|
|
|
|
|
+ list_add_tail(&th->node, &threads->dead);
|
|
if (lock)
|
|
if (lock)
|
|
- pthread_rwlock_unlock(&machine->threads_lock);
|
|
|
|
|
|
+ up_write(&threads->lock);
|
|
thread__put(th);
|
|
thread__put(th);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2140,21 +2170,26 @@ int machine__for_each_thread(struct machine *machine,
|
|
int (*fn)(struct thread *thread, void *p),
|
|
int (*fn)(struct thread *thread, void *p),
|
|
void *priv)
|
|
void *priv)
|
|
{
|
|
{
|
|
|
|
+ struct threads *threads;
|
|
struct rb_node *nd;
|
|
struct rb_node *nd;
|
|
struct thread *thread;
|
|
struct thread *thread;
|
|
int rc = 0;
|
|
int rc = 0;
|
|
|
|
+ int i;
|
|
|
|
|
|
- for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
|
|
|
|
- thread = rb_entry(nd, struct thread, rb_node);
|
|
|
|
- rc = fn(thread, priv);
|
|
|
|
- if (rc != 0)
|
|
|
|
- return rc;
|
|
|
|
- }
|
|
|
|
|
|
+ for (i = 0; i < THREADS__TABLE_SIZE; i++) {
|
|
|
|
+ threads = &machine->threads[i];
|
|
|
|
+ for (nd = rb_first(&threads->entries); nd; nd = rb_next(nd)) {
|
|
|
|
+ thread = rb_entry(nd, struct thread, rb_node);
|
|
|
|
+ rc = fn(thread, priv);
|
|
|
|
+ if (rc != 0)
|
|
|
|
+ return rc;
|
|
|
|
+ }
|
|
|
|
|
|
- list_for_each_entry(thread, &machine->dead_threads, node) {
|
|
|
|
- rc = fn(thread, priv);
|
|
|
|
- if (rc != 0)
|
|
|
|
- return rc;
|
|
|
|
|
|
+ list_for_each_entry(thread, &threads->dead, node) {
|
|
|
|
+ rc = fn(thread, priv);
|
|
|
|
+ if (rc != 0)
|
|
|
|
+ return rc;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|