Unix Signal Usage

Unix Signal Usage


Monitor Debugger Index Level addbi (D3/Unix)
Syntax
Category Unix
Type Definition
Description examines Unix signals in relationship to the Pick Virtual Machine.

This discussion is intended for experienced Unix programmers to interface Unix applications with Pick or to use Unix process synchronization in a purely Pick environment.
For performance reasons, Unix signals are not used in regular Pick activity. They are used solely to handle exceptions. Diverting signal usage for an application would simply remove nonessential facilities, like the possibility to send a message or to logoff a process. This does not mean that signals  can be used freely, though. The Pick Monitor provides a system call to process regular Pick signals inside a customized signal handler, thus combining system and application signal handling.

The following list, details the Pick signal system call and gives some examples of application signal handler.

Signal Usage
    
The following is a table of the signals currently used by D3. Future development may require using more signals.

D3 uses only Unix System V.3 signals, which are common to more recent Unix versions. Non Unix System V.3 signals are left to their default signal handler (normally SIG_IGN) as set by the system.

Numerical values may vary between Unix implementations. It is very important to use the proper include when writing in C or the include dm,bp,unix.h, signal.h when writing FlashBASIC programs using signals.

Signal     Description

SIGHUP     Hangup. When received, the process is logged off Pick, but remains connected to the virtual machine. The signal is controlled by the  hupcl command in the Pick configuration file. It is normally generated by the TTY device driver when data carrier is lost. This signal can be altered by the TCL command  trap  dcd  command .

SIGINT     Interrupt. Generated by the BREAK key and the alternate Virtual Machine.  The break character is defined by brkchr in the configuration file or by the TCL command  set-break . The process is sent to the FlashBASIC, or system debugger, if  brk-debug is on or a level is pushed if  brk-level is on.

SIGQUIT    Quit. Generated by the ESC key or the alternate escape character as defined by the  escchr in the configuration file or by the TCL command  set-esc . A level is pushed if  esc-level is on. If  esc-data is on, a signal is still generated, but eventually ignored by the Virtual debugger. The character defined by  set-esc will eventually be put in the process input buffer, but it must be emphasized that a noticeable delay can be experienced when inputting this character.

SIGILL     Illegal instruction. Sends the process to the system debugger with an 'illegal opcode' abort. Used for assembly single stepping on some implementations.

SIGTRAP    Trace trap. Sends the process to the system debugger with an 'illegal opcode' abort. Used for assembly single stepping on some implementations.

SIGIOT     I/O trap instruction. Sends the process to the system debugger with an 'illegal opcode' abort.

SIGEMT     Emulator trap. Sends the process to the system debugger with an 'illegal opcode' abort. Used for assembly single stepping on some implementations.

SIGFPE     Floating point exception. Sends the process to the system debugger with an 'illegal opcode' abort.

SIGKILL    Kill. This signal cannot be caught and will terminate the process immediately after doing a logoff. Killing the flusher of a virtual machine will log all processes off and shut down the virtual machine.

SIGBUS     Bus error. Sends the process to the system debugger with an 'illegal opcode' abort. Used for assembly single stepping on some implementations.

SIGSEGV    Segmentation violation. Sends the process to the system debugger with an 'illegal opcode' abort. Used for assembly single stepping on some implementations.

SIGSYS     Bad argument to a system call. Sends the process to the system debugger with an 'illegal opcode' abort.

SIGPIPE    Write to a pipe with no one to read it. The process is sent to the Virtual debugger. Pipes are sometimes used as 'tapes' to do file save. The other end of the pipe can be connected to a serial device, a communication server process... Therefore, when this signal is raised, the write system calls aborts. In an application environment, this signal should be caught and a message sent to the user saying 'Communication Server not Ready', for instance. The write system call would then be interrupted, reported to the save process as a 'parity' error, and the write would be retried until the write finally succeeds.

SIGALRM    Alarm clock. The default signal handler is a simple return. Therefore, the signal is active, but does nothing. It can be used in FlashBASIC, with the  %alarm() function, do set time outs around critical sections. This signal can be altered by the TCL  trap  alrm  command.

SIGTERM    Software termination signal. This signals terminates the Pick process, leaving it logged on, but disconnected. This signal 'freezes' the Pick environment. If the process is restarted, execution will resume where it stopped. Normally, this signal should be preceded by a SIGHUP to log the process off.

