comm.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. struct comm_str {
  11. char *str;
  12. struct rb_node rb_node;
  13. refcount_t refcnt;
  14. };
  15. /* Should perhaps be moved to struct machine */
  16. static struct rb_root comm_str_root;
  17. static struct rw_semaphore comm_str_lock = {.lock = PTHREAD_RWLOCK_INITIALIZER,};
  18. static struct comm_str *comm_str__get(struct comm_str *cs)
  19. {
  20. if (cs && refcount_inc_not_zero(&cs->refcnt))
  21. return cs;
  22. return NULL;
  23. }
  24. static void comm_str__put(struct comm_str *cs)
  25. {
  26. if (cs && refcount_dec_and_test(&cs->refcnt)) {
  27. down_write(&comm_str_lock);
  28. rb_erase(&cs->rb_node, &comm_str_root);
  29. up_write(&comm_str_lock);
  30. zfree(&cs->str);
  31. free(cs);
  32. }
  33. }
  34. static struct comm_str *comm_str__alloc(const char *str)
  35. {
  36. struct comm_str *cs;
  37. cs = zalloc(sizeof(*cs));
  38. if (!cs)
  39. return NULL;
  40. cs->str = strdup(str);
  41. if (!cs->str) {
  42. free(cs);
  43. return NULL;
  44. }
  45. refcount_set(&cs->refcnt, 1);
  46. return cs;
  47. }
  48. static
  49. struct comm_str *__comm_str__findnew(const char *str, struct rb_root *root)
  50. {
  51. struct rb_node **p = &root->rb_node;
  52. struct rb_node *parent = NULL;
  53. struct comm_str *iter, *new;
  54. int cmp;
  55. while (*p != NULL) {
  56. parent = *p;
  57. iter = rb_entry(parent, struct comm_str, rb_node);
  58. /*
  59. * If we race with comm_str__put, iter->refcnt is 0
  60. * and it will be removed within comm_str__put call
  61. * shortly, ignore it in this search.
  62. */
  63. cmp = strcmp(str, iter->str);
  64. if (!cmp && comm_str__get(iter))
  65. return iter;
  66. if (cmp < 0)
  67. p = &(*p)->rb_left;
  68. else
  69. p = &(*p)->rb_right;
  70. }
  71. new = comm_str__alloc(str);
  72. if (!new)
  73. return NULL;
  74. rb_link_node(&new->rb_node, parent, p);
  75. rb_insert_color(&new->rb_node, root);
  76. return new;
  77. }
  78. static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
  79. {
  80. struct comm_str *cs;
  81. down_write(&comm_str_lock);
  82. cs = __comm_str__findnew(str, root);
  83. up_write(&comm_str_lock);
  84. return cs;
  85. }
  86. struct comm *comm__new(const char *str, u64 timestamp, bool exec)
  87. {
  88. struct comm *comm = zalloc(sizeof(*comm));
  89. if (!comm)
  90. return NULL;
  91. comm->start = timestamp;
  92. comm->exec = exec;
  93. comm->comm_str = comm_str__findnew(str, &comm_str_root);
  94. if (!comm->comm_str) {
  95. free(comm);
  96. return NULL;
  97. }
  98. return comm;
  99. }
  100. int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
  101. {
  102. struct comm_str *new, *old = comm->comm_str;
  103. new = comm_str__findnew(str, &comm_str_root);
  104. if (!new)
  105. return -ENOMEM;
  106. comm_str__put(old);
  107. comm->comm_str = new;
  108. comm->start = timestamp;
  109. if (exec)
  110. comm->exec = true;
  111. return 0;
  112. }
  113. void comm__free(struct comm *comm)
  114. {
  115. comm_str__put(comm->comm_str);
  116. free(comm);
  117. }
  118. const char *comm__str(const struct comm *comm)
  119. {
  120. return comm->comm_str->str;
  121. }