瀏覽代碼

cnxcc: make cnxcc locks re-entrant

Federico Cabiddu 10 年之前
父節點
當前提交
a4cdd61afa
共有 5 個文件被更改,包括 178 次插入123 次删除
  1. 16 17
      modules/cnxcc/cnxcc_check.c
  2. 96 86
      modules/cnxcc/cnxcc_mod.c
  3. 52 4
      modules/cnxcc/cnxcc_mod.h
  4. 2 2
      modules/cnxcc/cnxcc_redis.c
  5. 12 14
      modules/cnxcc/cnxcc_rpc.c

+ 16 - 17
modules/cnxcc/cnxcc_check.c

@@ -24,9 +24,6 @@
 
 #include <stdio.h>
 
-#include "../../locking.h"
-#include "../../lock_ops.h"
-
 #include "cnxcc_mod.h"
 #include "cnxcc.h"
 #include "cnxcc_check.h"
@@ -40,7 +37,7 @@ void check_calls_by_money(unsigned int ticks, void *param) {
 	call_t *tmp_call = NULL;
 	int i;
 
-	lock_get(&_data.money.lock);
+	cnxcc_lock(_data.money.lock);
 
 	if (_data.money.credit_data_by_client->table)
 		for(i = 0; i < _data.money.credit_data_by_client->size; i++)
@@ -54,7 +51,7 @@ void check_calls_by_money(unsigned int ticks, void *param) {
 					break;
 				}*/
 
-				lock_get(&credit_data->lock);
+				cnxcc_lock(credit_data->lock);
 
 				clist_foreach_safe(credit_data->call_list, call, tmp_call, next) {
 					int consumed_time = 0;
@@ -88,7 +85,7 @@ void check_calls_by_money(unsigned int ticks, void *param) {
 				}
 
 				if (credit_data->concurrent_calls == 0) {
-					lock_release(&credit_data->lock);
+					cnxcc_unlock(credit_data->lock);
 					continue;
 				}
 
@@ -112,15 +109,16 @@ void check_calls_by_money(unsigned int ticks, void *param) {
 					terminate_all_calls(credit_data);
 
 					// make sure the rest of the servers kill the calls belonging to this customer
-					redis_publish_to_kill_list(credit_data);
-					lock_release(&credit_data->lock);
+					if (_data.redis)
+						redis_publish_to_kill_list(credit_data);
+					cnxcc_unlock(credit_data->lock);
 					break;
 				}
 
-				lock_release(&credit_data->lock);
+				cnxcc_unlock(credit_data->lock);
 			}
 
-	lock_release(&_data.money.lock);
+	cnxcc_unlock(_data.money.lock);
 }
 
 void check_calls_by_time(unsigned int ticks, void *param) {
@@ -129,7 +127,7 @@ void check_calls_by_time(unsigned int ticks, void *param) {
 	call_t *tmp_call = NULL;
 	int i;
 
-	lock_get(&_data.time.lock);
+	cnxcc_lock(_data.time.lock);
 
 	if (_data.time.credit_data_by_client->table)
 		for(i = 0; i < _data.time.credit_data_by_client->size; i++)
@@ -139,7 +137,7 @@ void check_calls_by_time(unsigned int ticks, void *param) {
 				int total_consumed_secs = 0;
 				double consumption_diff = 0/*, distributed_consumption = 0*/;
 
-				lock_get(&credit_data->lock);
+				cnxcc_lock(credit_data->lock);
 
 				/*if (i > SAFE_ITERATION_THRESHOLD)
 				{
@@ -169,7 +167,7 @@ void check_calls_by_time(unsigned int ticks, void *param) {
 				}
 
 				if (credit_data->concurrent_calls == 0) {
-					lock_release(&credit_data->lock);
+					cnxcc_unlock(credit_data->lock);
 					continue;
 				}
 
@@ -190,13 +188,14 @@ void check_calls_by_time(unsigned int ticks, void *param) {
 					terminate_all_calls(credit_data);
 
 					// make sure the rest of the servers kill the calls belonging to this customer
-					redis_publish_to_kill_list(credit_data);
-					lock_release(&credit_data->lock);
+					if (_data.redis)
+						redis_publish_to_kill_list(credit_data);
+					cnxcc_unlock(credit_data->lock);
 					break;
 				}
 
-				lock_release(&credit_data->lock);
+				cnxcc_unlock(credit_data->lock);
 			}
 
-	lock_release(&_data.time.lock);
+	cnxcc_unlock(_data.time.lock);
 }

+ 96 - 86
modules/cnxcc/cnxcc_mod.c

@@ -294,10 +294,12 @@ static int __mod_init(void) {
 	if (__init_hashtable(_data.channel.call_data_by_cid) != 0)
 		return -1;
 
-	lock_init(&_data.lock);
-	lock_init(&_data.time.lock);
-	lock_init(&_data.money.lock);
-	lock_init(&_data.channel.lock);
+
+	cnxcc_lock_init(_data.lock);
+
+	cnxcc_lock_init(_data.time.lock);
+	cnxcc_lock_init(_data.money.lock);
+	cnxcc_lock_init(_data.channel.lock);
 
 	register_mi_cmd(__mi_credit_control_stats, "cnxcc_stats", NULL, NULL, 0);
 
@@ -471,45 +473,45 @@ int try_get_credit_data_entry(str *client_id, credit_data_t **credit_data) {
 
 	/* by money */
 	hts = &_data.money;
-	lock_get(&hts->lock);
+	cnxcc_lock(hts->lock);
 
 	cd_entry = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
 
 	if (cd_entry != NULL) {
 		*credit_data	= cd_entry->u.p;
-		lock_release(&hts->lock);
+		cnxcc_unlock(hts->lock);
 		return 0;
 	}
 
-	lock_release(&hts->lock);
+	cnxcc_unlock(hts->lock);
 
 	/* by time */
 	hts = &_data.time;
-	lock_get(&hts->lock);
+	cnxcc_lock(hts->lock);
 
 	cd_entry = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
 
 	if (cd_entry != NULL) {
 		*credit_data	= cd_entry->u.p;
-		lock_release(&hts->lock);
+		cnxcc_unlock(hts->lock);
 		return 0;
 	}
 
-	lock_release(&hts->lock);
+	cnxcc_unlock(hts->lock);
 
 	/* by channel */
 	hts = &_data.channel;
-	lock_get(&hts->lock);
+	cnxcc_lock(hts->lock);
 
 	cd_entry = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
 
 	if (cd_entry != NULL) {
 		*credit_data	= cd_entry->u.p;
-		lock_release(&hts->lock);
+		cnxcc_unlock(hts->lock);
 		return 0;
 	}
 
-	lock_release(&hts->lock);
+	cnxcc_unlock(hts->lock);
 	return -1;
 }
 
@@ -520,45 +522,45 @@ int try_get_call_entry(str *callid, call_t **call, hash_tables_t **hts) {
 
 	/* by money */
 	*hts = &_data.money;
-	lock_get(&(*hts)->lock);
+	cnxcc_lock((*hts)->lock);
 
 	call_entry = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
 
 	if (call_entry != NULL) {
 		*call = call_entry->u.p;
-		lock_release(&(*hts)->lock);
+		cnxcc_unlock((*hts)->lock);
 		return 0;
 	}
 
-	lock_release(&(*hts)->lock);
+	cnxcc_unlock((*hts)->lock);
 
 	/* by time */
 	*hts = &_data.time;
-	lock_get(&(*hts)->lock);
+	cnxcc_lock((*hts)->lock);
 
 	call_entry = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
 
 	if (call_entry != NULL) {
 		*call = call_entry->u.p;
-		lock_release(&(*hts)->lock);
+		cnxcc_unlock((*hts)->lock);
 		return 0;
 	}
 
-	lock_release(&(*hts)->lock);
+	cnxcc_unlock((*hts)->lock);
 
 	/* by channel */
 	*hts = &_data.channel;
-	lock_get(&(*hts)->lock);
+	cnxcc_lock((*hts)->lock);
 
 	call_entry = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
 
 	if (call_entry != NULL) {
 		*call = call_entry->u.p;
-		lock_release(&(*hts)->lock);
+		cnxcc_unlock((*hts)->lock);
 		return 0;
 	}
 
-	lock_release(&(*hts)->lock);
+	cnxcc_unlock((*hts)->lock);
 	return -1;
 }
 
@@ -586,7 +588,7 @@ static void __stop_billing(str *callid) {
 		return;
 	}
 
-	lock_get(&hts->lock);
+	cnxcc_lock(hts->lock);
 
 	/*
 	 * Search credit_data by client_id
@@ -595,7 +597,7 @@ static void __stop_billing(str *callid) {
 
 	if (cd_entry == NULL) {
 		LM_ERR("Credit data not found for CID [%.*s], client-ID [%.*s]\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
-		lock_release(&hts->lock);
+		cnxcc_unlock(hts->lock);
 		return;
 	}
 
@@ -603,23 +605,23 @@ static void __stop_billing(str *callid) {
 
 	if (credit_data == NULL) {
 		LM_ERR("[%.*s]: credit_data pointer is null\n", callid->len, callid->s);
-		lock_release(&hts->lock);
+		cnxcc_unlock(hts->lock);
 		return;
 	}
 
-	lock_release(&hts->lock);
+	cnxcc_unlock(hts->lock);
 
 	/*
 	 * Update calls statistics
 	 */
-	lock_get(&_data.lock);
+	cnxcc_lock(_data.lock);
 
 	_data.stats->active--;
 	_data.stats->total--;
 
-	lock_release(&_data.lock);
+	cnxcc_unlock(_data.lock);
 
-	lock(&credit_data->lock);
+	cnxcc_lock(credit_data->lock);
 
 	LM_DBG("Call [%.*s] of client-ID [%.*s], ended\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
 
@@ -653,7 +655,13 @@ static void __stop_billing(str *callid) {
 	 * Remove (and free) the call from the list of calls of the current credit_data
 	 */
 	clist_rm(call, next, prev);
-	__free_call(call);
+	/* 
+	 * don't free the call if all the credit data is being deallocated,
+	 * it will be freed by terminate_all_calls()
+	 */
+	if (!credit_data->deallocating) {
+		__free_call(call);
+	}
 
 	/*
 	 * In case there are no active calls for a certain client, we remove the client-id from the hash table.
@@ -663,7 +671,7 @@ static void __stop_billing(str *callid) {
 		LM_DBG("Removing client [%.*s] and its calls from the list\n", credit_data->call_list->client_id.len, credit_data->call_list->client_id.s);
 
 		credit_data->deallocating = 1;
-		lock(&hts->lock);
+		cnxcc_lock(hts->lock);
 
 		if (_data.redis) {
 			redis_clean_up_if_last(credit_data);
@@ -675,7 +683,7 @@ static void __stop_billing(str *callid) {
 		 */
 		str_hash_del(cd_entry);
 
-		lock_release(&hts->lock);
+		cnxcc_unlock(hts->lock);
 
 		/*
 		 * Free client_id in list's root
@@ -686,7 +694,7 @@ static void __stop_billing(str *callid) {
 		/*
 		 * Release the lock since we are going to free the entry down below
 		 */
-		lock_release(&credit_data->lock);
+		cnxcc_unlock(credit_data->lock);
 
 		/*
 		 * Free the whole entry
@@ -699,7 +707,7 @@ static void __stop_billing(str *callid) {
 		return;
 	}
 
-	lock_release(&credit_data->lock);
+	cnxcc_unlock(credit_data->lock);
 }
 
 static void __setup_billing(str *callid, unsigned int h_entry, unsigned int h_id) {
@@ -708,7 +716,7 @@ static void __setup_billing(str *callid, unsigned int h_entry, unsigned int h_id
 
 	LM_DBG("Creating dialog for [%.*s], h_id [%u], h_entry [%u]\n", callid->len, callid->s, h_id, h_entry);
 
-//	lock_get(&_data.lock);
+//	cnxcc_lock(&_data);
 
 	/*
 	 * Search call data by call-id
@@ -731,21 +739,21 @@ static void __setup_billing(str *callid, unsigned int h_entry, unsigned int h_id
 	/*
 	 * Update calls statistics
 	 */
-	lock_get(&_data.lock);
+	cnxcc_lock(_data.lock);
 
 	_data.stats->active++;
 	_data.stats->total++;
 
-	lock_release(&_data.lock);
+	cnxcc_unlock(_data.lock);
 
-	lock_get(&call->lock);
+	cnxcc_lock(call->lock);
 
 	call->dlg_h_entry	= h_entry;
 	call->dlg_h_id		= h_id;
 
 	LM_DBG("Call [%.*s] from client [%.*s], created\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
 
-	lock_release(&call->lock);
+	cnxcc_unlock(call->lock);
 }
 
 static void __start_billing(str *callid, str *from_uri, str *to_uri, str tags[2]) {
@@ -756,7 +764,7 @@ static void __start_billing(str *callid, str *from_uri, str *to_uri, str tags[2]
 
 	LM_DBG("Billing started for call [%.*s]\n", callid->len, callid->s);
 
-//	lock_get(&_data.lock);
+//	cnxcc_lock(&_data);
 
 	/*
 	 * Search call data by call-id
@@ -776,7 +784,7 @@ static void __start_billing(str *callid, str *from_uri, str *to_uri, str tags[2]
 		return;
 	}
 
-	lock_get(&hts->lock);
+	cnxcc_lock(hts->lock);
 
 	/*
 	 * Search credit_data by client_id
@@ -785,7 +793,7 @@ static void __start_billing(str *callid, str *from_uri, str *to_uri, str tags[2]
 
 	if (cd_entry == NULL) {
 		LM_ERR("Credit data not found for CID [%.*s], client-ID [%.*s]\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
-		lock_release(&hts->lock);
+		cnxcc_unlock(hts->lock);
 		return;
 	}
 
@@ -793,13 +801,13 @@ static void __start_billing(str *callid, str *from_uri, str *to_uri, str tags[2]
 
 	if (credit_data == NULL) {
 		LM_ERR("[%.*s]: credit_data pointer is null\n", callid->len, callid->s);
-		lock_release(&hts->lock);
+		cnxcc_unlock(hts->lock);
 		return;
 	}
 
-	lock_release(&hts->lock);
+	cnxcc_unlock(hts->lock);
 
-	lock(&credit_data->lock);
+	cnxcc_lock(credit_data->lock);
 
 	/*
 	 * Now that the call is confirmed, we can increase the count of "concurrent_calls".
@@ -834,9 +842,9 @@ static void __start_billing(str *callid, str *from_uri, str *to_uri, str tags[2]
 	 */
 	call->max_amount = credit_data->max_amount - credit_data->consumed_amount;
 
-	lock_release(&credit_data->lock);
+	cnxcc_unlock(credit_data->lock);
 
-	lock_get(&call->lock);
+	cnxcc_lock(call->lock);
 
 	/*
 	 * Store from-tag value
@@ -870,7 +878,7 @@ static void __start_billing(str *callid, str *from_uri, str *to_uri, str tags[2]
 			call->sip_data.to_uri.len, call->sip_data.to_uri.s,
 			call->sip_data.to_tag.len, call->sip_data.to_tag.s);
 exit:
-	lock_release(&call->lock);
+	cnxcc_unlock(call->lock);
 }
 
 // must be called with lock held on credit_data
@@ -888,6 +896,7 @@ void terminate_all_calls(credit_data_t *credit_data) {
 		 */
 		_data.stats->dropped++;
 		terminate_call(call);
+		__free_call(call);
 	}
 }
 
@@ -1020,32 +1029,32 @@ error:
 }
 
 static credit_data_t *__get_or_create_credit_data_entry(str *client_id, credit_type_t type) {
-	struct str_hash_table *ht = NULL;
-	gen_lock_t *lock = NULL;
+	struct str_hash_table *sht = NULL;
+	struct hash_tables *ht;
 	struct str_hash_entry *e = NULL;
 	credit_data_t *credit_data = NULL;
 
 	switch(type) {
 	case CREDIT_MONEY:
-		ht = _data.money.credit_data_by_client;
-		lock =  &_data.money.lock;
+		sht = _data.money.credit_data_by_client;
+		ht =  &_data.money;
 		break;
 	case CREDIT_TIME:
-		ht = _data.time.credit_data_by_client;
-		lock =  &_data.time.lock;
+		sht = _data.time.credit_data_by_client;
+		ht =  &_data.time;
 		break;
 	case CREDIT_CHANNEL:
-		ht = _data.channel.credit_data_by_client;
-		lock =  &_data.channel.lock;
+		sht = _data.channel.credit_data_by_client;
+		ht =  &_data.channel;
 		break;
 	default:
 		LM_ERR("BUG: Something went terribly wrong\n");
 		return NULL;
 	}
 
-	lock_get(lock);
-	e = str_hash_get(ht, client_id->s, client_id->len);
-	lock_release(lock);
+	cnxcc_lock(ht->lock);
+	e = str_hash_get(sht, client_id->s, client_id->len);
+	cnxcc_unlock(ht->lock);
 
 	/*
 	 * Alloc new call_array_t if it doesn't exist
@@ -1066,11 +1075,11 @@ static credit_data_t *__get_or_create_credit_data_entry(str *client_id, credit_t
 		if (credit_data == NULL)
 			goto no_memory;
 
-		lock_get(lock);
-		str_hash_add(ht, e);
-		lock_release(lock);
+		cnxcc_lock(ht->lock);
+		str_hash_add(sht, e);
+		cnxcc_unlock(ht->lock);
 
-		LM_DBG("Call didn't exist. Allocated new entry\n");
+		LM_DBG("Credit entry didn't exist. Allocated new entry [%p]\n", e);
 	}
 
 	return (credit_data_t *) e->u.p;
@@ -1083,7 +1092,7 @@ no_memory:
 static credit_data_t *__alloc_new_credit_data(str *client_id, credit_type_t type) {
 	credit_data_t *credit_data = shm_malloc(sizeof(credit_data_t));;
 
-	lock_init(&credit_data->lock);
+	cnxcc_lock_init(credit_data->lock);
 
 	credit_data->call_list = shm_malloc(sizeof(call_t));
 
@@ -1135,7 +1144,8 @@ error:
 static call_t *__alloc_new_call_by_money(credit_data_t *credit_data, struct sip_msg *msg, 
 					double credit, double cost_per_second, int initial_pulse, int final_pulse) {
 	call_t *call = NULL;
-	lock_get(&credit_data->lock);
+
+	cnxcc_lock(credit_data->lock);
 
 	if (credit_data->call_list == NULL) {
 		LM_ERR("Credit data call list is NULL\n");
@@ -1183,7 +1193,7 @@ static call_t *__alloc_new_call_by_money(credit_data_t *credit_data, struct sip_
 	 */
 	clist_insert(credit_data->call_list, call, next, prev);
 
-	lock_init(&call->lock);
+	cnxcc_lock_init(call->lock);
 
 	/*
 	 * Increase the number of calls for this client. This call is not yet confirmed.
@@ -1192,21 +1202,21 @@ static call_t *__alloc_new_call_by_money(credit_data_t *credit_data, struct sip_
 	if (_data.redis)
 		redis_incr_by_int(credit_data, "number_of_calls", 1);
 
-	lock_release(&credit_data->lock);
+	cnxcc_unlock(credit_data->lock);
 
 	LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
 
 	return call;
 
 error:
-	lock_release(&credit_data->lock);
+	cnxcc_unlock(credit_data->lock);
 	return NULL;
 }
 
 static call_t *__alloc_new_call_by_time(credit_data_t *credit_data, struct sip_msg *msg, int max_secs) {
 	call_t *call = NULL;
 
-	lock_get(&credit_data->lock);
+	cnxcc_lock(credit_data->lock);
 
 	if (credit_data->call_list == NULL) {
 		LM_ERR("Credit data call list is NULL\n");
@@ -1250,7 +1260,7 @@ static call_t *__alloc_new_call_by_time(credit_data_t *credit_data, struct sip_m
 	 */
 	clist_insert(credit_data->call_list, call, next, prev);
 
-	lock_init(&call->lock);
+	cnxcc_lock_init(call->lock);
 
 	/*
 	 * Increase the number of calls for this client. This call is not yet confirmed.
@@ -1259,21 +1269,21 @@ static call_t *__alloc_new_call_by_time(credit_data_t *credit_data, struct sip_m
 	if (_data.redis)
 		redis_incr_by_int(credit_data, "number_of_calls", 1);
 
-	lock_release(&credit_data->lock);
+	cnxcc_unlock(credit_data->lock);
 
 	LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
 
 	return call;
 
 error:
-	lock_release(&credit_data->lock);
+	cnxcc_unlock(credit_data->lock);
 	return NULL;
 }
 
 static call_t *alloc_new_call_by_channel(credit_data_t *credit_data, struct sip_msg *msg, int max_chan) {
 	call_t *call = NULL;
 
-	lock_get(&credit_data->lock);
+	cnxcc_lock(credit_data->lock);
 
 	if (credit_data->call_list == NULL) {
 		LM_ERR("Credit data call list is NULL\n");
@@ -1317,7 +1327,7 @@ static call_t *alloc_new_call_by_channel(credit_data_t *credit_data, struct sip_
 	 */
 	clist_insert(credit_data->call_list, call, next, prev);
 
-	lock_init(&call->lock);
+	cnxcc_lock_init(call->lock);
 
 	/*
 	 * Increase the number of calls for this client. This call is not yet confirmed.
@@ -1326,7 +1336,7 @@ static call_t *alloc_new_call_by_channel(credit_data_t *credit_data, struct sip_
 	if (_data.redis)
 		redis_incr_by_int(credit_data, "number_of_calls", 1);
 
-	lock_release(&credit_data->lock);
+	cnxcc_unlock(credit_data->lock);
 
 	LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
 
@@ -1334,27 +1344,27 @@ static call_t *alloc_new_call_by_channel(credit_data_t *credit_data, struct sip_
 	return call;
 
 error:
-	lock_release(&credit_data->lock);
+	cnxcc_unlock(credit_data->lock);
 	return NULL;
 }
 
 static int __add_call_by_cid(str *cid, call_t *call, credit_type_t type) {
 	struct str_hash_table *ht	= NULL;
-	gen_lock_t *lock		= NULL;
+	cnxcc_lock_t lock;
 	struct str_hash_entry *e	= NULL;
 
 	switch(type) {
 	case CREDIT_MONEY:
 		ht	= _data.money.call_data_by_cid;
-		lock	=  &_data.money.lock;
+		lock	=  _data.money.lock;
 		break;
 	case CREDIT_TIME:
 		ht	= _data.time.call_data_by_cid;
-		lock	=  &_data.time.lock;
+		lock	=  _data.time.lock;
 		break;
 	case CREDIT_CHANNEL:
 		ht	= _data.channel.call_data_by_cid;
-		lock	=  &_data.channel.lock;
+		lock	=  _data.channel.lock;
 		break;
 	default:
 		LM_ERR("Something went terribly wrong\n");
@@ -1400,9 +1410,9 @@ static int __add_call_by_cid(str *cid, call_t *call, credit_type_t type) {
 
 	e->u.p	= call;
 
-	lock_get(lock);
+	cnxcc_lock(lock);
 	str_hash_add(ht, e);
-	lock_release(lock);
+	cnxcc_unlock(lock);
 
 	return 0;
 }
@@ -1805,9 +1815,9 @@ static int __update_max_time(struct sip_msg* msg, char* str_pv_client, char* str
 	call_t *call			= NULL,
 	       *tmp_call		= NULL;
 
-	lock_get(&_data.time.lock);
+	cnxcc_lock(_data.time.lock);
 	e = str_hash_get(ht, client_id_val.rs.s, client_id_val.rs.len);
-	lock_release(&_data.time.lock);
+	cnxcc_unlock(_data.time.lock);
 
 	if (e == NULL) {
 		LM_ERR("Client [%.*s] was not found\n", client_id_val.rs.len, client_id_val.rs.s);
@@ -1815,7 +1825,7 @@ static int __update_max_time(struct sip_msg* msg, char* str_pv_client, char* str
 	}
 		
 	credit_data = (credit_data_t *) e->u.p;
-	lock_get(&credit_data->lock);
+	cnxcc_lock(credit_data->lock);
 
 	LM_DBG("Updating max-secs for [%.*s] from [%f] to [%f]\n", e->key.len, e->key.s, credit_data->max_amount, credit_data->max_amount + secs);
 	
@@ -1834,7 +1844,7 @@ static int __update_max_time(struct sip_msg* msg, char* str_pv_client, char* str
 //redit_data->consumed_amount			= 0;
 
 
-	lock_release(&credit_data->lock);
+	cnxcc_unlock(credit_data->lock);
 
 	return 1;
 }

+ 52 - 4
modules/cnxcc/cnxcc_mod.h

@@ -25,11 +25,59 @@
 #define _CNXCC_MOD_H
 
 #include "../../locking.h"
+#include "../../atomic_ops.h"
 #include "../../str_hash.h"
 #include "../../parser/parse_rr.h"
 
 #define str_shm_free_if_not_null(_var_) if (_var_.s != NULL)  { shm_free(_var_.s); _var_.s = NULL; _var_.len = 0; }
 
+/*!
+ * \brief Init a cnxcc_lock 
+ * \param _entry locked entry
+ */
+#define cnxcc_lock_init(_entry) \
+	lock_init(&(_entry).lock); \
+	(_entry).rec_lock_level = 0;
+
+/*!
+ * \brief Set a cnxcc lock (re-entrant)
+ * \param _entry locked entry
+ */
+#define cnxcc_lock(_entry) \
+        do { \
+            int mypid; \
+            mypid = my_pid(); \
+            if (likely(atomic_get( &(_entry).locker_pid) != mypid)) { \
+                lock_get( &(_entry).lock); \
+                atomic_set( &(_entry).locker_pid, mypid); \
+            } else { \
+                /* locked within the same process that executed us */ \
+                (_entry).rec_lock_level++; \
+            } \
+        } while(0)
+
+
+/*!
+ * \brief Release a cnxcc lock
+ * \param _entry locked entry
+ */
+#define cnxcc_unlock(_entry) \
+        do { \
+            if (likely((_entry).rec_lock_level == 0)) { \
+                atomic_set( &(_entry).locker_pid, 0); \
+                lock_release( &(_entry).lock); \
+            } else  { \
+                /* recursive locked => decrease lock count */ \
+                (_entry).rec_lock_level--; \
+            } \
+        } while(0)
+
+typedef struct cnxcc_lock {
+	gen_lock_t lock;
+	atomic_t locker_pid;
+	int rec_lock_level;
+} cnxcc_lock_t;
+
 typedef struct stats {
 	unsigned int total;
 	unsigned int active;
@@ -52,13 +100,13 @@ typedef struct hash_tables {
 	struct str_hash_table *credit_data_by_client;
 	struct str_hash_table *call_data_by_cid;
 
-	gen_lock_t lock;
+	cnxcc_lock_t lock;
 } hash_tables_t;
 
 struct redis;
 
 typedef struct data {
-	gen_lock_t lock;
+	cnxcc_lock_t lock;
 
 	hash_tables_t time;
 	hash_tables_t money;
@@ -111,7 +159,7 @@ typedef struct call {
 	struct call *prev;
 	struct call *next;
 
-	gen_lock_t lock;
+	cnxcc_lock_t lock;
 
 	char confirmed;
 	double max_amount;
@@ -135,7 +183,7 @@ typedef struct call_array {
 } call_array_t;
 
 typedef struct credit_data {
-	gen_lock_t lock;
+	cnxcc_lock_t lock;
 
 	double max_amount;
 	double consumed_amount;

+ 2 - 2
modules/cnxcc/cnxcc_redis.c

@@ -531,7 +531,7 @@ static void __subscription_cb(redisAsyncContext *c, void *r, void *privdata) {
 	 if (try_get_credit_data_entry(&key, &credit_data) < 0)
 		 return;
 
-	 lock_get(&credit_data->lock);
+	 cnxcc_lock(credit_data->lock);
 
 	 if (credit_data->deallocating)
 		 goto done; // no need to terminate the calls. They are already being terminated
@@ -539,6 +539,6 @@ static void __subscription_cb(redisAsyncContext *c, void *r, void *privdata) {
 	 LM_ALERT("Got kill list entry for key [%.*s]\n", key.len, key.s);
 	 terminate_all_calls(credit_data);
 done:
-	 lock_release(&credit_data->lock);
+	 cnxcc_unlock(credit_data->lock);
 
 }

+ 12 - 14
modules/cnxcc/cnxcc_rpc.c

@@ -24,8 +24,6 @@
 
 #include <stdio.h>
 
-#include "../../locking.h"
-#include "../../lock_ops.h"
 #include "../../rpc.h"
 #include "../../rpc_lookup.h"
 
@@ -57,11 +55,11 @@ void rpc_kill_call(rpc_t* rpc, void* ctx) {
 
 	LM_ALERT("Killing call [%.*s] via XMLRPC request\n", callid.len, callid.s);
 
-	lock_get(&call->lock);
+	cnxcc_lock(call->lock);
 
 	terminate_call(call);
 
-	lock_release(&call->lock);
+	cnxcc_unlock(call->lock);
 }
 
 void rpc_check_client_stats(rpc_t* rpc, void* ctx) {
@@ -88,10 +86,10 @@ void rpc_check_client_stats(rpc_t* rpc, void* ctx) {
 		return;
 	}
 
-	lock_get(&credit_data->lock);
+	cnxcc_lock(credit_data->lock);
 
 	if (credit_data->number_of_calls <= 0) {
-		lock_release(&credit_data->lock);
+		cnxcc_unlock(credit_data->lock);
 		LM_INFO("No calls for current client\n");
 		return;
 	}
@@ -136,7 +134,7 @@ void rpc_check_client_stats(rpc_t* rpc, void* ctx) {
 		rows.s		= pkg_realloc(rows.s, rows.len + row_len);
 
 		if (rows.s == NULL) {
-			lock_release(&credit_data->lock);
+			cnxcc_unlock(credit_data->lock);
 			goto nomem;
 		}
 
@@ -146,7 +144,7 @@ void rpc_check_client_stats(rpc_t* rpc, void* ctx) {
 		index++;
 	}
 
-	lock_release(&credit_data->lock);
+	cnxcc_unlock(credit_data->lock);
 
 	if (rpc->add(ctx, "S", &rows) < 0) {
 		LM_ERR("%s: error creating RPC struct\n", __FUNCTION__);
@@ -167,13 +165,13 @@ static int iterate_over_table(hash_tables_t *hts, str *result, credit_type_t typ
 	char row_buffer[512];
 	int index = 0;
 
-	lock_get(&hts->lock);
+	cnxcc_lock(hts->lock);
 
 	if (hts->credit_data_by_client->table)
 		for(index = 0; index < hts->credit_data_by_client->size; index++)
 			clist_foreach_safe(&hts->credit_data_by_client->table[index], h_entry, tmp, next) {
 				credit_data_t *credit_data	= (credit_data_t *) h_entry->u.p;
-				lock_get(&credit_data->lock);
+				cnxcc_lock(credit_data->lock);
 
 				int row_len = 0;
 
@@ -212,13 +210,13 @@ static int iterate_over_table(hash_tables_t *hts, str *result, credit_type_t typ
 					return -1;
 				}
 
-				lock_release(&credit_data->lock);
+				cnxcc_unlock(credit_data->lock);
 
 				row_len 	= strlen(row_buffer);
 				result->s	= pkg_realloc(result->s, result->len + row_len);
 
 				if (result->s == NULL) {
-					lock_release(&hts->lock);
+					cnxcc_unlock(hts->lock);
 					goto nomem;
 				}
 
@@ -227,7 +225,7 @@ static int iterate_over_table(hash_tables_t *hts, str *result, credit_type_t typ
 
 			}
 
-	lock_release(&hts->lock);
+	cnxcc_unlock(hts->lock);
 
 	return 0;
 
@@ -249,7 +247,7 @@ void rpc_active_clients(rpc_t* rpc, void* ctx) {
 	iterate_over_table(&_data.time, &rows, CREDIT_TIME);
 	iterate_over_table(&_data.money, &rows, CREDIT_MONEY);
 
-	if (!rpc->add(ctx, "S", &rows) < 0) {
+	if (rpc->add(ctx, "S", &rows) < 0) {
 		LM_ERR("%s: error creating RPC struct\n", __FUNCTION__);
 	}