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 37
 	call_t *tmp_call = NULL;
41 38
 	int i;
42 39
 
43
-	lock_get(&_data.money.lock);
40
+	cnxcc_lock(_data.money.lock);
44 41
 
45 42
 	if (_data.money.credit_data_by_client->table)
46 43
 		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 51
 					break;
55 52
 				}*/
56 53
 
57
-				lock_get(&credit_data->lock);
54
+				cnxcc_lock(credit_data->lock);
58 55
 
59 56
 				clist_foreach_safe(credit_data->call_list, call, tmp_call, next) {
60 57
 					int consumed_time = 0;
... ...
@@ -88,7 +85,7 @@ void check_calls_by_money(unsigned int ticks, void *param) {
88 85
 				}
89 86
 
90 87
 				if (credit_data->concurrent_calls == 0) {
91
-					lock_release(&credit_data->lock);
88
+					cnxcc_unlock(credit_data->lock);
92 89
 					continue;
93 90
 				}
94 91
 
... ...
@@ -112,15 +109,16 @@ void check_calls_by_money(unsigned int ticks, void *param) {
112 109
 					terminate_all_calls(credit_data);
113 110
 
114 111
 					// 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);
112
+					if (_data.redis)
113
+						redis_publish_to_kill_list(credit_data);
114
+					cnxcc_unlock(credit_data->lock);
117 115
 					break;
118 116
 				}
119 117
 
120
-				lock_release(&credit_data->lock);
118
+				cnxcc_unlock(credit_data->lock);
121 119
 			}
122 120
 
123
-	lock_release(&_data.money.lock);
121
+	cnxcc_unlock(_data.money.lock);
124 122
 }
125 123
 
126 124
 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 127
 	call_t *tmp_call = NULL;
130 128
 	int i;
131 129
 
132
-	lock_get(&_data.time.lock);
130
+	cnxcc_lock(_data.time.lock);
133 131
 
134 132
 	if (_data.time.credit_data_by_client->table)
135 133
 		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 137
 				int total_consumed_secs = 0;
140 138
 				double consumption_diff = 0/*, distributed_consumption = 0*/;
141 139
 
142
-				lock_get(&credit_data->lock);
140
+				cnxcc_lock(credit_data->lock);
143 141
 
144 142
 				/*if (i > SAFE_ITERATION_THRESHOLD)
145 143
 				{
... ...
@@ -169,7 +167,7 @@ void check_calls_by_time(unsigned int ticks, void *param) {
169 167
 				}
170 168
 
171 169
 				if (credit_data->concurrent_calls == 0) {
172
-					lock_release(&credit_data->lock);
170
+					cnxcc_unlock(credit_data->lock);
173 171
 					continue;
174 172
 				}
175 173
 
... ...
@@ -190,13 +188,14 @@ void check_calls_by_time(unsigned int ticks, void *param) {
190 188
 					terminate_all_calls(credit_data);
191 189
 
192 190
 					// 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);
191
+					if (_data.redis)
192
+						redis_publish_to_kill_list(credit_data);
193
+					cnxcc_unlock(credit_data->lock);
195 194
 					break;
196 195
 				}
197 196
 
198
-				lock_release(&credit_data->lock);
197
+				cnxcc_unlock(credit_data->lock);
199 198
 			}
200 199
 
201
-	lock_release(&_data.time.lock);
200
+	cnxcc_unlock(_data.time.lock);
202 201
 }
... ...
@@ -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 473
 
472 474
 	/* by money */
473 475
 	hts = &_data.money;
474
-	lock_get(&hts->lock);
476
+	cnxcc_lock(hts->lock);
475 477
 
476 478
 	cd_entry = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
477 479
 
478 480
 	if (cd_entry != NULL) {
479 481
 		*credit_data	= cd_entry->u.p;
480
-		lock_release(&hts->lock);
482
+		cnxcc_unlock(hts->lock);
481 483
 		return 0;
482 484
 	}
483 485
 
484
-	lock_release(&hts->lock);
486
+	cnxcc_unlock(hts->lock);
485 487
 
486 488
 	/* by time */
487 489
 	hts = &_data.time;
488
-	lock_get(&hts->lock);
490
+	cnxcc_lock(hts->lock);
489 491
 
490 492
 	cd_entry = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
491 493
 
