I'm practicing C code with pipe system call, it works well with small chunks of data. but as the data goes beyond the pipe capacity, dead lock occurs.
My test system is Debian Sid, but i believe it share the common ground with other Linux distributions. This piece of code works well while the input file '/tmp/a.out' is small enough to fit within the pipe, but blocked as the file is up to 1M.
#include <sys/errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdio.h>
#define CHUNK 2048
int main() {
int fd=open("/tmp/a.out",O_RDONLY);
int pin[2];
int pout[2];
int nread;
char buff[CHUNK];
pipe(pin);
pipe(pout);
int rc;
pid_t pid=fork();
if (pid == 0) {
close(pin[1]);
dup2(pin[0],STDIN_FILENO);
close(pout[0]);
dup2(pout[1],STDOUT_FILENO);
execlp("cat","cat",(char *)0);
} else if (pid > 0) {
close(pin[0]);
close(pout[1]);
/* I think dead lock occurs here, but i can't figure out a way to avoid it */
while ( (nread=read(fd,buff,CHUNK)) > 0) write(pin[1],buff,nread);
close(pin[1]);
while ( (nread=read(pout[0],buff,CHUNK)) >0) write(STDOUT_FILENO,buff,nread);
waitpid(pid,&rc,0);
exit(rc);
} else {
perror("fork");
exit(errno);
}
}
Any suggestions? I know Python's subprocess class have something like subprocess.communicate() to avoid this kind of dead lock, but i don't know how to deal with it in C.
Many thanks.
The first process pipes into cat and cat pipes back into the first process. Hence, for cat to not block on piping back, the first process must also drain that pipe. E.g.:
fcntl(pout[0], F_SETFL, fcntl(pout[0], F_GETFL) | O_NONBLOCK);
while((nread=read(fd, buff, CHUNK)) > 0) {
write(pin[1], buff, nread); // TODO: check errors and partial writes here.
while((nread=read(pout[0],buff,CHUNK)) > 0) // pout[0] must be set into non-blocking mode.
write(STDOUT_FILENO, buff, nread);
}
A more robust way is to set both pin[1] and pout[0] into non-blocking mode, use select to determine whether pin[1] is ready for write and pout[0] for read and then do write/read correspondingly and handle partial reads and writes.
From your suggestions at least I have 2 ways to solve this problem
1. Setting 'NON-BLOCK' mode by 'fcntl' or 'select/poll/epoll'
Use concurrency such as 'pthread' for stdin pipe
piece of code attached.
struct data {
int from_fd;
int to_fd;
};
and code for pipes should look like
pthread_t t;
struct data d;
d.from_fd=fd;
d.to_fd=pin[1];
pthread_create(&t,NULL,&fd_to_pipe,(void*) &d);
while ( (nread=read(pout[0],buff,CHUNK)) >0) write(STDOUT_FILENO,buff,nread);
waitpid(pid,&rc,0);
pthread_join(t,NULL);
Thank you !
Related
In Linux (running on ARM) there is one process that has an open fd to /dev/watchdog/ and is sending an ioctl() each few seconds as a keep alive:
while (1) {
ioctl(fd, WDIOC_KEEPALIVE, 0);
sleep(10);
}
I want to send the keep alive from another process too, but I can't open another fd to /dev/watchdog/: when I tried to echo to /dev/watchdog/ I get the error "Device or resource busy".
Where I can see that the watchdog is defined to work only with 1 process at a time? (I saw in another Linux that some processes can open fd to /dev/watchdog/).
What can I do to feed the watchdog from 2 processes?
Due to the implementation of /dev/watchdog in the kernel, only one process can use it at the same time, so opening /dev/watchdog from two different processes is not possible.
You can see this right in the source code of the Linux kernel, specifically in drivers/watchdog/watchdog_dev.c. Here's the relevant snippet of code:
/*
* watchdog_open: open the /dev/watchdog* devices.
* #inode: inode of device
* #file: file handle to device
*
* When the /dev/watchdog* device gets opened, we start the watchdog.
* Watch out: the /dev/watchdog device is single open, so we make sure
* it can only be opened once.
*/
static int watchdog_open(struct inode *inode, struct file *file)
{
/* ... */
/* the watchdog is single open! */
if (test_and_set_bit(_WDOG_DEV_OPEN, &wd_data->status))
return -EBUSY;
/* ... */
If you want to feed the watchdog from two different processes, you can work around this issue by creating a simple "master" program that talks to the watchdog while orchestrating the two subprocesses as you wish. This can be done in different ways (pipes, sockets, threads, etc). A single popen() per child process seems like a simple solution.
Here's a working example, master.c:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/watchdog.h>
int main(int argc, char **argv) {
int watchdog_fd;
FILE *child1_fp, *child2_fp;
if (argc != 3 || !argv[1] || !*argv[1] || !argv[2] || !*argv[2]) {
fprintf(stderr, "Usage: %s 'CHILD_1_COMMAND' 'CHILD_2_COMMAND'\n", argv[0]);
return 1;
}
// Open a fd to talk to the watchdog.
watchdog_fd = open("/dev/watchdog", O_RDWR);
if (watchdog_fd == -1) {
perror("open failed");
return 1;
}
// Start the first process.
child1_fp = popen(argv[1], "r");
if (child1_fp == NULL) {
perror("popen (1) failed");
return 1;
}
// Start the second process.
child2_fp = popen(argv[2], "r");
if (child2_fp == NULL) {
perror("popen (2) failed");
return 1;
}
while (1) {
char tmp;
size_t count;
// Get one byte of data from each of the two processes.
count = fread(&tmp, 1, 1, child1_fp);
count += fread(&tmp, 1, 1, child2_fp);
// If both processes provided the data, ping the watchdog.
if (count == 2) {
if (ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0) < 0)
perror("ioctl failed");
}
}
return 0;
}
And two identical programs a.c and b.c just for testing purposes:
#include <stdio.h>
#include <unistd.h>
int main(void) {
setvbuf(stdout, NULL, _IONBF, 0);
while (1) {
putchar('x');
sleep(10);
}
}
Compile and run:
$ gcc -o master master.c
$ gcc -o a a.c
$ gcc -o b b.c
$ ./master ./a ./b
In the above example code, master pings the watchdog if and only if the two children are alive and running: if one of the two hangs or dies, the master will stop pinging the watchdog. However, it's simple to rework the logic to work differently, and it's also simple to make it work with more than two child processes.
I am attempting to implement a basic communication between two processes. I intend for each process to receive a piece of information then transmit one back. I am new to pipes so have attempted this using this code example:
How to send a simple string between two programs using pipes?
I set up the code and it works fine, I then duplicated the code for a second pipe in order to receive another integer. However my second pipe does not transmit the integer, the program receives a 0 instead.
program1.c:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define MAX_BUF 1024
int main()
{
int fd; // file descriptor
int fd_b;
int data = 5;
int buf; // buffer from fifo
char * fifo_one = "/tmp/fifo_one";
char * fifo_two = "/tmp/fifo_two";
// create fifo
mkfifo(fifo_one, 0666);
// write to FIFO
fd = open(fifo_one, O_WRONLY);
write(fd, &data, sizeof(&data));
close(fd);
// remove FIFO
unlink(fifo_one);
// receive from FIFO
fd_b = open(fifo_two, O_RDONLY);
read(fd_b, &buf, MAX_BUF);
printf("Received: %d\n", buf);
close(fd_b);
return 0;
}
program2.c:
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#define MAX_BUF 1024
int main()
{
int fd; // file descriptor
int fd_b;
char * fifo_one = "/tmp/fifo_one";
char * fifo_two = "/tmp/fifo_two";
int buf; // buffer from fifo
int ret_dat; // return data
// receive data from fifo
fd = open(fifo_one, O_RDONLY);
read(fd, &buf, MAX_BUF);
printf("Received: %d\n", buf);
close(fd);
// decide return
if (buf == 5) {
ret_dat = 10;
}
// send data back
// create fifo
mkfifo(fifo_two, 0666);
// write to FIFO
fd_b = open(fifo_two, O_WRONLY);
write(fd_b, &ret_dat, sizeof(&ret_dat));
close(fd_b);
// remove FIFO
unlink(fifo_sendBal);
return 0;
}
The second program receives the 5, but does not send back 10 successfully,
I understand that timings effect IPC so I have tried using sleep after certain events but I cannot get it to work.
The second program receives the 5, but does not send back 10 successfully ? The property of FIFO inter process communication created by calling mkfifo() is that both process should alive to communicate each other. From the manual page of mkfifo
Once you have created a FIFO special file in this way, any process
can open it for reading or writing, in the same way as an ordinary
file. However, it has to be open at both ends simultaneously before
you can proceed to do any input or output operations on it. Opening
a FIFO for reading normally blocks until some other process opens the
same FIFO for writing, and vice versa. See fifo(7) for nonblocking
handling of FIFO special files.
I modified a program from APUE, the program first open a file, then mark the fd as non-blocking, then continue write to the fd until write return -1.
I think since disk I/O is slow, when write buffers in OS is nearly full, the write system call will return -1, and the errno should be EAGAIN or EWOULDBLOCK.
But I ran the program for about several minutes and I repeated running the program serveral times, the write system call didn't returned -1 even once! Why?
Here's the code:
#include "apue.h"
#include <errno.h>
#include <fcntl.h>
char buf[4096];
int
main(void)
{
int nwrite;
int fd = open("a.txt", O_RDWR);
if(fd<0){
printf("fd<0\n");
return 0;
}
int i;
for(i = 0; i<sizeof(buf); i++)
buf[i] = i*2;
set_fl(fd, O_NONBLOCK); /* set nonblocking */
while (1) {
nwrite = write(fd, buf, sizeof(buf));
if (nwrite < 0) {
printf("write returned:%d, errno=%d\n", nwrite, errno);
return 0;
}
}
clr_fl(STDOUT_FILENO, O_NONBLOCK); /* clear nonblocking */
exit(0);
}
The O_NONBLOCK flag is primarily meaningful for file descriptors representing streams (e.g, pipes, sockets, and character devices), where it prevents read and write operations from blocking when there is no data waiting to read, or buffers are too full to write anything more at the moment. It has no effect on file descriptors opened to regular files; disk I/O delays are essentially ignored by the system.
If you want to do asynchronous I/O to files, you may want to take a look at the POSIX AIO interface. Be warned that it's rather hairy and infrequently used, though.
I'm learning to use epoll, and I wrote the following example
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <unistd.h>
int main() {
int epfd;
struct epoll_event ev;
struct epoll_event ret;
char buf[200];
int n,k,t;
epfd = epoll_create(100);
assert(0 ==
fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK)
);
ev.data.fd = 0;
ev.events = EPOLLIN | EPOLLET;
if(epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &ev) != 0)
perror("epoll_ctl");
while((n = epoll_wait(epfd, &ret, 1, -1)) > 0) {
printf("tick!\n");
if(ret.data.fd == 0) {
k=0;
while((t=read(0, buf, 100)) > 0) {
k+=t;
}
if(k == 0) {
close(0);
printf("stdin done\n");
}
}
}
perror("epoll");
return 0;
}
If you try running it in the terminal it won't work properly since fds 0, 1 and 2 all point to same open file, so close(0) won't remove stdin from the epoll set. You can get around this by doing "cat | ./a.out". Dirty trick, I know, but setting up a small example with named pipes or sockets would be more complicated.
Now, everything works and the file is removed from the epoll set, but then the next epoll_wait call blocks permanently since it's on an empty set! So I would need to detect if the epoll file descriptor (epfd) is an empty epoll set.
How can I get around this? (in a general manner, not just calling exit when stdin is done)
Thanks!
Basically, if you're using epoll "correctly", then you should never have a situation of an unexpectedly empty epoll set. You should know when there is more to do or not. Well, or that's the theory at least. Let me review it:
You are using EPOLLET here (which is, imho, the right think in general). It means that the file descriptor 0 is removed from the epoll when it is returned in &ret. At this point you should handle it by reading some amount of data from 0, as you do, but then "re-arming" it by adding again file descriptor 0 into the epoll (unless it was closed of course). For an example of how this is supposed to work, remove the inner loop and just do:
k = read(0, buf, 100);
reading a maximum of 100 bytes. The idea is that if you pipe a file bigger than that, it should go several times through the whole loop. In order to make this work, if k > 0, after you handle the k bytes, you need to call epoll_ctl(..EPOLL_CTL_ADD..) again.
Note an annoying detail: it's possible occasionally that the read() returns 0 bytes without meaning the file or socket is at the end. Check if errno == EAGAIN || errno == EWOULDBLOCK. To detect that case, and then epoll_ctl(..EPOLL_CTL_ADD..) again.
The epoll set will be empty when you've removed everything that was added. As far as I know, you can't introspect the epoll set to find out whether there are any file descriptors present. So, it's up to you to determine when the epoll set becomes empty as outlined in Armin's answer.
Since you haven't explained what you expect from your program, I'll take a guess that you expect it exit when stdin is closed, because doing a close(0) will potentially cause file descriptor 0 to be removed from the epoll set. However, the code as listed is flawed. If you continue to wait on an epoll set that doesn't contain any file descriptors (whether removed automatically or by using EPOLL_CTL_DEL), the epoll_wait will wait forever.
The following code shows this nicely.
#include <errno.h>
#include <stdio.h>
#include <sys/epoll.h>
int main() {
int epfd;
int n;
struct epoll_event ret;
epfd = epoll_create(100);
while((n = epoll_wait(epfd, &ret, 1, -1)) > 0) {
/* Never gets here. */
printf("tick!\n");
}
return 0;
}
The epoll set doesn't contain any file descriptors, so the epoll_wait wait forever. If you happened to have a file connected to stdin in your program and no other file descriptor in your program was connected to stdin, the close(0) would have removed fd 0 from the set, the epoll set becomes empty, and the next epoll_wait waits forever.
In general, you manage file descriptors in the epoll set yourself, not rely on close calls to automatically remove your file descriptor from the set. It's up to you to decide whether to continue waiting on the epoll set after you've done the close(0).
I'd also suggest that you change the structure of your program to epoll_wait after the read. This guarantees that you'll obtain any data that may have arrived on stdin before your first call to epoll_wait.
Also, be careful with code like this:
k=0;
while((t=read(0, buf, 100)) > 0) {
k+=t;
}
if(k == 0) {
close(0);
printf("stdin done\n");
}
If you assume that the read in the loop consecutively returns 100 followed by 0 indicating some data plus an end of file, the close(0) will not be called. The program will loop and wait forever again on epoll_wait. Best to check the result of each read specifically for end-of-file and errors.
In C pseudo-code:
while (1) {
fifo = open("fifo", O_RDONLY | O_NONBLOCK);
fd_set read;
FD_SET(fifo, &read);
select(nfds, &read, NULL, NULL, NULL);
}
The process sleeps as triggered by select() until another process writes into fifo. Afterwards it will always find fifo as a readable file descriptor.
How to avoid this behavior (that is, after fifo has been read once, how to make it be found as unreadable until it gets another write?)
You opened that FIFO as read only (O_RDONLY), whenever there is no writer to the FIFO, the read end will receive an EOF.
Select system call will return on EOF and for every EOF you handle there will be a new EOF. This is the reason for the observed behavior.
To avoid this open that FIFO for both reading and writing (O_RDWR). This ensures that you have at least one writer on the FIFO thus there wont be an EOF and as a result select won't return unless someone writes to that FIFO.
The simple answer is to read until read() returns EWOULDBLOCK (or EAGAIN), or craps out with an error.
What you are saying simply cannot be happening unless the operating system (or runtime) that you are using is buggy. Otherwise you must be doing something wrong. For example, select() is using level-triggered I/O. I'd think that, most likely, you are not draining the socket completely, and so select() always indicates that you have something left in there (this does not happen with edge-triggered event notifications).
Below is a simple example that shows how one should read until the read() returns EWOULDBLOCK in order to avoid leaving descriptor in readable state (I've compiled and tested this on OS X, and there is also mostly no error checking, but you should get the idea):
/*
* FIFO example using select.
*
* $ mkfifo /tmp/fifo
* $ clang -Wall -o test ./test.c
* $ ./test &
* $ echo 'hello' > /tmp/fifo
* $ echo 'hello world' > /tmp/fifo
* $ killall test
*/
#include <sys/types.h>
#include <sys/select.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd;
int n;
fd_set set;
ssize_t bytes;
size_t total_bytes;
char buf[1024];
fd = open("/tmp/fifo", O_RDWR | O_NONBLOCK);
if (fd == -1) {
perror("open");
return EXIT_FAILURE;
}
FD_ZERO(&set);
FD_SET(fd, &set);
for (;;) {
n = select(fd+1, &set, NULL, NULL, NULL);
if (!n)
continue;
if (n == -1) {
perror("select");
return EXIT_FAILURE;
}
if (FD_ISSET(fd, &set)) {
printf("Descriptor %d is ready.\n", fd);
total_bytes = 0;
for (;;) {
bytes = read(fd, buf, sizeof(buf));
if (bytes > 0) {
total_bytes += (size_t)bytes;
} else {
if (errno == EWOULDBLOCK) {
/* Done reading */
printf("done reading (%lu bytes)\n", total_bytes);
break;
} else {
perror("read");
return EXIT_FAILURE;
}
}
}
}
}
return EXIT_SUCCESS;
}
Basically, level-triggered I/O means that you get notified all the time if there is something to read, even though you might have been notified of this before. On a contrary, edge-triggered I/O means that you are getting notified only once every time new data arrives and it doesn't matter whether you read it or not. select() is a level-triggered I/O interface.
Hope it helps. Good Luck!