FIFOs / Named pipe

Created:

Updated:

FIFOs / Named pipe

FIFOs(it’s called to named pipe) is one of IPC(inter-process communication) way to send/receive data between processes. Especially, it can be used in diffferent processes which is not related with each other.
mkfifo() makes a FIFO special file which is entered into the filesystem. Once you have created a FIFO special file, any process can open it for reading or writing. One thing to note that it has to be opened at both ends simultaneously because it blocks reading until other processes open the FIFO special file for writing , and the other way around. If you use “O_NONBLOCK” flag when you call open() function, the FIFO works as nonblocking mode. In this case, opening for read-only succeeds even if other end has not opened for writing yet, and opening for write-only fails with ENXIO error unless the other end has already been opened. The FIFO’s permissions are specified by “mode” parameter of mkfifo(). It is modified by the process’s umask. Usually The permissions are (mode & ~umask). You can know default “umask” value by calling umaks() function in source code. O in terminal, run “umask” command.

Source code

fifo_write.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define FIFO_PATH "/tmp/test_fifo"
#define FIFO_WRITE_STRING "fifo write/read test!"

int main(int argc, char *argv[])
{ 
	int fifo_fd = -1;
	int fd = -1;
	int flag = O_WRONLY; 
	
	int default_umask = umask(0);
	printf("default umask = %o\n", default_umask);
	umask(default_umask);

	if (access(FIFO_PATH, F_OK) < 0) {
		fifo_fd = mkfifo(FIFO_PATH, 0777); 
		if (fifo_fd < 0 ) {
			perror("mkfifo error\n");
			exit(0);
		}
	}

	fd = open(FIFO_PATH, flag);
	if (fd < 0 ) {
		perror("fifo open error\n");
		exit(0);
	}

	printf("write data to fifo = %s\n", FIFO_WRITE_STRING);
	write(fd, FIFO_WRITE_STRING, strlen(FIFO_WRITE_STRING) + 1);
	close(fd);

	return 0; 
} 

In the code, “/tmp/test_fifo” is created only when the file does not exist.
umask() is used to see what is the default value of umask. Indeed it is no need to call here. This code opens FIFO special file, and writes FIFO_WRITE_STRING data, then closes the file.

fifo_read.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define FIFO_PATH "/tmp/test_fifo"
#define BUF_SIZE 255 

int main(int argc, char *argv[])
{ 
	int fifo_fd = -1;
	int fd = -1;
	int flag = O_RDONLY; 
	char buf[BUF_SIZE];
	int buf_size = BUF_SIZE;
	int cnt = 0;

	if (access(FIFO_PATH, F_OK) < 0) {
		fifo_fd = mkfifo(FIFO_PATH, 0777);

		if (fifo_fd < 0 ) {
			perror("mkfifo error\n");
			exit(0);
		}
	}

	fd = open(FIFO_PATH, flag);
	if (fd < 0 ) {
		perror("fifo open error\n");
		exit(0);
	}

	do {
		cnt = read(fd, buf, buf_size); 
		if(cnt > 0) {
			printf("read data from fifo: %s\n", buf); 
		}
	} while(cnt > 0);
	close(fd);

	return 0; 
}

This code reads data from FIFO special file repeatedly until the read byte is equal of less then 0.

Result of mkfifo()

1
2
$ ls -alh /tmp/test_fifo 
prwxr-xr-x 1 chuljeon39a chuljeon39a 0 Mar 30 01:41 /tmp/test_fifo

The first character ‘p’ means pipe. In source code, 0777 is used as a parameter of calling mkfifo(), but the permisson of “/tmp/test_file” is 0755. This is because the umask value is 0022, so (0777 & ~(0022)) == 0755

Output of fifo_write(result of fifo_write in terminal 1)

1
2
3
$ ./fifo_write 
default umask = 22
write data to fifo = fifo write/read test!

Output of fifo_read(result of fifo_read in terminal 2)

1
2
$ ./fifo_read 
read data from fifo: fifo write/read test!

Output of fifo_read(result of fifo_write and fifo_read in same terminal)

1
2
3
4
5
6
7
$ ./fifo_write &
[1] 10860
default umask = 22
$ ./fifo_read 
write data to fifo = fifo write/read test!
read data from fifo: fifo write/read test!
[1]+  Done                    ./fifo_write

Here, I run ./fifo_write and ./fifo_write in same terminal to see how it works. ./fifo_write is run first, but “write data to file…” is not printed immediately. This means that it is blocked at open(). And after run ./fifo_read, that string is printed. This means that it is unblocked by calling open() in other process(./fifo_read). Finally, ./fifo_write writes “fifo write/read test!” to FIFO file and ./fifo_read read it.

Leave a comment