File:  [Atari MiNT] / MiNT / doc / fifo.doc
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:56:11 2018 UTC (8 years, 1 month ago) by root
Branches: mint, MAIN
CVS tags: mint096, HEAD
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;

}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.