492 494
 	if (cd_entry != NULL) {
493 495
 		*credit_data	= cd_entry->u.p;
494
-		lock_release(&hts->lock);
496
+		cnxcc_unlock(hts->lock);
495 497
 		return 0;
496 498
 	}
497 499
 
498
-	lock_release(&hts->lock);
500
+	cnxcc_unlock(hts->lock);
499 501
 
500 502
 	/* by channel */
501 503
 	hts = &_data.channel;
502
-	lock_get(&hts->lock);
504
+	cnxcc_lock(hts->lock);
503 505
 
504 506
 	cd_entry = str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
505 507
 
506 508
 	if (cd_entry != NULL) {
507 509
 		*credit_data	= cd_entry->u.p;
508
-		lock_release(&hts->lock);
510
+		cnxcc_unlock(hts->lock);
509 511
 		return 0;
510 512
 	}
511 513
 
512
-	lock_release(&hts->lock);
514
+	cnxcc_unlock(hts->lock);
513 515
 	return -1;
514 516
 }
515 517
 
... ...
@@ -520,45 +522,45 @@ int try_get_call_entry(str *callid, call_t **call, hash_tables_t **hts) {
520 522
 
521 523
 	/* by money */
522 524
 	*hts = &_data.money;
523
-	lock_get(&(*hts)->lock);
525
+	cnxcc_lock((*hts)->lock);
524 526
 
525 527
 	call_entry = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
526 528
 
527 529
 	if (call_entry != NULL) {
528 530
 		*call = call_entry->u.p;
529
-		lock_release(&(*hts)->lock);
531
+		cnxcc_unlock((*hts)->lock);
530 532
 		return 0;
531 533
 	}
532 534
 
533
-	lock_release(&(*hts)->lock);
535
+	cnxcc_unlock((*hts)->lock);
534 536
 
535 537
 	/* by time */
536 538
 	*hts = &_data.time;
537
-	lock_get(&(*hts)->lock);
539
+	cnxcc_lock((*hts)->lock);
538 540
 
539 541
 	call_entry = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
540 542
 
541 543
 	if (call_entry != NULL) {
542 544
 		*call = call_entry->u.p;
543
-		lock_release(&(*hts)->lock);
545
+		cnxcc_unlock((*hts)->lock);
544 546
 		return 0;
545 547
 	}
546 548
 
547
-	lock_release(&(*hts)->lock);
549
+	cnxcc_unlock((*hts)->lock);
548 550
 
549 551
 	/* by channel */
550 552
 	*hts = &_data.channel;
551
-	lock_get(&(*hts)->lock);
553
+	cnxcc_lock((*hts)->lock);
552 554
 
553 555
 	call_entry = str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
554 556
 
555 557
 	if (call_entry != NULL) {
556 558
 		*call = call_entry->u.p;
557
-		lock_release(&(*hts)->lock);
559
+		cnxcc_unlock((*hts)->lock);
558 560
 		return 0;
559 561
 	}
560 562
 
561
-	lock_release(&(*hts)->lock);
563
+	cnxcc_unlock((*hts)->lock);
562 564
 	return -1;
563 565
 }
564 566
 
... ...
@@ -586,7 +588,7 @@ static void __stop_billing(str *callid) {
586 588
 		return;
587 589
 	}
588 590
 
589
-	lock_get(&hts->lock);
591
+	cnxcc_lock(hts->lock);
590 592
 
591 593
 	/*
592 594
 	 * Search credit_data by client_id
... ...
@@ -595,7 +597,7 @@ static void __stop_billing(str *callid) {
595 597
 
596 598
 	if (cd_entry == NULL) {
597 599
 		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);
600
+		cnxcc_unlock(hts->lock);
599 601
 		return;
600 602
 	}
601 603
 
... ...
@@ -603,23 +605,23 @@ static void __stop_billing(str *callid) {
603 605
 
604 606
 	if (credit_data == NULL) {
605 607
 		LM_ERR("[%.*s]: credit_data pointer is null\n", callid->len, callid->s);
606
-		lock_release(&hts->lock);
608
+		cnxcc_unlock(hts->lock);
607 609
 		return;
608 610
 	}
609 611
 
610
-	lock_release(&hts->lock);
612
+	cnxcc_unlock(hts->lock);
611 613
 
612 614
 	/*
613 615
 	 * Update calls statistics
614 616
 	 */
