|
A FIFO combines features of a file and a pipe. Like a file, it has a name,
and any process with the appropriate permissions may open it for reading
or writing. Unlike with a pipe, then, unrelated processes may
communicate over FIFO, since they need not rely on inheritance to
access it. Once opened, however, a FIFO acts more like a pipe than a file.
Written data is read back in first-in-first-out order, and single write
and read system calls are garanteed to be atomic, provided the amount
read or write doesn't exceed the capacity of the FIFO, which is the
same as the capacity of a pipe (implementation dependent, but at least
4096 bytes). Data once read can't be read again, nor is it possible to
position into FIFO.
Normally, when a FIFO is opened for reading, the open waits until it is also
opened for writing, usually by another process. Similary, an open for
writing blocks until the FIFO is opened for reading. Hence whichever
process, reader or writer, executes the open first will wait for the
other one. This allowes the processes to synchronize themselves before the
actual data transmission starts.
Some statements and functions known from the "File storage" section
will behave different operating on FIFOs.
- ASSIGN
-
ASSIGN statement won't lock a FIFO file (it's intended to be
used concurrently) unless you explicy use the LOCK# or UNLOCK #
statements.
If you close a FIFO file, and you're the last process opened
the FIFO in write mode, an EOF condition (which may be trapped
using and ON END statement) will be raised.
NOTE: ASSIGNing an FIFO file may result in blocking the
program if not executed in the appropritate order
- PRINT #, READ #
-
READ # and WRITE # statements will behave like operating on
a HP-UX sequential file. However any attempt to position into
FIFO file will be ignored.
NOTE: All data in a single PRINT# statement will be cached
in an internal buffer. To flush this buffer just issue
an PRINT# statement with an END keyword.
- SIZE
-
The SIZE function will return the number of bytes in the FIFO file.
You might check this value to avoid blocking due to overflow.
A FIFO must be created using the HP-UX mkfifo command.
COMMAND "!mkfifo FIFO.DATA"
will create the FIFO file FIFO.DATA.
Example unidirectional message passing
To execute the example program, start eloq, ATTACH to secondary task
and run FIFO program. Then DETACH back to foreground and run
FIFO program. After termination ATTACH to secondary task and
inspect the messages.
1000 ! RE-STORE "FIFO,TEST"
1010 ! SAMPLE UNIDIRECTIONAL MESSAGE PASSING
1011 !
1012 ! To execute sample program, start eloq, ATTACH to secondary task
1013 ! and run FIFO program. Then DETACH back to foreground and run
1014 ! FIFO program. After termination ATTACH to secondary task and
1015 ! inspect the messages.
1016 ! With little modification this could also be executed too by
1017 ! different (unrelated) tasks.
1020 !
1030 ! INITIAL ------------------------------------
1040 ! name of fifo file
1050 Fifo$="FIFO,TEST"
1060 ! create fifo, ignore any error
1070 COMMAND "!mkfifo "&MAPFNAME$(Fifo$)&".DATA; exit 0"
1080 ! execute slave part if secondary task
1090 IF OWNID THEN Slave
1100 !
1110 ! MASTER PART --------------------------------
1120 Master:!
1130 ! open fifo
1140 ASSIGN #1 TO Fifo$
1150 ON KEY #1:"SEND" GOSUB Send
1160 ON KEY #8:"EXIT" GOTO Exit
1170 WAIT
1180 Exit:!
1190 ! this will cause an eof on slave side
1200 ASSIGN * TO #1
1210 ! remove fifo file
1220 COMMAND "!rm "&MAPFNAME$(Fifo$)&".DATA"
1230 STOP
1240 Send:!
1250 LDISP "Sending message ..."
1260 ! write to fifo
1270 ! note: this will block if no more space in fifo
1280 ! SIZE may be checked before
1290 PRINT #1;"Ok"
1300 RETURN
1310 !
1320 ! SLAVE PART ---------------------------------
1330 Slave:!
1331 ! DETACH to primary task
1335 DETACH
1340 ! open fifo
1350 ! note: this will block until master side has been opened
1360 ASSIGN #1 TO Fifo$;READONLY
1370 ! catch eof
1380 ON END #1 GOTO Eof
1390 LOOP
1400 LDISP "waiting for message ..."
1410 ! read data from fifo, this will block until data are available
1420 READ #1;A$
1430 LDISP TIME$;":";A$
1440 END LOOP
1450 Eof: LDISP ""
1460 END
Bi-directional pipes
This example program, will pass some data to the HP-UX cat
command and read the output again.
1000 ! RE-STORE "FIFO2,TEST"
1010 ! Bi-directional pipes
1020 DIM A$[256]
1030 Fifo$="FIFO,TEST"
1040 R=1
1050 W=2
1060 !
1070 ! LOAD SUB "COUTIL,TEST"
1080 LDISP "Creating co process ..."
1090 C=CLOCK
1100 CALL Co_create(Fifo$,"cat",#W,#R)
1110 DISP (CLOCK-C)/1000;"Seconds"
1120 !
1130 C=CLOCK
1140 FOR I=1 TO 9
1141 !
1142 ! Send data to connected process
1150 FOR J=1 TO I
1160 A$="I="&VAL$(I)&",J="&VAL$(J)
1170 CALL Co_send(#W,A$)
1180 NEXT J
1181 !
1182 ! Flush buffer to avoid overflow in send
1190 CALL Co_flush(#W)
1210 !
1220 ! now check for anything in receive buffer to prevent blocking
1230 WHILE SIZE(R)
1240 IF NOT FNCo_read(#R,A$) THEN Eof
1250 GOSUB Data
1260 END WHILE
1270 NEXT I
1280 !
1290 ! send eof to connected process
1300 CALL Co_send_eof(#W)
1301 !
1302 ! wait for eof condition
1310 DISP "Waiting for EOF"
1320 WHILE FNCo_read(#R,A$)
1330 GOSUB Data
1340 END WHILE
1350 DISP (CLOCK-C)/1000;"Seconds"
1360 !
1370 Eof:!
1380 CALL Co_delete(Fifo$,#1,#2)
1390 END
1391 !
1392 Data:!
1393 LDISP ">";A$
1394 RETURN
1400 !
1410 ! ------------------------------------------------------------------------
1420 ! SUB ROUTINES
1430 ! ------------------------------------------------------------------------
1431 !
1432 ! ** create co-process and connect to fifos
1440 SUB Co_create(Fifo$,Cmd$,#1,#2)
1450 DIM Fifo_r$[80],Fifo_w$[80]
1460 CALL Fifo_name(Fifo$,Fifo_w$,Fifo_r$)
1470 COMMAND "!mkfifo "&MAPFNAME$(Fifo_w$)&".DATA "&MAPFNAME$(Fifo_r$)&".DATA"&"; exit 0"
1480 ASSIGN #1 TO Fifo_w$
1490 ASSIGN #2 TO Fifo_r$
1500 COMMAND "!"&Cmd$&" <"&MAPFNAME$(Fifo_w$)&".DATA >"&MAPFNAME$(Fifo_r$)&".DATA 2>&1 &"
1510 ASSIGN #2 TO Fifo_r$;READONLY
1520 SUBEND
1530 !
1540 ! ** close and remove fifo files
1550 SUB Co_delete(Fifo$,#1,#2)
1560 DIM Fifo_r$[80],Fifo_w$[80]
1570 CALL Fifo_name(Fifo$,Fifo_w$,Fifo_r$)
1580 COMMAND "!rm -f "&MAPFNAME$(Fifo_w$)&".DATA "&MAPFNAME$(Fifo_r$)&".DATA"
1590 ASSIGN * TO #1
1600 ASSIGN * TO #2
1610 SUBEND
1620 !
1630 ! ** Build r/w fifo filename
1640 SUB Fifo_name(Fifo$,W$,R$)
1650 P=POS(Fifo$,":")
1660 IF NOT P THEN P=POS(Fifo$,",")
1670 IF NOT P THEN P=LEN(Fifo$)+1
1680 R$=Fifo$[1,P-1]&"R"&Fifo$[P]
1690 W$=Fifo$[1,P-1]&"W"&Fifo$[P]
1700 SUBEND
1710 !
1720 ! ** Write data to co-process (into buffer)
1730 SUB Co_send(#1,A$)
1740 PRINT #1;A$
1750 SUBEND
1760 !
1770 ! ** Flush buffers
1780 SUB Co_flush(#1)
1790 PRINT #1;END
1800 SUBEND
1810 !
1820 ! ** Send eof to co-process
1830 SUB Co_send_eof(#1)
1840 ASSIGN * TO #1
1850 SUBEND
1860 !
1870 ! ** Read line from co-process, returns 0 on eof
1880 DEF FNCo_read(#2,A$)
1890 ON END #2 GOTO Eof
1900 READ #2;A$
1910 RETURN 1
1920 Eof:!
1930 RETURN 0
1940 FNEND
Another using Bi-directional pipes
This example program, will pass some data to the HP-UX sort
command and read the output again.
1000 ! RE-STORE "FIFO3,TEST"
1010 DIM A$[256]
1020 Fifo$="FIFO,TEST"
1030 R=1
1040 W=2
1050 !
1060 LOAD SUB "COUTIL,TEST"
1070 LDISP "Creating co process ..."
1080 C=CLOCK
1090 CALL Co_create(Fifo$,"sort",#W,#R)
1100 DISP (CLOCK-C)/1000;"Seconds"
1110 !
1120 LDISP "Sending data ..."
1130 ASSIGN #3 TO "TACPR,FILES"
1140 ON END #3 GOTO Eof_3
1150 C=CLOCK
1160 Cnt=0
1170 LOOP
1180 READ #3;A$
1190 CALL Co_send(#W,A$)
1200 Cnt=Cnt+1
1210 END LOOP
1220 Eof_3:ASSIGN * TO #3
1230 CALL Co_send_eof(#W)
1240 DISP (CLOCK-C)/1000;"Seconds"
1250 DISP "# lines =";Cnt
1260 !
1270 LDISP "Receiving results ..."
1280 C=CLOCK
1290 Cnt=0
1300 WHILE FNCo_read(#R,A$)
1310 ! LDISP A$
1320 Cnt=Cnt+1
1330 END WHILE
1340 DISP (CLOCK-C)/1000;"Seconds"
1350 DISP "# lines =";Cnt
1360 CALL Co_delete(Fifo$,#1,#2)
1370 END
1380 !
|
|