Asterisk - The Open Source Telephony Project GIT-master-b023714
Loading...
Searching...
No Matches
Data Structures | Macros | Functions | Variables
test_astobj2_thrash.c File Reference
#include "asterisk.h"
#include <pthread.h>
#include "asterisk/astobj2.h"
#include "asterisk/hashtab.h"
#include "asterisk/lock.h"
#include "asterisk/module.h"
#include "asterisk/test.h"
#include "asterisk/time.h"
#include "asterisk/utils.h"
Include dependency graph for test_astobj2_thrash.c:

Go to the source code of this file.

Data Structures

struct  hash_test
 

Macros

#define COUNT_SLEEP_US   500
 
#define HASH_BUCKETS   151
 
#define MAX_HASH_ENTRIES   15000
 
#define MAX_TEST_SECONDS   60
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
 AST_TEST_DEFINE (hash_test)
 
static int compare_strings (void *lhs, void *rhs, int flags)
 
static int hash_string (const void *obj, const int flags)
 
static void * hash_test_count (void *d)
 
static void * hash_test_grow (void *d)
 Grow the hash data as specified.
 
static void * hash_test_lookup (void *d)
 
static void * hash_test_shrink (void *d)
 
static void ht_delete (void *obj)
 Free test element.
 
static char * ht_new (int i)
 Create test element.
 
static int increment_count (void *obj, void *arg, int flags)
 
static int is_timed_out (struct hash_test const *data)
 
static int load_module (void)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "astobj2 container thrash test" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static int alloc_count = 0
 
static const struct ast_module_infoast_module_info = &__mod_info
 

Macro Definition Documentation

◆ COUNT_SLEEP_US

#define COUNT_SLEEP_US   500

Definition at line 54 of file test_astobj2_thrash.c.

◆ HASH_BUCKETS

#define HASH_BUCKETS   151

Definition at line 52 of file test_astobj2_thrash.c.

◆ MAX_HASH_ENTRIES

#define MAX_HASH_ENTRIES   15000

Definition at line 47 of file test_astobj2_thrash.c.

◆ MAX_TEST_SECONDS

#define MAX_TEST_SECONDS   60

Definition at line 55 of file test_astobj2_thrash.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 359 of file test_astobj2_thrash.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 359 of file test_astobj2_thrash.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 359 of file test_astobj2_thrash.c.

◆ AST_TEST_DEFINE()

AST_TEST_DEFINE ( hash_test  )

Definition at line 247 of file test_astobj2_thrash.c.

