[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: address@hidden: Re: address@hidden: emacs-21.2.90 on HP 11.0]]
From: |
Stef Van Vlierberghe |
Subject: |
Re: address@hidden: Re: address@hidden: emacs-21.2.90 on HP 11.0]] |
Date: |
Fri, 12 Jul 2002 23:52:13 +0200 |
Richard Stallman writes:
> On hp-ux, ioctl TIOCGPGRP always fails with errno ENOTTY (this is normal,
> explained in the USG part of create_process).
>
> I cannot find that explanation, and I am not sure what "the USG part
> of create_process" refers to. Would you please show me the specific
> code you mean? I'm trying to understand this. In particular,
> I wonder why this code
>
> if (!NILP (p->subtty))
> err = ioctl (XFASTINT (p->subtty), TIOCGPGRP, &gid);
>
> does not get the right value.
>
> Does err get set to -1 when the ioctl fails?
Below you will find the source code of create_process, where
I have put a !!! in front of the lines that are executed in
create_process when we use M-x shell (I'm a big fan of the
emacs macro's and the gdb-mode).
This explains how we have NILP (p->subtty), and hence the
'else' part of the 'if' you mentioned above is of interest :
else
err = ioctl (XINT (p->infd), TIOCGPGRP, &gid);
Here err is returned -1 and errno is 25=ENOTTY, which makes
sense because p->infd was set to inchannel, which is a PTY
returned from allocate_pty (); (I thought a pty and a tty were
like two ends of the same comms channel, but I guess this
difference matters for the ioctl).
This failure passes by unnoticed, because the err is not tested
(unless if this #ifdef pfa kicks in, which does such a test and
might already have worked around the same problem in a very
awkward way).
So, if the uninitialized gid is initially -1, then the error
is discovered accidentally, no_pgrp = 1;, and this leads us
to the kill (XFASTINT (p->pid), signo);, which send the signal
to the shell, which does not interrupt the cat.
If the uninitialized gid is initially 1, then the error is not
discovered, gid is then set to -1 but that won't matter anymore,
and we get to ioctl (XINT (p->infd), TIOCSIGSEND, signo);
which does indeed kill the cat.
Conclusion : setting gid initially to 1 is a workaround for us,
but the way it works is major voodoo.
P.S. neither of us understood what a USG system is, why HP is
one, and why somebody believes HP can't have a pty/tty creation
during a fork()/exec() construct, surely a program like xterm must
accomplish this.
Best regards.
=============================================================
void
create_process (process, new_argv, current_dir)
Lisp_Object process;
char **new_argv;
Lisp_Object current_dir;
{
int pid, inchannel, outchannel;
int sv[2];
#ifdef POSIX_SIGNALS
sigset_t procmask;
sigset_t blocked;
struct sigaction sigint_action;
struct sigaction sigquit_action;
#ifdef AIX
struct sigaction sighup_action;
#endif
#else /* !POSIX_SIGNALS */
#if 0
#ifdef SIGCHLD
SIGTYPE (*sigchld)();
#endif
#endif /* 0 */
#endif /* !POSIX_SIGNALS */
/* Use volatile to protect variables from being clobbered by longjmp. */
volatile int forkin, forkout;
!!! volatile int pty_flag = 0;
#ifndef USE_CRT_DLL
extern char **environ;
#endif
!!! Lisp_Object buffer = XPROCESS (process)->buffer;
!!! inchannel = outchannel = -1;
#ifdef HAVE_PTYS
!!! if (!NILP (Vprocess_connection_type))
!!! outchannel = inchannel = allocate_pty ();
!!! if (inchannel >= 0)
{
#ifndef USG
/* On USG systems it does not work to open the pty's tty here
and then close and reopen it in the child. */
#ifdef O_NOCTTY
/* Don't let this terminal become our controlling terminal
(in case we don't have one). */
forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
#else
forkout = forkin = emacs_open (pty_name, O_RDWR, 0);
#endif
if (forkin < 0)
report_file_error ("Opening pty", Qnil);
#else
!!! forkin = forkout = -1;
#endif /* not USG */
!!! pty_flag = 1;
}
else
#endif /* HAVE_PTYS */
#ifdef SKTPAIR
{
if (socketpair (AF_UNIX, SOCK_STREAM, 0, sv) < 0)
report_file_error ("Opening socketpair", Qnil);
outchannel = inchannel = sv[0];
forkout = forkin = sv[1];
}
#else /* not SKTPAIR */
{
int tem;
tem = pipe (sv);
if (tem < 0)
report_file_error ("Creating pipe", Qnil);
inchannel = sv[0];
forkout = sv[1];
tem = pipe (sv);
if (tem < 0)
{
emacs_close (inchannel);
emacs_close (forkout);
report_file_error ("Creating pipe", Qnil);
}
outchannel = sv[1];
forkin = sv[0];
}
#endif /* not SKTPAIR */
#if 0
/* Replaced by close_process_descs */
set_exclusive_use (inchannel);
set_exclusive_use (outchannel);
#endif
/* Stride people say it's a mystery why this is needed
as well as the O_NDELAY, but that it fails without this. */
#if defined (STRIDE) || (defined (pfa) && defined (HAVE_PTYS))
{
int one = 1;
ioctl (inchannel, FIONBIO, &one);
}
#endif
#ifdef O_NONBLOCK
!!! fcntl (inchannel, F_SETFL, O_NONBLOCK);
!!! fcntl (outchannel, F_SETFL, O_NONBLOCK);
#else
#ifdef O_NDELAY
fcntl (inchannel, F_SETFL, O_NDELAY);
fcntl (outchannel, F_SETFL, O_NDELAY);
#endif
#endif
/* Record this as an active process, with its channels.
As a result, child_setup will close Emacs's side of the pipes. */
!!! chan_process[inchannel] = process;
!!! XSETINT (XPROCESS (process)->infd, inchannel);
!!! XSETINT (XPROCESS (process)->outfd, outchannel);
/* Record the tty descriptor used in the subprocess. */
!!! if (forkin < 0)
!!! XPROCESS (process)->subtty = Qnil;
else
XSETFASTINT (XPROCESS (process)->subtty, forkin);
!!! XPROCESS (process)->pty_flag = (pty_flag ? Qt : Qnil);
!!! XPROCESS (process)->status = Qrun;
!!! if (!proc_decode_coding_system[inchannel])
!!! proc_decode_coding_system[inchannel]
= (struct coding_system *) xmalloc (sizeof (struct coding_system));
!!! setup_coding_system (XPROCESS (process)->decode_coding_system,
proc_decode_coding_system[inchannel]);
!!! if (!proc_encode_coding_system[outchannel])
!!! proc_encode_coding_system[outchannel]
= (struct coding_system *) xmalloc (sizeof (struct coding_system));
!!! setup_coding_system (XPROCESS (process)->encode_coding_system,
proc_encode_coding_system[outchannel]);
/* Delay interrupts until we have a chance to store
the new fork's pid in its process structure */
#ifdef POSIX_SIGNALS
!!! sigemptyset (&blocked);
#ifdef SIGCHLD
!!! sigaddset (&blocked, SIGCHLD);
#endif
#ifdef HAVE_VFORK
/* On many hosts (e.g. Solaris 2.4), if a vforked child calls `signal',
this sets the parent's signal handlers as well as the child's.
So delay all interrupts whose handlers the child might munge,
and record the current handlers so they can be restored later. */
sigaddset (&blocked, SIGINT ); sigaction (SIGINT , 0, &sigint_action );
sigaddset (&blocked, SIGQUIT); sigaction (SIGQUIT, 0, &sigquit_action);
#ifdef AIX
sigaddset (&blocked, SIGHUP ); sigaction (SIGHUP , 0, &sighup_action );
#endif
#endif /* HAVE_VFORK */
!!! sigprocmask (SIG_BLOCK, &blocked, &procmask);
#else /* !POSIX_SIGNALS */
#ifdef SIGCHLD
#ifdef BSD4_1
sighold (SIGCHLD);
#else /* not BSD4_1 */
#if defined (BSD_SYSTEM) || defined (UNIPLUS) || defined (HPUX)
sigsetmask (sigmask (SIGCHLD));
#else /* ordinary USG */
#if 0
sigchld_deferred = 0;
sigchld = signal (SIGCHLD, create_process_sigchld);
#endif
#endif /* ordinary USG */
#endif /* not BSD4_1 */
#endif /* SIGCHLD */
#endif /* !POSIX_SIGNALS */
!!! FD_SET (inchannel, &input_wait_mask);
!!! FD_SET (inchannel, &non_keyboard_wait_mask);
!!! if (inchannel > max_process_desc)
!!! max_process_desc = inchannel;
/* Until we store the proper pid, enable sigchld_handler
to recognize an unknown pid as standing for this process.
It is very important not to let this `marker' value stay
in the table after this function has returned; if it does
it might cause call-process to hang and subsequent asynchronous
processes to get their return values scrambled. */
!!! XSETINT (XPROCESS (process)->pid, -1);
!!! BLOCK_INPUT;
{
/* child_setup must clobber environ on systems with true vfork.
Protect it from permanent change. */
!!! char **save_environ = environ;
!!! current_dir = ENCODE_FILE (current_dir);
#ifndef WINDOWSNT
!!! pid = vfork ();
!!! if (pid == 0)
#endif /* not WINDOWSNT */
{
int xforkin = forkin;
int xforkout = forkout;
#if 0 /* This was probably a mistake--it duplicates code later on,
but fails to handle all the cases. */
/* Make sure SIGCHLD is not blocked in the child. */
sigsetmask (SIGEMPTYMASK);
#endif
/* Make the pty be the controlling terminal of the process. */
#ifdef HAVE_PTYS
/* First, disconnect its current controlling terminal. */
#ifdef HAVE_SETSID
/* We tried doing setsid only if pty_flag, but it caused
process_set_signal to fail on SGI when using a pipe. */
setsid ();
/* Make the pty's terminal the controlling terminal. */
if (pty_flag)
{
#ifdef TIOCSCTTY
/* We ignore the return value
because address@hidden says that is necessary on Linux. */
ioctl (xforkin, TIOCSCTTY, 0);
#endif
}
#else /* not HAVE_SETSID */
#ifdef USG
/* It's very important to call setpgrp here and no time
afterwards. Otherwise, we lose our controlling tty which
is set when we open the pty. */
setpgrp ();
#endif /* USG */
#endif /* not HAVE_SETSID */
#if defined (HAVE_TERMIOS) && defined (LDISC1)
if (pty_flag && xforkin >= 0)
{
struct termios t;
tcgetattr (xforkin, &t);
t.c_lflag = LDISC1;
if (tcsetattr (xforkin, TCSANOW, &t) < 0)
emacs_write (1, "create_process/tcsetattr LDISC1 failed\n", 39);
}
#else
#if defined (NTTYDISC) && defined (TIOCSETD)
if (pty_flag && xforkin >= 0)
{
/* Use new line discipline. */
int ldisc = NTTYDISC;
ioctl (xforkin, TIOCSETD, &ldisc);
}
#endif
#endif
#ifdef TIOCNOTTY
/* In 4.3BSD, the TIOCSPGRP bug has been fixed, and now you
can do TIOCSPGRP only to the process's controlling tty. */
if (pty_flag)
{
/* I wonder: would just ioctl (0, TIOCNOTTY, 0) work here?
I can't test it since I don't have 4.3. */
int j = emacs_open ("/dev/tty", O_RDWR, 0);
ioctl (j, TIOCNOTTY, 0);
emacs_close (j);
#ifndef USG
/* In order to get a controlling terminal on some versions
of BSD, it is necessary to put the process in pgrp 0
before it opens the terminal. */
#ifdef HAVE_SETPGID
setpgid (0, 0);
#else
setpgrp (0, 0);
#endif
#endif
}
#endif /* TIOCNOTTY */
#if !defined (RTU) && !defined (UNIPLUS) && !defined (DONT_REOPEN_PTY)
/*** There is a suggestion that this ought to be a
conditional on TIOCSPGRP,
or !(defined (HAVE_SETSID) && defined (TIOCSCTTY)).
Trying the latter gave the wrong results on Debian GNU/Linux 1.1;
that system does seem to need this code, even though
both HAVE_SETSID and TIOCSCTTY are defined. */
/* Now close the pty (if we had it open) and reopen it.
This makes the pty the controlling terminal of the subprocess. */
if (pty_flag)
{
#ifdef SET_CHILD_PTY_PGRP
int pgrp = getpid ();
#endif
/* I wonder if emacs_close (emacs_open (pty_name, ...))
would work? */
if (xforkin >= 0)
emacs_close (xforkin);
xforkout = xforkin = emacs_open (pty_name, O_RDWR, 0);
if (xforkin < 0)
{
emacs_write (1, "Couldn't open the pty terminal ", 31);
emacs_write (1, pty_name, strlen (pty_name));
emacs_write (1, "\n", 1);
_exit (1);
}
#ifdef SET_CHILD_PTY_PGRP
ioctl (xforkin, TIOCSPGRP, &pgrp);
ioctl (xforkout, TIOCSPGRP, &pgrp);
#endif
}
#endif /* not UNIPLUS and not RTU and not DONT_REOPEN_PTY */
#ifdef SETUP_SLAVE_PTY
if (pty_flag)
{
SETUP_SLAVE_PTY;
}
#endif /* SETUP_SLAVE_PTY */
#ifdef AIX
/* On AIX, we've disabled SIGHUP above once we start a child on a pty.
Now reenable it in the child, so it will die when we want it to. */
if (pty_flag)
signal (SIGHUP, SIG_DFL);
#endif
#endif /* HAVE_PTYS */
signal (SIGINT, SIG_DFL);
signal (SIGQUIT, SIG_DFL);
/* Stop blocking signals in the child. */
#ifdef POSIX_SIGNALS
sigprocmask (SIG_SETMASK, &procmask, 0);
#else /* !POSIX_SIGNALS */
#ifdef SIGCHLD
#ifdef BSD4_1
sigrelse (SIGCHLD);
#else /* not BSD4_1 */
#if defined (BSD_SYSTEM) || defined (UNIPLUS) || defined (HPUX)
sigsetmask (SIGEMPTYMASK);
#else /* ordinary USG */
#if 0
signal (SIGCHLD, sigchld);
#endif
#endif /* ordinary USG */
#endif /* not BSD4_1 */
#endif /* SIGCHLD */
#endif /* !POSIX_SIGNALS */
if (pty_flag)
child_setup_tty (xforkout);
#ifdef WINDOWSNT
pid = child_setup (xforkin, xforkout, xforkout,
new_argv, 1, current_dir);
#else /* not WINDOWSNT */
child_setup (xforkin, xforkout, xforkout,
new_argv, 1, current_dir);
#endif /* not WINDOWSNT */
}
!!! environ = save_environ;
}
!!! UNBLOCK_INPUT;
/* This runs in the Emacs process. */
!!! if (pid < 0)
{
if (forkin >= 0)
emacs_close (forkin);
if (forkin != forkout && forkout >= 0)
emacs_close (forkout);
}
else
{
/* vfork succeeded. */
!!! XSETFASTINT (XPROCESS (process)->pid, pid);
#ifdef WINDOWSNT
register_child (pid, inchannel);
#endif /* WINDOWSNT */
/* If the subfork execv fails, and it exits,
this close hangs. I don't know why.
So have an interrupt jar it loose. */
{
struct atimer *timer;
EMACS_TIME offset;
!!! stop_polling ();
!!! EMACS_SET_SECS_USECS (offset, 1, 0);
!!! timer = start_atimer (ATIMER_RELATIVE, offset, create_process_1, 0);
!!! XPROCESS (process)->subtty = Qnil;
!!! if (forkin >= 0)
emacs_close (forkin);
!!! cancel_atimer (timer);
!!! start_polling ();
}
!!! if (forkin != forkout && forkout >= 0)
emacs_close (forkout);
#ifdef HAVE_PTYS
!!! if (pty_flag)
!!! XPROCESS (process)->tty_name = build_string (pty_name);
else
#endif
XPROCESS (process)->tty_name = Qnil;
}
/* Restore the signal state whether vfork succeeded or not.
(We will signal an error, below, if it failed.) */
#ifdef POSIX_SIGNALS
#ifdef HAVE_VFORK
/* Restore the parent's signal handlers. */
sigaction (SIGINT, &sigint_action, 0);
sigaction (SIGQUIT, &sigquit_action, 0);
#ifdef AIX
sigaction (SIGHUP, &sighup_action, 0);
#endif
#endif /* HAVE_VFORK */
/* Stop blocking signals in the parent. */
!!! sigprocmask (SIG_SETMASK, &procmask, 0);
#else /* !POSIX_SIGNALS */
#ifdef SIGCHLD
#ifdef BSD4_1
sigrelse (SIGCHLD);
#else /* not BSD4_1 */
#if defined (BSD_SYSTEM) || defined (UNIPLUS) || defined (HPUX)
sigsetmask (SIGEMPTYMASK);
#else /* ordinary USG */
#if 0
signal (SIGCHLD, sigchld);
/* Now really handle any of these signals
that came in during this function. */
if (sigchld_deferred)
kill (getpid (), SIGCHLD);
#endif
#endif /* ordinary USG */
#endif /* not BSD4_1 */
#endif /* SIGCHLD */
#endif /* !POSIX_SIGNALS */
/* Now generate the error if vfork failed. */
!!! if (pid < 0)
--
Stef Van Vlierberghe Eurocontrol - CFMU room 20115
address@hidden Raketstraat 96
Tel: +32 2 729 97 32 B-1130 BRUSSELS
Fax: +32 2 729 90 22 Belgium