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