|
|
MiNT 0.96 pl14
Using Fifo's:
Fifo's (first-in first-out pipes) are actually very easy to
use. Here are a couple of things to keep in mind:
(1) The server program (the one that's going to be listening
for requests from clients) should create the fifo with
Fcreate(). The file descriptor returned from Fcreate is
the "server" descriptor; descriptors returned by Fopen will
be "client" descriptors. Data written to the server descriptor
can be read by client descriptors, and vice-versa.
(2) Fifos are by default bidirectional. You can create a single
directional fifo by creating the fifo "read only"; in this case,
only the server descriptor can be written to, and only client
descriptors can be read from.
(3) Be careful not to mix data up; if two clients are trying to
read from the same fifo at the same time, they each may read
data intended for the other. The easiest way to avoid this is
by having every client lock the fifo before accessing it,
and unlock the fifo when finished. It's also possible (if you're
careful) to use the fact that all writes of <1024 bytes are atomic
(i.e. take place in one "chunk") to avoid interleaving of data;
but locks are probably safer.
The flags to the Fcreate() system call used to create the fifo can
be used to control the way the fifo works. For most applications,
the flags should probably be 0, i.e. the call should look like
serverfd = Fcreate("U:\\PIPE\\FIFO", 0);
but for some specialized applications it may be useful to use one
or more of the following flags (they may be or'd together:
FA_RDONLY: Make the fifo unidirectional; the server fd will be write
only, and the client fd read only.
FA_HIDDEN: Make reads from the fifo return "end of file" if no other
process has the fifo open for writing. This is normally not desired
for server processes, since the server's read will often occur
when nobody has the fifo open, and should wait until some client
does want to use the fifo.
FA_SYSTEM: Make the fifo a "pseudo-terminal". This type of fifo behaves
just like a terminal, and most of the terminal control Fcntl calls
can operate on it. Also, data can be passed through the fifo in long
words rather than in bytes, if the Fputchar() system call is used.
This allows the server program to pass the extended BIOS information
(such as the shift key status and scan code) to be returned by Bconin()
calls on the client side of the pipe. The 'extra' 3 bytes of the longword
could also be used for other out of band data as well.
FA_CHANGED: Make the fifo return from an Fread() call as soon as any data are
available (just like a terminal). This isn't necessary if the FA_SYSTEM
bit is set (since pseudo-terminals already act like terminals), but is
useful for making ordinary fifo's emulate Unix pipe semantics.
Here is a sample pair of applications. The server program ("fortserv.c")
creates a fifo and listens on it for requests. When it receives a
request, it writes a cute saying (a "fortune cookie") back to the fifo.
The client program ("fortune.c") opens the fifo, writes a request,
reads the response, and prints the result on the terminal. These are
very simple minded applications, but it should give you an idea of
the flavour of how to use fifos for interprocess communication.
-------------------------- fortserv.c -------------------------
/* fortune server: send cookies to clients */
/* illustrates server side use of fifos */
/*
* This program opens a fifo ("U:\PIPE\FORTUNE")
* and listens to requests on that fifo. When it
* gets a request (consisting of a single '?'
* character) it writes back as a reply a 1 byte
* "length" followed by a randomly selected saying.
* BUGS:
* - maximum of 255 characters for a fortune
* - the fortunes aren't particularly interesting
*/
#ifdef __GNUC__
#include <minimal.h>
#endif
#include <osbind.h>
#include <mintbind.h>
#include <string.h>
#define FIFONAME "U:\\PIPE\\FORTUNE"
#define MAXSIZE 255
/* witty (?) sayings */
char * sayings[] = {
"Core fault -- program dumped.",
"Don't worry, be happy!",
"Help! I'm trapped in a fortune cookie factory!",
"\"Home is where you wear-a your hat.\"",
"I want a cookie.",
"MS-DOS: just say \"no\".",
"Never play leapfrog with a unicorn.",
"No matter where you go, there you are.",
"Sorry, I'm out of short, pithy sayings today.\r\nTry again later.",
"They say that playing NetHack is like walking into a death trap.",
"Vision hazy, try again later.",
"What? You expected something funny?",
"Why is it that UFO's always seem to visit idiots?",
"Your puny intellect is no match for our superior weapons.",
};
#define NUMSAYINGS (sizeof(sayings) / sizeof(char *))
/* file descriptor for the fortune fifo */
int fd;
/* send a witty saying out through the fifo */
void
send_saying()
{
int i;
char *s;
char tmpbuf[MAXSIZE+1];
/* pick a saying at random */
i = ((unsigned)Random() >> 1) % NUMSAYINGS;
s = sayings[i];
/* construct the message to send */
i = (int)strlen(s);
tmpbuf[0] = i;
strcpy(tmpbuf+1,s);
/* we really should check for an error */
(void)Fwrite(fd, (long)i+1, tmpbuf);
}
/* main function: create the fifo, then sit around
* listening for requests
*/
int
main(argc, argv, envp)
int argc;
char **argv, **envp;
{
char c;
long r;
fd = Fcreate(FIFONAME, 0);
if (fd < 0) {
Cconws("Couldn't create ");
Cconws(FIFONAME);
Cconws("!\r\n");
Pterm(1);
}
for(;;) {
r = Fread(fd, 1L, &c);
if (r != 1) { /* read error?? */
break;
}
if (c == '?') { /* request for saying */
send_saying();
}
/* could have other requests here */
}
return 0;
}
------------------------ fortune.c ----------------------
/* fortune client: get a fortune cookie from
* the fortune server
*/
/* illustrates client side use of fifos */
#ifdef __GNUC__
#include <minimal.h>
#endif
#include <osbind.h>
#include <mintbind.h>
#define FIFONAME "U:\\PIPE\\FORTUNE"
#define BUFSIZ 256
#define F_SETLKW 7
struct flock {
short l_type; /* type of lock */
#define F_RDLCK 0
#define F_WRLCK 1
#define F_UNLCK 3
short l_whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
long l_start; /* start of locked region */
long l_len; /* length of locked region */
short l_pid; /* pid of locking process
(F_GETLK only) */
};
int
main(argc, argv, envp)
int argc;
char **argv, **envp;
{
int fd;
char buf[BUFSIZ];
unsigned char len;
struct flock lock;
long r;
/* open the fifo */
fd = Fopen(FIFONAME, 2);
if (fd < 0) {
Cconws("Couldn't open ");
Cconws(FIFONAME);
Cconws("!\r\n");
Pterm(1);
}
/* get a lock; this makes sure that two fortune
* programs don't try to send requests and read
* replys at the same time
*/
lock.l_type = F_WRLCK;
/* lock the whole file -- only thing that makes sense
* for a fifo
*/
lock.l_whence = 0;
lock.l_start = lock.l_len = 0L;
r = Fcntl(fd, &lock, F_SETLKW);
if (r != 0) {
Cconws("Couldn't get a lock!\r\n");
Pterm(r);
}
/* write the request */
Fwrite(fd, 1L, "?");
/* wait for a reply */
/* the fortune server writes a 1 byte length, followed by
* the fortune itself
*/
r = Fread(fd, 1L, &len);
if (r != 1L || len != Fread(fd, (long)len, buf)) {
Cconws("Error reading fortune!\r\n");
Pterm(1);
}
buf[len] = 0;
/* unlock the fifo */
lock.l_type = F_UNLCK;
(void) Fcntl(fd, &lock, F_SETLKW);
Fclose(fd);
/* now write the fortune to the screen */
Cconws(buf);
Cconws("\r\n");
return 0;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.