SIGUSR1    User-defined signal 1. Not used. Can be used freely by the applications.

SIGUSR2    User-defined signal 2. Force the process to examine its current state, possibly changing it. This signal is used for Pick message, by the TCL  logoff ,  TCL ,  END commands. Sending this signal out of context will cause no harm. This should be the way, for instance, to wake up a process waiting in a  %pause() system call. This signal can be used by applications, provided they call the Pick signal handler inside their customized signal handler. See the section about the examples below.

SIGCLD    Death of a child. Not used.

SIGPWR    Power fail. When received, the process is logged off Pick, but remains connected to the virtual machine. The behavior of the system depends on how the hardware generates this signal. If there is no battery back-up, it is unlikely that the virtual machine will be brought down gently. The system usually change its running state, which will control what happens. A  ap - k command should be inserted in the appropriate shell script associated to the new run level. This signal can be altered by the TCL  trap  pwr  command.


Pick Signal System Call

The Pick monitor provides a system call to inform the Pick Virtual environment of an incoming signal. This C function is normally called by the default signal system handlers, but it can be called by an application signal handler too.

This function is defined as follows:

#include "/usr/lib/pick/include/sigmon.h"

void sigmon( code )
int code;

code is the action code, as described in the following table. Note some functions  do not return to the caller .


Code          Value/Description
db_slcout     0/No operation. Simply forces the process to examine its current state. This function must be called by the  SIGUSR2 signal handler.

db_privop      7/Privileged opcode. Sends the caller to the system debugger. This call does not return to the caller. This call can be used to abort a C program, even if not called from a signal handler.

db_break       10/Interrupt. Sends the process to the FlashBASIC, or system debugger. This function must be called by the  SIGINT signal handler. Going to the system debugger is not immediate. Normally, the process will enter the debugger (or push a level) when the signal handler terminates.

db_esc         12/Quit. Pushes a level . This function must be called by the  SIGQUIT signal handler. Normally, the process will push a level when the signal handler terminates.

db_logoff      14/Log off. This function is normally called by the  SIGHUP handler. It can be called by other signal handlers as part of the application (like  SIGALRM for instance, to log off a process after a given time).

db_pwrdown     -1/Disconnect. The process is disconnected from the virtual machine, but remains logged on.


Examples

This sections shows some simple examples of using signals in a Pick application, or cooperating with Unix applications. All these examples require writing a C signal handler, which must be linked with the Pick monitor, as detailed in this document.

Time out

The purpose is to write a signal handler which will log the user process off if there is no activity for a given time. It is assumed the user is in a FlashBASIC application, waiting input.

-  Write the following signal handler and function

setalrm.c:

#include <signal.h>
#include "/usr/lib/pick/include/sigmon.h"

myalrm(){
   /* signal handler. When activated,
      log the process off */
      sigmon( db_logoff );
}

/* Set the new signal handler
   Set the signal handler to
   the application signal handler.
   Return the address of the
   previous signal handler, so
   that the basic application
   can remove the time out
*/

void (*setalrm())(){
   return signal(SIGALRM, myalrm );
}
<

-  Compile the previous program and incorporate it to the Pick monitor, by typing, in the  dm account:

addbi  setalrm  signal
ar  vru  libgm.a  setalrm.o
make  -f  /usr/lib/pick/Makefile

Note this incorporates the user-defined function  setalrm() as well as the system call  signal() not normally shipped with the Monitor. The latter will be extracted from the standard C library. The  %setalrm function can then be called from FlashBASIC.

-  Enter the following 'application' program

*
* Reprogram the alarm handler,
* keeping the previous system
* handler
* Note the function pointer
* returned by the function
* is treated as a pointer to a character.

include dm,bp,unix.h signal.h
old$alarm = (char*)%setalrm()
*
loop
   * Set the alarm to 10 minutes
   * From now on, if the user
   * doesn't enter a command before
   * 10 minutes, the process will
   * be logged off.
   %alarm(600)
   * .. display application entry screen here
   crt 'Command : ':
   input command
while 1 do
   begin case
        case command = 'a'
             * ... put command 'a' routine
        case command = 'end'
             print 'end of the application'
             * disable the alarm and set the default alarm
             * handler back to the default.
             %alarm( 0 )
             %signal( SIGALRM, (char*)old$alarm )
             chain 'off'
   end case
