Blocked revisions 74262 via svnmerge
[asterisk/asterisk.git] / doc / macroexclusive.txt
1 About the MacroExclusive application
2 ------------------------------------
3
4 Steve Davies <steve@connection-telecom.com
5
6
7 The MacroExclusive application was added to solve the problem of
8 synchronisation between calls running at the same time.
9
10 This is usually an issue when you have calls manipulating global
11 variables or the Asterisk database, but may be useful elsewhere.
12
13 Consider this example macro, intended to return a "next" number -
14 each caller is intended to get a different number:
15
16 [macro-next]
17 exten => s,1,Set(RESULT=${COUNT})
18 exten => s,n,SetGlobalVar(COUNT=$[${COUNT} + 1])
19
20 The problem is that in a box with high activity, you can be sure
21 that two calls will come along together - both will get the same
22 "RESULT", or the "COUNT" value will get mangled.
23
24 Calling this Macro via MacroExclusive will use a mutex to make sure
25 that only one call executes in the Macro at a time.  This ensures
26 that the two lines execute as a unit.
27
28 Note that even the s,2 line above has its own race problem.  Two
29 calls running that line at once will step on each other and
30 the count will end up as +1 rather than +2.
31
32 I've also been able to use MacroExclusive where I have two Macros
33 that need to be mutually exclusive.
34
35 Here's the example:
36
37 [macro-push]
38 ; push value ${ARG2} onto stack ${ARG1}
39 exten => s,1,Set(DB(STACK/${ARG1})=${ARG2}^${DB(STACK/${ARG1})})
40
41 [macro-pop]
42 ; pop top value from stack ${ARG1}
43 exten => s,1,Set(RESULT=${DB(STACK/${ARG1})})
44 exten => s,n,Set(DB(STACK/${ARG1})=${CUT(RESULT,^,2)})
45 exten => s,n,Set(RESULT=${CUT(RESULT,^,1)})
46
47 All that futzing with the STACK/${ARG1} in the astdb needs protecting
48 if this is to work.  But neither push nor pop can run together.
49
50 So add this "pattern":
51
52 [macro-stack]
53 exten => Macro(${ARG1},${ARG2},${ARG3})
54
55 ... and use it like so:
56
57 exten => s,1,MacroExclusive(stack,push,MYSTACK,bananas)
58 exten => s,n,MacroExclusive(stack,push,MYSTACK,apples)
59 exten => s,n,MacroExclusive(stack,push,MYSTACK,guavas)
60 exten => s,n,MacroExclusive(stack,push,MYSTACK,pawpaws)
61 exten => s,n,MacroExclusive(stack,pop,MYSTACK) ; RESULT gets pawpaws (yum)
62 exten => s,n,MacroExclusive(stack,pop,MYSTACK) ; RESULT gets guavas
63 exten => s,n,MacroExclusive(stack,pop,MYSTACK) ; RESULT gets apples
64 exten => s,n,MacroExclusive(stack,pop,MYSTACK) ; RESULT gets bananas
65
66 We get to the push and pop macros "via" the stack macro.  But only one call
67 can execute the stack macro at a time; ergo, only one of push OR pop can
68 run at a time.
69
70 Hope people find this useful.
71
72 Lastly, its worth pointing out that only Macros that access shared data
73 will require this MacroExclusive protection.  And Macro's that you call
74 with macroExclusive should run quickly or you will clog up your Asterisk
75 system.
76
77 Regards,
78 Steve