Contents
Here's some code to signal a long-running application whether it should continue or quit. It uses a value in a file which can be set externally. As Oleg comments at the bottom of this page, there may be a simpler way to do this.
Example Use
An example of using this code can be found here.
Complete Script
The lines in "setFlagFileName" are more complicated than they need to be as they are customized to work differently on different machines that I use. This code can be simplified even to the point of hard-coding it to return a specific filename.
NB.* semaphore.ijs: simple binary signalling via a flag file.
NB.* initFlagFile: initialize flag file for semaphoring.
NB.* setFlagFileName: Set name of file to use for semaphore flag.
NB.* lookAtLight: show value of light: Y=green.
NB.* initLight: initialize flag file.
NB.* switchLight: toggle light between Y (go) and N (stop).
NB.* setLight: set "light" (value in flag file) to specific value: Y or N.
NB.* greenLight: check semaphore file to see if we have green-light to proceed.
NB.* checkLight: check if light setting has been acknowledged; wait until
NB.* ackLight: acknowledge that we've seen the light
load 'filefns'
require 'logger' NB. Message display and logging
NB. FLAGFL=: 'C:\Temp\greenLight.flag' NB. Default flag file
egUse=: 0 : 0
setFlagFileName 'c:\amisc\txt\quote.flag'
'Y' initFlagFile FLAGFL
while. greenLight '' do. something end.
)
coclass 'semaphore'
coinsert 'base'
initFlagFile=: 3 : 0
NB.* initFlagFile: initialize flag file for semaphoring.
'' initFlagFile y
:
if. 0=#y do.
if. 0>4!:0 <'FLAGFL' do.
FLAGFL=: setFlagFileName ''
end.
else. FLAGFL=: setFlagFileName y
end.
if. 0~:#x. do. x. setLight '' end.
NB.EG FLAGFL=: 'Y' initFlagFl '\Temp\loadsome.flag' NB. Global set by caller.
)
setFlagFileName=: 3 : 0 NB. Set name of file to use for
NB.* setFlagFileName: Set name of file to use for semaphore flag.
fff=. '\FlagFl.NOW',~getTempDir '' NB. Temp file to keep name in.
if. 0=#y do. NB. Name is either non-empty argument
if. 0>4!:0 <'FLAGFL' do. NB. or existing global var
if. fexist fff do. NB. or in temp file
FLAGFL=: 1!:1 <fff
else. NB. or default value(s).
domain=. 0{whoami ''
sharedisk=. 'F:'
locals=. '[desktop name]';<'[laptop name]' NB. SET THESE: 2 machine names.
if. domain e. locals do. NB. Local domain so no F:
sharedisk=. 'C:' end.
FLAGFL=: <sharedisk,'\amisc\loadsome.flag'
end.
end.
else. FLAGFL=: y NB. Argument is ultimate override.
end.
(openbox FLAGFL) 1!:2 boxopen fff NB. Use temp file to pass arg.
boxopen FLAGFL
NB.EG FLAGFL=: setFlagFileName '\Temp\loadsome.flag' NB. Persistent global
)
lookAtLight=: 3 : 0
NB.* lookAtLight: show value of light: Y=green.
initFlagFile ''
if. 0=#y do. y=. FLAGFL end.
1!:1 boxopen y
)
initLight=: 3 : 0
NB.* initLight: initialize flag file.
'' initLight y
:
initFlagFile ''
signal=. <y
if. 0=#y do.
signal=. boxopen FLAGFL
end.
x. 1!:2 signal
NB.EG initLight '\somedir\somefile.flag'
)
switchLight=: 3 : 0
NB.* switchLight: toggle light between Y (go) and N (stop).
'' switchLight y
:
initFlagFile ''
maxtry=. 99
signal=. <y
if. 0=#y do.
signal=. FLAGFL
end.
signal=. boxopen signal
val=. toupper {.x.
if. 0=#x. do.
sigctr=. 0 NB. Check up to "maxtry" times in case
while. 3>sigctr do. NB. of network or other flakiness.
try. flag=. {. 1!:1 signal NB. Will sometimes fail because of
sigctr=. maxtry NB. file across network?
catch. wait >:?5 [ sigctr=. >:sigctr
end.
end.
if. sigctr<maxtry do.
logMsg_logger_ 'Unable to switch light at ',showdate ''
logMsg_logger_ 'for signal file ',(>signal),'.'
flushLog_logger_ '' [ val=. 'X' NB. Set arbitrary error value.
else.
if. 'Y'={.toupper flag do. val=. 'N'
else. val=. 'Y' end.
end.
end.
val 1!:2 signal NB. Will this work if read had trouble?
val NB. Return current value.
NB.EG switchLight '' NB. Flip flag to opposite for default file.
NB.EG 'Y' switchLight 'C:\Temp\foo.flag' NB. Set flag to 'Y' for foo file.
NB.EG 'N' switchLight '' NB. Set flag to 'N' (halt) for default file.
)
setLight=: 3 : 0
NB.* setLight: set "light" (value in flag file) to specific value: Y or N.
'Y' setLight y NB. Set to go by default
:
initFlagFile ''
signalFl=. y
if. 0=#y do.
signalFl=. FLAGFL
end.
signalFl=. boxopen signalFl
val=. toupper 1{.x.
val 1!:2 signalFl
val
NB.EG '' setLight '' NB. Flip flag to go ('Y') for default file.
NB.EG 'Y' setLight 'foo.flag' NB. Set flag to 'Y' for foo file.
NB.EG 'N' setLight '' NB. Set flag to 'N' (halt) for default file.
)
greenLight=: 3 : 0
NB.* greenLight: check semaphore file to see if we have green-light to proceed.
signal=. y
initFlagFile ''
if. 0=#y do.
signal=. FLAGFL
end.
signal=. boxopen signal
flag=. 1{. 1!:1 signal
if. 'Y'=toupper flag do.
1
else.
0
end.
NB.EG if. greenLight '' do. NB. proceed else. NB. halt end.
)
checkLight=: 3 : 0
NB.* checkLight: check if light setting has been acknowledged; wait until
NB. it has been or we lose patience (time out).
(5,_) checkLight y NB. Default to 5 seconds between checks, infinite patience.
:
initFlagFile ''
elapsed=. qai '' NB. Track elapsed time.
'waittm patience'=. x NB. Seconds to wait between checks, max seconds.
signal=. <y
if. 0=#y do.
signal=. FLAGFL
end.
flag=. 3{. 1!:1 signal
exit=. 0
ack=. 0 NB. No acknowledgement to start.
NB. Loop until we get acknowledgement or we're out of patience.
while. ('OK'-: _2{. flag) *. -.exit do.
wait (waittm) NB. Wait a little bit before checking again.
if. patience<(qai '')-elapsed do.
exit=. 1 NB. Drop out of loop if we're out of patience.
end.
flag=. 3{. 1!:1 signal
end.
ack=. 'OK'-: _2{. flag
)
ackLight=: 3 : 0
NB.* ackLight: acknowledge that we've seen the light
signal=. <y
initFlagFile ''
if. 0=#y do.
signal=. FLAGFL
end.
signal=. boxopen signal
flag=. {. 1!:1 signal
val=. (toupper flag),'OK'
val 1!:2 signal
val
NB.EG ackLight '' NB. Acknowledge reading flag from default file.
NB.EG ackLight 'C:\temp\gnarly.flag' NB. Acknowledge reading gnarly file flag.
)
coclass 'base'
coinsert 'semaphore'
Included Code
The requirement of "filefns" is probably only for the "fexist" function which is defined thusly:
NB.* fexist: 1 if named file exists, 0 otherwise. fexist=: (1:@(1!:4) ::0:@((([:< 8 u:>) ::])&>)@(<^:(L.=0:)))
Also, "whoami" - used to distinguish between machines - is defined (for Windows):
whoami=: 3 : 0
sess=. spawn 'net config workstation'
sess=. dsp&.><;._1 LF,sess-.CR NB. Vec of lines
sess=. ><;._1&.> ' ',&.>,sess NB. Mat of words
strs=. 'COMPUTER';<'USER' NB. Strings to key on
wh=. (<toupper&.>0{"1 sess)e.&.> <&.>strs NB. Which lines start with strings
wh=. ;b2i&.>(<(toupper&.>1{"1 sess)e. <'NAME')*.&.>wh
wh{2{"1 sess
NB.EG 'machine userid'=. whoami ''
)The code for "logger" is here.
Comment
See also semaphore pattern implemented much more simply in Scripts/Pump, basically doing fwrite at the beginning and watching for fexist in a loop. Compare with requirements at the top of this page. -- OlegKobchenko 2008-01-16 02:33:54
