mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-29 23:39:35 +00:00 
			
		
		
		
	git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@39683 65c4cc65-6c06-0410-ace0-fbb531ad65f3
		
			
				
	
	
		
			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
 |