# Synchronizing two D3 processes

On most conventional D3 implementations, synchronizing
two D3 processes is done either through polling for the existence
of a file or, more preferably, by using a FlashBASIC lock instruction.
On most implementations, however, the FlashBASIC lock instruction
itself involves, internally, a polling, thus causing the waiting process
to consume CPU resources. By using signals, it is possible to have
a process waiting for a signal to occur (a Break, log off or a signal
generated by another process, possibly a UNIX process or a D3 process
from another D3 virtual machine) without any CPU consumption.

This example illustrates one phantom task waiting for a signal sent by a user to read a
 message in a pipe where the user has deposited the message. In practice, this
 communication with the message would be better achieved via 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 (D3 and UNIX) by writing a temporary file that contains its process ID, which
 other processes use to send a signal to it.

## Phantom task waiting for a signal in a one-to-one pipe communication example

The signal handler uses SIGUSR1. The message is in ASCII, containing
 a header and some data, and displays as:

```
+---+---+--------//-----------+
| |NL | +
+---+---+--------//-----------+
| | |
| | +- Data (code dependent)
| +---------- New line (discarded)
+-------------- command code
 T : Terminate
 M : Message
 R : file receive
```

## Synchronizing two D3 processes

Steps to synchronize two D3 processes using signals from another virtual machine:

- Enter the c signal handler. For example: ```
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 phantom task code in the item dm,bp, pserver. For example: ```
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 &#39;!rm -f /tmp/pserverid&#39;
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 &#39;":PIPE:"&#39;. 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 knows 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=&#39;T&#39;
095 * Terminate
096 gosub terminate
097 stop 1,"PSERVER: Terminated"
098 case code=&#39;M&#39;
099 * Message.
100 execute "msg * PSERVER: ":message
101 case code=&#39;R&#39;
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: &#39;":filename:"&#39; is not filename"
115 end
116 end case
117 *
118 Enter
119 *
120 * Clean everything
121 terminate:*
122 %close(fd)
123 %signal( SIGUSR1, (char*)old$usr1 )
124 execute &#39;!rm -f /tmp/pserverid&#39;
125 break on
126 Enter
127 *
128 end
```

- Create a named communication pipe from TCL. Enter: Note: You must be a superuser (su) in order to enter the commands below. ```
su
mknod /dev/mypipe p
chmod 0666 /dev/mypipe
exit
``` Exit returns you to TCL.

- Compile and catalog the FlashBASIC program.

- Compile the c program, and then add it to the built-in function list. For example: ```
addbi setusr1
cc -c setusr1.c
ar vru libgmu.a setusr1.o
```

- To use the customized monitor with a phantom process, shut down and move the customized monitor to the common directory /usr/bin while in single-user mode. For example: ```
shutdown
make -f /usr/lib/pick/Makefile
init s
mv /usr/bin/d3 /usr/bin/ap.save
mv ./d3 /usr/bin
init 2
``` Restart the D3 virtual machine.

- Create the phantom task server. Type: ```
z pserver
``` The server now waits for a signal to read the message. Normally, this would be done by another process (D3 UNIX). To test this, the shell script sends messages, small UNIX files, or terminates 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 D3 server is active
if [ ! -r $SERVERID ]
then
 echo D3 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 D3 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
 # D3.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 D3.file item"
 echo " snd m message"
 echo " snd t"
 ;;
esac
# Wake up the server by sending SIGUSR1
# -30 for AIX; -16 for LINUX
kill -30 $PSERVERID
```

- Test the server. Enter from shell: ```
snd m Hi there
```

- Enter from D3 to send a D3 message to all D3 users: ```
snd r /etc/inittab dm,pointer-file, inittab
```

- Enter from UNIX to send the file /etc/inittab into the D3 item dm,pointer-file, inittab. ```
snd t
``` This command terminates the server process.

---
Source: https://d3codex.com/unix/synchronizing-two-d3-processes/ - part of the D3Codex reference.
