Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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 /* Should perhaps be moved to struct machine */
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          * If we race with comm_str__put, iter->refcnt is 0
0074          * and it will be removed within comm_str__put call
0075          * shortly, ignore it in this search.
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 }