Browse code

cnxcc: make cnxcc locks re-entrant

Federico Cabiddu authored on 11/11/2015 12:08:52
Showing 5 changed files
... ...
@@ -24,9 +24,6 @@
24 24
 
25 25
 #include <stdio.h>
26 26
 
27
-#include "../../locking.h"
28
-#include "../../lock_ops.h"
29
-
30 27
 #include "cnxcc_mod.h"
31 28
 #include "cnxcc.h"
32 29
 #include "cnxcc_check.h"
... ...
@@ -40,7 +37,7 @@ void check_calls_by_money(unsigned int ticks, void *param) {
40 40
 	call_t *tmp_call = NULL;
41 41
 	int i;
42 42
 
43
-	lock_get(&_data.money.lock);
43
+	cnxcc_lock(_data.money.lock);
44 44
 
45 45
 	if (_data.money.credit_data_by_client->table)
46 46
 		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) {
54 54
 					break;
55 55
 				}*/
56 56
 
57
-				lock_get(&credit_data->lock);
57
+				cnxcc_lock(credit_data->lock);
58 58
 
59 59
 				clist_foreach_safe(credit_data->call_list, call, tmp_call, next) {
60 60
 					int consumed_time = 0;
... ...
@@ -88,7 +85,7 @@ void check_calls_by_money(unsigned int ticks, void *param) {
88 88
 				}
89 89
 
90 90
 				if (credit_data->concurrent_calls == 0) {
91
-					lock_release(&credit_data->lock);
91
+					cnxcc_unlock(credit_data->lock);
92 92
 					continue;
93 93
 				}
94 94
 
... ...
@@ -112,15 +109,16 @@ void check_calls_by_money(unsigned int ticks, void *param) {
112 112
 					terminate_all_calls(credit_data);
113 113
 
114 114
 					// make sure the rest of the servers kill the calls belonging to this customer
115
-					redis_publish_to_kill_list(credit_data);
116
-					lock_release(&credit_data->lock);
115
+					if (_data.redis)
116
+						redis_publish_to_kill_list(credit_data);
117
+					cnxcc_unlock(credit_data->lock);
117 118
 					break;
118 119
 				}
119 120
 
120
-				lock_release(&credit_data->lock);
121
+				cnxcc_unlock(credit_data->lock);
121 122
 			}
122 123
 
123
-	lock_release(&_data.money.lock);
124
+	cnxcc_unlock(_data.money.lock);
124 125
 }
125 126
 
