79 lines
2.7 KiB
Text
79 lines
2.7 KiB
Text
![]() |
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
|