repeat

Note that, in the example above, if the alarm was not disabled and if the signal handler is not reset to the default, the alarm clock would have continued to run, even if the process went back to TCL, thus logging it off later. A small FlashBASIC program, just rearming the alarm can be written to incorporate the alarm  in PROCs or menus to achieve the same time out capability in TCL.

Synchronizing Two Pick Processes

On conventional Pick implementations, synchronizing two Pick processes is done either through polling for the existence of a file or, a little better, by using a FlashBASIC LOCK instruction. On most implementations, however, the FlashBASIC LOCK instruction itself involves, internally, a polling, thus making the waiting process to consume cpu resource. By using signals, it is possible to have a process waiting for a signal to occur (a BREAK, logoff or a signal generated by another process, possibly a Unix process or a Pick process from another Pick virtual machine) without any cpu consumption.

The following example has one phantom task waiting for a signal sent by 'somebody' to go read a message in a pipe where the 'somebody' has deposited a message. This communication with message, probably, would be better achieved through Unix messages, but this is merely an example. Also, this is a one to one communication. Multiple partners in this scheme would require semaphores. The server process makes itself visible to the entire system (Pick and Unix) by writing a temporary file which contains its process id, which other processes use to send a signal to it.

The (simple) signal handler uses  SIGUSR1 . The 'message' is in ASCII, containing a header and some data. The message has the following format:

+---+---+--------//-----------+
|   |NL |                     +
+---+---+--------//-----------+
 |   |          |
 |   |          +- Data (code dependent)
 |   +------------ New line (discarded)
 +---------------- Command code.
                    T : Terminate
                    M : Message
                    R : file receive
-  Enter the following C signal handler:

setusr1.c:

#include <signal.h>
#include "/usr/lib/pick/include/sigmon.h"

myusr1(){
   /* Just reset the signal for next time */
   signal( SIGUSR1, myusr1 );
}

/* Set the new signal handler
   Set the signal handler to the
      application signal handler.
   Return the address of the
      previous signal handler
      so that the basic application
      can remove the time out
*/

void (*setusr1())(){
   return signal(SIGUSR1, myusr1 );
}

-  Enter the following phantom task code in the item  dm,bp,  pserver :

pserver
001 !
002 * Example of a file server running as
003 * a phantom
004 * Commands are received on a named pipe.
005 *
006 include dm,bp,unix.h signal.h
007 include dm,bp,unix.h mode.h
008 include dm,bp,unix.h fcntl.h
009 *
010 * Defines:
011 equ NL to char(10)   ;* UNIX line terminator
012 equ AM to char(254)
013 equ PIPE to "/dev/mypipe"
014 equ BUFSIZE to 10000 ;* max message size
015 *
016 char buffer[BUFSIZE]
107 *
018 * Remove temporary file
019 execute '!rm -f /tmp/pserverid'
020 *
021 restart:*
022 *
023 * Open the communication pipe in read
024 * only, no wait on read
025 * If open error, stop, sending a
026 * message back to the originating
027 * process.
028 fd=%open(PIPE, O$RDONLY+O$NDELAY)
029 if fd<0 then
030     stop 1,"Cannot open '":PIPE:"'. Error ":system(0)
031 end
032 *
033 * Do not allow BREAK from now on
034 break off
035 *
036 * Create the temporary file which
037 * contains our pid, so that
038 * everybody on the system will
039 * know the server id
040 mypid=%pgetpid(-1)
041 execute "!echo ":mypid:" > /tmp/pserverid"
042 *
043 * Reprogram the alarm handler,
044 * keeping the previous system handler
045 * Note the function pointer returned
046 * by the function is treated as
047 * a pointer to a character.
048 old$usr1 = (char*)%setusr1()
049 *
050 * Go try read the pipe. If there is no
051 * message, the signal we received
052 * was not an application one. May be
053 * somebody tried to log us off
054 * so close the pipe, restore the
055 * signal and wait a bit. If we come
056 * come back, was a false alarm. Restart.
057 loop while 1 do
058     * Wait for a signal
059     %pause()
060     *
061     * Read the pipe
062     n=%read(fd, buffer, BUFSIZE )
063     *
064     begin case
065         case n=-1
066              * IO error
067              gosub terminate
068              stop 1,"PSERVER: IO error ":system(0)
069         case n=0
070              * Pipe is empty...
071              * The signals we got is not
072              * the one we expected. Enable
073              * break to allow for a
074              * possible
075              * logoff, and restart
076              gosub terminate
077              sleep 1
078              goto restart
079         case 1
080              * Got something (n is the
081              * number of byte)
082              * The 1st byte is a code,
083              * the second a new line
084              * (discarded)
085              code=buffer[1,1]
086              message=buffer[3,n-2]
087              * Go handle the message
088              gosub do$it
089     end case
090 repeat
091 *
092 do$it:*
093 begin case
094     case code='T'
095          * Terminate
096          gosub terminate
097          stop 1,"PSERVER: Terminated"
098     case code='M'
099          * Message.
100          execute "msg * PSERVER: ":message
101     case code='R'
102          * Receive a file. The message is
103          * full filename (NL) item (NL)
104          * text
105          convert NL to AM in message
106          filename=message<1>
107          item=message<2>
108          message=delete(message,1)
109          message=delete(message,1)
110          open filename then
111              write message on item
112              close
113          end else
114              execute "msg !0 PSERVER: '":filename:"' is not filename"
115          end
116 end case
117 *
118 return
119 *
120 * Clean everything
121 terminate:*
122    %close(fd)
123    %signal( SIGUSR1, (char*)old$usr1 )
124    execute '!rm -f /tmp/pserverid'
125    break on
126 return
127 *
128  end


