Subject: Spawn and binary pipe read hangs in B19
From: [email-masked] (Craig Setera)

23 Jun 1998 02:21:08 -0700
Message-ID: <5010400024261593000002L032*.cygnus.gnu-win32@MHS>
Mime-Version: 1.0
Content-Type: text/plain
To: <[email-masked]>

Can anyone look at the attached code and tell me what if anything I'm
doing wrong.  This is a small (in comparison to the real code) testcase
that seems to point to a bug in B19.  If compiled to use fork/exec for
the child process creation, both processes will run to completion as
expected.  If, on the other hand, spawn() is used, the child process hangs
on the first pipe read and neither process is able to complete.  This can
be tested by compiling the code with the variable "childCreateMode" set
to either FORK_PROCESS or SPAWN_PROCESS and then running
"caller.exe".  I'm running with B19 on NT (Sergey's May build I believe).

Any help would be greatly appreciated.

Thanks,
Craig

===================== Begin common.c ==========================

#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

#define FALSE 0
#define TRUE 1

static unsigned char buffer[1024];

void
printBytes(FILE *fp, char *leader, char *data, int size)
{
  int i;
  char ascii[128];
  char buffer[128];
  char aByte;

  ascii[0] = '\0';
  fprintf(fp, "%s: ", leader);

  for (i = 0; i < size; i++) {
    aByte = (char) data[i];
    fprintf(fp, "%02X ", aByte);
    if (isprint(aByte)) {
      sprintf(buffer, "%c", aByte);
      strcat(ascii, buffer);
    } else {
      strcat(ascii, ".");
    }

    if (!((i + 1) % 16)) {
      fprintf(fp, "  %s\n", ascii);
      fflush(fp);
      fprintf(fp, "%s: ", leader);
      ascii[0] = '\0';
    }
  }

  if (strlen(ascii) > 0) {
    for (i = 0; i < (16 - strlen(ascii)); i++) {
      fprintf(fp, "   ");
    }
    fprintf(fp, "  %s\n", ascii);
    fflush(fp);
  }
}

int
writeBytes(int fd, int counter, FILE *logFile)
{
  int count = (counter * 10) + 1;
  int bytes;
  unsigned char *buf = buffer;
  int i = 0;

  for (i = 0; i < count; i++)
    buffer[i] = (unsigned char) ((i + 1) % 255);
  buffer[count - 1] = '\0';

  fprintf(logFile, "Entering writeBytes... attempting to write %d bytes\n",
count);
  printBytes(logFile, "\twriteBytes: ", buffer, count);

  while (count > 0)
    {
      do {
 bytes = write(fd, (char*) buf, count);
 fprintf(logFile, "\tWrote %d bytes\n", bytes);
 fflush(logFile);
      } while ((bytes == -1) && ((errno == EAGAIN) || (errno == EINTR)));

      if (bytes == -1)
 {
   fprintf(logFile, "\tWrite error\n");
   fflush(logFile);
   return FALSE;
 }

      count -= bytes;
      buf += bytes;
    }

  fprintf(logFile, "Leaving writeBytes\n");
  fflush(logFile);
}

int
readBytes(int fd, int counter, FILE *logFile)
{
  int bytes;
  int count = (counter * 10) + 1;
  int totalCount = count;
  unsigned char *buf = buffer;

  fprintf(logFile, "Entering readBytes... attempting to read %d bytes\n",
count);
  fflush(logFile);

  while (count > 0)
    {
      do {
 bytes = read(fd, (char*) buf, count);
 fprintf(logFile, "\tRead %d bytes\n", bytes);
 fflush(logFile);
      } while ((bytes == -1) && ((errno == EAGAIN) || (errno == EINTR)));

      if (bytes == -1)
 {
   fprintf(logFile, "\tError reading\n");
   fflush(logFile);
   return FALSE;
 }

      if (bytes == 0)
 {
   fprintf(logFile, "\tUnexpected EOF\n");
   fflush(logFile);
   return FALSE;
 }

      count -= bytes;
      buf += bytes;
    }

  printBytes(logFile, "\treadBytes: ", buffer, totalCount);
  fprintf(logFile, "Leaving readBytes\n");
  fflush(logFile);
}

========================== Begin caller.c =======================

#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define PIPE_READ   0
#define PIPE_WRITE  1