126 127
 void check_calls_by_time(unsigned int ticks, void *param) {
... ...
@@ -129,7 +127,7 @@ void check_calls_by_time(unsigned int ticks, void *param) {
129 129
 	call_t *tmp_call = NULL;
130 130
 	int i;
131 131
 
132
-	lock_get(&_data.time.lock);
132
+	cnxcc_lock(_data.time.lock);
133 133
 
134 134
 	if (_data.time.credit_data_by_client->table)
135 135
 		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) {
139 139
 				int total_consumed_secs = 0;
140 140
 				double consumption_diff = 0/*, distributed_consumption = 0*/;
141 141
 
142
-				lock_get(&credit_data->lock);
142
+				cnxcc_lock(credit_data->lock);
143 143
 
144 144
 				/*if (i > SAFE_ITERATION_THRESHOLD)
145 145
 				{
... ...
@@ -169,7 +167,7 @@ void check_calls_by_time(unsigned int ticks, void *param) {
169 169
 				}
170 170
 
171 171
 				if (credit_data->concurrent_calls == 0) {
172
-					lock_release(&credit_data->lock);
172
+					cnxcc_unlock(credit_data->lock);
173 173
 					continue;
174 174
 				}
175 175
 
... ...
@@ -190,13 +188,14 @@ void check_calls_by_time(unsigned int ticks, void *param) {
190 190
 					terminate_all_calls(credit_data);
191 191
 
192 192
 					// make sure the rest of the servers kill the calls belonging to this customer
193
-					redis_publish_to_kill_list(credit_data);
194
-					lock_release(&credit_data->lock);
193
+					if (_data.redis)
194
+						redis_publish_to_kill_list(credit_data);
195
+					cnxcc_unlock(credit_data->lock);
195 196
 					break;
196 197
 				}
197 198
 
198
-				lock_release(&credit_data->lock);
199
+				cnxcc_unlock(credit_data->lock);
199 200
 			}
200 201
 
201
-	lock_release(&_data.time.lock);
202
+	cnxcc_unlock(_data.time.lock);
202 203
 }
... ...
@@ -294,10 +294,12 @@ static int __mod_init(void) {
294 294
 	if (__init_hashtable(_data.channel.call_data_by_cid) != 0)
295 295
 		return -1;
296 296
 
297
-	lock_init(&_data.lock);
298
-	lock_init(&_data.time.lock);
299
-	lock_init(&_data.money.lock);
300
-	lock_init(&_data.channel.lock);
297
+
298
+	cnxcc_lock_init(_data.lock);
299
+
300
+	cnxcc_lock_init(_data.time.lock);
301
+	cnxcc_lock_init(_data.money.lock);
302
+	cnxcc_lock_init(_data.channel.lock);
301 303
 
302 304
 	register_mi_cmd(__mi_credit_control_stats, "cnxcc_stats", NULL, NULL, 0);
303 305
 
... ...
@@ -471,45 +473,45 @@ int try_get_credit_data_entry(str *client_id, credit_data_t **credit_data) {
471 471
 
472 472
 	/* by money */
473 473
 	hts = &_data.money;
474
-	lock_get(&hts->lock);
474
+	cnxcc_lock(hts->lock);
475 475
 
476 476
 	cd_entry = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
477 477
 
478 478
 	if (cd_entry != NULL) {
479 479
 		*credit_data	= cd_entry->u.p;
480
-		lock_release(&hts->lock);
480
+		cnxcc_unlock(hts->lock);
481 481
 		return 0;
482 482
 	}
483 483
 
484
-	lock_release(&hts->lock);
484
+	cnxcc_unlock(hts->lock);
485 485
 
486 486
 	/* by time */
487 487
 	hts = &_data.time;
488
-	lock_get(&hts->lock);
488
+	cnxcc_lock(hts->lock);
489 489
 
490 490
 	cd_entry = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
491 491
 
492 492
 	if (cd_entry != NULL) {
493 493
 		*credit_data	= cd_entry->u.p;
494
-		lock_release(&hts->lock);
494
+		cnxcc_unlock(hts->lock);
495 495
 		return 0;
496 496
 	}
497 497
 
498
-	lock_release(&hts->lock);
498
+	cnxcc_unlock(hts->lock);
499 499
 
500 500
 	/* by channel */
501 501
 	hts = &_data.channel;
502
-	lock_get(&hts->lock);
502
+	cnxcc_lock(hts->lock);
503 503
 
504 504
 	cd_entry = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
505 505
 
506 506
 	if (cd_entry != NULL) {
507 507
 		*credit_data	= cd_entry->u.p;
508
-		lock_release(&hts->lock);
508
+		cnxcc_unlock(hts->lock);
509 509
 		return 0;
510 510
 	}
511 511
 
512
-	lock_release(&hts->lock);
512
+	cnxcc_unlock(hts->lock);
513 513
 	return -1;
514 514
 }
515 515
 
... ...
@@ -520,45 +522,45 @@ int try_get_call_entry(str *callid, call_t **call, hash_tables_t **hts) {
520 520
 
521 521
 	/* by money */
522 522
 	*hts = &_data.money;
523
-	lock_get(&(*hts)->lock);
523
+	cnxcc_lock((*hts)->lock);
524 524
 
525 525
 	call_entry = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
526 526
 
527 527
 	if (call_entry != NULL) {
528 528
 		*call = call_entry->u.p;
529
-		lock_release(&(*hts)->lock);
529
+		cnxcc_unlock((*hts)->lock);
530 530
 		return 0;
531 531
 	}
532 532
 
533
-	lock_release(&(*hts)->lock);
533
+	cnxcc_unlock((*hts)->lock);
534 534
 
535 535
 	/* by time */
536 536
 	*hts = &_data.time;
537
-	lock_get(&(*hts)->lock);
537
+	cnxcc_lock((*hts)->lock);
538 538
 
539 539
 	call_entry = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
540 540
 
541 541
 	if (call_entry != NULL) {
542 542
 		*call = call_entry->u.p;
543
-		lock_release(&(*hts)->lock);
543
+		cnxcc_unlock((*hts)->lock);
544 544
 		return 0;
545 545
 	}
546 546
 
547
-	lock_release(&(*hts)->lock);
547
+	cnxcc_unlock((*hts)->lock);
548 548
 
549 549
 	/* by channel */
550 550
 	*hts = &_data.channel;
551
-	lock_get(&(*hts)->lock);
551
+	cnxcc_lock((*hts)->lock);
552 552
 
553 553
 	call_entry = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
554 554
 
555 555
 	if (call_entry != NULL) {
556 556
 		*call = call_entry->u.p;
557
-		lock_release(&(*hts)->lock);
557
+		cnxcc_unlock((*hts)->lock);
558 558
 		return 0;
559 559
 	}
560 560
 
561
-	lock_release(&(*hts)->lock);
561
+	cnxcc_unlock((*hts)->lock);
562 562
 	return -1;
563 563
 }
564 564
 
... ...
@@ -586,7 +588,7 @@ static void __stop_billing(str *callid) {
586 586
 		return;
587 587
 	}
588 588
 
589
-	lock_get(&hts->lock);
589
+	cnxcc_lock(hts->lock);
590 590
 
591 591
 	/*
592 592
 	 * Search credit_data by client_id
... ...
@@ -595,7 +597,7 @@ static void __stop_billing(str *callid) {
595 595
 
596 596
 	if (cd_entry == NULL) {
597 597
 		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);
598
-		lock_release(&hts->lock);
598
+		cnxcc_unlock(hts->lock);
599 599
 		return;
600 600
 	}
601 601
 
... ...
@@ -603,23 +605,23 @@ static void __stop_billing(str *callid) {
603 603
 
604 604
 	if (credit_data == NULL) {
605 605
 		LM_ERR("[%.*s]: credit_data pointer is null\n", callid->len, callid->s);
606
-		lock_release(&hts->lock);
606
+		cnxcc_unlock(hts->lock);
607 607
 		return;
608 608
 	}
609 609
 
610
-	lock_release(&hts->lock);
610
+	cnxcc_unlock(hts->lock);
611 611
 
612 612
 	/*
613 613
 	 * Update calls statistics
614 614
 	 */
615
-	lock_get(&_data.lock);
615
+	cnxcc_lock(_data.lock);
616 616
 
617 617
 	_data.stats->active--;
618 618
 	_data.stats->total--;
619 619
 
620
-	lock_release(&_data.lock);
620
+	cnxcc_unlock(_data.lock);
621 621
 
622
-	lock(&credit_data->lock);
622
+	cnxcc_lock(credit_data->lock);
623 623
 
624 624
 	LM_DBG("Call [%.*s] of client-ID [%.*s], ended\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
625 625
 
... ...
@@ -653,7 +655,13 @@ static void __stop_billing(str *callid) {
653 653
 	 * Remove (and free) the call from the list of calls of the current credit_data
654 654
 	 */
655 655
 	clist_rm(call, next, prev);
656
-	__free_call(call);
656
+	/* 
657
+	 * don't free the call if all the credit data is being deallocated,
658
+	 * it will be freed by terminate_all_calls()
659
+	 */
660
+	if (!credit_data->deallocating) {
661
+		__free_call(call);
662
+	}
657 663
 
658 664
 	/*
659 665
 	 * 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) {
663 663
 		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);
664 664
 
665 665
 		credit_data->deallocating = 1;
666
-		lock(&hts->lock);
666
+		cnxcc_lock(hts->lock);
667 667
 
668 668
 		if (_data.redis) {
669 669
 			redis_clean_up_if_last(credit_data);
... ...
@@ -675,7 +683,7 @@ static void __stop_billing(str *callid) {
675 675
 		 */
676 676
 		str_hash_del(cd_entry);
677 677
 
678
-		lock_release(&hts->lock);
678
+		cnxcc_unlock(hts->lock);
679 679
 
680 680
 		/*
681 681
 		 * Free client_id in list's root
... ...
@@ -686,7 +694,7 @@ static void __stop_billing(str *callid) {
686 686
 		/*
687 687
 		 * Release the lock since we are going to free the entry down below
688 688
 		 */
689
-		lock_release(&credit_data->lock);
689
+		cnxcc_unlock(credit_data->lock);
690 690
 
691 691
 		/*
692 692
 		 * Free the whole entry
... ...
@@ -699,7 +707,7 @@ static void __stop_billing(str *callid) {
699 699
 		return;
700 700
 	}
701 701
 
702
-	lock_release(&credit_data->lock);
702
+	cnxcc_unlock(credit_data->lock);
703 703
 }
704 704
 
705 705
 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
708 708
 
709 709
 	LM_DBG("Creating dialog for [%.*s], h_id [%u], h_entry [%u]\n", callid->len, callid->s, h_id, h_entry);
710 710
 
711
-//	lock_get(&_data.lock);
711
+//	cnxcc_lock(&_data);
712 712
 
713 713
 	/*
714 714
 	 * Search call data by call-id
... ...
@@ -731,21 +739,21 @@ static void __setup_billing(str *callid, unsigned int h_entry, unsigned int h_id
731 731
 	/*
732 732
 	 * Update calls statistics
733 733
 	 */
734
-	lock_get(&_data.lock);
734
+	cnxcc_lock(_data.lock);
735 735
 
736 736
 	_data.stats->active++;
737 737
 	_data.stats->total++;
738 738
 
739
-	lock_release(&_data.lock);
739
+	cnxcc_unlock(_data.lock);
740 740
 
741
-	lock_get(&call->lock);
741
+	cnxcc_lock(call->lock);
742 742
 
743 743
 	call->dlg_h_entry	= h_entry;
744 744
 	call->dlg_h_id		= h_id;
745 745
 
746 746
 	LM_DBG("Call [%.*s] from client [%.*s], created\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
747 747
 
748
-	lock_release(&call->lock);
748
+	cnxcc_unlock(call->lock);
749 749
 }
750 750
 
751 751
 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]
756 756
 
757 757
 	LM_DBG("Billing started for call [%.*s]\n", callid->len, callid->s);
758 758
 
759
-//	lock_get(&_data.lock);
759
+//	cnxcc_lock(&_data);
760 760
 
761 761
 	/*
762 762
 	 * 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]
776 776
 		return;
777 777
 	}
778 778
 
779
-	lock_get(&hts->lock);
779
+	cnxcc_lock(hts->lock);
780 780
 
781 781
 	/*
782 782
 	 * 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]
785 785
 
786 786
 	if (cd_entry == NULL) {
787 787
 		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);
788
-		lock_release(&hts->lock);
788
+		cnxcc_unlock(hts->lock);
789 789
 		return;
790 790
 	}
791 791
 
... ...
@@ -793,13 +801,13 @@ static void __start_billing(str *callid, str *from_uri, str *to_uri, str tags[2]
793 793
 
794 794
 	if (credit_data == NULL) {
795 795
 		LM_ERR("[%.*s]: credit_data pointer is null\n", callid->len, callid->s);
796
-		lock_release(&hts->lock);
796
+		cnxcc_unlock(hts->lock);
797 797
 		return;
798 798
 	}
799 799
 
800
-	lock_release(&hts->lock);
800
+	cnxcc_unlock(hts->lock);
801 801
 
802
-	lock(&credit_data->lock);
802
+	cnxcc_lock(credit_data->lock);
803 803
 
804 804
 	/*
805 805
 	 * 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]
834 834
 	 */
835 835
 	call->max_amount = credit_data->max_amount - credit_data->consumed_amount;
836 836
 
837
-	lock_release(&credit_data->lock);
837
+	cnxcc_unlock(credit_data->lock);
838 838
 
839
-	lock_get(&call->lock);
839
+	cnxcc_lock(call->lock);
840 840
 
841 841
 	/*
842 842
 	 * Store from-tag value
... ...
@@ -870,7 +878,7 @@ static void __start_billing(str *callid, str *from_uri, str *to_uri, str tags[2]
870 870
 			call->sip_data.to_uri.len, call->sip_data.to_uri.s,
871 871
 			call->sip_data.to_tag.len, call->sip_data.to_tag.s);
872 872
 exit:
873
-	lock_release(&call->lock);
873
+	cnxcc_unlock(call->lock);
874 874
 }
875 875
 
876 876
 // must be called with lock held on credit_data
... ...
@@ -888,6 +896,7 @@ void terminate_all_calls(credit_data_t *credit_data) {
888 888
 		 */
889 889
 		_data.stats->dropped++;
890 890
 		terminate_call(call);
891
+		__free_call(call);
891 892
 	}
892 893
 }
