[Tutor] async signal/notification & resulting action bet 2 seperate progr

Michael P. Reilly arcege@speakeasy.net
Thu, 31 May 2001 08:38:44 -0400 (EDT)


GADGIL PRASAD     /INFRA/INFOTECH wrote
> hello,
> 
> I am trying to write a generic monitering agent.
> 
> There will be some monitoring task for the AGENT_program. This program
> (currently) does the reqd check every polling interval. It's basically
> doing the monitering in a continous while loop, sleeping the poll_interval
> time, for every pass through the loop.
> 
> But some things are important enough that I might want an near immidiate
> notification rather than at the next poll after the severity of the
> monitered
> thing changes.
> 
> How do I implement such an out of the poll notification ?
> 
> I guess, for such a task, the Monitered thing will need to send a 
> signal/exception/whatever to my monitering program. My monitering program
> will
> awaken on reciept of such an event, and make another pass through the while
> loop.
> 
> I checked, signal()/pause()/exception related stuff, in PY-TUT. But, I don't
> know
> how to send the messages bet 2 diff programs/processes.
> 
> Can someone pl. explain what do I need to do in this case ?

If it is UNIX then you can use signals, otherwise I would suggest
using select and named pipes or sockets (sockets on WinXX) to send
notifications.  (Below is all "pseudocode" and not meant to be working
code.)

Signals:
First choose a signal to use, there are some common signals that are
"used" already.  SIGHUP for server restart, SIGTERM to terminate, SIGINT
and SIGQUIT (keyboard interrupts) should be ignored.  But there are
plenty of others: USR1, USR2 (SIGALRM is likely being used by sleep).
For this, let's assume that we'll use SIGUSR1.

* server (with loop)
signal_seen = 0
def signal_handler(signum, frame):
  global signal_seen
  signal_seen = 1
  do_something_in_the_signal()
signal.signal(signal.SIGUSR1, signal_handler)
while 1:
  signal_seen = 0
  time.sleep(wait_for_a_time)
  if signal_seen:
    continue # go back to sleep
  do_what_needs_to_be_done()
  # it is possible that signal came here, so set variable to zero before
  # sleep

* client
# if the server spawned the client, then use os.getppid, otherwise one
# common convention is to put the server's PID in a file
srvpid = get_server_pid()
...
os.kill(srvpid, signal.SIGUSR1)



Using select with named pipes:
The server creates a named uni-directional pipe to receive messages
from client programs (it could be as simple as a single character).
This is a mechanism that some implementations of UNIX printers use.

* server
def read_pipe(svrpipe):
  msg = svrpipe.readline() # assumes newline-terminated message
  do_something_in_the_signal()
os.mkfifo(ServerPipeFilename, 0600)
try:
  svrpipe = open(ServerPipeFilename, 'r')
  while 1:
    [r, w, e] = select.select([svrpipe], [], [], wait_for_a_time)
    if r:  # we received a notification
      assert(r == [svrpipe])
      read_pipe(svrpipe)
    else:
      do_what_needs_to_be_done()
finally:
  svrpipe.close()
  os.remove(ServerPipeFilename)

* client
# we don't make the named pipe here, if the pipe doesn't exist,
# then the server is not running
svrpipe = open(ServerPipeFilename, 'w')
...
try:
  svrpipe.write(NotificationMsg)
except EnvironmentError, err:
  if err.errno == errno.EPIPE:
    print 'Server closed'
  else:
    raise

The same thing could be done with sockets (UNIX domain or INET); depending
on implementations, you might loose the EPIPE notification in the client.
UNIX domain sockets are more like named pipes (creating a local file)
and are more secure than INET sockets.

The asyncore module can do a lot of this as well; but since a lot of
the work is not within the handlers, I see using asyncore as overkill.

  -Arcege

-- 
+----------------------------------+-----------------------------------+
| Michael P. Reilly                | arcege@speakeasy.net              |