lkml.org 
[lkml]   [1996]   [Mar]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectExit signal received with output pending
The program below demonstrates what I believe is a Linux bug.  It
starts a child process and starts reading the child's standard output.
It exits when it receives a SIGCHLD signal indicating that the child
has exited. It seems to me that this signal should not be received
until end of file is received on the child's standard output.
--
David Fox http://found.cs.nyu.edu/fox xoF divaD
NYU Media Research Lab baL hcraeseR aideM UYN

----------------- Cut Here ---------------------
// procbug.c - demonstrate a Linux kernel bug?
// David Fox, NYU Media Research Lab, 9 Mar 1996.
//
// Run the following program with arguments like
//
// % ./procbug "/bin/sh" "-c" "yes | cat -n | head -2000"
//
// About half the time I get only 1820 lines of output. How about
// you?

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <minmax.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>

// These macros define which end of the pipes we read from and which
// we write to.

#define READEND 0
#define WRITEEND 1

class ChildProcess {
public:
ChildProcess(const char** argv, int infd=-1, int outfd=-1, int errfd=-1);
~ChildProcess();

// Input(), output(), and error() return the file descriptors through
// which you can communicate with the process. Getpid() returns the
// child's process id.

int input() {return infd_;}
int output() {return outfd_;}
int error() {return errfd_;}
int getpid() {return pid_;}
private:
void Init(const char* path, const char** argv,
int infd, int outfd, int errfd);

int infd_;
int outfd_;
int errfd_;
int pid_;
};

inline void doclose(int fd)
{
if (close(fd) == -1) {
perror("close");
exit(1);
}
}

inline void dodup(int fd1, int fd2)
{
if (fd1 != fd2) {if (dup2(fd1, fd2) == -1) {perror("dup"); exit(1);}}
}

ChildProcess::ChildProcess(const char** argv, int infd, int outfd, int errfd)
{
infd_ = infd; outfd_ = outfd; errfd_ = errfd;

int pfdin[2];
int pfdout[2];
int pfderr[2];

// Thank God I never have to write this again!

if (infd_ == -1) {if (pipe(pfdin) == -1) {perror("pipe"); exit(1);}}
if (outfd_ == -1) {if (pipe(pfdout) == -1) {perror("pipe"); exit(1);}}
if (errfd_ == -1) {if (pipe(pfderr) == -1) {perror("pipe"); exit(1);}}

switch (pid_ = fork()) {
case -1:
perror("fork");
exit(1);
case 0:

// This section is executed by the child process. We close the
// three standard file descriptors and dup the child end of the
// three pipes so the child process standard descriptors and the
// pipes are the same file.

dodup(infd_ == -1 ? pfdin[READEND] : infd_, STDIN_FILENO);
dodup(outfd_ == -1 ? pfdout[WRITEEND] : outfd_, STDOUT_FILENO);
dodup(errfd_ == -1 ? pfderr[WRITEEND] : errfd_, STDERR_FILENO);

// Here we close all the pipe descriptors, either because they
// are the parent end of the pipe or because we have duped them
// above as file descriptors 0, 1, and 2.

if (infd_ == -1) {doclose(pfdin[WRITEEND]); doclose(pfdin[READEND]);}
else if (infd_ != 0) {doclose(infd_);}

if (outfd_ == -1) {doclose(pfdout[READEND]); doclose(pfdout[WRITEEND]);}
else if (outfd_ != 1) {doclose(outfd_);}

if (errfd_ == -1){doclose(pfderr[READEND]); doclose(pfderr[WRITEEND]);}
else if (errfd_ != 2) {doclose(errfd_);}

// Launch the child program.

execvp(argv[0], (char**)argv);
perror("execvp"); // Not reached.
exit(1);
}

// This section is executed by the parent process.

// Close the child end of each pipe. If we opened a pipe for this
// fd then assign the parent's fd. If an fd was supplied no pipe
// was opened so no fd is available for the parent, set it to -1.

if (infd_ == -1) {doclose(pfdin[READEND]); infd_ = pfdin[WRITEEND];}
else infd_ = -1;
if (outfd_ == -1) {doclose(pfdout[WRITEEND]); outfd_ = pfdout[READEND];}
else outfd_ = -1;
if (errfd_ == -1) {doclose(pfderr[WRITEEND]); errfd_ = pfderr[READEND];}
else errfd_ = -1;
}

ChildProcess::~ChildProcess()
{
close(infd_);
close(outfd_);
close(errfd_);
::wait(0);
}

void sigchld_handler(int signo)
{
//printf("sigchld_handler\n");
int status;
int pid = wait(&status);
if (WIFEXITED(status)) exit(0);
}

main(int ac, char *av[])
{
char buf[512];

if (av[ac] != 0) {
fprintf(stderr, "Sorry, av[%d] is not NULL, I thought it would be.\n", ac);
exit(1);
}

ChildProcess p((const char **)&av[1]);

signal(SIGCHLD, sigchld_handler);

fd_set readfds;
FD_ZERO(&readfds);
FD_SET(p.output(), &readfds);
FD_SET(p.error(), &readfds);
while (1) {
int count = 0;
select(getdtablesize(), &readfds, 0, 0, 0);
if (FD_ISSET(p.output(), &readfds)) {
count = read(p.output(), buf, 512);
if (count) write(STDOUT_FILENO, buf, count);
else exit(0);
}
if (FD_ISSET(p.error(), &readfds)) {
count = read(p.error(), buf, 512);
if (count) write(STDERR_FILENO, buf, count);
else exit(0);
}
}
}


\
 
 \ /
  Last update: 2005-03-22 13:36    [W:0.035 / U:2.576 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site