1
1
// SPDX-License-Identifier: GPL-2.0
2
2
#include "comm.h"
3
3
#include <errno.h>
4
- #include <stdlib.h>
5
- #include <stdio.h>
6
4
#include <string.h>
5
+ #include <internal/rc_check.h>
7
6
#include <linux/refcount.h>
8
- #include <linux/rbtree.h>
9
7
#include <linux/zalloc.h>
10
8
#include "rwsem.h"
11
9
12
- struct comm_str {
13
- char * str ;
14
- struct rb_node rb_node ;
10
+ DECLARE_RC_STRUCT (comm_str ) {
15
11
refcount_t refcnt ;
12
+ char str [];
16
13
};
17
14
18
- /* Should perhaps be moved to struct machine */
19
- static struct rb_root comm_str_root ;
20
- static struct rw_semaphore comm_str_lock = {.lock = PTHREAD_RWLOCK_INITIALIZER ,};
15
+ static struct comm_strs {
16
+ struct rw_semaphore lock ;
17
+ struct comm_str * * strs ;
18
+ int num_strs ;
19
+ int capacity ;
20
+ } _comm_strs ;
21
+
22
+ static void comm_strs__init (void )
23
+ {
24
+ init_rwsem (& _comm_strs .lock );
25
+ _comm_strs .capacity = 16 ;
26
+ _comm_strs .num_strs = 0 ;
27
+ _comm_strs .strs = calloc (16 , sizeof (* _comm_strs .strs ));
28
+ }
29
+
30
+ static struct comm_strs * comm_strs__get (void )
31
+ {
32
+ static pthread_once_t comm_strs_type_once = PTHREAD_ONCE_INIT ;
33
+
34
+ pthread_once (& comm_strs_type_once , comm_strs__init );
35
+
36
+ return & _comm_strs ;
37
+ }
38
+
39
+ static refcount_t * comm_str__refcnt (struct comm_str * cs )
40
+ {
41
+ return & RC_CHK_ACCESS (cs )-> refcnt ;
42
+ }
43
+
44
+ static const char * comm_str__str (const struct comm_str * cs )
45
+ {
46
+ return & RC_CHK_ACCESS (cs )-> str [0 ];
47
+ }
21
48
22
49
static struct comm_str * comm_str__get (struct comm_str * cs )
23
50
{
24
- if (cs && refcount_inc_not_zero (& cs -> refcnt ))
25
- return cs ;
51
+ struct comm_str * result ;
52
+
53
+ if (RC_CHK_GET (result , cs ))
54
+ refcount_inc_not_zero (comm_str__refcnt (cs ));
26
55
27
- return NULL ;
56
+ return result ;
28
57
}
29
58
30
59
static void comm_str__put (struct comm_str * cs )
31
60
{
32
- if (cs && refcount_dec_and_test (& cs -> refcnt )) {
33
- down_write (& comm_str_lock );
34
- rb_erase (& cs -> rb_node , & comm_str_root );
35
- up_write (& comm_str_lock );
36
- zfree (& cs -> str );
37
- free (cs );
61
+ if (cs && refcount_dec_and_test (comm_str__refcnt (cs ))) {
62
+ struct comm_strs * comm_strs = comm_strs__get ();
63
+ int i ;
64
+
65
+ down_write (& comm_strs -> lock );
66
+ for (i = 0 ; i < comm_strs -> num_strs ; i ++ ) {
67
+ if (comm_strs -> strs [i ] == cs )
68
+ break ;
69
+ }
70
+ for (; i < comm_strs -> num_strs - 1 ; i ++ )
71
+ comm_strs -> strs [i ] = comm_strs -> strs [i + 1 ];
72
+
73
+ comm_strs -> num_strs -- ;
74
+ up_write (& comm_strs -> lock );
75
+ RC_CHK_FREE (cs );
76
+ } else {
77
+ RC_CHK_PUT (cs );
38
78
}
39
79
}
40
80
41
- static struct comm_str * comm_str__alloc (const char * str )
81
+ static struct comm_str * comm_str__new (const char * str )
42
82
{
43
- struct comm_str * cs ;
83
+ struct comm_str * result = NULL ;
84
+ RC_STRUCT (comm_str ) * cs ;
44
85
45
- cs = zalloc (sizeof (* cs ));
46
- if (!cs )
47
- return NULL ;
48
-
49
- cs -> str = strdup (str );
50
- if (!cs -> str ) {
51
- free (cs );
52
- return NULL ;
86
+ cs = malloc (sizeof (* cs ) + strlen (str ) + 1 );
87
+ if (ADD_RC_CHK (result , cs )) {
88
+ refcount_set (comm_str__refcnt (result ), 1 );
89
+ strcpy (& cs -> str [0 ], str );
53
90
}
91
+ return result ;
92
+ }
54
93
55
- refcount_set (& cs -> refcnt , 1 );
94
+ static int comm_str__cmp (const void * _lhs , const void * _rhs )
95
+ {
96
+ const struct comm_str * lhs = * (const struct comm_str * const * )_lhs ;
97
+ const struct comm_str * rhs = * (const struct comm_str * const * )_rhs ;
56
98
57
- return cs ;
99
+ return strcmp ( comm_str__str ( lhs ), comm_str__str ( rhs )) ;
58
100
}
59
101
60
- static
61
- struct comm_str * __comm_str__findnew (const char * str , struct rb_root * root )
102
+ static int comm_str__search (const void * _key , const void * _member )
62
103
{
63
- struct rb_node * * p = & root -> rb_node ;
64
- struct rb_node * parent = NULL ;
65
- struct comm_str * iter , * new ;
66
- int cmp ;
67
-
68
- while (* p != NULL ) {
69
- parent = * p ;
70
- iter = rb_entry (parent , struct comm_str , rb_node );
71
-
72
- /*
73
- * If we race with comm_str__put, iter->refcnt is 0
74
- * and it will be removed within comm_str__put call
75
- * shortly, ignore it in this search.
76
- */
77
- cmp = strcmp (str , iter -> str );
78
- if (!cmp && comm_str__get (iter ))
79
- return iter ;
80
-
81
- if (cmp < 0 )
82
- p = & (* p )-> rb_left ;
83
- else
84
- p = & (* p )-> rb_right ;
85
- }
104
+ const char * key = _key ;
105
+ const struct comm_str * member = * (const struct comm_str * const * )_member ;
86
106
87
- new = comm_str__alloc (str );
88
- if (!new )
89
- return NULL ;
107
+ return strcmp (key , comm_str__str (member ));
108
+ }
109
+
110
+ static struct comm_str * __comm_strs__find (struct comm_strs * comm_strs , const char * str )
111
+ {
112
+ struct comm_str * * result ;
90
113
91
- rb_link_node ( & new -> rb_node , parent , p );
92
- rb_insert_color ( & new -> rb_node , root );
114
+ result = bsearch ( str , comm_strs -> strs , comm_strs -> num_strs , sizeof ( struct comm_str * ),
115
+ comm_str__search );
93
116
94
- return new ;
117
+ if (!result )
118
+ return NULL ;
119
+
120
+ return comm_str__get (* result );
95
121
}
96
122
97
- static struct comm_str * comm_str__findnew (const char * str , struct rb_root * root )
123
+ static struct comm_str * comm_strs__findnew (const char * str )
98
124
{
99
- struct comm_str * cs ;
125
+ struct comm_strs * comm_strs = comm_strs__get ();
126
+ struct comm_str * result ;
100
127
101
- down_write (& comm_str_lock );
102
- cs = __comm_str__findnew (str , root );
103
- up_write (& comm_str_lock );
128
+ if (!comm_strs )
129
+ return NULL ;
104
130
105
- return cs ;
131
+ down_read (& comm_strs -> lock );
132
+ result = __comm_strs__find (comm_strs , str );
133
+ up_read (& comm_strs -> lock );
134
+ if (result )
135
+ return result ;
136
+
137
+ down_write (& comm_strs -> lock );
138
+ result = __comm_strs__find (comm_strs , str );
139
+ if (!result ) {
140
+ if (comm_strs -> num_strs == comm_strs -> capacity ) {
141
+ struct comm_str * * tmp ;
142
+
143
+ tmp = reallocarray (comm_strs -> strs ,
144
+ comm_strs -> capacity + 16 ,
145
+ sizeof (* comm_strs -> strs ));
146
+ if (!tmp ) {
147
+ up_write (& comm_strs -> lock );
148
+ return NULL ;
149
+ }
150
+ comm_strs -> strs = tmp ;
151
+ comm_strs -> capacity += 16 ;
152
+ }
153
+ result = comm_str__new (str );
154
+ if (result ) {
155
+ comm_strs -> strs [comm_strs -> num_strs ++ ] = result ;
156
+ qsort (comm_strs -> strs , comm_strs -> num_strs , sizeof (struct comm_str * ),
157
+ comm_str__cmp );
158
+ }
159
+ }
160
+ up_write (& comm_strs -> lock );
161
+ return result ;
106
162
}
107
163
108
164
struct comm * comm__new (const char * str , u64 timestamp , bool exec )
@@ -115,7 +171,7 @@ struct comm *comm__new(const char *str, u64 timestamp, bool exec)
115
171
comm -> start = timestamp ;
116
172
comm -> exec = exec ;
117
173
118
- comm -> comm_str = comm_str__findnew (str , & comm_str_root );
174
+ comm -> comm_str = comm_strs__findnew (str );
119
175
if (!comm -> comm_str ) {
120
176
free (comm );
121
177
return NULL ;
@@ -128,7 +184,7 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
128
184
{
129
185
struct comm_str * new , * old = comm -> comm_str ;
130
186
131
- new = comm_str__findnew (str , & comm_str_root );
187
+ new = comm_strs__findnew (str );
132
188
if (!new )
133
189
return - ENOMEM ;
134
190
@@ -149,5 +205,5 @@ void comm__free(struct comm *comm)
149
205
150
206
const char * comm__str (const struct comm * comm )
151
207
{
152
- return comm -> comm_str -> str ;
208
+ return comm_str__str ( comm -> comm_str ) ;
153
209
}
0 commit comments