xref: /linux/tools/perf/util/comm.c (revision 9be95bdc53c12ada23e39027237fd05e1393d893)
1 #include "comm.h"
2 #include "util.h"
3 #include <errno.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <linux/refcount.h>
8 #include "rwsem.h"
9 
10 struct comm_str {
11 	char *str;
12 	struct rb_node rb_node;
13 	refcount_t refcnt;
14 };
15 
16 /* Should perhaps be moved to struct machine */
17 static struct rb_root comm_str_root;
18 static struct rw_semaphore comm_str_lock = {.lock = PTHREAD_RWLOCK_INITIALIZER,};
19 
20 static struct comm_str *comm_str__get(struct comm_str *cs)
21 {
22 	if (cs)
23 		refcount_inc(&cs->refcnt);
24 	return cs;
25 }
26 
27 static void comm_str__put(struct comm_str *cs)
28 {
29 	if (cs && refcount_dec_and_test(&cs->refcnt)) {
30 		down_write(&comm_str_lock);
31 		rb_erase(&cs->rb_node, &comm_str_root);
32 		up_write(&comm_str_lock);
33 		zfree(&cs->str);
34 		free(cs);
35 	}
36 }
37 
38 static struct comm_str *comm_str__alloc(const char *str)
39 {
40 	struct comm_str *cs;
41 
42 	cs = zalloc(sizeof(*cs));
43 	if (!cs)
44 		return NULL;
45 
46 	cs->str = strdup(str);
47 	if (!cs->str) {
48 		free(cs);
49 		return NULL;
50 	}
51 
52 	refcount_set(&cs->refcnt, 1);
53 
54 	return cs;
55 }
56 
57 static
58 struct comm_str *__comm_str__findnew(const char *str, struct rb_root *root)
59 {
60 	struct rb_node **p = &root->rb_node;
61 	struct rb_node *parent = NULL;
62 	struct comm_str *iter, *new;
63 	int cmp;
64 
65 	while (*p != NULL) {
66 		parent = *p;
67 		iter = rb_entry(parent, struct comm_str, rb_node);
68 
69 		cmp = strcmp(str, iter->str);
70 		if (!cmp)
71 			return comm_str__get(iter);
72 
73 		if (cmp < 0)
74 			p = &(*p)->rb_left;
75 		else
76 			p = &(*p)->rb_right;
77 	}
78 
79 	new = comm_str__alloc(str);
80 	if (!new)
81 		return NULL;
82 
83 	rb_link_node(&new->rb_node, parent, p);
84 	rb_insert_color(&new->rb_node, root);
85 
86 	return new;
87 }
88 
89 static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
90 {
91 	struct comm_str *cs;
92 
93 	down_write(&comm_str_lock);
94 	cs = __comm_str__findnew(str, root);
95 	up_write(&comm_str_lock);
96 
97 	return cs;
98 }
99 
100 struct comm *comm__new(const char *str, u64 timestamp, bool exec)
101 {
102 	struct comm *comm = zalloc(sizeof(*comm));
103 
104 	if (!comm)
105 		return NULL;
106 
107 	comm->start = timestamp;
108 	comm->exec = exec;
109 
110 	comm->comm_str = comm_str__findnew(str, &comm_str_root);
111 	if (!comm->comm_str) {
112 		free(comm);
113 		return NULL;
114 	}
115 
116 	return comm;
117 }
118 
119 int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
120 {
121 	struct comm_str *new, *old = comm->comm_str;
122 
123 	new = comm_str__findnew(str, &comm_str_root);
124 	if (!new)
125 		return -ENOMEM;
126 
127 	comm_str__put(old);
128 	comm->comm_str = new;
129 	comm->start = timestamp;
130 	if (exec)
131 		comm->exec = true;
132 
133 	return 0;
134 }
135 
136 void comm__free(struct comm *comm)
137 {
138 	comm_str__put(comm->comm_str);
139 	free(comm);
140 }
141 
142 const char *comm__str(const struct comm *comm)
143 {
144 	return comm->comm_str->str;
145 }
146