mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 18:55:19 +00:00 
			
		
		
		
	
		
			
	
	
		
			79 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			79 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | About the MacroExclusive application | ||
|  | ------------------------------------ | ||
|  | 
 | ||
|  | Steve Davies <steve@connection-telecom.com | ||
|  | 
 | ||
|  | 
 | ||
|  | The MacroExclusive application was added to solve the problem of | ||
|  | synchronisation between calls running at the same time. | ||
|  | 
 | ||
|  | This is usually an issue when you have calls manipulating global | ||
|  | variables or the Asterisk database, but may be useful elsewhere. | ||
|  | 
 | ||
|  | Consider this example macro, intended to return a "next" number - | ||
|  | each caller is intended to get a different number: | ||
|  | 
 | ||
|  | [macro-next] | ||
|  | exten => s,1,Set(RESULT=${COUNT}) | ||
|  | exten => s,n,SetGlobalVar(COUNT=$[${COUNT} + 1]) | ||
|  | 
 | ||
|  | The problem is that in a box with high activity, you can be sure | ||
|  | that two calls will come along together - both will get the same | ||
|  | "RESULT", or the "COUNT" value will get mangled. | ||
|  | 
 | ||
|  | Calling this Macro via MacroExclusive will use a mutex to make sure | ||
|  | that only one call executes in the Macro at a time.  This ensures | ||
|  | that the two lines execute as a unit. | ||
|  | 
 | ||
|  | Note that even the s,2 line above has its own race problem.  Two | ||
|  | calls running that line at once will step on each other and | ||
|  | the count will end up as +1 rather than +2. | ||
|  | 
 | ||
|  | I've also been able to use MacroExclusive where I have two Macros | ||
|  | that need to be mutually exclusive. | ||
|  | 
 | ||
|  | Here's the example: | ||
|  | 
 | ||
|  | [macro-push] | ||
|  | ; push value ${ARG2} onto stack ${ARG1} | ||
|  | exten => s,1,Set(DB(STACK/${ARG1})=${ARG2}^${DB(STACK/${ARG1})}) | ||
|  | 
 | ||
|  | [macro-pop] | ||
|  | ; pop top value from stack ${ARG1} | ||
|  | exten => s,1,Set(RESULT=${DB(STACK/${ARG1})}) | ||
|  | exten => s,n,Set(DB(STACK/${ARG1})=${CUT(RESULT,^,2)}) | ||
|  | exten => s,n,Set(RESULT=${CUT(RESULT,^,1)}) | ||
|  | 
 | ||
|  | All that futzing with the STACK/${ARG1} in the astdb needs protecting | ||
|  | if this is to work.  But neither push nor pop can run together. | ||
|  | 
 | ||
|  | So add this "pattern": | ||
|  | 
 | ||
|  | [macro-stack] | ||
|  | exten => Macro(${ARG1},${ARG2},${ARG3}) | ||
|  | 
 | ||
|  | ... and use it like so: | ||
|  | 
 | ||
|  | exten => s,1,MacroExclusive(stack,push,MYSTACK,bananas) | ||
|  | exten => s,n,MacroExclusive(stack,push,MYSTACK,apples) | ||
|  | exten => s,n,MacroExclusive(stack,push,MYSTACK,guavas) | ||
|  | exten => s,n,MacroExclusive(stack,push,MYSTACK,pawpaws) | ||
|  | exten => s,n,MacroExclusive(stack,pop,MYSTACK) ; RESULT gets pawpaws (yum) | ||
|  | exten => s,n,MacroExclusive(stack,pop,MYSTACK) ; RESULT gets guavas | ||
|  | exten => s,n,MacroExclusive(stack,pop,MYSTACK) ; RESULT gets apples | ||
|  | exten => s,n,MacroExclusive(stack,pop,MYSTACK) ; RESULT gets bananas | ||
|  | 
 | ||
|  | We get to the push and pop macros "via" the stack macro.  But only one call | ||
|  | can execute the stack macro at a time; ergo, only one of push OR pop can | ||
|  | run at a time. | ||
|  | 
 | ||
|  | Hope people find this useful. | ||
|  | 
 | ||
|  | Lastly, its worth pointing out that only Macros that access shared data | ||
|  | will require this MacroExclusive protection.  And Macro's that you call | ||
|  | with macroExclusive should run quickly or you will clog up your Asterisk | ||
|  | system. | ||
|  | 
 | ||
|  | Regards, | ||
|  | Steve |