#define P_WAIT     0
#define P_NOWAIT    1

#define O_TEXT  0x0100 /* text file */
#define _O_TEXT  0x0100 /* text file */
#define O_BINARY 0x0200 /* binary file */
#define _O_BINARY 0x0200 /* binary file */

#define SPAWN_PROCESS 0
#define FORK_PROCESS 1

int my_read, my_write;
int his_read, his_write;
int pid;
FILE *logFile;

/**
 * Start the process by using fork/exec
 */
int
fork_callee(char *args[])
{
  pid = fork();

  if (pid == 0)
    {
      close(my_read);
      close(my_write);

      /* Execute the filter. The "_exit" call should never
       *  be reached, unless some strange error condition
       *  exists.
       */
      execvp(args[0], args);
      _exit(1);
    }
}

/**
 * Start the process by using spawn
 */
int
spawn_callee(char *args[])
{
  pid = spawnv(P_NOWAIT, args[0], args);
  return pid;
}

int
main(int argc, char *argv[])
{
  int i;
  int pid;
  int pipe1[2];
  int pipe2[2];
  char *args[4];
  int childCreateMode = FORK_PROCESS;

  logFile = fopen("caller.log", "wt");

  /*
   * Open two pipes. (Bidirectional communication).
   */
  fprintf(logFile, "Opening pipes\n");
  fflush(logFile);
  if ((pipe(pipe1) == -1) || (pipe(pipe2) == -1))
    {
      fprintf(logFile, "error opening pipes\n");
      fflush(logFile);
      return 0;
    }

  my_read = pipe1[PIPE_READ];
  my_write = pipe2[PIPE_WRITE];
  his_read = pipe2[PIPE_READ];
  his_write = pipe1[PIPE_WRITE];

  /* Set to binary mode */
  setmode(my_read, _O_BINARY);
  setmode(my_write, _O_BINARY);
  setmode(his_read, _O_BINARY);
  setmode(his_write, _O_BINARY);

  /**
   * Build the arguments for calling
   */
  for (i = 0; i < 3; i++)
    args[i] = (char *) malloc(50);

  strcpy(args[0], "callee.exe");
  sprintf(args[1], "%d", his_read);
  sprintf(args[2], "%d", his_write);
  args[3] = NULL;

  fprintf(logFile, "Starting child process\n");
  fflush(logFile);

  ///////////////////////////////////////////
  // This is the switch that leads to the
  // problem!!!
  ///////////////////////////////////////////
  if (childCreateMode == SPAWN_PROCESS)
    spawn_callee(args);
  else
    fork_callee(args);

  if (pid == -1)
    {
      fprintf(logFile, "unable to run child process\n");
      fflush(logFile);
      return 0;
    }

  close(his_read);  his_read  = -1;
  close(his_write); his_write = -1;

  for (i = 1; i < 100; i++) {
    writeBytes(my_write, i, logFile);
    readBytes(my_read, i, logFile);
  }

  fclose(logFile);

  return 0;
}

============================= Begin callee.c ======================

#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>

int _readfd = 0;
int _writefd = 0;

static unsigned char buffer[1024];

static FILE *logFile;

int
main (int argc, char *argv[])
{
  int i;

  logFile = fopen("callee.log", "wt");

  fprintf(logFile, "Getting file descriptors\n");
  fflush(logFile);

  _readfd = atoi(argv[1]);
  _writefd = atoi(argv[2]);

  fprintf(logFile, "Got file descriptors\n");
  fprintf(logFile, "readfd = %d\n", _readfd);
  fprintf(logFile, "writefd = %d\n", _writefd);
  fflush(logFile);

  for (i = 1; i < 100; i++) {
    readBytes(_readfd, i, logFile);
    writeBytes(_writefd, i, logFile);
  }

  fclose(logFile);

  return 0;
}

====================== Begin build commands =============
gcc -c common.c
gcc -c caller.c
gcc -c callee.c
gcc -o caller.exe caller.o common.o
gcc -o callee.exe callee.o common.o

Craig Setera
AS/400 Enterprise Java Development
IBM Rochester
[email-masked]
(507) 253-3387 - Tie: 553-3387
-
For help on using this list (especially unsubscribing), send a message to
"[email-masked]" with one line of text: "help".