0001
0002 #include "comm.h"
0003 #include <errno.h>
0004 #include <stdlib.h>
0005 #include <stdio.h>
0006 #include <string.h>
0007 #include <linux/refcount.h>
0008 #include <linux/rbtree.h>
0009 #include <linux/zalloc.h>
0010 #include "rwsem.h"
0011
0012 struct comm_str {
0013 char *str;
0014 struct rb_node rb_node;
0015 refcount_t refcnt;
0016 };
0017
0018
0019 static struct rb_root comm_str_root;
0020 static struct rw_semaphore comm_str_lock = {.lock = PTHREAD_RWLOCK_INITIALIZER,};
0021
0022 static struct comm_str *comm_str__get(struct comm_str *cs)
0023 {
0024 if (cs && refcount_inc_not_zero(&cs->refcnt))
0025 return cs;
0026
0027 return NULL;
0028 }
0029
0030 static void comm_str__put(struct comm_str *cs)
0031 {
0032 if (cs && refcount_dec_and_test(&cs->refcnt)) {
0033 down_write(&comm_str_lock);
0034 rb_erase(&cs->rb_node, &comm_str_root);
0035 up_write(&comm_str_lock);
0036 zfree(&cs->str);
0037 free(cs);
0038 }
0039 }
0040
0041 static struct comm_str *comm_str__alloc(const char *str)
0042 {
0043 struct comm_str *cs;
0044
0045 cs = zalloc(sizeof(*cs));
0046 if (!cs)
0047 return NULL;
0048
0049 cs->str = strdup(str);
0050 if (!cs->str) {
0051 free(cs);
0052 return NULL;
0053 }
0054
0055 refcount_set(&cs->refcnt, 1);
0056
0057 return cs;
0058 }
0059
0060 static
0061 struct comm_str *__comm_str__findnew(const char *str, struct rb_root *root)
0062 {
0063 struct rb_node **p = &root->rb_node;
0064 struct rb_node *parent = NULL;
0065 struct comm_str *iter, *new;
0066 int cmp;
0067
0068 while (*p != NULL) {
0069 parent = *p;
0070 iter = rb_entry(parent, struct comm_str, rb_node);
0071
0072
0073
0074
0075
0076
0077 cmp = strcmp(str, iter->str);
0078 if (!cmp && comm_str__get(iter))
0079 return iter;
0080
0081 if (cmp < 0)
0082 p = &(*p)->rb_left;
0083 else
0084 p = &(*p)->rb_right;
0085 }
0086
0087 new = comm_str__alloc(str);
0088 if (!new)
0089 return NULL;
0090
0091 rb_link_node(&new->rb_node, parent, p);
0092 rb_insert_color(&new->rb_node, root);
0093
0094 return new;
0095 }
0096
0097 static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
0098 {
0099 struct comm_str *cs;
0100
0101 down_write(&comm_str_lock);
0102 cs = __comm_str__findnew(str, root);
0103 up_write(&comm_str_lock);
0104
0105 return cs;
0106 }
0107
0108 struct comm *comm__new(const char *str, u64 timestamp, bool exec)
0109 {
0110 struct comm *comm = zalloc(sizeof(*comm));
0111
0112 if (!comm)
0113 return NULL;
0114
0115 comm->start = timestamp;
0116 comm->exec = exec;
0117
0118 comm->comm_str = comm_str__findnew(str, &comm_str_root);
0119 if (!comm->comm_str) {
0120 free(comm);
0121 return NULL;
0122 }
0123
0124 return comm;
0125 }
0126
0127 int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
0128 {
0129 struct comm_str *new, *old = comm->comm_str;
0130
0131 new = comm_str__findnew(str, &comm_str_root);
0132 if (!new)
0133 return -ENOMEM;
0134
0135 comm_str__put(old);
0136 comm->comm_str = new;
0137 comm->start = timestamp;
0138 if (exec)
0139 comm->exec = true;
0140
0141 return 0;
0142 }
0143
0144 void comm__free(struct comm *comm)
0145 {
0146 comm_str__put(comm->comm_str);
0147 free(comm);
0148 }
0149
0150 const char *comm__str(const struct comm *comm)
0151 {
0152 return comm->comm_str->str;
0153 }