615
-	lock_get(&_data.lock);
617
+	cnxcc_lock(_data.lock);
616 618
 
617 619
 	_data.stats->active--;
618 620
 	_data.stats->total--;
619 621
 
620
-	lock_release(&_data.lock);
622
+	cnxcc_unlock(_data.lock);
621 623
 
622
-	lock(&credit_data->lock);
624
+	cnxcc_lock(credit_data->lock);
623 625
 
624 626
 	LM_DBG("Call [%.*s] of client-ID [%.*s], ended\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
625 627
 
... ...
@@ -653,7 +655,13 @@ static void __stop_billing(str *callid) {
653 655
 	 * Remove (and free) the call from the list of calls of the current credit_data
654 656
 	 */
655 657
 	clist_rm(call, next, prev);
656
-	__free_call(call);
658
+	/* 
659
+	 * don't free the call if all the credit data is being deallocated,
660
+	 * it will be freed by terminate_all_calls()
661
+	 */
662
+	if (!credit_data->deallocating) {
663
+		__free_call(call);
664
+	}
657 665
 
658 666
 	/*
659 667
 	 * 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 671
 		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 672
 
665 673
 		credit_data->deallocating = 1;
666
-		lock(&hts->lock);
674
+		cnxcc_lock(hts->lock);
667 675
 
668 676
 		if (_data.redis) {
669 677
 			redis_clean_up_if_last(credit_data);
... ...
@@ -675,7 +683,7 @@ static void __stop_billing(str *callid) {
675 683
 		 */
676 684
 		str_hash_del(cd_entry);
677 685
 
678
-		lock_release(&hts->lock);
686
+		cnxcc_unlock(hts->lock);
679 687
 
680 688
 		/*
681 689
 		 * Free client_id in list's root
... ...
@@ -686,7 +694,7 @@ static void __stop_billing(str *callid) {
686 694
 		/*
687 695
 		 * Release the lock since we are going to free the entry down below
688 696
 		 */
689
-		lock_release(&credit_data->lock);
697
+		cnxcc_unlock(credit_data->lock);
690 698
 
691 699
 		/*
692 700
 		 * Free the whole entry
... ...
@@ -699,7 +707,7 @@ static void __stop_billing(str *callid) {
699 707
 		return;
700 708
 	}
701 709
 
702
-	lock_release(&credit_data->lock);
710
+	cnxcc_unlock(credit_data->lock);
703 711
 }
704 712
 
705 713
 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 716
 
709 717
 	LM_DBG("Creating dialog for [%.*s], h_id [%u], h_entry [%u]\n", callid->len, callid->s, h_id, h_entry);
710 718
 
711
-//	lock_get(&_data.lock);
719
+//	cnxcc_lock(&_data);
712 720
 
713 721
 	/*
714 722
 	 * 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 739
 	/*
732 740
 	 * Update calls statistics
733 741
 	 */
734
-	lock_get(&_data.lock);
742
+	cnxcc_lock(_data.lock);
735 743
 
736 744
 	_data.stats->active++;
737 745
 	_data.stats->total++;
738 746
 
739
-	lock_release(&_data.lock);
747
+	cnxcc_unlock(_data.lock);
740 748
 
741
-	lock_get(&call->lock);
749
+	cnxcc_lock(call->lock);
742 750
 
743 751
 	call->dlg_h_entry	= h_entry;
744 752
 	call->dlg_h_id		= h_id;
745 753
 
746 754
 	LM_DBG("Call [%.*s] from client [%.*s], created\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
747 755
 
748
-	lock_release(&call->lock);
756
+	cnxcc_unlock(call->lock);
749 757
 }
750 758
 
751 759
 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 764
 
757 765
 	LM_DBG("Billing started for call [%.*s]\n", callid->len, callid->s);
758 766
 
759
-//	lock_get(&_data.lock);
767
+//	cnxcc_lock(&_data);
760 768
 
761 769
 	/*
762 770
 	 * 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 784
 		return;
777 785
 	}
778 786
 
779
-	lock_get(&hts->lock);
787
+	cnxcc_lock(hts->lock);
780 788
 
781 789
 	/*
782 790
 	 * 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 793
 
786 794
 	if (cd_entry == NULL) {
787 795
 		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);
796
+		cnxcc_unlock(hts->lock);
789 797
 		return;
790 798
 	}
791 799
 
... ...
@@ -793,13 +801,13 @@ static void __start_billing(str *callid, str *from_uri, str *to_uri, str tags[2]
793 801
 
794 802
 	if (credit_data == NULL) {
795 803
 		LM_ERR("[%.*s]: credit_data pointer is null\n", callid->len, callid->s);
796
-		lock_release(&hts->lock);
804
+		cnxcc_unlock(hts->lock);
797 805
 		return;
798 806
 	}
799 807
 
800
-	lock_release(&hts->lock);
808
+	cnxcc_unlock(hts->lock);
801 809
 
802
-	lock(&credit_data->lock);
810
+	cnxcc_lock(credit_data->lock);
803 811
 
804 812
 	/*
805 813
 	 * 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 842
 	 */
835 843
 	call->max_amount = credit_data->max_amount - credit_data->consumed_amount;
836 844
 
837
-	lock_release(&credit_data->lock);
845
+	cnxcc_unlock(credit_data->lock);
838 846
 
839
-	lock_get(&call->lock);
847
+	cnxcc_lock(call->lock);
840 848
 
841 849
 	/*
842 850
 	 * Store from-tag value
... ...
@@ -870,7 +878,7 @@ static void __start_billing(str *callid, str *from_uri, str *to_uri, str tags[2]
870 878
 			call->sip_data.to_uri.len, call->sip_data.to_uri.s,
871 879
 			call->sip_data.to_tag.len, call->sip_data.to_tag.s);
872 880
 exit:
873
-	lock_release(&call->lock);
881
+	cnxcc_unlock(call->lock);
874 882
 }
875 883
 
876 884
 // must be called with lock held on credit_data
... ...
@@ -888,6 +896,7 @@ void terminate_all_calls(credit_data_t *credit_data) {
888 896
 		 */
889 897
 		_data.stats->dropped++;
890 898
 		terminate_call(call);
899
+		__free_call(call);
891 900
 	}
892 901
 }