248{
250 struct hash_test data = {};
251 pthread_t grow_thread, count_thread, lookup_thread, shrink_thread;
252 void *thread_results;
253 int i;
254
255 switch (cmd) {
256 case TEST_INIT:
257 info->name = "thrash";
258 info->category = "/main/astobj2/";
259 info->summary = "Testing astobj2 container concurrency";
260 info->description = "Test astobj2 container concurrency correctness.";
261 return AST_TEST_NOT_RUN;
262 case TEST_EXECUTE:
263 break;
264 }
265
266 ast_test_status_update(test, "Executing hash concurrency test...\n");
267 data.preload = MAX_HASH_ENTRIES / 2;
268 data.max_grow = MAX_HASH_ENTRIES - data.preload;
272
273 if (data.to_be_thrashed == NULL) {
274 ast_test_status_update(test, "Allocation failed\n");
275 /* Nothing needs to be freed; early return is fine */
276 return AST_TEST_FAIL;
277 }
278
279 /* preload with data to delete */
280 for (i = 1; i < data.preload; ++i) {
281 char *ht = ht_new(-i);
282 if (ht == NULL) {
283 ast_test_status_update(test, "Allocation failed\n");
284 ao2_ref(data.to_be_thrashed, -1);
285 return AST_TEST_FAIL;
286 }
287 ao2_link(data.to_be_thrashed, ht);
288 ao2_ref(ht, -1);
289 }
290
291 /* add data.max_grow entries to the ao2 container */
292 ast_pthread_create(&grow_thread, NULL, hash_test_grow, &data);
293 /* continually count the keys added by the grow thread */
294 ast_pthread_create(&count_thread, NULL, hash_test_count, &data);
295 /* continually lookup keys added by the grow thread */
296 ast_pthread_create(&lookup_thread, NULL, hash_test_lookup, &data);
297 /* delete all keys preloaded into the ao2 container */
298 ast_pthread_create(&shrink_thread, NULL, hash_test_shrink, &data);
299
300 pthread_join(grow_thread, &thread_results);
301 if (thread_results != NULL) {
302 ast_test_status_update(test, "Growth thread failed: %s\n",
303 (char *)thread_results);
304 res = AST_TEST_FAIL;
305 }
306
307 pthread_join(count_thread, &thread_results);
308 if (thread_results != NULL) {
309 ast_test_status_update(test, "Count thread failed: %s\n",
310 (char *)thread_results);
311 res = AST_TEST_FAIL;
312 }
313
314 pthread_join(lookup_thread, &thread_results);
315 if (thread_results != NULL) {
316 ast_test_status_update(test, "Lookup thread failed: %s\n",
317 (char *)thread_results);
318 res = AST_TEST_FAIL;
319 }
320
321 pthread_join(shrink_thread, &thread_results);
322 if (thread_results != NULL) {
323 ast_test_status_update(test, "Shrink thread failed: %s\n",
324 (char *)thread_results);
325 res = AST_TEST_FAIL;
326 }
327
328 if (ao2_container_count(data.to_be_thrashed) != data.max_grow) {
330 "Invalid ao2 container size. Expected: %d, Actual: %d\n",
332 res = AST_TEST_FAIL;
333 }
334
335 ao2_ref(data.to_be_thrashed, -1);
336
337 /* check for object leaks */
338 if (ast_atomic_fetchadd_int(&alloc_count, 0) != 0) {
339 ast_test_status_update(test, "Leaked %d objects!\n",
341 res = AST_TEST_FAIL;
342 }
343
344 return res;
345}
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition astobj2.h:1303
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition lock.h:764
#define NULL
Definition resample.c:96
struct timeval deadline
struct ao2_container * to_be_thrashed
@ TEST_INIT
Definition test.h:200
@ TEST_EXECUTE
Definition test.h:201
#define ast_test_status_update(a, b, c...)
Definition test.h:129
ast_test_result_state
Definition test.h:193
@ AST_TEST_PASS
Definition test.h:195
@ AST_TEST_FAIL
Definition test.h:196
@ AST_TEST_NOT_RUN
Definition test.h:194
static void * hash_test_lookup(void *d)
static void * hash_test_shrink(void *d)
#define MAX_TEST_SECONDS
static void * hash_test_count(void *d)
static int compare_strings(void *lhs, void *rhs, int flags)
static int hash_string(const void *obj, const int flags)
static char * ht_new(int i)
Create test element.
#define MAX_HASH_ENTRIES
static void * hash_test_grow(void *d)
Grow the hash data as specified.
#define HASH_BUCKETS
static int alloc_count
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition extconf.c:2280
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition time.h:235
#define ast_pthread_create(a, b, c, d)
Definition utils.h:621

References alloc_count, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ao2_container_count(), ao2_link, ao2_ref, ast_atomic_fetchadd_int(), ast_pthread_create, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, ast_tv(), ast_tvadd(), ast_tvnow(), compare_strings(), hash_test::deadline, HASH_BUCKETS, hash_string(), hash_test_count(), hash_test_grow(), hash_test_lookup(), hash_test_shrink(), ht_new(), hash_test::max_grow, MAX_HASH_ENTRIES, MAX_TEST_SECONDS, NULL, hash_test::preload, TEST_EXECUTE, TEST_INIT, and hash_test::to_be_thrashed.

◆ compare_strings()

static int compare_strings ( void *  lhs,
void *  rhs,
int  flags 
)
static

Definition at line 236 of file test_astobj2_thrash.c.

237{
238 const char *lhs_str = lhs;
239 const char *rhs_str = rhs;
240 if (strcasecmp(lhs_str, rhs_str) == 0) {
241 return CMP_MATCH | CMP_STOP;
242 } else {
243 return 0;
244 }
245}
@ CMP_MATCH
Definition astobj2.h:1027
@ CMP_STOP
Definition astobj2.h:1028

References CMP_MATCH, and CMP_STOP.

Referenced by AST_TEST_DEFINE().

◆ hash_string()

static int hash_string ( const void *  obj,
const int  flags 
)
static

Definition at line 231 of file test_astobj2_thrash.c.

232{
234}
unsigned int ast_hashtab_hash_string_nocase(const void *obj)
Hashes a string to a number ignoring case.
Definition hashtab.c:181

References ast_hashtab_hash_string_nocase().

Referenced by AST_TEST_DEFINE().

◆ hash_test_count()

static void * hash_test_count ( void *  d)
static

Continuously iterate through all the entries in the hash

Definition at line 203 of file test_astobj2_thrash.c.

204{
205 const struct hash_test *data = d;
206 int count = 0;
207 int last_count = 0;
208
209 while (count < data->max_grow) {
210 last_count = count;
211 count = 0;
213
214 if (last_count == count) {
215 /* Allow other threads to run. */
216 usleep(COUNT_SLEEP_US);
217 } else if (last_count > count) {
218 /* Make sure the ao2 container never shrinks */
219 return "ao2 container unexpectedly shrank";
220 }
221
222 if (is_timed_out(data)) {
223 return "Count timed out";
224 }
225 }
226
227 /* Successfully iterated over all of the expected elements */
228 return NULL;
229}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
@ OBJ_MULTIPLE
Definition astobj2.h:1049
static int is_timed_out(struct hash_test const *data)
static int increment_count(void *obj, void *arg, int flags)
#define COUNT_SLEEP_US
static struct test_val d

References ao2_callback, COUNT_SLEEP_US, d, increment_count(), is_timed_out(), hash_test::max_grow, NULL, OBJ_MULTIPLE, and hash_test::to_be_thrashed.

Referenced by AST_TEST_DEFINE().

◆ hash_test_grow()

static void * hash_test_grow ( void *  d)
static

Grow the hash data as specified.

Definition at line 98 of file test_astobj2_thrash.c.

99{
100 struct hash_test *data = d;
101 int i;
102
103 for (i = 0; i < data->max_grow; ++i) {
104 char *ht;
105 if (is_timed_out(data)) {
106 printf("Growth timed out at %d\n", i);
107 return "Growth timed out";
108 }
109 ht = ht_new(i);
110 if (ht == NULL) {
111 return "Allocation failed";
112 }
113 ao2_link(data->to_be_thrashed, ht);
114 ao2_ref(ht, -1);
116 }
117 return NULL;
118}

References ao2_link, ao2_ref, ast_atomic_fetchadd_int(), d, hash_test::grow_count, ht_new(), is_timed_out(), hash_test::max_grow, NULL, and hash_test::to_be_thrashed.

Referenced by AST_TEST_DEFINE().

◆ hash_test_lookup()

static void * hash_test_lookup ( void *  d)
static

Randomly lookup data in the hash

Definition at line 121 of file test_astobj2_thrash.c.

122{
123 struct hash_test *data = d;
124 int max;
125 unsigned seed = time(NULL);
126
127 /* ast_atomic_fetchadd_int provide a memory fence so that the optimizer doesn't
128 * optimize away reads.
129 */
130 while ((max = ast_atomic_fetchadd_int(&data->grow_count, 0)) < data->max_grow) {
131 int i;
132 char *obj;
133 char *from_ao2;
134
135 if (is_timed_out(data)) {
136 return "Lookup timed out";
137 }
138
139 if (max == 0) {
140 /* No data yet; yield and try again */
141 sched_yield();
142 continue;
143 }
144
145 /* Randomly lookup one object from the hash */
146 i = rand_r(&seed) % max;
147 obj = ht_new(i);
148 if (obj == NULL) {
149 return "Allocation failed";
150 }
151 from_ao2 = ao2_find(data->to_be_thrashed, obj, OBJ_POINTER);
152 ao2_ref(obj, -1);
153 ao2_ref(from_ao2, -1);
154 if (from_ao2 == NULL) {
155 return "Key unexpectedly missing";
156 }
157 }
158
159 return NULL;
160}
#define OBJ_POINTER
Definition astobj2.h:1150
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
#define max(a, b)
Definition f2c.h:198

References ao2_find, ao2_ref, ast_atomic_fetchadd_int(), d, hash_test::grow_count, ht_new(), is_timed_out(), max, hash_test::max_grow, NULL, OBJ_POINTER, and hash_test::to_be_thrashed.

Referenced by AST_TEST_DEFINE().

◆ hash_test_shrink()

static void * hash_test_shrink ( void *  d)
static

Delete entries from the hash

Definition at line 163 of file test_astobj2_thrash.c.

164{
165 const struct hash_test *data = d;
166 int i;
167
168 for (i = 1; i < data->preload; ++i) {
169 char *obj = ht_new(-i);
170 char *from_ao2;
171
172 if (obj == NULL) {
173 return "Allocation failed";
174 }
175 from_ao2 = ao2_find(data->to_be_thrashed, obj, OBJ_UNLINK | OBJ_POINTER);
176
177 ao2_ref(obj, -1);
178 if (from_ao2) {
179 ao2_ref(from_ao2, -1);
180 } else {
181 return "Could not find object to delete";
182 }
183
184 if (is_timed_out(data)) {
185 return "Shrink timed out";
186 }
187 }
188
189 return NULL;
190}
@ OBJ_UNLINK
Definition astobj2.h:1039

References ao2_find, ao2_ref, d, ht_new(), is_timed_out(), NULL, OBJ_POINTER, OBJ_UNLINK, hash_test::preload, and hash_test::to_be_thrashed.

Referenced by AST_TEST_DEFINE().

◆ ht_delete()

static void ht_delete ( void *  obj)
static

Free test element.

Definition at line 77 of file test_astobj2_thrash.c.

References alloc_count, and ast_atomic_fetchadd_int().

Referenced by ht_new().

◆ ht_new()

static char * ht_new ( int  i)
static

Create test element.

Definition at line 83 of file test_astobj2_thrash.c.

84{
85 const int buflen = 12;
86 char *keybuf = ao2_alloc(buflen, ht_delete);
87 int needed;
88 if (keybuf == NULL) {
89 return NULL;
90 }
91 needed = snprintf(keybuf, buflen, "key%08x", (unsigned)i);
93 ast_assert(needed + 1 <= buflen);
94 return keybuf;
95}
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
static void ht_delete(void *obj)
Free test element.
#define ast_assert(a)
Definition utils.h:776

References alloc_count, ao2_alloc, ast_assert, ast_atomic_fetchadd_int(), ht_delete(), and NULL.

Referenced by AST_TEST_DEFINE(), hash_test_grow(), hash_test_lookup(), and hash_test_shrink().

◆ increment_count()

static int increment_count ( void *  obj,
void *  arg,
int  flags 
)
static

ao2_callback for hash_test_count

Definition at line 193 of file test_astobj2_thrash.c.

193 {
194 char *ht = obj;
195 int *count = arg;
196 if (strncmp(ht, "key0", 4) == 0) {
197 ++(*count);
198 }
199 return 0;
200}

Referenced by hash_test_count().

◆ is_timed_out()

static int is_timed_out ( struct hash_test const *  data)
static

Definition at line 72 of file test_astobj2_thrash.c.

72 {
73 return ast_tvdiff_us(data->deadline, ast_tvnow()) < 0;
74}
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition time.h:87

References ast_tvdiff_us(), ast_tvnow(), and hash_test::deadline.

Referenced by hash_test_count(), hash_test_grow(), hash_test_lookup(), and hash_test_shrink().

◆ load_module()

static int load_module ( void  )
static

Definition at line 353 of file test_astobj2_thrash.c.

354{
357}
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
#define AST_TEST_REGISTER(cb)
Definition test.h:127

References AST_MODULE_LOAD_SUCCESS, and AST_TEST_REGISTER.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 347 of file test_astobj2_thrash.c.

348{
350 return 0;
351}
#define AST_TEST_UNREGISTER(cb)
Definition test.h:128

References AST_TEST_UNREGISTER.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "astobj2 container thrash test" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 359 of file test_astobj2_thrash.c.

◆ alloc_count

int alloc_count = 0
static

Definition at line 70 of file test_astobj2_thrash.c.

Referenced by AST_TEST_DEFINE(), ht_delete(), and ht_new().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 359 of file test_astobj2_thrash.c.