893 894
 
... ...
@@ -1020,32 +1029,32 @@ error:
1020 1020
 }
1021 1021
 
1022 1022
 static credit_data_t *__get_or_create_credit_data_entry(str *client_id, credit_type_t type) {
1023
-	struct str_hash_table *ht = NULL;
1024
-	gen_lock_t *lock = NULL;
1023
+	struct str_hash_table *sht = NULL;
1024
+	struct hash_tables *ht;
1025 1025
 	struct str_hash_entry *e = NULL;
1026 1026
 	credit_data_t *credit_data = NULL;
1027 1027
 
1028 1028
 	switch(type) {
1029 1029
 	case CREDIT_MONEY:
1030
-		ht = _data.money.credit_data_by_client;
1031
-		lock =  &_data.money.lock;
1030
+		sht = _data.money.credit_data_by_client;
1031
+		ht =  &_data.money;
1032 1032
 		break;
1033 1033
 	case CREDIT_TIME:
1034
-		ht = _data.time.credit_data_by_client;
1035
-		lock =  &_data.time.lock;
1034
+		sht = _data.time.credit_data_by_client;
1035
+		ht =  &_data.time;
1036 1036
 		break;
1037 1037
 	case CREDIT_CHANNEL:
1038
-		ht = _data.channel.credit_data_by_client;
1039
-		lock =  &_data.channel.lock;
1038
+		sht = _data.channel.credit_data_by_client;
1039
+		ht =  &_data.channel;
1040 1040
 		break;
1041 1041
 	default:
1042 1042
 		LM_ERR("BUG: Something went terribly wrong\n");
1043 1043
 		return NULL;
1044 1044
 	}
1045 1045
 
1046
-	lock_get(lock);
1047
-	e = str_hash_get(ht, client_id->s, client_id->len);
1048
-	lock_release(lock);
1046
+	cnxcc_lock(ht->lock);
1047
+	e = str_hash_get(sht, client_id->s, client_id->len);
1048
+	cnxcc_unlock(ht->lock);
1049 1049
 
1050 1050
 	/*
1051 1051
 	 * 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
1066 1066
 		if (credit_data == NULL)
1067 1067
 			goto no_memory;
1068 1068
 
1069
-		lock_get(lock);
1070
-		str_hash_add(ht, e);
1071
-		lock_release(lock);
1069
+		cnxcc_lock(ht->lock);
1070
+		str_hash_add(sht, e);
1071
+		cnxcc_unlock(ht->lock);
1072 1072
 
1073
-		LM_DBG("Call didn't exist. Allocated new entry\n");
1073
+		LM_DBG("Credit entry didn't exist. Allocated new entry [%p]\n", e);
1074 1074
 	}
1075 1075
 
1076 1076
 	return (credit_data_t *) e->u.p;
... ...
@@ -1083,7 +1092,7 @@ no_memory:
1083 1083
 static credit_data_t *__alloc_new_credit_data(str *client_id, credit_type_t type) {
1084 1084
 	credit_data_t *credit_data = shm_malloc(sizeof(credit_data_t));;
1085 1085
 
1086
-	lock_init(&credit_data->lock);
1086
+	cnxcc_lock_init(credit_data->lock);
1087 1087
 
1088 1088
 	credit_data->call_list = shm_malloc(sizeof(call_t));
1089 1089
 
... ...
@@ -1135,7 +1144,8 @@ error:
1135 1135
 static call_t *__alloc_new_call_by_money(credit_data_t *credit_data, struct sip_msg *msg, 
1136 1136
 					double credit, double cost_per_second, int initial_pulse, int final_pulse) {
1137 1137
 	call_t *call = NULL;
1138
-	lock_get(&credit_data->lock);
1138
+
1139
+	cnxcc_lock(credit_data->lock);
1139 1140
 
1140 1141
 	if (credit_data->call_list == NULL) {
1141 1142
 		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_
1183 1183
 	 */
1184 1184
 	clist_insert(credit_data->call_list, call, next, prev);
1185 1185
 
1186
-	lock_init(&call->lock);
1186
+	cnxcc_lock_init(call->lock);
1187 1187
 
1188 1188
 	/*
1189 1189
 	 * 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_
1192 1192
 	if (_data.redis)
1193 1193
 		redis_incr_by_int(credit_data, "number_of_calls", 1);
1194 1194
 
1195
-	lock_release(&credit_data->lock);
1195
+	cnxcc_unlock(credit_data->lock);
1196 1196
 
1197 1197
 	LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
1198 1198
 
1199 1199
 	return call;
1200 1200
 
1201 1201
 error:
1202
-	lock_release(&credit_data->lock);
1202
+	cnxcc_unlock(credit_data->lock);
1203 1203
 	return NULL;
1204 1204
 }
1205 1205
 
1206 1206
 static call_t *__alloc_new_call_by_time(credit_data_t *credit_data, struct sip_msg *msg, int max_secs) {
1207 1207
 	call_t *call = NULL;
1208 1208
 
1209
-	lock_get(&credit_data->lock);
1209
+	cnxcc_lock(credit_data->lock);
1210 1210
 
1211 1211
 	if (credit_data->call_list == NULL) {
1212 1212
 		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
1250 1250
 	 */
1251 1251
 	clist_insert(credit_data->call_list, call, next, prev);
1252 1252
 
1253
-	lock_init(&call->lock);
1253
+	cnxcc_lock_init(call->lock);
1254 1254
 
1255 1255
 	/*
1256 1256
 	 * 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
1259 1259
 	if (_data.redis)
1260 1260
 		redis_incr_by_int(credit_data, "number_of_calls", 1);
1261 1261
 
1262
-	lock_release(&credit_data->lock);
1262
+	cnxcc_unlock(credit_data->lock);
1263 1263
 
1264 1264
 	LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
1265 1265
 
1266 1266
 	return call;
1267 1267
 
1268 1268
 error:
1269
-	lock_release(&credit_data->lock);
1269
+	cnxcc_unlock(credit_data->lock);
1270 1270
 	return NULL;
1271 1271
 }
1272 1272
 
1273 1273
 static call_t *alloc_new_call_by_channel(credit_data_t *credit_data, struct sip_msg *msg, int max_chan) {
1274 1274
 	call_t *call = NULL;
1275 1275
 
1276
-	lock_get(&credit_data->lock);
1276
+	cnxcc_lock(credit_data->lock);
1277 1277
 
1278 1278
 	if (credit_data->call_list == NULL) {
1279 1279
 		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_
1317 1317
 	 */
1318 1318
 	clist_insert(credit_data->call_list, call, next, prev);
1319 1319
 
1320
-	lock_init(&call->lock);
1320
+	cnxcc_lock_init(call->lock);
1321 1321
 
1322 1322
 	/*
1323 1323
 	 * 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_
1326 1326
 	if (_data.redis)
1327 1327
 		redis_incr_by_int(credit_data, "number_of_calls", 1);
1328 1328
 
1329
-	lock_release(&credit_data->lock);
1329
+	cnxcc_unlock(credit_data->lock);
1330 1330
 
1331 1331
 	LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
1332 1332
 
... ...
@@ -1334,27 +1344,27 @@ static call_t *alloc_new_call_by_channel(credit_data_t *credit_data, struct sip_
1334 1334
 	return call;
1335 1335
 
1336 1336
 error:
1337
-	lock_release(&credit_data->lock);
1337
+	cnxcc_unlock(credit_data->lock);
1338 1338
 	return NULL;
1339 1339
 }
1340 1340
 
1341 1341
 static int __add_call_by_cid(str *cid, call_t *call, credit_type_t type) {
1342 1342
 	struct str_hash_table *ht	= NULL;
1343
-	gen_lock_t *lock		= NULL;
1343
+	cnxcc_lock_t lock;
1344 1344
 	struct str_hash_entry *e	= NULL;
1345 1345
 
1346 1346
 	switch(type) {
1347 1347
 	case CREDIT_MONEY:
1348 1348
 		ht	= _data.money.call_data_by_cid;
1349
-		lock	=  &_data.money.lock;
1349
+		lock	=  _data.money.lock;
1350 1350
 		break;
1351 1351
 	case CREDIT_TIME:
1352 1352
 		ht	= _data.time.call_data_by_cid;
1353
-		lock	=  &_data.time.lock;
1353
+		lock	=  _data.time.lock;
1354 1354
 		break;
1355 1355
 	case CREDIT_CHANNEL:
1356 1356
 		ht	= _data.channel.call_data_by_cid;
1357
-		lock	=  &_data.channel.lock;
1357
+		lock	=  _data.channel.lock;
1358 1358
 		break;
1359 1359
 	default:
1360 1360
 		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) {
1400 1400
 
1401 1401
 	e->u.p	= call;
1402 1402
 
1403
-	lock_get(lock);
1403
+	cnxcc_lock(lock);
1404 1404
 	str_hash_add(ht, e);
1405
-	lock_release(lock);
1405
+	cnxcc_unlock(lock);
1406 1406
 
1407 1407
 	return 0;
1408 1408
 }
... ...
@@ -1805,9 +1815,9 @@ static int __update_max_time(struct sip_msg* msg, char* str_pv_client, char* str
1805 1805
 	call_t *call			= NULL,
1806 1806
 	       *tmp_call		= NULL;
1807 1807
 
1808
-	lock_get(&_data.time.lock);
1808
+	cnxcc_lock(_data.time.lock);
1809 1809
 	e = str_hash_get(ht, client_id_val.rs.s, client_id_val.rs.len);
1810
-	lock_release(&_data.time.lock);
1810
+	cnxcc_unlock(_data.time.lock);
1811 1811
 
1812 1812
 	if (e == NULL) {
1813 1813
 		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
1815 1815
 	}
1816 1816
 		
1817 1817
 	credit_data = (credit_data_t *) e->u.p;
1818
-	lock_get(&credit_data->lock);
1818
+	cnxcc_lock(credit_data->lock);
1819 1819
 
1820 1820
 	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);
1821 1821
 	
... ...
@@ -1834,7 +1844,7 @@ static int __update_max_time(struct sip_msg* msg, char* str_pv_client, char* str
1834 1834
 //redit_data->consumed_amount			= 0;
1835 1835
 
1836 1836
 
1837
-	lock_release(&credit_data->lock);
1837
+	cnxcc_unlock(credit_data->lock);
1838 1838
 
1839 1839
 	return 1;
1840 1840
 }
... ...
@@ -25,11 +25,59 @@
25 25
 #define _CNXCC_MOD_H
26 26
 
27 27
 #include "../../locking.h"
28
+#include "../../atomic_ops.h"
28 29
 #include "../../str_hash.h"
29 30
 #include "../../parser/parse_rr.h"
30 31
 
31 32
 #define str_shm_free_if_not_null(_var_) if (_var_.s != NULL)  { shm_free(_var_.s); _var_.s = NULL; _var_.len = 0; }
32 33
 
34
+/*!
35
+ * \brief Init a cnxcc_lock 
36
+ * \param _entry locked entry
37
+ */
38
+#define cnxcc_lock_init(_entry) \
39
+	lock_init(&(_entry).lock); \
40
+	(_entry).rec_lock_level = 0;
41
+
42
+/*!
43
+ * \brief Set a cnxcc lock (re-entrant)
44
+ * \param _entry locked entry
45
+ */
46
+#define cnxcc_lock(_entry) \
47
+        do { \
48
+            int mypid; \
49
+            mypid = my_pid(); \
50
+            if (likely(atomic_get( &(_entry).locker_pid) != mypid)) { \
51
+                lock_get( &(_entry).lock); \
52
+                atomic_set( &(_entry).locker_pid, mypid); \
53
+            } else { \
54
+                /* locked within the same process that executed us */ \
55
+                (_entry).rec_lock_level++; \
56
+            } \
57
+        } while(0)
58
+
59
+
60
+/*!
61
+ * \brief Release a cnxcc lock
62
+ * \param _entry locked entry
63
+ */
64
+#define cnxcc_unlock(_entry) \
65
+        do { \
66
+            if (likely((_entry).rec_lock_level == 0)) { \
67
+                atomic_set( &(_entry).locker_pid, 0); \
68
+                lock_release( &(_entry).lock); \
69
+            } else  { \
70
+                /* recursive locked => decrease lock count */ \
71
+                (_entry).rec_lock_level--; \
72
+            } \
73
+        } while(0)
74
+
75
+typedef struct cnxcc_lock {
76
+	gen_lock_t lock;
77
+	atomic_t locker_pid;
78
+	int rec_lock_level;
79
+} cnxcc_lock_t;
80
+
33 81
 typedef struct stats {
34 82
 	unsigned int total;
35 83
 	unsigned int active;
... ...
@@ -52,13 +100,13 @@ typedef struct hash_tables {
52 52
 	struct str_hash_table *credit_data_by_client;
53 53
 	struct str_hash_table *call_data_by_cid;
54 54
 
55
-	gen_lock_t lock;
55
+	cnxcc_lock_t lock;
56 56
 } hash_tables_t;
57 57
 
58 58
 struct redis;
59 59
 
60 60
 typedef struct data {
61
-	gen_lock_t lock;
61
+	cnxcc_lock_t lock;
62 62
 
63 63
 	hash_tables_t time;
64 64
 	hash_tables_t money;
... ...
@@ -111,7 +159,7 @@ typedef struct call {
111 111
 	struct call *prev;
112 112
 	struct call *next;
113 113
 
114
-	gen_lock_t lock;
114
+	cnxcc_lock_t lock;
115 115
 
116 116
 	char confirmed;
117 117
 	double max_amount;
... ...
@@ -135,7 +183,7 @@ typedef struct call_array {
135 135
 } call_array_t;
136 136
 
137 137
 typedef struct credit_data {
138
-	gen_lock_t lock;
138
+	cnxcc_lock_t lock;
139 139
 
140 140
 	double max_amount;
141 141
 	double consumed_amount;
... ...
@@ -531,7 +531,7 @@ static void __subscription_cb(redisAsyncContext *c, void *r, void *privdata) {
531 531
 	 if (try_get_credit_data_entry(&key, &credit_data) < 0)
532 532
 		 return;
533 533
 
534
-	 lock_get(&credit_data->lock);
534
+	 cnxcc_lock(credit_data->lock);
535 535
 
536 536
 	 if (credit_data->deallocating)
537 537
 		 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) {
539 539
 	 LM_ALERT("Got kill list entry for key [%.*s]\n", key.len, key.s);
540 540
 	 terminate_all_calls(credit_data);
541 541
 done:
542
-	 lock_release(&credit_data->lock);
542
+	 cnxcc_unlock(credit_data->lock);
543 543
 
544 544
 }
... ...
@@ -24,8 +24,6 @@
24 24
 
25 25
 #include <stdio.h>
26 26
 
27
-#include "../../locking.h"
28
-#include "../../lock_ops.h"
29 27
 #include "../../rpc.h"
30 28
 #include "../../rpc_lookup.h"
31 29
 
... ...
@@ -57,11 +55,11 @@ void rpc_kill_call(rpc_t* rpc, void* ctx) {
57 57
 
58 58
 	LM_ALERT("Killing call [%.*s] via XMLRPC request\n", callid.len, callid.s);
59 59
 
60
-	lock_get(&call->lock);
60
+	cnxcc_lock(call->lock);
61 61
 
62 62
 	terminate_call(call);
63 63
 
64
-	lock_release(&call->lock);
64
+	cnxcc_unlock(call->lock);
65 65
 }
66 66
 
67 67
 void rpc_check_client_stats(rpc_t* rpc, void* ctx) {
... ...
@@ -88,10 +86,10 @@ void rpc_check_client_stats(rpc_t* rpc, void* ctx) {
88 88
 		return;
89 89
 	}
90 90
 
91
-	lock_get(&credit_data->lock);
91
+	cnxcc_lock(credit_data->lock);
92 92
 
93 93
 	if (credit_data->number_of_calls <= 0) {
94
-		lock_release(&credit_data->lock);
94
+		cnxcc_unlock(credit_data->lock);
95 95
 		LM_INFO("No calls for current client\n");
96 96
 		return;
97 97
 	}
... ...
@@ -136,7 +134,7 @@ void rpc_check_client_stats(rpc_t* rpc, void* ctx) {
136 136
 		rows.s		= pkg_realloc(rows.s, rows.len + row_len);
137 137
 
138 138
 		if (rows.s == NULL) {
139
-			lock_release(&credit_data->lock);
139
+			cnxcc_unlock(credit_data->lock);
140 140
 			goto nomem;
141 141
 		}
142 142
 
... ...
@@ -146,7 +144,7 @@ void rpc_check_client_stats(rpc_t* rpc, void* ctx) {
146 146
 		index++;
147 147
 	}
148 148
 
149
-	lock_release(&credit_data->lock);
149
+	cnxcc_unlock(credit_data->lock);
150 150
 
151 151
 	if (rpc->add(ctx, "S", &rows) < 0) {
152 152
 		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
167 167
 	char row_buffer[512];
168 168
 	int index = 0;
169 169
 
170
-	lock_get(&hts->lock);
170
+	cnxcc_lock(hts->lock);
171 171
 
172 172
 	if (hts->credit_data_by_client->table)
173 173
 		for(index = 0; index < hts->credit_data_by_client->size; index++)
174 174
 			clist_foreach_safe(&hts->credit_data_by_client->table[index], h_entry, tmp, next) {
175 175
 				credit_data_t *credit_data	= (credit_data_t *) h_entry->u.p;
176
-				lock_get(&credit_data->lock);
176
+				cnxcc_lock(credit_data->lock);
177 177
 
178 178
 				int row_len = 0;
179 179
 
... ...
@@ -212,13 +210,13 @@ static int iterate_over_table(hash_tables_t *hts, str *result, credit_type_t typ
212 212
 					return -1;
213 213
 				}
214 214
 
215
-				lock_release(&credit_data->lock);
215
+				cnxcc_unlock(credit_data->lock);
216 216
 
217 217
 				row_len 	= strlen(row_buffer);
218 218
 				result->s	= pkg_realloc(result->s, result->len + row_len);
219 219
 
220 220
 				if (result->s == NULL) {
221
-					lock_release(&hts->lock);
221
+					cnxcc_unlock(hts->lock);
222 222
 					goto nomem;
223 223
 				}
224 224
 
... ...
@@ -227,7 +225,7 @@ static int iterate_over_table(hash_tables_t *hts, str *result, credit_type_t typ
227 227
 
228 228
 			}
229 229
 
230
-	lock_release(&hts->lock);
230
+	cnxcc_unlock(hts->lock);
231 231
 
232 232
 	return 0;
233 233
 
... ...
@@ -249,7 +247,7 @@ void rpc_active_clients(rpc_t* rpc, void* ctx) {
249 249
 	iterate_over_table(&_data.time, &rows, CREDIT_TIME);
250 250
 	iterate_over_table(&_data.money, &rows, CREDIT_MONEY);
251 251
 
252
-	if (!rpc->add(ctx, "S", &rows) < 0) {
252
+	if (rpc->add(ctx, "S", &rows) < 0) {
253 253
 		LM_ERR("%s: error creating RPC struct\n", __FUNCTION__);
254 254
 	}
255 255