Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Functions | Variables
test_scoped_lock.c File Reference

SCOPED_LOCK unit tests. More...

#include "asterisk.h"
#include "asterisk/test.h"
#include "asterisk/utils.h"
#include "asterisk/module.h"
#include "asterisk/astobj2.h"
Include dependency graph for test_scoped_lock.c:

Go to the source code of this file.

Data Structures

struct  test_struct
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
 AST_TEST_DEFINE (lock_test)
 
 AST_TEST_DEFINE (cleanup_order)
 
static int load_module (void)
 
static void lock_it (ast_mutex_t *lock)
 
static struct test_structtest_iterator_next (struct ao2_iterator *iter)
 wrapper for ao2_iterator_next More...
 
static void test_lock (struct test_struct *test)
 lock callback function More...
 
static struct test_structtest_ref (struct test_struct *test)
 ref callback function More...
 
static void test_unlock (struct test_struct *test)
 unlock callback function More...
 
static void test_unref (struct test_struct *test)
 unref callback function More...
 
static int unload_module (void)
 
static void unlock_it (ast_mutex_t *lock)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "SCOPED_LOCK test module" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_testcurrent_test
 
static int indicator
 
static ast_mutex_t the_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 

Detailed Description

SCOPED_LOCK unit tests.

Author
Mark Michelson mmich[email protected]elso[email protected][email protected][email protected]ium.[email protected]com

Definition in file test_scoped_lock.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 283 of file test_scoped_lock.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 283 of file test_scoped_lock.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 283 of file test_scoped_lock.c.

◆ AST_TEST_DEFINE() [1/2]

AST_TEST_DEFINE ( lock_test  )

Definition at line 55 of file test_scoped_lock.c.

References ast_log, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, indicator, sip_to_pjsip::info(), lock, lock_it(), LOG_ERROR, SCOPED_LOCK, test, TEST_EXECUTE, TEST_INIT, the_lock, and unlock_it().

56 {
58  int i;
59 
60  switch(cmd) {
61  case TEST_INIT:
62  info->name = "lock_test";
63  info->category = "/main/lock/";
64  info->summary = "SCOPED_LOCK test";
65  info->description =
66  "Tests that scoped locks are scoped as they are expected to be";
67  return AST_TEST_NOT_RUN;
68  case TEST_EXECUTE:
69  break;
70  }
71 
73  indicator = 0;
74  {
76  if (indicator != 1) {
77  ast_log(LOG_ERROR, "The lock was not acquired via RAII");
78  res = AST_TEST_FAIL;
79  }
80  }
81  if (indicator != 0) {
82  ast_log(LOG_ERROR, "The lock was not released when the variable went out of scope");
83  res = AST_TEST_FAIL;
84  }
85 
86  for (i = 0; i < 10; ++i) {
88  if (indicator != 1) {
89  ast_log(LOG_ERROR, "The lock was not acquired via RAII");
90  res = AST_TEST_FAIL;
91  }
92  }
93 
94  if (indicator != 0) {
95  ast_log(LOG_ERROR, "The lock was not released when the variable went out of scope");
96  res = AST_TEST_FAIL;
97  }
98 
99  return res;
100 }
static ast_mutex_t the_lock
static int indicator
static void lock_it(ast_mutex_t *lock)
#define ast_log
Definition: astobj2.c:42
ast_mutex_t lock
Definition: app_meetme.c:1091
#define SCOPED_LOCK(varname, lock, lockfunc, unlockfunc)
Scoped Locks.
Definition: lock.h:581
#define LOG_ERROR
Definition: logger.h:285
def info(msg)
static void unlock_it(ast_mutex_t *lock)
ast_test_result_state
Definition: test.h:200
static struct ast_test * current_test
static struct ast_test * test
Definition: localtime.c:115

◆ AST_TEST_DEFINE() [2/2]

AST_TEST_DEFINE ( cleanup_order  )

Definition at line 197 of file test_scoped_lock.c.

References ao2_alloc, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_cleanup, ao2_container_alloc_hash, ao2_iterator_destroy(), ao2_iterator_init(), ao2_link, ast_log, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, container, sip_to_pjsip::info(), lock, LOG_ERROR, NULL, RAII_VAR, SCOPED_LOCK, test, TEST_EXECUTE, TEST_INIT, test_iterator_next(), test_lock(), test_ref(), test_unlock(), and test_unref().