893 902
 
... ...
@@ -1020,32 +1029,32 @@ error:
1020 1029
 }
1021 1030
 
1022 1031
 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;
1032
+	struct str_hash_table *sht = NULL;
1033
+	struct hash_tables *ht;
1025 1034
 	struct str_hash_entry *e = NULL;
1026 1035
 	credit_data_t *credit_data = NULL;
1027 1036
 
1028 1037
 	switch(type) {
1029 1038
 	case CREDIT_MONEY:
1030
-		ht = _data.money.credit_data_by_client;
1031
-		lock =  &_data.money.lock;
1039
+		sht = _data.money.credit_data_by_client;
1040
+		ht =  &_data.money;
1032 1041
 		break;
1033 1042
 	case CREDIT_TIME:
1034
-		ht = _data.time.credit_data_by_client;
1035
-		lock =  &_data.time.lock;
1043
+		sht = _data.time.credit_data_by_client;
1044
+		ht =  &_data.time;
1036 1045
 		break;
1037 1046
 	case CREDIT_CHANNEL:
1038
-		ht = _data.channel.credit_data_by_client;
1039
-		lock =  &_data.channel.lock;
1047
+		sht = _data.channel.credit_data_by_client;
1048
+		ht =  &_data.channel;
1040 1049
 		break;
1041 1050
 	default:
1042 1051
 		LM_ERR("BUG: Something went terribly wrong\n");
1043 1052
 		return NULL;
1044 1053
 	}
1045 1054
 
1046
-	lock_get(lock);
1047
-	e = str_hash_get(ht, client_id->s, client_id->len);
1048
-	lock_release(lock);
1055
+	cnxcc_lock(ht->lock);
1056
+	e = str_hash_get(sht, client_id->s, client_id->len);
1057
+	cnxcc_unlock(ht->lock);
1049 1058
 
