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