-  Create a communication pipe by doing the following from TCL:

su   (must be superuser to do the following )
mknod  /dev/mypipe  p  
chmod  0666  /dev/mypipe
exit  (Get back to TCL)

-  Compile and catalog the FlashBASIC program, compile the C program and add it to the built in function list by:

addbi  setusr1
cc  -c  setusr1.c
ar  vru  libgmu.a  setusr1.o

To be able to use the customized monitor with a phantom process, it is necessary to shutdown and to move the customized monitor to the common directory  /usr/bin while being in single user mode.

shutdown
make  -f  /usr/lib/pick/Makefile
init  s (wait for the system to effectively go to single user)
mv  /usr/bin/ap  /usr/bin/ap.save
mv  ./ap  /usr/bin
init  2  (go back to multiuser)

Restart the Pick virtual machine.

-  Create the phantom task server:

z  pserver

-  The server is now waiting for a signal to read the message. Normally, this would be done by another process (Pick or Unix), but, just to test this, the following shell script allows sending messages, small Unix files or terminate the server:

snd:

# Send a command to pserver through a pipe
PIPE=/dev/mypipe             # the communication pipe
SERVERID=/tmp/pserverid      # where the server puts its PID
COMMAND=$1

# Make sure the Pick server is active
if [ ! -r $SERVERID ]
then
   echo Pick server is not active
   exit 1
fi
# Get the server pid
PSERVERID=`cat $SERVERID`

# Send it a signal 0 to test its existence
kill -0 $PSERVERID
if [  $? != 0 ]
then
   echo Pick server is not active. PID is not valid.
   exit 1
fi

# Parse command
case $COMMAND in
   "r"|"R")
       # Receive a file : snd r unix.file
       # pick.file item
       echo "R\n$3\n$4\n~`cat $2~`" > $PIPE
       ;;
   "m"|"M")
       # Send a message: snd m <text>
       shift
       echo "M\n$*" > $PIPE
       ;;
   "t"|"T")
       # Terminate
       echo "T\n" > $PIPE
       ;;
   *)
       echo "usage: snd r unix.file pick.file item"
       echo "       snd m message"
       echo "       snd t"
       ;;
esac

# Wake up the server by sending SIGUSR1
# -30 for AIX; -16 for SCO, DG
kill -30 $PSERVERID

-  Test the server by the following commands (from Shell):

snd  m  Hi there  

This command should send a Pick message to all Pick users.

snd  r  /etc/inittab  dm,pointer-file,  inittab  

This command should send the Unix file  /etc/inittab into the Pick item  dm,pointer-file,  inittab .

snd  t

This command should terminate the server process.
Options
See Also
Example
Warnings
Compatibility D3/Unix
Monitor Debugger Index Level addbi (D3/Unix)