1050 1059
 	/*
1051 1060
 	 * 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 1075
 		if (credit_data == NULL)
1067 1076
 			goto no_memory;
1068 1077
 
1069
-		lock_get(lock);
1070
-		str_hash_add(ht, e);
1071
-		lock_release(lock);
1078
+		cnxcc_lock(ht->lock);
1079
+		str_hash_add(sht, e);
1080
+		cnxcc_unlock(ht->lock);
1072 1081
 
1073
-		LM_DBG("Call didn't exist. Allocated new entry\n");
1082
+		LM_DBG("Credit entry didn't exist. Allocated new entry [%p]\n", e);
1074 1083
 	}
1075 1084
 
1076 1085
 	return (credit_data_t *) e->u.p;
... ...
@@ -1083,7 +1092,7 @@ no_memory:
1083 1092
 static credit_data_t *__alloc_new_credit_data(str *client_id, credit_type_t type) {
1084 1093
 	credit_data_t *credit_data = shm_malloc(sizeof(credit_data_t));;
1085 1094
 
1086
-	lock_init(&credit_data->lock);
1095
+	cnxcc_lock_init(credit_data->lock);
1087 1096
 
1088 1097
 	credit_data->call_list = shm_malloc(sizeof(call_t));
1089 1098
 
... ...
@@ -1135,7 +1144,8 @@ error:
1135 1144
 static call_t *__alloc_new_call_by_money(credit_data_t *credit_data, struct sip_msg *msg, 
1136 1145
 					double credit, double cost_per_second, int initial_pulse, int final_pulse) {
1137 1146
 	call_t *call = NULL;
1138
-	lock_get(&credit_data->lock);
1147
+
1148
+	cnxcc_lock(credit_data->lock);
1139 1149
 
1140 1150
 	if (credit_data->call_list == NULL) {
1141 1151
 		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 1193
 	 */
1184 1194
 	clist_insert(credit_data->call_list, call, next, prev);
1185 1195
 
1186
-	lock_init(&call->lock);
1196
+	cnxcc_lock_init(call->lock);
1187 1197
 
1188 1198
 	/*
1189 1199
 	 * 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 1202
 	if (_data.redis)
1193 1203
 		redis_incr_by_int(credit_data, "number_of_calls", 1);
1194 1204
 
1195
-	lock_release(&credit_data->lock);
1205
+	cnxcc_unlock(credit_data->lock);
1196 1206
 
1197 1207
 	LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
1198 1208
 
1199 1209
 	return call;
1200 1210
 
1201 1211
 error:
1202
-	lock_release(&credit_data->lock);
1212
+	cnxcc_unlock(credit_data->lock);
1203 1213
 	return NULL;
1204 1214
 }
1205 1215
 
1206 1216
 static call_t *__alloc_new_call_by_time(credit_data_t *credit_data, struct sip_msg *msg, int max_secs) {
1207 1217
 	call_t *call = NULL;
1208 1218
 
1209
-	lock_get(&credit_data->lock);
1219
+	cnxcc_lock(credit_data->lock);
1210 1220
 
1211 1221
 	if (credit_data->call_list == NULL) {
1212 1222
 		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 1260
 	 */
1251 1261
 	clist_insert(credit_data->call_list, call, next, prev);
1252 1262
 
1253
-	lock_init(&call->lock);
1263
+	cnxcc_lock_init(call->lock);
1254 1264
 
1255 1265
 	/*
1256 1266
 	 * 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 1269
 	if (_data.redis)
1260 1270
 		redis_incr_by_int(credit_data, "number_of_calls", 1);
1261 1271
 
1262
-	lock_release(&credit_data->lock);
1272
+	cnxcc_unlock(credit_data->lock);
1263 1273
 
1264 1274
 	LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
1265 1275
 
1266 1276
 	return call;
1267 1277
 
1268 1278
 error:
1269
-	lock_release(&credit_data->lock);
1279
+	cnxcc_unlock(credit_data->lock);
1270 1280
 	return NULL;
1271 1281
 }
1272 1282
 
1273 1283
 static call_t *alloc_new_call_by_channel(credit_data_t *credit_data, struct sip_msg *msg, int max_chan) {
1274 1284
 	call_t *call = NULL;
1275 1285
 
1276
-	lock_get(&credit_data->lock);
1286
+	cnxcc_lock(credit_data->lock);
1277 1287
 
1278 1288
 	if (credit_data->call_list == NULL) {
1279 1289
 		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 1327
 	 */
1318 1328
 	clist_insert(credit_data->call_list, call, next, prev);
1319 1329
 
1320
-	lock_init(&call->lock);
1330
+	cnxcc_lock_init(call->lock);
1321 1331
 
