Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 27 Feb 2001 16:26:23 -0500 (EST)
From:      Peter Dufault <dufault@hda.hda.com>
To:        Marc W <mwlist@lanfear.com>
Cc:        freebsd-hackers@FreeBSD.ORG
Subject:   Re: Where can I find out rules on blocking in threads?
Message-ID:  <200102272126.f1RLQNH24622@hda.hda.com>
In-Reply-To: <200102272051.MAA42206@akira.lanfear.com> from Marc W at "Feb 27, 2001 12:51:11 pm"

next in thread | previous in thread | raw e-mail | index | archive | help
>     it gets worse -- when i change my loop to be:
> 
>     while (1) {
> 
>             fifo = open(fifoPath, O_RDONLY | O_NONBLOCK);
>             cread = read(fifo, buf, sizeof(buf));
>             if (cread > 0) do_something();
>             close(fifo);
>             usleep(100000);
>     }
> 
>     anybody who tries to open the write end of the fifo ends up hanging
> ..

It's a little messier than I hoped.  As long as no one has opened the
FIFO for write read returns a zero with errno clear.  If you don't have
time slicing turned on for the threads you'll hang forever.

You'll have to do something like this:

#include <unistd.h>

#include <sys/stat.h>
#include <sys/types.h>

#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>

struct threadstuff {
	int rfid, wfid;
	const char *name;
};

static void *
reader(void *arg) {
	int flags;
	ssize_t r;
	char buff[32];
	int cr;

	struct threadstuff *pts = (struct threadstuff *)arg;

	fprintf(stderr, "Opening %s for read, non-blocking...\n", pts->name);

	pts->rfid = open(pts->name, O_RDONLY | O_NONBLOCK);

	fprintf(stderr, "reader got fid %d, setting to blocking...\n", pts->rfid);

	(void)fcntl(pts->rfid, F_GETFL, &flags);
	flags &= ~O_NONBLOCK;
	(void)fcntl(pts->rfid, F_SETFL, &flags);

	fprintf(stderr, "Trying to read something from the FIFO...\n");

	cr = 0;

	/*
	 * You better have round robin turned on here or be sure
	 * the writer is of higher priority or you'll just buzz
	 * away the CPU.
	 */

	do {
		errno = 0;
		r = read(pts->rfid, buff, sizeof(buff) - 1);

		if (errno == 0 && r == 0) {
			/* No one has the FIFO open for write.
			 * You should delay here (or preferably synchronize) 
			 * to avoid busy waiting.
			 */
			cr++;
			fprintf(stderr, "%s(%3d) No writer yet.\r",
				((cr % 5) == 1) ? "\n" : "", cr);
		}
	} while (r == 0);

	if (r < 0) {
		perror("Read of FIFO");
	} else {
		buff[r] = 0;
		fprintf(stderr, "Read \"%s\".\n", buff);
	}

	return 0;
}

static void *
writer(void *arg) {
	char something[] = "Something";

	struct threadstuff *pts = (struct threadstuff *)arg;

	fprintf(stderr, "Opening %s for write\n", pts->name);

	pts->wfid = open(pts->name, O_WRONLY);

	fprintf(stderr, "writer got fid %d.\n", pts->wfid);

	write(pts->wfid, something, sizeof(something));

	return 0;
}

int
main(int ac, char *av[]) {
	pthread_t r, w;
	void *value;

	struct threadstuff ts;

	ts.name =  "./my_fifo";
	ts.rfid = ts.wfid = -1;

	(void)unlink(ts.name);
	(void)mkfifo(ts.name, 0666);

	pthread_create(&r, 0, reader, (void *)&ts);
	pthread_create(&w, 0, writer, (void *)&ts);

	pthread_join(r, &value);
	pthread_join(w, &value);

	if (ts.rfid != -1)
		(void)close(ts.rfid);

	if (ts.wfid != -1)
		(void)close(ts.wfid);

	return 0;
}

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200102272126.f1RLQNH24622>