diff --git a/doc/macroexclusive.txt b/doc/macroexclusive.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a31114936b978492a9098038eb95137c30ef16f --- /dev/null +++ b/doc/macroexclusive.txt @@ -0,0 +1,78 @@ +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