Asterisk - The Open Source Telephony Project GIT-master-f36a736
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 (cleanup_order)
 
 AST_TEST_DEFINE (lock_test)
 
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_test * current_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.nosp@m.elso.nosp@m.n@dig.nosp@m.ium..nosp@m.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 ( cleanup_order  )

Definition at line 197 of file test_scoped_lock.c.

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 }
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 }
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}
ast_mutex_t lock
Definition: app_sla.c:331
#define ast_log
Definition: astobj2.c:42
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#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
#define LOG_ERROR
#define SCOPED_LOCK(varname, lock, lockfunc, unlockfunc)
Scoped Locks.
Definition: lock.h:583
def info(msg)
struct ao2_container * container
Definition: res_fax.c:501
#define NULL
Definition: resample.c:96
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
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 struct test_struct * test_ref(struct test_struct *test)
ref callback function
static void test_unref(struct test_struct *test)
unref callback function
static void test_unlock(struct test_struct *test)
unlock callback function
static struct ast_test * current_test
static void test_lock(struct test_struct *test)
lock callback function
static struct test_struct * test_iterator_next(struct ao2_iterator *iter)
wrapper for ao2_iterator_next
#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:941

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, current_test, sip_to_pjsip::info(), lock, LOG_ERROR, NULL, RAII_VAR, SCOPED_LOCK, TEST_EXECUTE, TEST_INIT, test_iterator_next(), test_lock(), test_ref(), test_unlock(), and test_unref().

◆ AST_TEST_DEFINE() [2/2]

AST_TEST_DEFINE ( lock_test  )

Definition at line 55 of file test_scoped_lock.c.

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 void lock_it(ast_mutex_t *lock)
static void unlock_it(ast_mutex_t *lock)
static int indicator

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

◆ load_module()

static int load_module ( void  )
static

Definition at line 276 of file test_scoped_lock.c.

277{
278 AST_TEST_REGISTER(lock_test);
279 AST_TEST_REGISTER(cleanup_order);
281}
@ 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.

◆ lock_it()

static void lock_it ( ast_mutex_t lock)
static

Definition at line 43 of file test_scoped_lock.c.

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

References ast_mutex_lock, indicator, and lock.

Referenced by AST_TEST_DEFINE().

◆ 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.

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 ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459

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

Referenced by AST_TEST_DEFINE().

◆ 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.

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 ao2_lock(a)
Definition: astobj2.h:717
#define ast_test_status_update(a, b, c...)
Definition: test.h:129

References ao2_lock, ast_test_status_update, and current_test.

Referenced by AST_TEST_DEFINE().

◆ 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.

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}

References ao2_ref, ast_test_status_update, and current_test.

Referenced by AST_TEST_DEFINE(), and test_iterator_next().

◆ 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.

132{
133 ast_test_status_update(current_test, "Unlock is occurring\n");
135 if (test->reffed) {
136 test->locked = 0;
137 }
138}
#define ao2_unlock(a)
Definition: astobj2.h:729

References ao2_unlock, ast_test_status_update, and current_test.

Referenced by AST_TEST_DEFINE().

◆ 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.

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}

References ao2_ref, ast_test_status_update, and current_test.

Referenced by AST_TEST_DEFINE().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 269 of file test_scoped_lock.c.

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

References AST_TEST_UNREGISTER.

◆ unlock_it()

static void unlock_it ( ast_mutex_t lock)
static

Definition at line 49 of file test_scoped_lock.c.

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

References ast_mutex_unlock, indicator, and lock.

Referenced by AST_TEST_DEFINE().

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.

Referenced by AST_TEST_DEFINE(), test_lock(), test_ref(), test_unlock(), and test_unref().

◆ 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().