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