198 {
200  struct ao2_iterator iter;
201  struct test_struct *object_iter;
203  RAII_VAR(struct test_struct *, object, NULL, ao2_cleanup);
204 
205  switch(cmd) {
206  case TEST_INIT:
207  info->name = "cleanup_order_test";
208  info->category = "/main/lock/";
209  info->summary = "cleanup order test";
210  info->description =
211  "Tests that variables with cleanup attributes are cleaned up\n"
212  "in the reverse order they are declared.";
213  return AST_TEST_NOT_RUN;
214  case TEST_EXECUTE:
215  break;
216  }
217  current_test = test;
218 
220  object = ao2_alloc(sizeof(*object), NULL);
221  if (!object || !container) {
222  /* Allocation failure. We can't even pretend to do this test properly */
223  return AST_TEST_FAIL;
224  }
225 
226  {
227  /* Purpose of this block is to make sure that the cleanup operations
228  * run in the reverse order that they were created here.
229  */
230  RAII_VAR(struct test_struct *, object2, test_ref(object), test_unref);
232  if (!object->reffed || !object->locked) {
233  ast_log(LOG_ERROR, "Test failed due to out of order initializations");
234  res = AST_TEST_FAIL;
235  }
236  }
237 
238  if (object->reffed || object->locked) {
239  ast_log(LOG_ERROR, "Test failed due to out of order cleanups\n");
240  res = AST_TEST_FAIL;
241  }
242 
243  /* Now link the object into the container for a little experiment ... */
244  ao2_link(container, object);
245 
246  /* This loop is to ensure that unrefs in a for loop occur after the cleanup
247  * operations of items inside the loop. If we hope to be able to mix scoped locks
248  * and ao2 refs, this is the way to go about it.
249  */
250  for (iter = ao2_iterator_init(container, 0);
251  (object_iter = test_iterator_next(&iter));
252  test_unref(object_iter)) {
253  SCOPED_LOCK(lock, object_iter, test_lock, test_unlock);
254  if (!object->reffed || !object->locked) {
255  ast_log(LOG_ERROR, "Test failed due to out of order initializations");
256  res = AST_TEST_FAIL;
257  }
258  }
259  ao2_iterator_destroy(&iter);
260 
261  if (object->reffed || object->locked) {
262  ast_log(LOG_ERROR, "Test failed due to out of order cleanups\n");
263  res = AST_TEST_FAIL;
264  }
265 
266  return res;
267 }
static void test_lock(struct test_struct *test)
lock callback function
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define NULL
Definition: resample.c:96
static struct test_struct * test_ref(struct test_struct *test)
ref callback function
#define ast_log
Definition: astobj2.c:42
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
ast_mutex_t lock
Definition: app_meetme.c:1091
#define SCOPED_LOCK(varname, lock, lockfunc, unlockfunc)
Scoped Locks.
Definition: lock.h:581
struct ao2_container * container
Definition: res_fax.c:502
#define LOG_ERROR
Definition: logger.h:285
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
static void test_unlock(struct test_struct *test)
unlock callback function
static void test_unref(struct test_struct *test)
unref callback function
def info(msg)
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static struct test_struct * test_iterator_next(struct ao2_iterator *iter)
wrapper for ao2_iterator_next
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Generic container type.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
ast_test_result_state
Definition: test.h:200
static struct ast_test * current_test
static struct ast_test * test
Definition: localtime.c:115
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ load_module()

static int load_module ( void  )
static

Definition at line 276 of file test_scoped_lock.c.

References AST_MODULE_LOAD_SUCCESS, and AST_TEST_REGISTER.

277 {
278  AST_TEST_REGISTER(lock_test);
279  AST_TEST_REGISTER(cleanup_order);
281 }
#define AST_TEST_REGISTER(cb)
Definition: test.h:127

◆ lock_it()

static void lock_it ( ast_mutex_t lock)
static

Definition at line 43 of file test_scoped_lock.c.

References ast_mutex_lock, and indicator.

Referenced by AST_TEST_DEFINE().

44 {
45  indicator = 1;
46  ast_mutex_lock(lock);
47 }
static int indicator
#define ast_mutex_lock(a)
Definition: lock.h:187

◆ test_iterator_next()

static struct test_struct* test_iterator_next ( struct ao2_iterator iter)
static

wrapper for ao2_iterator_next

Grabs the next item in the container and replaces the ref acquired from ao2_iterator_next() with a call to test_ref().

Definition at line 179 of file test_scoped_lock.c.

References ao2_iterator_next, ao2_ref, NULL, test, and test_ref().

