Mailing Lists: Apple Mailing Lists

Image of Mac OS face in stamp
 
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: fork, pipes, and Tiger



pipefd[0] is out and pipefd[1] is in.

You have them backwards, which incorrectly assumes bidirectional pipes.

Either fix your code, or use socketpair() instead of pipe().

See also:

	<http://www.opengroup.org/onlinepubs/009695399/functions/pipe.html>


...
"Data can be written to the file descriptor fildes[1] and read from the
file descriptor fildes[0]. A read on the file descriptor fildes[0] shall
access data written to the file descriptor fildes[1] on a first-in- first-out
basis. It is unspecified whether fildes[0] is also open for writing and
whether fildes[1] is also open for reading."
...


The pipe() implementation in Tiger changed to one that was significantly faster, adopted from the code by John Dyson that's in FreeBSD.

Now broken code no longer works; before pipe() was internally implemented with socketpair(), which is no longer the case (even though we go out of our way to not break some applications which assume you can make some calls on pipes that technically you should only bellowed to make on sockets).

-- Terry

On Dec 22, 2005, at 2:22 PM, Martin Costabel wrote:
I am trying to understand why TeXmacs' shell plugin doesn't work on Tiger. This plugin is a simple binary executable compiled from the C+ + code I am attaching below. It is supposed to run /bin/sh as a child and run its stdin/out through the calling process. This works on OSX 10.3, but not on 10.4. What has changed on Tiger with respect to fork/pipes?

If you compile the attached file tm_shell.cpp simply with

  g++ -o tm_shell tm_shell.cpp

and then run ./tm_shell from the command line, it should just look like a new shell with a different prompt. This is also what happens on Panther. On Tiger, what happens is

% ./tm_shell
verbatim:Shell session inside TeXmacsverbatim:
[1]  + 21241 Suspended (tty input)     ./tm_shell

If I fg the process, it suspends itself immediately again. This is also what happens when one tries to run the shell plugin from within TeXmacs; the whole TeXmacs process gets suspended and has to be forcibly killed.

It doesn't matter where the binary is compiled, on Panther or on Tiger, or with which version of g++. If the identical binary is run on Panther, it works; if it is run on Tiger, it doesn't.

Does anyone see what is wrong with the code or why it wouldn't work on Tiger?

Here is the code:
/ ******************************************************************************
* MODULE : tm_shell.cpp
* DESCRIPTION: TeXmacs shell
* COPYRIGHT : (C) 2000 Joris van der Hoeven
*******************************************************************************
* This software falls under the GNU general public license and comes WITHOUT
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
* If you don't have this file, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/


#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/wait.h>
using namespace std;

typedef char* charp;
extern charp* environ;

#define ERROR (-1)
#define STDIN 0
#define STDOUT 1
#define STDERR 2
#define IN 0
#define OUT 1

#define DATA_BEGIN   ((char) 2)
#define DATA_END     ((char) 5)
#define DATA_ESCAPE  ((char) 27)
//#define DATA_BEGIN   "[BEGIN]"
//#define DATA_END     "[END]"
//#define DATA_ESCAPE  "[ESCAPE]"

int pid; // process identifier of the child
int tochild[2]; // for data going to the child
int fromchild[2]; // for data coming from the child
int in; // file descriptor for data going to the child
int out; // file descriptor for data coming from the child
FILE* fin; // file associated to in


/ ******************************************************************************
* Handling shell input and output
******************************************************************************/


void
append (charp &s, char c, int& pos, int& max) {
  if (pos == max) {
    int i;
    charp r= s;
    max <<= 1;
    s= (charp) malloc (max);
    for (i=0; i<pos; i++) s[i]=r[i];
    free (r);
  }
  s[pos++]= c;
}

void
shell_output (bool hide= false) {
  int output_pos= 0;
  int output_max= 1024;
  charp output= (charp) malloc (output_max);
  cout << DATA_BEGIN << "verbatim:";

  while (true) {
    fd_set rfds;
    FD_ZERO (&rfds);
    FD_SET (out, &rfds);
    int max_fd= out+1;
    struct timeval tv;
    tv.tv_sec  = 0;
    tv.tv_usec = 100;
    int nr= select (max_fd, &rfds, NULL, NULL, &tv);
    if (nr==0) {
      fflush (stdout);
      continue;
    }

    if (FD_ISSET (out, &rfds)) {
      int i, r;
      char outbuf[1024];
      r = read (out, outbuf, 1024);
      if (r == ERROR) {
        cerr << "TeXmacs shell] read failed\n";
        wait (NULL);
        exit (1);
      }
      else if (r == 0) {
        kill (pid, SIGKILL);
        cout << DATA_END;
        fflush (stdout);
        exit (0);
      }
      else for (i=0; i<r; i++) {
        append (output, outbuf[i], output_pos, output_max);
        if (outbuf[i]=='\n') {
          append (output, '\0', output_pos, output_max);
          if (hide) hide= false;
          else cout << output;
          fflush (stdout);
          output_pos= 0;
        }
      }
    }

    if (strncmp (output, "tmshell$ ", 9) == 0)
      break;
  }

  cout << DATA_END;
  fflush (stdout);
  free (output);
}

void
shell_input () {
  char input [10000];
  cin.getline (input, 10000, '\n');
  strcat (input, "\n");
  write (in, input, strlen (input));
  fflush (fin);
}

void
shell_interrupt (int sig) {
  cout << DATA_BEGIN << "scheme:(with \"color\" \"red\" \"";
  cout << "Interrupted TeXmacs shell";
  cout << "\")" << DATA_END;
  cout << DATA_END;
  // kill (pid, SIGINT); // Why does this not work ???
  kill (pid, SIGKILL);
  exit (0);
}

/ ******************************************************************************
* Launching the shell using a fork
******************************************************************************/


volatile void
invoke_shell () {
  charp argv[3];
  argv[0] = "sh";
  argv[1] = "-i";
  argv[2] = 0;
  execve("/bin/sh", argv, environ);
  exit(127);
}

int
main () {
  setenv ("PS1", "tmshell$ ", true);
  cout << DATA_BEGIN << "verbatim:";
  cout << "Shell session inside TeXmacs";
  pipe (tochild);
  pipe (fromchild);
  pid= fork ();
  if (pid==0) { // the child
    dup2 (tochild [IN], STDIN);
    close (tochild [IN]);
    close (fromchild [IN]);
    close (tochild [OUT]);
    dup2 (fromchild [OUT], STDOUT);
    dup2 (STDOUT, STDERR);
    close (fromchild [OUT]);
    invoke_shell ();
    exit (127);
  }
  else { // the main process
    int sig;
    out= fromchild [IN];
    close (fromchild [OUT]);
    in= tochild [OUT];
    close (tochild [IN]);
    fin= fdopen (in, "w");
    signal (SIGINT, shell_interrupt);
    shell_output (true);
    cout << DATA_END;
    while (true) {
      shell_input ();
      shell_output ();
    }
  }
  return 0;
}
/**************************/

--
Martin


_______________________________________________ Do not post admin requests to the list. They will be ignored. Unix-porting mailing list (email@hidden) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/unix-porting/email@hidden

This email sent to email@hidden

_______________________________________________ Do not post admin requests to the list. They will be ignored. Unix-porting mailing list (email@hidden) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/unix-porting/email@hidden

This email sent to email@hidden
References: 
 >fork, pipes, and Tiger (From: Martin Costabel <email@hidden>)



Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Contact Apple | Terms of Use | Privacy Policy

Copyright © 2007 Apple Inc. All rights reserved.