1322 1332
 	/*
1323 1333
 	 * 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 1336
 	if (_data.redis)
1327 1337
 		redis_incr_by_int(credit_data, "number_of_calls", 1);
1328 1338
 
1329
-	lock_release(&credit_data->lock);
1339
+	cnxcc_unlock(credit_data->lock);
1330 1340
 
1331 1341
 	LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
1332 1342
 
... ...
@@ -1334,27 +1344,27 @@ static call_t *alloc_new_call_by_channel(credit_data_t *credit_data, struct sip_
1334 1344
 	return call;
1335 1345
 
1336 1346
 error:
1337
-	lock_release(&credit_data->lock);
1347
+	cnxcc_unlock(credit_data->lock);
1338 1348
 	return NULL;
1339 1349
 }
1340 1350
 
1341 1351
 static int __add_call_by_cid(str *cid, call_t *call, credit_type_t type) {
1342 1352
 	struct str_hash_table *ht	= NULL;
1343
-	gen_lock_t *lock		= NULL;
1353
+	cnxcc_lock_t lock;
1344 1354
 	struct str_hash_entry *e	= NULL;
1345 1355
 
1346 1356
 	switch(type) {
1347 1357
 	case CREDIT_MONEY:
1348 1358
 		ht	= _data.money.call_data_by_cid;
1349
-		lock	=  &_data.money.lock;
1359
+		lock	=  _data.money.lock;
1350 1360
 		break;
1351 1361
 	case CREDIT_TIME:
1352 1362
 		ht	= _data.time.call_data_by_cid;
1353
-		lock	=  &_data.time.lock;
1363
+		lock	=  _data.time.lock;
1354 1364
 		break;
1355 1365
 	case CREDIT_CHANNEL:
1356 1366
 		ht	= _data.channel.call_data_by_cid;
1357
-		lock	=  &_data.channel.lock;
1367
+		lock	=  _data.channel.lock;
1358 1368
 		break;
1359 1369
 	default:
1360 1370
 		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 1410
 
1401 1411
 	e->u.p	= call;
1402 1412
 
1403
-	lock_get(lock);
1413
+	cnxcc_lock(lock);
1404 1414
 	str_hash_add(ht, e);
1405
-	lock_release(lock);
1415
+	cnxcc_unlock(lock);
1406 1416
 
1407 1417
 	return 0;
1408 1418
 }
... ...
@@ -1805,9 +1815,9 @@ static int __update_max_time(struct sip_msg* msg, char* str_pv_client, char* str
1805 1815
 	call_t *call			= NULL,
1806 1816
 	       *tmp_call		= NULL;
1807 1817
 
1808
-	lock_get(&_data.time.lock);
1818
+	cnxcc_lock(_data.time.lock);
1809 1819
 	e = str_hash_get(ht, client_id_val.rs.s, client_id_val.rs.len);
1810
-	lock_release(&_data.time.lock);
1820
+	cnxcc_unlock(_data.time.lock);
1811 1821
 
1812 1822
 	if (e == NULL) {
1813 1823
 		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 1825
 	}
1816 1826
 		
1817 1827
 	credit_data = (credit_data_t *) e->u.p;
1818
-	lock_get(&credit_data->lock);
1828
+	cnxcc_lock(credit_data->lock);
1819 1829
 
1820 1830
 	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 1831
 	
... ...
@@ -1834,7 +1844,7 @@ static int __update_max_time(struct sip_msg* msg, char* str_pv_client, char* str
1834 1844
 //redit_data->consumed_amount			= 0;
1835 1845
 
1836 1846
 
1837
-	lock_release(&credit_data->lock);
1847
+	cnxcc_unlock(credit_data->lock);
1838 1848
 
1839 1849
 	return 1;
1840 1850
 }
... ...
@@ -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 100
 	struct str_hash_table *credit_data_by_client;
53 101
 	struct str_hash_table *call_data_by_cid;
54 102
 
55
-	gen_lock_t lock;
103
+	cnxcc_lock_t lock;
56 104
 } hash_tables_t;
57 105
 
58 106
 struct redis;
59 107
 
60 108
 typedef struct data {
61
-	gen_lock_t lock;
109
+	cnxcc_lock_t lock;
62 110
 
63 111
 	hash_tables_t time;
64 112
 	hash_tables_t money;
... ...
@@ -111,7 +159,7 @@ typedef struct call {
111 159
 	struct call *prev;
112 160
 	struct call *next;
113 161
 
114
-	gen_lock_t lock;
162
+	cnxcc_lock_t lock;
115 163
 
116 164
 	char confirmed;
117 165
 	double max_amount;
... ...
@@ -135,7 +183,7 @@ typedef struct call_array {
135 183
 } call_array_t;
136 184
 
137 185
 typedef struct credit_data {
138
-	gen_lock_t lock;
186
+	cnxcc_lock_t lock;
139 187
 
140 188
 	double max_amount;
141 189
 	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 55
 
58 56
 	LM_ALERT("Killing call [%.*s] via XMLRPC request\n", callid.len, callid.s);
59 57
 
60
-	lock_get(&call->lock);
58
+	cnxcc_lock(call->lock);
61 59
 
62 60
 	terminate_call(call);
63 61
 
64
-	lock_release(&call->lock);
62
+	cnxcc_unlock(call->lock);
65 63
 }
66 64
 
67 65
 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 86
 		return;
89 87
 	}
90 88
 
91
-	lock_get(&credit_data->lock);
89
+	cnxcc_lock(credit_data->lock);
92 90
 
93 91
 	if (credit_data->number_of_calls <= 0) {
94
-		lock_release(&credit_data->lock);
92
+		cnxcc_unlock(credit_data->lock);
95 93
 		LM_INFO("No calls for current client\n");
96 94
 		return;
97 95
 	}
... ...
@@ -136,7 +134,7 @@ void rpc_check_client_stats(rpc_t* rpc, void* ctx) {
136 134
 		rows.s		= pkg_realloc(rows.s, rows.len + row_len);
137 135
 
138 136
 		if (rows.s == NULL) {
139
-			lock_release(&credit_data->lock);
137
+			cnxcc_unlock(credit_data->lock);
140 138
 			goto nomem;
141 139
 		}
142 140
 
... ...
@@ -146,7 +144,7 @@ void rpc_check_client_stats(rpc_t* rpc, void* ctx) {
146 144
 		index++;
147 145
 	}
148 146
 
149
-	lock_release(&credit_data->lock);
147
+	cnxcc_unlock(credit_data->lock);
150 148
 
151 149
 	if (rpc->add(ctx, "S", &rows) < 0) {
152 150
 		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 165
 	char row_buffer[512];
168 166
 	int index = 0;
169 167
 
170
-	lock_get(&hts->lock);
168
+	cnxcc_lock(hts->lock);
171 169
 
172 170
 	if (hts->credit_data_by_client->table)
173 171
 		for(index = 0; index < hts->credit_data_by_client->size; index++)
174 172
 			clist_foreach_safe(&hts->credit_data_by_client->table[index], h_entry, tmp, next) {
175 173
 				credit_data_t *credit_data	= (credit_data_t *) h_entry->u.p;
176
-				lock_get(&credit_data->lock);
174
+				cnxcc_lock(credit_data->lock);
177 175
 
178 176
 				int row_len = 0;
179 177
 
... ...
@@ -212,13 +210,13 @@ static int iterate_over_table(hash_tables_t *hts, str *result, credit_type_t typ
212 210
 					return -1;
213 211
 				}
214 212
 
215
-				lock_release(&credit_data->lock);
213
+				cnxcc_unlock(credit_data->lock);
216 214
 
217 215
 				row_len 	= strlen(row_buffer);
218 216
 				result->s	= pkg_realloc(result->s, result->len + row_len);
219 217
 
220 218
 				if (result->s == NULL) {
221
-					lock_release(&hts->lock);
219
+					cnxcc_unlock(hts->lock);
222 220
 					goto nomem;
223 221
 				}
224 222
 
... ...
@@ -227,7 +225,7 @@ static int iterate_over_table(hash_tables_t *hts, str *result, credit_type_t typ
227 225
 
228 226
 			}
229 227
 
230
-	lock_release(&hts->lock);
228
+	cnxcc_unlock(hts->lock);
231 229
 
232 230
 	return 0;
233 231
 
... ...
@@ -249,7 +247,7 @@ void rpc_active_clients(rpc_t* rpc, void* ctx) {
249 247
 	iterate_over_table(&_data.time, &rows, CREDIT_TIME);
250 248
 	iterate_over_table(&_data.money, &rows, CREDIT_MONEY);
251 249
 
252
-	if (!rpc->add(ctx, "S", &rows) < 0) {
250
+	if (rpc->add(ctx, "S", &rows) < 0) {
253 251
 		LM_ERR("%s: error creating RPC struct\n", __FUNCTION__);
254 252
 	}
255 253