If the z/OS® UNIX XL C/C++ application
program you are developing requires its active processes to communicate
with other processes that are active but may not be from the same
program, code your application program to create a named pipe (FIFO file).
Named pipes allow transfer of data between processes in a FIFO manner
and synchronization of process execution. Use of a named pipe allows
processes to communicate even though they do not know what processes
are on the other end of the pipe. Named pipes differ from standard
unnamed pipes, created using the pipe() function,
in that they involve the creation of a real file that is available
for I/O operations to properly authorized processes.
Within the application program, you create a named pipe by coding
a mkfifo() or mknod() function.
You give the FIFO a name and an access mode when you create it. If
the access mode allows all users read and write access to the named
pipe, any process that knows its name can use it to send or receive
data.
Processes can use the open() function
to access named pipes and then use the regular I/O functions for files,
such as read(), write(), and close(), when
manipulating named pipes. Buffered I/O functions can also be used
to access and manipulate named pipes. For more information on the mkfifo() and mknod() functions
and the file I/O functions, see z/OS XL C/C++ Runtime Library Reference.
Restriction: If fopen() is used to open
named pipes in a multi-threaded environment, a deadlock will occur.
This deadlock is caused by a named pipe waiting for the other end
of the pipe to be opened, while still holding the fopen() multi-thread
mutex. To prevent this deadlock, use open() to open
the named pipe, instead of fopen().
z/OS UNIX does
security checks on named pipes.
The following steps outline how to use a named pipe from z/OS UNIX XL C/C++ application
programs:
- Create a named pipe using the mkfifo() function.
Only one of the processes that use the named pipe needs to do this.
- Access the named pipe using the appropriate I/O method.
- Communicate through the pipe with another process using file I/O
functions:
- Write data to the named pipe.
- Read data from the named pipe.
- Close the named pipe.
- If the process created the named pipe and the named pipe is no
longer needed, remove that named pipe using the unlink() function.
A process running the following simple example program creates
a new named pipe with the file pathname pointed to by the path value
coded in the mkfifo() function.
The access mode of the new named pipe is initialized from the mode value
coded in the mkfifo() function.
The file permission bits of the mode argument are modified by the
process file creation mask.
As an example, a process running the program code (CCNGHF2) in
Figure 1 creates a child process and then creates
a named pipe called
fifo.test. The child process
then writes a data string to the pipe file. The parent process reads
from the pipe file and verifies that the data string it reads is the
expected one.
Note: The two processes are related and have agreed
to communicate through the named pipe. They need not be related, however.
Other authorized users can run the same program and participate in
(or interfere with) the process communication.
Figure 1. Named pipes example/* this example shows how named pipes may be used */
#define _OPEN_SYS
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>
/* *
* Sample use of mkfifo() *
* */
main()
{ /* start of program */
int flags, ret_value, c_status;
pid_t pid;
size_t n_elements;
char char_ptr[32];
char str[] = "string for fifo ";
char fifoname[] = "temp.fifo";
FILE *rd_stream,*wr_stream;
if ((mkfifo(fifoname,S_IRWXU)) != 0) {
printf("Unable to create a fifo; errno=%d\n",errno);
exit(1); /* Print error message and return */
}
if ((pid = fork()) < 0) {
perror("fork failed");
exit(2);
}
if (pid == (pid_t)0) { /* CHILD process */
/* issue fopen for write end of the fifo */
wr_stream = fopen(fifoname,"w");
if (wr_stream == (FILE *) NULL) {
printf("In child process\n");
printf("fopen returned a NULL, expected valid stream\n");
exit(100);
}
/* perform a write */
n_elements = fwrite(str,1,strlen(str),wr_stream);
if (n_elements != (size_t) strlen(str)) {
printf("Fwrite returned %d, expected %d\n",
(int)n_elements,strlen(str));
exit(101);
}
exit(0); /* return success to parent */
}
else { /* PARENT process */
/* issue fopen for read */
rd_stream = fopen(fifoname,"r");
if (rd_stream == (FILE *) NULL) {
printf("In parent process\n");
printf("fopen returned a NULL, expected valid pointer\n");
exit(2);
}
|
/* get current flag settings of file */
if ((flags = fcntl(fileno(rd_stream),F_GETFL)) == -1) {
printf("fcntl returned -1 for %s\n",fifoname);
exit(3);
}
/* clear O_NONBLOCK and reset file flags */
flags &= (O_NONBLOCK);
if ((fcntl(fileno(rd_stream),F_SETFL,flags)) == -1) {
printf("\nfcntl returned -1 for %s",fifoname);
exit(4);
}
/* try to read the string */
ret_value = fread(char_ptr,sizeof(char),strlen(str),rd_stream);
if (ret_value != strlen(str)) {
printf("\nFread did not read %d elements as expected ",
strlen(str));
printf("\nret_value is %d ",ret_value);
exit(6);
}
if (strncmp(char_ptr,str,strlen(str))) {
printf("\ncontents of char_ptr are %s ",
char_ptr);
printf("\ncontents of str are %s ",
str);
printf("\nThese should be equal");
exit(7);
}
ret_value = fclose(rd_stream);
if (ret_value != 0) {
printf("\nFclose failed for %s",fifoname);
printf("\nerrno is %d",errno);
exit(8);
}
ret_value = remove(fifoname);
if (ret_value != 0) {
printf("\nremove failed for %s",fifoname);
printf("\nerrno is %d",errno);
exit(9);
}
pid = wait(c_status);
if ((WIFEXITED(c_status) !=0) &&; (WEXITSTATUS(c_status) !=0)) {
printf("\nchild exited with code %d",WEXITSTATUS(c_status));
exit(10);
}
} /* end of else clause */
printf("About to issue exit(0), \
processing completed successfully\n");
exit(0);
}
|