blob: 327e01cb1aa2f6647a36144d4c984c104520d5ab [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001// SPDX-License-Identifier: GPL-2.0
2#include "comm.h"
3#include "util.h"
4#include <errno.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <linux/refcount.h>
9
10struct 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 */
17static struct rb_root comm_str_root;
18
19static struct comm_str *comm_str__get(struct comm_str *cs)
20{
21 if (cs && refcount_inc_not_zero(&cs->refcnt))
22 return cs;
23
24 return NULL;
25}
26
27static void comm_str__put(struct comm_str *cs)
28{
29 if (cs && refcount_dec_and_test(&cs->refcnt)) {
30 rb_erase(&cs->rb_node, &comm_str_root);
31 zfree(&cs->str);
32 free(cs);
33 }
34}
35
36static struct comm_str *comm_str__alloc(const char *str)
37{
38 struct comm_str *cs;
39
40 cs = zalloc(sizeof(*cs));
41 if (!cs)
42 return NULL;
43
44 cs->str = strdup(str);
45 if (!cs->str) {
46 free(cs);
47 return NULL;
48 }
49
50 refcount_set(&cs->refcnt, 1);
51
52 return cs;
53}
54
55static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
56{
57 struct rb_node **p = &root->rb_node;
58 struct rb_node *parent = NULL;
59 struct comm_str *iter, *new;
60 int cmp;
61
62 while (*p != NULL) {
63 parent = *p;
64 iter = rb_entry(parent, struct comm_str, rb_node);
65
66 /*
67 * If we race with comm_str__put, iter->refcnt is 0
68 * and it will be removed within comm_str__put call
69 * shortly, ignore it in this search.
70 */
71 cmp = strcmp(str, iter->str);
72 if (!cmp && comm_str__get(iter))
73 return iter;
74
75 if (cmp < 0)
76 p = &(*p)->rb_left;
77 else
78 p = &(*p)->rb_right;
79 }
80
81 new = comm_str__alloc(str);
82 if (!new)
83 return NULL;
84
85 rb_link_node(&new->rb_node, parent, p);
86 rb_insert_color(&new->rb_node, root);
87
88 return new;
89}
90
91struct comm *comm__new(const char *str, u64 timestamp, bool exec)
92{
93 struct comm *comm = zalloc(sizeof(*comm));
94
95 if (!comm)
96 return NULL;
97
98 comm->start = timestamp;
99 comm->exec = exec;
100
101 comm->comm_str = comm_str__findnew(str, &comm_str_root);
102 if (!comm->comm_str) {
103 free(comm);
104 return NULL;
105 }
106
107 return comm;
108}
109
110int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
111{
112 struct comm_str *new, *old = comm->comm_str;
113
114 new = comm_str__findnew(str, &comm_str_root);
115 if (!new)
116 return -ENOMEM;
117
118 comm_str__put(old);
119 comm->comm_str = new;
120 comm->start = timestamp;
121 if (exec)
122 comm->exec = true;
123
124 return 0;
125}
126
127void comm__free(struct comm *comm)
128{
129 comm_str__put(comm->comm_str);
130 free(comm);
131}
132
133const char *comm__str(const struct comm *comm)
134{
135 return comm->comm_str->str;
136}