Referenced by AST_TEST_DEFINE().

180 {
181  struct test_struct *test = ao2_iterator_next(iter);
182 
183  if (!test) {
184  return NULL;
185  }
186 
187  /* Remove ref from ao2_iterator_next() and replace it with
188  * a test_ref() call. The order here is safe since we can guarantee
189  * the container still has a ref to the test structure.
190  */
191  ao2_ref(test, -1);
192  test_ref(test);
193 
194  return test;
195 }
#define NULL
Definition: resample.c:96
static struct test_struct * test_ref(struct test_struct *test)
ref callback function
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
static struct ast_test * test
Definition: localtime.c:115

◆ test_lock()

static void test_lock ( struct test_struct test)
static

lock callback function

Locks the object passed in. Only sets the locked flag if the object is reffed. This allows us to check that locking is always occurring after reffing.

Definition at line 115 of file test_scoped_lock.c.

References ao2_lock, ast_test_status_update, test_struct::locked, and test_struct::reffed.

Referenced by AST_TEST_DEFINE().

116 {
117  ast_test_status_update(current_test, "Lock is occurring\n");
118  ao2_lock(test);
119  if (test->reffed) {
120  test->locked = 1;
121  }
122 }
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_lock(a)
Definition: astobj2.h:718
static struct ast_test * current_test

◆ test_ref()

static struct test_struct* test_ref ( struct test_struct test)
static

ref callback function

Refs the object passed in. Only sets the reffed flag if the object is not locked. This allows us to ensure that reffing always occurs before locking.

Definition at line 147 of file test_scoped_lock.c.

References ao2_ref, ast_test_status_update, test_struct::locked, test_struct::reffed, and test.

Referenced by AST_TEST_DEFINE(), and test_iterator_next().

148 {
149  ast_test_status_update(current_test, "Ref is occurring\n");
150  ao2_ref(test, +1);
151  if (!test->locked) {
152  test->reffed = 1;
153  }
154  return test;
155 }
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static struct ast_test * current_test
static struct ast_test * test
Definition: localtime.c:115

◆ test_unlock()

static void test_unlock ( struct test_struct test)
static

unlock callback function

Unlocks the object passed in. Only clears the locked flag if the object is still reffed. This allows us to ensure that unlocking is always occurring before unreffing.

Definition at line 131 of file test_scoped_lock.c.

References ao2_unlock, ast_test_status_update, test_struct::locked, and test_struct::reffed.

Referenced by AST_TEST_DEFINE().

132 {
133  ast_test_status_update(current_test, "Unlock is occurring\n");
134  ao2_unlock(test);
135  if (test->reffed) {
136  test->locked = 0;
137  }
138 }
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static struct ast_test * current_test

◆ test_unref()

static void test_unref ( struct test_struct test)
static

unref callback function

Unrefs the object passed in. Only sets the unreffed flag if the object is not locked. This allows us to ensure that unreffing always occurs after unlocking.

Definition at line 164 of file test_scoped_lock.c.

References ao2_ref, ast_test_status_update, test_struct::locked, and test_struct::reffed.

Referenced by AST_TEST_DEFINE().

165 {
166  ast_test_status_update(current_test, "Unref is occurring\n");
167  ao2_ref(test, -1);
168  if (!test->locked) {
169  test->reffed = 0;
170  }
171 }
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static struct ast_test * current_test

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 269 of file test_scoped_lock.c.

References AST_TEST_UNREGISTER.

270 {
271  AST_TEST_UNREGISTER(lock_test);
272  AST_TEST_UNREGISTER(cleanup_order);
273  return 0;
274 }
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

◆ unlock_it()

static void unlock_it ( ast_mutex_t lock)
static

Definition at line 49 of file test_scoped_lock.c.

References ast_mutex_unlock, and indicator.

Referenced by AST_TEST_DEFINE().

50 {
51  indicator = 0;
52  ast_mutex_unlock(lock);
53 }
static int indicator
#define ast_mutex_unlock(a)
Definition: lock.h:188

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "SCOPED_LOCK test module" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .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 283 of file test_scoped_lock.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 283 of file test_scoped_lock.c.

◆ current_test

struct ast_test* current_test
static

Definition at line 40 of file test_scoped_lock.c.

◆ indicator

int indicator
static

◆ the_lock

ast_mutex_t the_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
static

Definition at line 41 of file test_scoped_lock.c.

Referenced by AST_TEST_DEFINE().