summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <cgf@redhat.com>2004-01-15 18:29:36 +0000
committerChristopher Faylor <cgf@redhat.com>2004-01-15 18:29:36 +0000
commitf45e9b4d5654d6667b3f6e06903f47df713f1052 (patch)
tree3d81a6dce900e161b97a6525c890b20af11f9cc2
parent9294f69cba58d397d8de931fca9269b406da1588 (diff)
downloadgdb-f45e9b4d5654d6667b3f6e06903f47df713f1052.tar.gz
* gentls_offsets: Reinstate unlink of temp files.
-rw-r--r--winsup/cygwin/ChangeLog4
-rw-r--r--winsup/cygwin/cygtls.cc7
-rw-r--r--winsup/cygwin/cygtls.h3
-rw-r--r--winsup/cygwin/dcrt0.cc6
-rw-r--r--winsup/cygwin/exceptions.cc157
-rw-r--r--winsup/cygwin/fhandler_termios.cc349
-rw-r--r--winsup/cygwin/fhandler_tty.cc1415
-rwxr-xr-xwinsup/cygwin/gentls_offsets79
-rw-r--r--winsup/cygwin/include/cygwin/signal.h187
-rw-r--r--winsup/cygwin/signal.cc507
-rw-r--r--winsup/cygwin/sigproc.cc132
-rw-r--r--winsup/cygwin/sigproc.h110
-rw-r--r--winsup/cygwin/thread.cc6
-rw-r--r--winsup/cygwin/winsup.h4
14 files changed, 2835 insertions, 131 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index f1e3f2f0dc0..16aa73fe5b4 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,7 @@
+2004-01-15 Christopher Faylor <cgf@redhat.com>
+
+ * gentls_offsets: Reinstate unlink of temp files.
+
2004-01-14 Christopher Faylor <cgf@redhat.com>
* fhandler_console.cc (fhandler_console::close): Fix debugging output.
diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc
index 5c9fa615f2e..ecec3f52bd0 100644
--- a/winsup/cygwin/cygtls.cc
+++ b/winsup/cygwin/cygtls.cc
@@ -20,6 +20,7 @@ details. */
#include "dtable.h"
#include "cygheap.h"
#include "cygthread.h"
+#include "sigproc.h"
class sentry
{
@@ -189,6 +190,12 @@ _threadinfo::find_tls (int sig)
return res;
}
+void
+_threadinfo::set_siginfo (sigpacket *pack)
+{
+ infodata = pack->si;
+}
+
extern "C" DWORD __stdcall RtlUnwind (void *, void *, void *, DWORD);
static int
handle_threadlist_exception (EXCEPTION_RECORD *e, void *frame, CONTEXT *, void *)
diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h
index 779e42b8981..ab82bac9dfe 100644
--- a/winsup/cygwin/cygtls.h
+++ b/winsup/cygwin/cygtls.h
@@ -120,7 +120,7 @@ struct _threadinfo
static void call2 (DWORD (*) (void *, void *), void *, void *) __attribute__ ((regparm (3)));
static struct _threadinfo *find_tls (int sig);
void remove (DWORD);
- void push (__stack_t, bool = false);
+ void push (__stack_t, bool = false) __attribute__ ((regparm (3)));
__stack_t pop ();
bool isinitialized () {return initialized == CYGTLS_INITIALIZED || initialized == CYGTLS_EXCEPTION;}
void set_state (bool);
@@ -131,6 +131,7 @@ struct _threadinfo
__attribute__((regparm(3)));
void init_threadlist_exceptions (struct _exception_list *);
operator HANDLE () const {return tid->win32_obj_id;}
+ void set_siginfo (struct sigpacket *) __attribute__ ((regparm (3)));
/*gentls_offsets*/
};
#pragma pack(pop)
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
index 3d6b7a89b4e..4b905b77488 100644
--- a/winsup/cygwin/dcrt0.cc
+++ b/winsup/cygwin/dcrt0.cc
@@ -1042,9 +1042,13 @@ do_exit (int status)
/* Kill orphaned children on group leader exit */
if (myself->has_pgid_children && myself->pid == myself->pgid)
{
+ siginfo_t si;
+ si.si_signo = -SIGHUP;
+ si.si_code = SI_KERNEL;
+ si.si_pid = si.si_uid = si.si_errno = 0;
sigproc_printf ("%d == pgrp %d, send SIG{HUP,CONT} to stopped children",
myself->pid, myself->pgid);
- kill_pgrp (myself->pgid, -SIGHUP);
+ kill_pgrp (myself->pgid, si);
}
}
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 597c58e47d1..1fea4cd7c23 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -419,30 +419,56 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *)
RtlUnwind (frame, ret_here, e0, 0);
__asm__ volatile (".equ _ret_here,.");
- int sig;
+ siginfo_t si;
/* Coerce win32 value to posix value. */
switch (e.ExceptionCode)
{
case STATUS_FLOAT_DENORMAL_OPERAND:
case STATUS_FLOAT_DIVIDE_BY_ZERO:
- case STATUS_FLOAT_INEXACT_RESULT:
case STATUS_FLOAT_INVALID_OPERATION:
- case STATUS_FLOAT_OVERFLOW:
case STATUS_FLOAT_STACK_CHECK:
+ si.si_signo = SIGFPE;
+ si.si_sigval.sival_int = FPE_FLTSUB;
+ break;
+ case STATUS_FLOAT_INEXACT_RESULT:
+ si.si_signo = SIGFPE;
+ si.si_sigval.sival_int = FPE_FLTRES;
+ break;
+ case STATUS_FLOAT_OVERFLOW:
+ si.si_signo = SIGFPE;
+ si.si_sigval.sival_int = FPE_FLTOVF;
+ break;
case STATUS_FLOAT_UNDERFLOW:
+ si.si_signo = SIGFPE;
+ si.si_sigval.sival_int = FPE_FLTUND;
+ break;
case STATUS_INTEGER_DIVIDE_BY_ZERO:
+ si.si_signo = SIGFPE;
+ si.si_sigval.sival_int = FPE_INTDIV;
+ break;
case STATUS_INTEGER_OVERFLOW:
- sig = SIGFPE;
+ si.si_signo = SIGFPE;
+ si.si_sigval.sival_int = FPE_INTOVF;
break;
case STATUS_ILLEGAL_INSTRUCTION:
+ si.si_signo = SIGILL;
+ si.si_sigval.sival_int = ILL_ILLOPC;
+ break;
+
case STATUS_PRIVILEGED_INSTRUCTION:
+ si.si_signo = SIGILL;
+ si.si_sigval.sival_int = ILL_PRVOPC;
+ break;
+
case STATUS_NONCONTINUABLE_EXCEPTION:
- sig = SIGILL;
+ si.si_signo = SIGILL;
+ si.si_sigval.sival_int = ILL_ILLADR;
break;
case STATUS_TIMEOUT:
- sig = SIGALRM;
+ si.si_signo = SIGALRM;
+ si.si_sigval.sival_int = 0;
break;
case STATUS_ACCESS_VIOLATION:
@@ -453,11 +479,13 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *)
case STATUS_NO_MEMORY:
case STATUS_INVALID_DISPOSITION:
case STATUS_STACK_OVERFLOW:
- sig = SIGSEGV;
+ si.si_signo = SIGSEGV;
+ si.si_sigval.sival_int = SEGV_MAPERR;
break;
case STATUS_CONTROL_C_EXIT:
- sig = SIGINT;
+ si.si_signo = SIGINT;
+ si.si_sigval.sival_int = 0;
break;
case STATUS_INVALID_HANDLE:
@@ -476,13 +504,14 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *)
}
debug_printf ("In cygwin_except_handler exc %p at %p sp %p", e.ExceptionCode, in.Eip, in.Esp);
- debug_printf ("In cygwin_except_handler sig = %d at %p", sig, in.Eip);
+ debug_printf ("In cygwin_except_handler sig = %d at %p", si.si_signo, in.Eip);
- if (global_sigs[sig].sa_mask & SIGTOMASK (sig))
- syscall_printf ("signal %d, masked %p", sig, global_sigs[sig].sa_mask);
+ if (global_sigs[si.si_signo].sa_mask & SIGTOMASK (si.si_signo))
+ syscall_printf ("signal %d, masked %p", si.si_signo,
+ global_sigs[si.si_signo].sa_mask);
debug_printf ("In cygwin_except_handler calling %p",
- global_sigs[sig].sa_handler);
+ global_sigs[si.si_signo].sa_handler);
DWORD *ebp = (DWORD *)in.Esp;
for (DWORD *bpend = (DWORD *) __builtin_frame_address (0); ebp > bpend; ebp--)
@@ -494,23 +523,18 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *)
if (!myself->progname[0]
|| GetCurrentThreadId () == sigtid
- || (void *) global_sigs[sig].sa_handler == (void *) SIG_DFL
- || (void *) global_sigs[sig].sa_handler == (void *) SIG_IGN
- || (void *) global_sigs[sig].sa_handler == (void *) SIG_ERR)
+ || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_DFL
+ || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_IGN
+ || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_ERR)
{
/* Print the exception to the console */
- if (1)
- {
- for (int i = 0; status_info[i].name; i++)
- {
- if (status_info[i].code == e.ExceptionCode)
- {
- if (!myself->ppid_handle)
- system_printf ("Exception: %s", status_info[i].name);
- break;
- }
- }
- }
+ for (int i = 0; status_info[i].name; i++)
+ if (status_info[i].code == e.ExceptionCode)
+ {
+ if (!myself->ppid_handle)
+ system_printf ("Exception: %s", status_info[i].name);
+ break;
+ }
/* Another exception could happen while tracing or while exiting.
Only do this once. */
@@ -529,11 +553,13 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *)
stackdump ((DWORD) ebp, 0, 1);
}
- signal_exit (0x80 | sig); // Flag signal + core dump
+ signal_exit (0x80 | si.si_signo); // Flag signal + core dump
}
- _my_tls.push ((__stack_t) ebp, true);
- sig_send (NULL, sig, &_my_tls); // Signal myself
+ si.si_addr = ebp;
+ si.si_code = SI_KERNEL;
+ si.si_errno = si.si_pid = si.si_uid = 0;
+ sig_send (NULL, si, &_my_tls); // Signal myself
return 1;
}
#endif /* __i386__ */
@@ -605,7 +631,14 @@ sig_handle_tty_stop (int sig)
{
pinfo parent (myself->ppid);
if (ISSTATE (parent, PID_NOCLDSTOP))
- sig_send (parent, SIGCHLD);
+ {
+ siginfo_t si;
+ si.si_signo = SIGCHLD;
+ si.si_code = SI_KERNEL;
+ si.si_sigval.sival_int = CLD_STOPPED;
+ si.si_errno = si.si_pid = si.si_uid = si.si_errno = 0;
+ sig_send (parent, si);
+ }
}
sigproc_printf ("process %d stopped by signal %d, myself->ppid_handle %p",
myself->pid, sig, myself->ppid_handle);
@@ -814,8 +847,8 @@ ctrl_c_handler (DWORD type)
{
if (type == CTRL_CLOSE_EVENT)
{
- saw_close = true;
sig_send (NULL, SIGHUP);
+ saw_close = true;
return FALSE;
}
if (!saw_close && type == CTRL_LOGOFF_EVENT)
@@ -849,7 +882,7 @@ ctrl_c_handler (DWORD type)
a CTRL_C_EVENT or CTRL_BREAK_EVENT. */
{
t->last_ctrl_c = GetTickCount ();
- kill (-myself->pid, SIGINT);
+ killsys (-myself->pid, SIGINT);
t->last_ctrl_c = GetTickCount ();
return TRUE;
}
@@ -884,9 +917,9 @@ set_signal_mask (sigset_t newmask, sigset_t oldmask)
}
int __stdcall
-sig_handle (int sig, sigset_t mask, int pid, _threadinfo *tls)
+sigpacket::process ()
{
- if (sig == SIGCONT)
+ if (si.si_signo == SIGCONT)
{
DWORD stopped = myself->process_state & PID_STOPPED;
myself->stopsig = 0;
@@ -901,41 +934,44 @@ sig_handle (int sig, sigset_t mask, int pid, _threadinfo *tls)
}
int rc = 1;
- bool insigwait_mask = tls ? sigismember (&tls->sigwait_mask, sig) : false;
+ bool insigwait_mask = tls ? sigismember (&tls->sigwait_mask, si.si_signo) : false;
bool special_case = ISSTATE (myself, PID_STOPPED) || main_vfork->pid;
- bool masked = sigismember (&mask, sig);
- if (sig != SIGKILL && sig != SIGSTOP
+ bool masked = sigismember (mask, si.si_signo);
+ if (si.si_signo != SIGKILL && si.si_signo != SIGSTOP
&& (special_case || main_vfork->pid || masked || insigwait_mask
- || (tls && sigismember (&tls->sigmask, sig))))
+ || (tls && sigismember (&tls->sigmask, si.si_signo))))
{
- sigproc_printf ("signal %d blocked", sig);
+ sigproc_printf ("signal %d blocked", si.si_signo);
if ((!special_case && !masked)
- && (insigwait_mask || (tls = _threadinfo::find_tls (sig)) != NULL))
+ && (insigwait_mask || (tls = _threadinfo::find_tls (si.si_signo)) != NULL))
goto thread_specific;
rc = -1;
goto done;
}
/* Clear pending SIGCONT on stop signals */
- if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
+ if (si.si_signo == SIGSTOP || si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU)
sig_clear (SIGCONT);
- sigproc_printf ("signal %d processing", sig);
- struct sigaction thissig = global_sigs[sig];
+ sigproc_printf ("signal %d processing", si.si_signo);
+ struct sigaction thissig = global_sigs[si.si_signo];
void *handler;
handler = (void *) thissig.sa_handler;
myself->rusage_self.ru_nsignals++;
- if (sig == SIGKILL)
+ if (si.si_signo == SIGKILL)
goto exit_sig;
- if (sig == SIGSTOP)
+ if (!tls)
+ tls = _main_tls;
+
+ if (si.si_signo == SIGSTOP)
goto stop;
#if 0
char sigmsg[24];
- __small_sprintf (sigmsg, "cygwin: signal %d\n", sig);
+ __small_sprintf (sigmsg, "cygwin: signal %d\n", si.si_signo);
OutputDebugString (sigmsg);
#endif
@@ -943,14 +979,14 @@ sig_handle (int sig, sigset_t mask, int pid, _threadinfo *tls)
{
if (insigwait_mask)
goto thread_specific;
- if (sig == SIGCHLD || sig == SIGIO || sig == SIGCONT || sig == SIGWINCH
- || sig == SIGURG)
+ if (si.si_signo == SIGCHLD || si.si_signo == SIGIO || si.si_signo == SIGCONT || si.si_signo == SIGWINCH
+ || si.si_signo == SIGURG)
{
- sigproc_printf ("default signal %d ignored", sig);
+ sigproc_printf ("default signal %d ignored", si.si_signo);
goto done;
}
- if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
+ if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU)
goto stop;
goto exit_sig;
@@ -958,7 +994,7 @@ sig_handle (int sig, sigset_t mask, int pid, _threadinfo *tls)
if (handler == (void *) SIG_IGN)
{
- sigproc_printf ("signal %d ignored", sig);
+ sigproc_printf ("signal %d ignored", si.si_signo);
goto done;
}
@@ -973,34 +1009,37 @@ stop:
goto done;
handler = (void *) sig_handle_tty_stop;
thissig = global_sigs[SIGSTOP];
+ goto dosig1;
dosig:
+ tls->set_siginfo (this);
+dosig1:
/* Dispatch to the appropriate function. */
- sigproc_printf ("signal %d, about to call %p", sig, handler);
- rc = setup_handler (sig, handler, thissig, tls ?: _main_tls);
+ sigproc_printf ("signal %d, about to call %p", si.si_signo, handler);
+ rc = setup_handler (si.si_signo, handler, thissig, tls);
done:
sigproc_printf ("returning %d", rc);
return rc;
thread_specific:
- tls->sig = sig;
+ tls->sig = si.si_signo;
sigproc_printf ("releasing sigwait for thread");
SetEvent (tls->event);
goto done;
exit_sig:
- if (sig == SIGQUIT || sig == SIGABRT)
+ if (si.si_signo == SIGQUIT || si.si_signo == SIGABRT)
{
CONTEXT c;
c.ContextFlags = CONTEXT_FULL;
GetThreadContext (hMainThread, &c);
if (!try_to_debug ())
stackdump (c.Ebp, 1, 1);
- sig |= 0x80;
+ si.si_signo |= 0x80;
}
- sigproc_printf ("signal %d, about to call do_exit", sig);
- signal_exit (sig);
+ sigproc_printf ("signal %d, about to call do_exit", si.si_signo);
+ signal_exit (si.si_signo);
/* Never returns */
}
diff --git a/winsup/cygwin/fhandler_termios.cc b/winsup/cygwin/fhandler_termios.cc
new file mode 100644
index 00000000000..398dabd9eec
--- /dev/null
+++ b/winsup/cygwin/fhandler_termios.cc
@@ -0,0 +1,349 @@
+/* fhandler_termios.cc
+
+ Copyright 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <sys/termios.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "sigproc.h"
+#include "pinfo.h"
+#include "tty.h"
+#include "sys/cygwin.h"
+
+/* Common functions shared by tty/console */
+
+void
+fhandler_termios::tcinit (tty_min *this_tc, bool force)
+{
+ /* Initial termios values */
+
+ tc = this_tc;
+
+ if (force || !TTYISSETF (INITIALIZED))
+ {
+ tc->ti.c_iflag = BRKINT | ICRNL | IXON;
+ tc->ti.c_oflag = OPOST | ONLCR;
+ tc->ti.c_cflag = B38400 | CS8 | CREAD;
+ tc->ti.c_lflag = ISIG | ICANON | ECHO | IEXTEN;
+
+ tc->ti.c_cc[VDISCARD] = CFLUSH;
+ tc->ti.c_cc[VEOL] = CEOL;
+ tc->ti.c_cc[VEOL2] = CEOL2;
+ tc->ti.c_cc[VEOF] = CEOF;
+ tc->ti.c_cc[VERASE] = CERASE;
+ tc->ti.c_cc[VINTR] = CINTR;
+ tc->ti.c_cc[VKILL] = CKILL;
+ tc->ti.c_cc[VLNEXT] = CLNEXT;
+ tc->ti.c_cc[VMIN] = 1;
+ tc->ti.c_cc[VQUIT] = CQUIT;
+ tc->ti.c_cc[VREPRINT] = CRPRNT;
+ tc->ti.c_cc[VSTART] = CSTART;
+ tc->ti.c_cc[VSTOP] = CSTOP;
+ tc->ti.c_cc[VSUSP] = CSUSP;
+ tc->ti.c_cc[VSWTC] = CSWTCH;
+ tc->ti.c_cc[VTIME] = 0;
+ tc->ti.c_cc[VWERASE] = CWERASE;
+
+ tc->ti.c_ispeed = tc->ti.c_ospeed = B38400;
+ tc->pgid = myself->pgid;
+ TTYSETF (INITIALIZED);
+ }
+}
+
+int
+fhandler_termios::tcsetpgrp (const pid_t pgid)
+{
+ termios_printf ("tty %d pgid %d, sid %d, tsid %d", tc->ntty, pgid,
+ myself->sid, tc->getsid ());
+ if (myself->sid != tc->getsid ())
+ {
+ set_errno (EPERM);
+ return -1;
+ }
+ tc->setpgid (pgid);
+ return 0;
+}
+
+int
+fhandler_termios::tcgetpgrp ()
+{
+ return tc->pgid;
+}
+
+void
+tty_min::kill_pgrp (int sig)
+{
+ int killself = 0;
+ winpids pids ((DWORD) PID_MAP_RW);
+ siginfo_t si;
+ si.si_signo = sig;
+ si.si_code = SI_KERNEL;
+ si.si_pid = si.si_uid = si.si_errno = 0;
+ for (unsigned i = 0; i < pids.npids; i++)
+ {
+ _pinfo *p = pids[i];
+ if (!proc_exists (p) || p->ctty != ntty || p->pgid != pgid)
+ continue;
+ if (p == myself)
+ killself++;
+ else
+ (void) sig_send (p, si);
+ }
+ if (killself)
+ sig_send (myself, si);
+}
+
+bg_check_types
+fhandler_termios::bg_check (int sig)
+{
+ if (!myself->pgid || tc->getpgid () == myself->pgid ||
+ myself->ctty != tc->ntty ||
+ ((sig == SIGTTOU) && !(tc->ti.c_lflag & TOSTOP)))
+ return bg_ok;
+
+ if (sig < 0)
+ sig = -sig;
+
+ termios_printf ("bg I/O pgid %d, tpgid %d, ctty %d",
+ myself->pgid, tc->getpgid (), myself->ctty);
+
+ if (tc->getsid () == 0)
+ {
+ /* The pty has been closed by the master. Return an EOF
+ indication. FIXME: There is nothing to stop somebody
+ from reallocating this pty. I think this is the case
+ which is handled by unlockpt on a Unix system. */
+ termios_printf ("closed by master");
+ return bg_eof;
+ }
+
+ /* If the process group is no more or if process is ignoring or blocks 'sig',
+ return with error */
+ int pgid_gone = !pid_exists (myself->pgid);
+ int sigs_ignored =
+ ((void *) global_sigs[sig].sa_handler == (void *) SIG_IGN) ||
+ (myself->getsigmask () & SIGTOMASK (sig));
+
+ if (pgid_gone)
+ goto setEIO;
+ else if (!sigs_ignored)
+ /* nothing */;
+ else if (sig == SIGTTOU)
+ return bg_ok; /* Just allow the output */
+ else
+ goto setEIO; /* This is an output error */
+
+ /* Don't raise a SIGTT* signal if we have already been interrupted
+ by another signal. */
+ if (WaitForSingleObject (signal_arrived, 0) != WAIT_OBJECT_0)
+ {
+ siginfo_t si;
+ si.si_signo = sig;
+ si.si_code = SI_KERNEL;
+ si.si_pid = si.si_uid = si.si_errno = 0;
+ kill_pgrp (myself->pgid, si);
+ }
+ return bg_signalled;
+
+setEIO:
+ set_errno (EIO);
+ return bg_error;
+}
+
+#define set_input_done(x) input_done = input_done || (x)
+
+inline void
+fhandler_termios::echo_erase (int force)
+{
+ if (force || tc->ti.c_lflag & ECHO)
+ doecho ("\b \b", 3);
+}
+
+line_edit_status
+fhandler_termios::line_edit (const char *rptr, int nread, termios& ti)
+{
+ line_edit_status ret = line_edit_ok;
+ char c;
+ int input_done = 0;
+ bool sawsig = false;
+ int iscanon = ti.c_lflag & ICANON;
+
+ while (nread-- > 0)
+ {
+ c = *rptr++;
+
+ termios_printf ("char %c", c);
+
+ /* Check for special chars */
+
+ if (c == '\r')
+ {
+ if (ti.c_iflag & IGNCR)
+ continue;
+ if (ti.c_iflag & ICRNL)
+ {
+ c = '\n';
+ set_input_done (iscanon);
+ }
+ }
+ else if (c == '\n')
+ {
+ if (ti.c_iflag & INLCR)
+ c = '\r';
+ else
+ set_input_done (iscanon);
+ }
+
+ if (ti.c_iflag & ISTRIP)
+ c &= 0x7f;
+ if (ti.c_lflag & ISIG)
+ {
+ int sig;
+ if (CCEQ (ti.c_cc[VINTR], c))
+ sig = SIGINT;
+ else if (CCEQ (ti.c_cc[VQUIT], c))
+ sig = SIGQUIT;
+ else if (CCEQ (ti.c_cc[VSUSP], c))
+ sig = SIGTSTP;
+ else
+ goto not_a_sig;
+
+ termios_printf ("got interrupt %d, sending signal %d", c, sig);
+ eat_readahead (-1);
+ tc->kill_pgrp (sig);
+ ti.c_lflag &= ~FLUSHO;
+ sawsig = true;
+ goto restart_output;
+ }
+ not_a_sig:
+ if (ti.c_iflag & IXON)
+ {
+ if (CCEQ (ti.c_cc[VSTOP], c))
+ {
+ if (!tc->output_stopped)
+ {
+ tc->output_stopped = 1;
+ acquire_output_mutex (INFINITE);
+ }
+ continue;
+ }
+ else if (CCEQ (ti.c_cc[VSTART], c))
+ {
+ restart_output:
+ tc->output_stopped = 0;
+ release_output_mutex ();
+ continue;
+ }
+ else if ((ti.c_iflag & IXANY) && tc->output_stopped)
+ goto restart_output;
+ }
+ if (iscanon && ti.c_lflag & IEXTEN && CCEQ (ti.c_cc[VDISCARD], c))
+ {
+ ti.c_lflag ^= FLUSHO;
+ continue;
+ }
+ if (!iscanon)
+ /* nothing */;
+ else if (CCEQ (ti.c_cc[VERASE], c))
+ {
+ if (eat_readahead (1))
+ echo_erase ();
+ continue;
+ }
+ else if (CCEQ (ti.c_cc[VWERASE], c))
+ {
+ int ch;
+ do
+ if (!eat_readahead (1))
+ break;
+ else
+ echo_erase ();
+ while ((ch = peek_readahead (1)) >= 0 && !isspace (ch));
+ continue;
+ }
+ else if (CCEQ (ti.c_cc[VKILL], c))
+ {
+ int nchars = eat_readahead (-1);
+ if (ti.c_lflag & ECHO)
+ while (nchars--)
+ echo_erase (1);
+ continue;
+ }
+ else if (CCEQ (ti.c_cc[VREPRINT], c))
+ {
+ if (ti.c_lflag & ECHO)
+ {
+ doecho ("\n\r", 2);
+ doecho (rabuf, ralen);
+ }
+ continue;
+ }
+ else if (CCEQ (ti.c_cc[VEOF], c))
+ {
+ termios_printf ("EOF");
+ (void) accept_input ();
+ ret = line_edit_input_done;
+ continue;
+ }
+ else if (CCEQ (ti.c_cc[VEOL], c) ||
+ CCEQ (ti.c_cc[VEOL2], c) ||
+ c == '\n')
+ {
+ set_input_done (1);
+ termios_printf ("EOL");
+ }
+
+ if (ti.c_iflag & IUCLC && isupper (c))
+ c = cyg_tolower (c);
+
+ put_readahead (c);
+ if (ti.c_lflag & ECHO)
+ doecho (&c, 1);
+ if (!iscanon || input_done)
+ {
+ int status = accept_input ();
+ if (status != 1)
+ {
+ ret = status ? line_edit_error : line_edit_pipe_full;
+ eat_readahead (1);
+ break;
+ }
+ ret = line_edit_input_done;
+ input_done = 0;
+ }
+ }
+
+ if (!iscanon && ralen > 0)
+ ret = line_edit_input_done;
+
+ if (sawsig)
+ ret = line_edit_signalled;
+
+ return ret;
+}
+
+void
+fhandler_termios::fixup_after_fork (HANDLE parent)
+{
+ fhandler_base::fixup_after_fork (parent);
+ fork_fixup (parent, get_output_handle (), "output_handle");
+}
+
+_off64_t
+fhandler_termios::lseek (_off64_t, int)
+{
+ set_errno (ESPIPE);
+ return -1;
+}
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
new file mode 100644
index 00000000000..33c7f379dad
--- /dev/null
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -0,0 +1,1415 @@
+/* fhandler_tty.cc
+
+ Copyright 1997, 1998, 2000, 2001, 2002, 2003 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <wingdi.h>
+#include <winuser.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "sigproc.h"
+#include "pinfo.h"
+#include "cygheap.h"
+#include "shared_info.h"
+#include "cygserver.h"
+#include "cygthread.h"
+
+/* Tty master stuff */
+
+fhandler_tty_master NO_COPY *tty_master;
+
+static DWORD WINAPI process_input (void *); // Input queue thread
+static DWORD WINAPI process_output (void *); // Output queue thread
+static DWORD WINAPI process_ioctl (void *); // Ioctl requests thread
+
+fhandler_tty_master::fhandler_tty_master ()
+ : fhandler_pty_master (), console (NULL)
+{
+}
+
+int
+fhandler_tty_slave::get_unit ()
+{
+ return dev () == FH_TTY ? myself->ctty : dev ().minor;
+}
+
+void
+fhandler_tty_master::set_winsize (bool sendSIGWINCH)
+{
+ winsize w;
+ console->ioctl (TIOCGWINSZ, &w);
+ get_ttyp ()->winsize = w;
+ if (sendSIGWINCH)
+ tc->kill_pgrp (SIGWINCH);
+}
+
+int
+fhandler_tty_master::init ()
+{
+ slave = dev ();
+ termios_printf ("Creating master for tty%d", get_unit ());
+
+ if (init_console ())
+ {
+ termios_printf ("can't create fhandler");
+ return -1;
+ }
+
+ termios ti;
+ memset (&ti, 0, sizeof (ti));
+ console->tcsetattr (0, &ti);
+
+ cygwin_shared->tty[get_unit ()]->common_init (this);
+
+ set_winsize (false);
+
+ inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE);
+ set_close_on_exec (true);
+
+ cygthread *h;
+ h = new cygthread (process_input, cygself, "ttyin");
+ h->SetThreadPriority (THREAD_PRIORITY_HIGHEST);
+ h->zap_h ();
+
+ h = new cygthread (process_ioctl, cygself, "ttyioctl");
+ h->SetThreadPriority (THREAD_PRIORITY_HIGHEST);
+ h->zap_h ();
+
+ h = new cygthread (process_output, cygself, "ttyout");
+ h->SetThreadPriority (THREAD_PRIORITY_HIGHEST);
+ h->zap_h ();
+
+ return 0;
+}
+
+#ifdef DEBUGGING
+static class mutex_stack
+{
+public:
+ const char *fn;
+ int ln;
+ const char *tname;
+} ostack[100];
+
+static int osi;
+#endif /*DEBUGGING*/
+
+DWORD
+fhandler_tty_common::__acquire_output_mutex (const char *fn, int ln,
+ DWORD ms)
+{
+ if (strace.active)
+ strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: waiting %d ms", ln, ms);
+ DWORD res = WaitForSingleObject (output_mutex, ms);
+ if (res == WAIT_OBJECT_0)
+ {
+#ifndef DEBUGGING
+ if (strace.active)
+ strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: acquired", ln, res);
+#else
+ ostack[osi].fn = fn;
+ ostack[osi].ln = ln;
+ ostack[osi].tname = cygthread::name ();
+ termios_printf ("acquired for %s:%d, osi %d", fn, ln, osi);
+ osi++;
+#endif
+ }
+ return res;
+}
+
+void
+fhandler_tty_common::__release_output_mutex (const char *fn, int ln)
+{
+ if (ReleaseMutex (output_mutex))
+ {
+#ifndef DEBUGGING
+ if (strace.active)
+ strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex released", ln);
+#else
+ if (osi > 0)
+ osi--;
+ termios_printf ("released at %s:%d, osi %d", fn, ln, osi);
+ termios_printf (" for %s:%d (%s)", ostack[osi].fn, ostack[osi].ln, ostack[osi].tname);
+ ostack[osi].ln = -ln;
+#endif
+ }
+}
+
+/* Process tty input. */
+
+void
+fhandler_pty_master::doecho (const void *str, DWORD len)
+{
+ acquire_output_mutex (INFINITE);
+ if (!WriteFile (get_ttyp ()->to_master, str, len, &len, NULL))
+ termios_printf ("Write to %p failed, %E", get_ttyp ()->to_master);
+// WaitForSingleObject (output_done_event, INFINITE);
+ release_output_mutex ();
+}
+
+int
+fhandler_pty_master::accept_input ()
+{
+ DWORD bytes_left;
+ int ret = 1;
+
+ (void) WaitForSingleObject (input_mutex, INFINITE);
+
+ bytes_left = eat_readahead (-1);
+
+ if (!bytes_left)
+ {
+ termios_printf ("sending EOF to slave");
+ get_ttyp ()->read_retval = 0;
+ }
+ else
+ {
+ char *p = rabuf;
+ DWORD rc;
+ DWORD written = 0;
+
+ termios_printf ("about to write %d chars to slave", bytes_left);
+ rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+ if (!rc)
+ {
+ debug_printf ("error writing to pipe %E");
+ get_ttyp ()->read_retval = -1;
+ ret = -1;
+ }
+ else
+ {
+ get_ttyp ()->read_retval = 1;
+ p += written;
+ bytes_left -= written;
+ if (bytes_left > 0)
+ {
+ debug_printf ("to_slave pipe is full");
+ puts_readahead (p, bytes_left);
+ ret = 0;
+ }
+ }
+ }
+
+ SetEvent (input_available_event);
+ ReleaseMutex (input_mutex);
+ return ret;
+}
+
+static DWORD WINAPI
+process_input (void *)
+{
+ char rawbuf[INP_BUFFER_SIZE];
+
+ while (1)
+ {
+ size_t nraw = INP_BUFFER_SIZE;
+ tty_master->console->read ((void *) rawbuf, nraw);
+ if (tty_master->line_edit (rawbuf, nraw, tty_master->get_ttyp ()->ti)
+ == line_edit_signalled)
+ tty_master->console->eat_readahead (-1);
+ }
+}
+
+bool
+fhandler_pty_master::hit_eof ()
+{
+ if (get_ttyp ()->was_opened && !get_ttyp ()->slave_alive ())
+ {
+ /* We have the only remaining open handle to this pty, and
+ the slave pty has been opened at least once. We treat
+ this as EOF. */
+ termios_printf ("all other handles closed");
+ return 1;
+ }
+ return 0;
+}
+
+/* Process tty output requests */
+
+int
+fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on)
+{
+ size_t rlen;
+ char outbuf[OUT_BUFFER_SIZE + 1];
+ DWORD n;
+ int column = 0;
+ int rc = 0;
+
+ if (len == 0)
+ goto out;
+
+ if (need_nl)
+ {
+ /* We need to return a left over \n character, resulting from
+ \r\n conversion. Note that we already checked for FLUSHO and
+ output_stopped at the time that we read the character, so we
+ don't check again here. */
+ if (buf)
+ buf[0] = '\n';
+ need_nl = 0;
+ rc = 1;
+ goto out;
+ }
+
+
+ for (;;)
+ {
+ /* Set RLEN to the number of bytes to read from the pipe. */
+ rlen = len;
+ if (get_ttyp ()->ti.c_oflag & OPOST && get_ttyp ()->ti.c_oflag & ONLCR)
+ {
+ /* We are going to expand \n to \r\n, so don't read more than
+ half of the number of bytes requested. */
+ rlen /= 2;
+ if (rlen == 0)
+ rlen = 1;
+ }
+ if (rlen > sizeof outbuf)
+ rlen = sizeof outbuf;
+
+ HANDLE handle = get_io_handle ();
+
+ n = 0; // get_readahead_into_buffer (outbuf, len);
+ if (!n)
+ {
+ /* Doing a busy wait like this is quite inefficient, but nothing
+ else seems to work completely. Windows should provide some sort
+ of overlapped I/O for pipes, or something, but it doesn't. */
+ while (1)
+ {
+ if (!PeekNamedPipe (handle, NULL, 0, NULL, &n, NULL))
+ goto err;
+ if (n > 0)
+ break;
+ if (hit_eof ())
+ goto out;
+ /* DISCARD (FLUSHO) and tcflush can finish here. */
+ if (n == 0 && (get_ttyp ()->ti.c_lflag & FLUSHO || !buf))
+ goto out;
+ if (n == 0 && is_nonblocking ())
+ {
+ set_errno (EAGAIN);
+ rc = -1;
+ break;
+ }
+
+ Sleep (10);
+ }
+
+ if (ReadFile (handle, outbuf, rlen, &n, NULL) == FALSE)
+ goto err;
+ }
+
+ termios_printf ("bytes read %u", n);
+ get_ttyp ()->write_error = 0;
+ if (output_done_event != NULL)
+ SetEvent (output_done_event);
+
+ if (get_ttyp ()->ti.c_lflag & FLUSHO || !buf)
+ continue;
+
+ char *optr;
+ optr = buf;
+ if (pktmode_on)
+ *optr++ = TIOCPKT_DATA;
+
+ if (!(get_ttyp ()->ti.c_oflag & OPOST)) // post-process output
+ {
+ memcpy (optr, outbuf, n);
+ optr += n;
+ }
+ else // raw output mode
+ {
+ char *iptr = outbuf;
+
+ while (n--)
+ {
+ switch (*iptr)
+ {
+ case '\r':
+ if ((get_ttyp ()->ti.c_oflag & ONOCR) && column == 0)
+ {
+ iptr++;
+ continue;
+ }
+ if (get_ttyp ()->ti.c_oflag & OCRNL)
+ *iptr = '\n';
+ else
+ column = 0;
+ break;
+ case '\n':
+ if (get_ttyp ()->ti.c_oflag & ONLCR)
+ {
+ *optr++ = '\r';
+ column = 0;
+ }
+ if (get_ttyp ()->ti.c_oflag & ONLRET)
+ column = 0;
+ break;
+ default:
+ column++;
+ break;
+ }
+
+ /* Don't store data past the end of the user's buffer. This
+ can happen if the user requests a read of 1 byte when
+ doing \r\n expansion. */
+ if (optr - buf >= (int) len)
+ {
+ if (*iptr != '\n' || n != 0)
+ system_printf ("internal error: %d unexpected characters", n);
+ need_nl = 1;
+ break;
+ }
+
+ *optr++ = *iptr++;
+ }
+ }
+ rc = optr - buf;
+ break;
+
+ err:
+ if (GetLastError () == ERROR_BROKEN_PIPE)
+ rc = 0;
+ else
+ {
+ __seterrno ();
+ rc = -1;
+ }
+ break;
+ }
+
+out:
+ termios_printf ("returning %d", rc);
+ return rc;
+}
+
+static DWORD WINAPI
+process_output (void *)
+{
+ char buf[OUT_BUFFER_SIZE * 2];
+
+ for (;;)
+ {
+ int n = tty_master->process_slave_output (buf, OUT_BUFFER_SIZE, 0);
+ if (n <= 0)
+ {
+ if (n < 0)
+ termios_printf ("ReadFile %E");
+ ExitThread (0);
+ }
+ n = tty_master->console->write ((void *) buf, (size_t) n);
+ tty_master->get_ttyp ()->write_error = n == -1 ? get_errno () : 0;
+ }
+}
+
+
+/* Process tty ioctl requests */
+
+static DWORD WINAPI
+process_ioctl (void *)
+{
+ while (1)
+ {
+ WaitForSingleObject (tty_master->ioctl_request_event, INFINITE);
+ termios_printf ("ioctl() request");
+ tty_master->get_ttyp ()->ioctl_retval =
+ tty_master->console->ioctl (tty_master->get_ttyp ()->cmd,
+ (void *) &tty_master->get_ttyp ()->arg);
+ SetEvent (tty_master->ioctl_done_event);
+ }
+}
+
+/**********************************************************************/
+/* Tty slave stuff */
+
+fhandler_tty_slave::fhandler_tty_slave ()
+ : fhandler_tty_common ()
+{
+ set_r_no_interrupt (1);
+}
+
+/* FIXME: This function needs to close handles when it has
+ a failing condition. */
+int
+fhandler_tty_slave::open (int flags, mode_t)
+{
+ if (get_device () == FH_TTY)
+ pc.dev.tty_to_real_device ();
+ fhandler_tty_slave *arch = (fhandler_tty_slave *)
+ cygheap->fdtab.find_archetype (pc.dev);
+ if (arch)
+ {
+ *this = *(fhandler_tty_slave *) arch;
+ termios_printf ("copied tty fhandler archetype");
+ cygheap->open_fhs++;
+ goto out;
+ }
+
+ tcinit (cygwin_shared->tty[get_unit ()]);
+
+ attach_tty (get_unit ());
+
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
+ /* Create synchronisation events */
+ char buf[40];
+
+ /* output_done_event may or may not exist. It will exist if the tty
+ was opened by fhandler_tty_master::init, normally called at
+ startup if use_tty is non-zero. It will not exist if this is a
+ pty opened by fhandler_pty_master::open. In the former case, tty
+ output is handled by a separate thread which controls output. */
+ __small_sprintf (buf, OUTPUT_DONE_EVENT, get_unit ());
+ output_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);
+
+ if (!(output_mutex = get_ttyp ()->open_output_mutex ()))
+ {
+ termios_printf ("open output mutex failed, %E");
+ __seterrno ();
+ return 0;
+ }
+ if (!(input_mutex = get_ttyp ()->open_input_mutex ()))
+ {
+ termios_printf ("open input mutex failed, %E");
+ __seterrno ();
+ return 0;
+ }
+ __small_sprintf (buf, INPUT_AVAILABLE_EVENT, get_unit ());
+ if (!(input_available_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf)))
+ {
+ termios_printf ("open input event failed, %E");
+ __seterrno ();
+ return 0;
+ }
+
+ /* The ioctl events may or may not exist. See output_done_event,
+ above. */
+ __small_sprintf (buf, IOCTL_REQUEST_EVENT, get_unit ());
+ ioctl_request_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);
+ __small_sprintf (buf, IOCTL_DONE_EVENT, get_unit ());
+ ioctl_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);
+
+ /* FIXME: Needs a method to eliminate tty races */
+ {
+ acquire_output_mutex (500);
+ inuse = get_ttyp ()->create_inuse (TTY_SLAVE_ALIVE);
+ get_ttyp ()->was_opened = true;
+ release_output_mutex ();
+ }
+
+ /* Duplicate tty handles. */
+
+ if (!get_ttyp ()->from_slave || !get_ttyp ()->to_slave)
+ {
+ termios_printf ("tty handles have been closed");
+ set_errno (EACCES);
+ return 0;
+ }
+
+ HANDLE from_master_local;
+ HANDLE to_master_local;
+ from_master_local = to_master_local = NULL;
+
+#ifdef USE_SERVER
+ if (!wincap.has_security ()
+ || cygserver_running == CYGSERVER_UNAVAIL
+ || !cygserver_attach_tty (&from_master_local, &to_master_local))
+#endif
+ {
+#ifdef USE_SERVER
+ termios_printf ("cannot dup handles via server. using old method.");
+#endif
+ HANDLE tty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE,
+ get_ttyp ()->master_pid);
+ termios_printf ("tty own handle %p",tty_owner);
+ if (tty_owner == NULL)
+ {
+ termios_printf ("can't open tty (%d) handle process %d",
+ get_unit (), get_ttyp ()->master_pid);
+ __seterrno ();
+ return 0;
+ }
+
+ if (!DuplicateHandle (tty_owner, get_ttyp ()->from_master,
+ hMainProc, &from_master_local, 0, TRUE,
+ DUPLICATE_SAME_ACCESS))
+ {
+ termios_printf ("can't duplicate input, %E");
+ __seterrno ();
+ return 0;
+ }
+
+ if (!DuplicateHandle (tty_owner, get_ttyp ()->to_master,
+ hMainProc, &to_master_local, 0, TRUE,
+ DUPLICATE_SAME_ACCESS))
+ {
+ termios_printf ("can't duplicate output, %E");
+ __seterrno ();
+ return 0;
+ }
+ CloseHandle (tty_owner);
+ }
+
+ termios_printf ("duplicated from_master %p->%p from tty_owner",
+ get_ttyp ()->from_master, from_master_local);
+ termios_printf ("duplicated to_master %p->%p from tty_owner",
+ get_ttyp ()->to_master, to_master_local);
+
+ set_io_handle (from_master_local);
+ set_output_handle (to_master_local);
+
+ set_open_status ();
+ if (cygheap->open_fhs++ == 0 && !GetConsoleCP () && !output_done_event
+ && wincap.pty_needs_alloc_console () && !GetProcessWindowStation ())
+ {
+ BOOL b;
+ HWINSTA h = CreateWindowStation (NULL, 0, GENERIC_READ | GENERIC_WRITE, &sec_none_nih);
+ termios_printf ("CreateWindowStation %p, %E", h);
+ if (h)
+ {
+ b = SetProcessWindowStation (h);
+ termios_printf ("SetProcessWindowStation %d, %E", b);
+ }
+ b = AllocConsole (); // will cause flashing if workstation
+ // stuff fails
+ termios_printf ("%d = AllocConsole (), %E", b);
+ if (b)
+ init_console_handler ();
+ }
+
+ // FIXME: Do this better someday
+ arch = (fhandler_tty_slave *) cmalloc (HEAP_ARCHETYPES, sizeof (*this));
+ *((fhandler_tty_slave **) cygheap->fdtab.add_archetype ()) = arch;
+ archetype = arch;
+ *arch = *this;
+
+out:
+ usecount = 0;
+ archetype->usecount++;
+ report_tty_counts (this, "opened", "incremented ", "");
+ myself->set_ctty (get_ttyp (), flags, arch);
+
+ return 1;
+}
+
+int
+fhandler_tty_slave::close ()
+{
+ if (!--cygheap->open_fhs && myself->ctty == -1)
+ FreeConsole ();
+
+ archetype->usecount--;
+ report_tty_counts (this, "closed", "decremented ", "");
+
+ if (archetype->usecount)
+ {
+#ifdef DEBUGGING
+ if (archetype->usecount < 0)
+ system_printf ("error: usecount %d", archetype->usecount);
+#endif
+ termios_printf ("just returning because archetype usecount is != 0");
+ return 0;
+ }
+
+ termios_printf ("closing last open %s handle", ttyname ());
+ return fhandler_tty_common::close ();
+}
+
+int
+fhandler_tty_slave::cygserver_attach_tty (LPHANDLE from_master_ptr,
+ LPHANDLE to_master_ptr)
+{
+#ifndef USE_SERVER
+ return 0;
+#else
+ if (!from_master_ptr || !to_master_ptr)
+ return 0;
+
+ client_request_attach_tty req ((DWORD) get_ttyp ()->master_pid,
+ (HANDLE) get_ttyp ()->from_master,
+ (HANDLE) get_ttyp ()->to_master);
+
+ if (req.make_request () == -1 || req.error_code ())
+ return 0;
+
+ *from_master_ptr = req.from_master ();
+ *to_master_ptr = req.to_master ();
+
+ return 1;
+#endif
+}
+
+void
+fhandler_tty_slave::init (HANDLE, DWORD a, mode_t)
+{
+ int flags = 0;
+
+ a &= GENERIC_READ | GENERIC_WRITE;
+ if (a == GENERIC_READ)
+ flags = O_RDONLY;
+ if (a == GENERIC_WRITE)
+ flags = O_WRONLY;
+ if (a == (GENERIC_READ | GENERIC_WRITE))
+ flags = O_RDWR;
+
+ open (flags);
+}
+
+int
+fhandler_tty_slave::write (const void *ptr, size_t len)
+{
+ DWORD n, towrite = len;
+
+ termios_printf ("tty%d, write(%x, %d)", get_unit (), ptr, len);
+
+ acquire_output_mutex (INFINITE);
+
+ while (len)
+ {
+ n = min (OUT_BUFFER_SIZE, len);
+ char *buf = (char *)ptr;
+ ptr = (char *) ptr + n;
+ len -= n;
+
+ /* Previous write may have set write_error to != 0. Check it here.
+ This is less than optimal, but the alternative slows down tty
+ writes enormously. */
+ if (get_ttyp ()->write_error)
+ {
+ set_errno (get_ttyp ()->write_error);
+ towrite = (DWORD) -1;
+ break;
+ }
+
+ if (WriteFile (get_output_handle (), buf, n, &n, NULL) == FALSE)
+ {
+ DWORD err = GetLastError ();
+ termios_printf ("WriteFile failed, %E");
+ switch (err)
+ {
+ case ERROR_NO_DATA:
+ err = ERROR_IO_DEVICE;
+ default:
+ __seterrno_from_win_error (err);
+ }
+ raise (SIGHUP); /* FIXME: Should this be SIGTTOU? */
+ towrite = (DWORD) -1;
+ break;
+ }
+
+ if (output_done_event != NULL)
+ {
+ DWORD rc;
+ DWORD x = n * 1000;
+ rc = WaitForSingleObject (output_done_event, x);
+ termios_printf ("waited %d ms for output_done_event, WFSO %d", x, rc);
+ }
+ }
+ release_output_mutex ();
+ return towrite;
+}
+
+void __stdcall
+fhandler_tty_slave::read (void *ptr, size_t& len)
+{
+ int totalread = 0;
+ int vmin = 0;
+ int vtime = 0; /* Initialized to prevent -Wuninitialized warning */
+ size_t readlen;
+ DWORD bytes_in_pipe;
+ char buf[INP_BUFFER_SIZE];
+ char peek_buf[INP_BUFFER_SIZE];
+ DWORD time_to_wait;
+ DWORD rc;
+ HANDLE w4[2];
+
+ termios_printf ("read(%x, %d) handle %p", ptr, len, get_handle ());
+
+ if (!ptr) /* Indicating tcflush(). */
+ time_to_wait = 0;
+ else if ((get_ttyp ()->ti.c_lflag & ICANON))
+ time_to_wait = INFINITE;
+ else
+ {
+ vmin = get_ttyp ()->ti.c_cc[VMIN];
+ if (vmin > INP_BUFFER_SIZE)
+ vmin = INP_BUFFER_SIZE;
+ vtime = get_ttyp ()->ti.c_cc[VTIME];
+ if (vmin < 0)
+ vmin = 0;
+ if (vtime < 0)
+ vtime = 0;
+ if (!vmin && !vtime)
+ time_to_wait = 0;
+ else
+ time_to_wait = !vtime ? INFINITE : 100 * vtime;
+ }
+
+ w4[0] = signal_arrived;
+ w4[1] = input_available_event;
+
+ DWORD waiter = !ptr ? 0 : INFINITE;
+ while (len)
+ {
+ rc = WaitForMultipleObjects (2, w4, FALSE, waiter);
+
+ if (rc == WAIT_TIMEOUT)
+ break;
+
+ if (rc == WAIT_FAILED)
+ {
+ termios_printf ("wait for input event failed, %E");
+ break;
+ }
+
+ if (rc == WAIT_OBJECT_0)
+ {
+ /* if we've received signal after successfully reading some data,
+ just return all data successfully read */
+ if (totalread > 0)
+ break;
+ set_sig_errno (EINTR);
+ len = (size_t) -1;
+ return;
+ }
+
+ rc = WaitForSingleObject (input_mutex, 1000);
+ if (rc == WAIT_FAILED)
+ {
+ termios_printf ("wait for input mutex failed, %E");
+ break;
+ }
+ else if (rc == WAIT_TIMEOUT)
+ {
+ termios_printf ("failed to acquire input mutex after input event arrived");
+ break;
+ }
+ if (!PeekNamedPipe (get_handle (), peek_buf, sizeof (peek_buf), &bytes_in_pipe, NULL, NULL))
+ {
+ termios_printf ("PeekNamedPipe failed, %E");
+ raise (SIGHUP);
+ bytes_in_pipe = 0;
+ }
+
+ /* On first peek determine no. of bytes to flush. */
+ if (!ptr && len == UINT_MAX)
+ len = (size_t) bytes_in_pipe;
+
+ if (ptr && !vmin && !time_to_wait)
+ {
+ ReleaseMutex (input_mutex);
+ len = (size_t) bytes_in_pipe;
+ return;
+ }
+
+ readlen = min (bytes_in_pipe, min (len, sizeof (buf)));
+
+ if (ptr && vmin && readlen > (unsigned) vmin)
+ readlen = vmin;
+
+ DWORD n = 0;
+ if (readlen)
+ {
+ termios_printf ("reading %d bytes (vtime %d)", readlen, vtime);
+ if (ReadFile (get_handle (), buf, readlen, &n, NULL) == FALSE)
+ {
+ termios_printf ("read failed, %E");
+ raise (SIGHUP);
+ }
+ /* MSDN states that 5th prameter can be used to determine total
+ number of bytes in pipe, but for some reason this number doesn't
+ change after successful read. So we have to peek into the pipe
+ again to see if input is still available */
+ if (!PeekNamedPipe (get_handle (), peek_buf, 1, &bytes_in_pipe, NULL, NULL))
+ {
+ termios_printf ("PeekNamedPipe failed, %E");
+ raise (SIGHUP);
+ bytes_in_pipe = 0;
+ }
+ if (n)
+ {
+ len -= n;
+ totalread += n;
+ if (ptr)
+ {
+ memcpy (ptr, buf, n);
+ ptr = (char *) ptr + n;
+ }
+ }
+ }
+
+ if (!bytes_in_pipe)
+ ResetEvent (input_available_event);
+
+ ReleaseMutex (input_mutex);
+
+ if (!ptr)
+ {
+ if (!bytes_in_pipe)
+ break;
+ continue;
+ }
+
+ if (get_ttyp ()->read_retval < 0) // read error
+ {
+ set_errno (-get_ttyp ()->read_retval);
+ totalread = -1;
+ break;
+ }
+ if (get_ttyp ()->read_retval == 0) //EOF
+ {
+ termios_printf ("saw EOF");
+ break;
+ }
+ if (get_ttyp ()->ti.c_lflag & ICANON || is_nonblocking ())
+ break;
+ if (vmin && totalread >= vmin)
+ break;
+
+ /* vmin == 0 && vtime == 0:
+ * we've already read all input, if any, so return immediately
+ * vmin == 0 && vtime > 0:
+ * we've waited for input 10*vtime ms in WFSO(input_available_event),
+ * no matter whether any input arrived, we shouldn't wait any longer,
+ * so return immediately
+ * vmin > 0 && vtime == 0:
+ * here, totalread < vmin, so continue waiting until more data
+ * arrive
+ * vmin > 0 && vtime > 0:
+ * similar to the previous here, totalread < vmin, and timer
+ * hadn't expired -- WFSO(input_available_event) != WAIT_TIMEOUT,
+ * so "restart timer" and wait until more data arrive
+ */
+
+ if (vmin == 0)
+ break;
+
+ if (n)
+ waiter = time_to_wait;
+ }
+ termios_printf ("%d=read(%x, %d)", totalread, ptr, len);
+ len = (size_t) totalread;
+ return;
+}
+
+int
+fhandler_tty_slave::dup (fhandler_base *child)
+{
+ fhandler_tty_slave *arch = (fhandler_tty_slave *) archetype;
+ *(fhandler_tty_slave *) child = *arch;
+ child->usecount = 0;
+ arch->usecount++;
+ cygheap->open_fhs++;
+ report_tty_counts (child, "duped", "incremented ", "");
+ myself->set_ctty (get_ttyp (), openflags, arch);
+ return 0;
+}
+
+int
+fhandler_tty_common::dup (fhandler_base *child)
+{
+ fhandler_tty_slave *fts = (fhandler_tty_slave *) child;
+ int errind;
+
+ fts->tcinit (get_ttyp ());
+
+ attach_tty (get_unit ());
+
+ HANDLE nh;
+
+ if (output_done_event == NULL)
+ fts->output_done_event = NULL;
+ else if (!DuplicateHandle (hMainProc, output_done_event, hMainProc,
+ &fts->output_done_event, 0, 1,
+ DUPLICATE_SAME_ACCESS))
+ {
+ errind = 1;
+ goto err;
+ }
+ if (ioctl_request_event == NULL)
+ fts->ioctl_request_event = NULL;
+ else if (!DuplicateHandle (hMainProc, ioctl_request_event, hMainProc,
+ &fts->ioctl_request_event, 0, 1,
+ DUPLICATE_SAME_ACCESS))
+ {
+ errind = 2;
+ goto err;
+ }
+ if (ioctl_done_event == NULL)
+ fts->ioctl_done_event = NULL;
+ else if (!DuplicateHandle (hMainProc, ioctl_done_event, hMainProc,
+ &fts->ioctl_done_event, 0, 1,
+ DUPLICATE_SAME_ACCESS))
+ {
+ errind = 3;
+ goto err;
+ }
+ if (!DuplicateHandle (hMainProc, input_available_event, hMainProc,
+ &fts->input_available_event, 0, 1,
+ DUPLICATE_SAME_ACCESS))
+ {
+ errind = 4;
+ goto err;
+ }
+ if (!DuplicateHandle (hMainProc, output_mutex, hMainProc,
+ &fts->output_mutex, 0, 1,
+ DUPLICATE_SAME_ACCESS))
+ {
+ errind = 5;
+ goto err;
+ }
+ if (!DuplicateHandle (hMainProc, input_mutex, hMainProc,
+ &fts->input_mutex, 0, 1,
+ DUPLICATE_SAME_ACCESS))
+ {
+ errind = 6;
+ goto err;
+ }
+ if (!DuplicateHandle (hMainProc, get_handle (), hMainProc,
+ &nh, 0, 1,
+ DUPLICATE_SAME_ACCESS))
+ {
+ errind = 7;
+ goto err;
+ }
+ fts->set_io_handle (nh);
+
+ if (!DuplicateHandle (hMainProc, get_output_handle (), hMainProc,
+ &nh, 0, 1,
+ DUPLICATE_SAME_ACCESS))
+ {
+ errind = 8;
+ goto err;
+ }
+ fts->set_output_handle (nh);
+
+ if (inuse == NULL)
+ fts->inuse = NULL;
+ else if (!DuplicateHandle (hMainProc, inuse, hMainProc,
+ &fts->inuse, 0, 1,
+ DUPLICATE_SAME_ACCESS))
+ {
+ errind = 9;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ __seterrno ();
+ termios_printf ("dup %d failed in DuplicateHandle, %E", errind);
+ return -1;
+}
+
+int
+fhandler_tty_slave::tcgetattr (struct termios *t)
+{
+ *t = get_ttyp ()->ti;
+ return 0;
+}
+
+int
+fhandler_tty_slave::tcsetattr (int, const struct termios *t)
+{
+ acquire_output_mutex (INFINITE);
+ get_ttyp ()->ti = *t;
+ release_output_mutex ();
+ return 0;
+}
+
+int
+fhandler_tty_slave::tcflush (int queue)
+{
+ int ret = 0;
+
+ termios_printf ("tcflush(%d) handle %p", queue, get_handle ());
+
+ if (queue == TCIFLUSH || queue == TCIOFLUSH)
+ {
+ size_t len = UINT_MAX;
+ read (NULL, len);
+ ret = len >= 0;
+ }
+ if (queue == TCOFLUSH || queue == TCIOFLUSH)
+ {
+ /* do nothing for now. */
+ }
+
+ termios_printf ("%d=tcflush(%d)", ret, queue);
+ return ret;
+}
+
+int
+fhandler_tty_slave::ioctl (unsigned int cmd, void *arg)
+{
+ termios_printf ("ioctl (%x)", cmd);
+
+ if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid
+ && myself->ctty == get_unit () && (get_ttyp ()->ti.c_lflag & TOSTOP))
+ {
+ /* background process */
+ termios_printf ("bg ioctl pgid %d, tpgid %d, ctty %d",
+ myself->pgid, get_ttyp ()->getpgid (), myself->ctty);
+ raise (SIGTTOU);
+ }
+
+ int retval;
+ switch (cmd)
+ {
+ case TIOCGWINSZ:
+ case TIOCSWINSZ:
+ case TIOCLINUX:
+ break;
+ case FIONBIO:
+ set_nonblocking (*(int *) arg);
+ retval = 0;
+ goto out;
+ default:
+ set_errno (EINVAL);
+ return -1;
+ }
+
+ acquire_output_mutex (INFINITE);
+
+ get_ttyp ()->cmd = cmd;
+ get_ttyp ()->ioctl_retval = 0;
+ switch (cmd)
+ {
+ case TIOCGWINSZ:
+ get_ttyp ()->arg.winsize = get_ttyp ()->winsize;
+ if (ioctl_request_event)
+ SetEvent (ioctl_request_event);
+ *(struct winsize *) arg = get_ttyp ()->arg.winsize;
+ if (ioctl_done_event)
+ WaitForSingleObject (ioctl_done_event, INFINITE);
+ get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
+ break;
+ case TIOCSWINSZ:
+ if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
+ || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
+ {
+ if (!ioctl_request_event)
+ get_ttyp ()->ioctl_retval = -EINVAL;
+ else
+ {
+ get_ttyp ()->arg.winsize = *(struct winsize *) arg;
+ SetEvent (ioctl_request_event);
+ get_ttyp ()->winsize = *(struct winsize *) arg;
+ killsys (-get_ttyp ()->getpgid (), SIGWINCH);
+ if (ioctl_done_event)
+ WaitForSingleObject (ioctl_done_event, INFINITE);
+ }
+ }
+ break;
+ case TIOCLINUX:
+ int val = *(unsigned char *) arg;
+ if (val != 6 || !ioctl_request_event || !ioctl_done_event)
+ get_ttyp ()->ioctl_retval = -EINVAL;
+ else
+ {
+ get_ttyp ()->arg.value = val;
+ SetEvent (ioctl_request_event);
+ WaitForSingleObject (ioctl_done_event, INFINITE);
+ *(unsigned char *) arg = get_ttyp ()->arg.value & 0xFF;
+ }
+ break;
+ }
+
+ release_output_mutex ();
+ retval = get_ttyp ()->ioctl_retval;
+ if (retval < 0)
+ {
+ set_errno (-retval);
+ retval = -1;
+ }
+
+out:
+ termios_printf ("%d = ioctl (%x)", retval, cmd);
+ return retval;
+}
+
+/*******************************************************
+ fhandler_pty_master
+*/
+fhandler_pty_master::fhandler_pty_master ()
+ : fhandler_tty_common ()
+{
+}
+
+int
+fhandler_pty_master::open (int flags, mode_t)
+{
+ int ntty = cygwin_shared->tty.allocate_tty (0);
+ if (ntty < 0)
+ return 0;
+
+ slave = *ttys_dev;
+ slave.setunit (ntty);
+ cygwin_shared->tty[ntty]->common_init (this);
+ inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE);
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
+ set_open_status ();
+
+ termios_printf ("opened pty master tty%d", get_unit ());
+ return 1;
+}
+
+int
+fhandler_tty_common::close ()
+{
+ termios_printf ("tty%d <%p,%p> closing", get_unit (), get_handle (), get_output_handle ());
+ if (output_done_event && !CloseHandle (output_done_event))
+ termios_printf ("CloseHandle (output_done_event), %E");
+ if (ioctl_done_event && !CloseHandle (ioctl_done_event))
+ termios_printf ("CloseHandle (ioctl_done_event), %E");
+ if (ioctl_request_event && !CloseHandle (ioctl_request_event))
+ termios_printf ("CloseHandle (ioctl_request_event), %E");
+ if (inuse && !CloseHandle (inuse))
+ termios_printf ("CloseHandle (inuse), %E");
+ if (!ForceCloseHandle (input_mutex))
+ termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex);
+ if (!ForceCloseHandle (output_mutex))
+ termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
+
+ /* Send EOF to slaves if master side is closed */
+ if (!get_ttyp ()->master_alive ())
+ {
+ termios_printf ("no more masters left. sending EOF");
+ SetEvent (input_available_event);
+ }
+
+ if (!ForceCloseHandle (input_available_event))
+ termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event);
+ if (!ForceCloseHandle1 (get_handle (), from_pty))
+ termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ());
+ if (!ForceCloseHandle1 (get_output_handle (), to_pty))
+ termios_printf ("CloseHandle (get_output_handle ()<%p>), %E", get_output_handle ());
+
+ inuse = NULL;
+ set_io_handle (NULL);
+ return 0;
+}
+
+int
+fhandler_pty_master::close ()
+{
+#if 0
+ while (accept_input () > 0)
+ continue;
+#endif
+ fhandler_tty_common::close ();
+
+ if (!get_ttyp ()->master_alive ())
+ {
+ termios_printf ("freeing tty%d (%d)", get_unit (), get_ttyp ()->ntty);
+#if 0
+ if (get_ttyp ()->to_slave)
+ ForceCloseHandle1 (get_ttyp ()->to_slave, to_slave);
+ if (get_ttyp ()->from_slave)
+ ForceCloseHandle1 (get_ttyp ()->from_slave, from_slave);
+#endif
+ if (get_ttyp ()->from_master)
+ CloseHandle (get_ttyp ()->from_master);
+ if (get_ttyp ()->to_master)
+ CloseHandle (get_ttyp ()->to_master);
+ get_ttyp ()->init ();
+ }
+
+ return 0;
+}
+
+int
+fhandler_pty_master::write (const void *ptr, size_t len)
+{
+ int i;
+ char *p = (char *) ptr;
+ termios ti = tc->ti;
+
+ for (i = 0; i < (int) len; i++)
+ {
+ line_edit_status status = line_edit (p++, 1, ti);
+ if (status > line_edit_signalled)
+ {
+ if (status != line_edit_pipe_full)
+ i = -1;
+ break;
+ }
+ }
+ return i;
+}
+
+void __stdcall
+fhandler_pty_master::read (void *ptr, size_t& len)
+{
+ len = (size_t) process_slave_output ((char *) ptr, len, pktmode);
+ return;
+}
+
+int
+fhandler_pty_master::tcgetattr (struct termios *t)
+{
+ *t = cygwin_shared->tty[get_unit ()]->ti;
+ return 0;
+}
+
+int
+fhandler_pty_master::tcsetattr (int, const struct termios *t)
+{
+ cygwin_shared->tty[get_unit ()]->ti = *t;
+ return 0;
+}
+
+int
+fhandler_pty_master::tcflush (int queue)
+{
+ int ret = 0;
+
+ termios_printf ("tcflush(%d) handle %p", queue, get_handle ());
+
+ if (queue == TCIFLUSH || queue == TCIOFLUSH)
+ ret = process_slave_output (NULL, OUT_BUFFER_SIZE, 0);
+ else if (queue == TCIFLUSH || queue == TCIOFLUSH)
+ {
+ /* do nothing for now. */
+ }
+
+ termios_printf ("%d=tcflush(%d)", ret, queue);
+ return ret;
+}
+
+int
+fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
+{
+ switch (cmd)
+ {
+ case TIOCPKT:
+ pktmode = *(int *) arg;
+ break;
+ case TIOCGWINSZ:
+ *(struct winsize *) arg = get_ttyp ()->winsize;
+ break;
+ case TIOCSWINSZ:
+ if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
+ || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
+ {
+ get_ttyp ()->winsize = *(struct winsize *) arg;
+ killsys (-get_ttyp ()->getpgid (), SIGWINCH);
+ }
+ break;
+ case FIONBIO:
+ set_nonblocking (*(int *) arg);
+ break;
+ default:
+ set_errno (EINVAL);
+ return -1;
+ }
+ return 0;
+}
+
+char *
+fhandler_pty_master::ptsname ()
+{
+ static char buf[32];
+
+ __small_sprintf (buf, "/dev/tty%d", get_unit ());
+ return buf;
+}
+
+void
+fhandler_tty_common::set_close_on_exec (int val)
+{
+ if (archetype)
+ set_close_on_exec_flag (val);
+ else
+ {
+ if (output_done_event)
+ set_inheritance (output_done_event, val);
+ if (ioctl_request_event)
+ set_inheritance (ioctl_request_event, val);
+ if (ioctl_done_event)
+ set_inheritance (ioctl_done_event, val);
+ if (inuse)
+ set_inheritance (inuse, val);
+ set_inheritance (output_mutex, val);
+ set_inheritance (input_mutex, val);
+ set_inheritance (input_available_event, val);
+ set_inheritance (output_handle, val);
+#ifndef DEBUGGING
+ fhandler_base::set_close_on_exec (val);
+#else
+ /* FIXME: This is a duplication from fhandler_base::set_close_on_exec.
+ It is here because we need to specify the "from_pty" stuff here or
+ we'll get warnings from ForceCloseHandle when debugging. */
+ set_inheritance (get_io_handle (), val);
+ set_close_on_exec_flag (val);
+#endif
+ }
+}
+
+void
+fhandler_tty_slave::fixup_after_fork (HANDLE parent)
+{
+ // fhandler_tty_common::fixup_after_fork (parent);
+ report_tty_counts (this, "inherited", "", "");
+}
+
+void
+fhandler_tty_common::fixup_after_fork (HANDLE parent)
+{
+ fhandler_termios::fixup_after_fork (parent);
+ if (output_done_event)
+ fork_fixup (parent, output_done_event, "output_done_event");
+ if (ioctl_request_event)
+ fork_fixup (parent, ioctl_request_event, "ioctl_request_event");
+ if (ioctl_done_event)
+ fork_fixup (parent, ioctl_done_event, "ioctl_done_event");
+ if (output_mutex)
+ fork_fixup (parent, output_mutex, "output_mutex");
+ if (input_mutex)
+ fork_fixup (parent, input_mutex, "input_mutex");
+ if (input_available_event)
+ fork_fixup (parent, input_available_event, "input_available_event");
+ fork_fixup (parent, inuse, "inuse");
+}
+
+void
+fhandler_pty_master::set_close_on_exec (int val)
+{
+ fhandler_tty_common::set_close_on_exec (val);
+
+ /* FIXME: There is a console handle leak here. */
+ if (get_ttyp ()->master_pid == GetCurrentProcessId ())
+ {
+ get_ttyp ()->from_slave = get_handle ();
+ get_ttyp ()->to_slave = get_output_handle ();
+ termios_printf ("from_slave %p, to_slave %p", get_handle (),
+ get_output_handle ());
+ }
+}
+
+int
+fhandler_tty_master::init_console ()
+{
+ console = (fhandler_console *) build_fh_dev (*console_dev, "/dev/ttym");
+ if (console == NULL)
+ return -1;
+
+ console->init (INVALID_HANDLE_VALUE, GENERIC_READ | GENERIC_WRITE, O_BINARY);
+ cygheap->open_fhs--; /* handled when individual fds are opened */
+ console->set_r_no_interrupt (1);
+ return 0;
+}
diff --git a/winsup/cygwin/gentls_offsets b/winsup/cygwin/gentls_offsets
new file mode 100755
index 00000000000..375b668408f
--- /dev/null
+++ b/winsup/cygwin/gentls_offsets
@@ -0,0 +1,79 @@
+#!/usr/bin/perl -s
+my $tls = shift;
+my $tls_out = shift;
+open(TLS, $tls) or die "$0: couldn't open tls file \"$tls\" - $!\n";
+my $struct = '';
+my @fields = ();
+my $def = '';
+$tls = join('', <TLS>);
+$tls =~ s/\n[^\n]*gentls_offsets[^\n]*\n(.+)\Z/$1/os;
+my $pre = $`;
+substr($tls, 0, length($pre)) = '';
+$pre =~ s/\n#ifndef _[^\n]+\n/\n/os;
+$pre .= "\n//*/";
+$tls =~ s%/\*\s*gentls_offsets.*?/\*\s*gentls_offsets\s*\*/%%ogs;
+foreach ($tls =~ /^.*\n/mg) {
+ $def .= $_ if $struct;
+ last if /^};/o;
+ /^\s*typedef/o and do {
+ $def .= $_ ;
+ next;
+ };
+ if (!s/;.*$//o) {
+ if (!$struct && /^\s*(?:struct|class)\s*([a-z_0-9]+)/o) {
+ $def .= $_;
+ $struct = $1
+ }
+ next;
+ }
+ s/(?:\[[^\]]*\]|struct|class)//o;
+ s/^\s+\S+\s+//o;
+ s/[\*\s()]+//go;
+ for my $f (split(/,/)) {
+ push(@fields, $f);
+ }
+}
+close TLS;
+open(TMP, '>', "/tmp/$$.cc") or die "$0: couldn't open temporary index file \"/tmp/$$.c\" - $!\n";
+print TMP <<EOF;
+#define __INSIDE_CYGWIN__
+#define __attribute__(X)
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+typedef void *HANDLE;
+$pre
+$def
+int
+main(int argc, char **argv)
+{
+ $struct foo[1];
+# define foo_end ((char *) (foo + 1))
+# define offset(f) (((char *) &(foo->f)) - foo_end)
+EOF
+ print TMP 'puts ("//;# autogenerated: Do not edit.\n");', "\n\n";
+ for my $f (@fields) {
+ print TMP ' printf ("//; $tls::', $f, ' = %d;\n", ', "offset($f));\n";
+ }
+ print TMP ' puts ("//; __DATA__\n");', "\n";
+ for my $f (@fields) {
+ print TMP ' printf ("#define tls_', $f, ' (%d)\n", ', "offset($f));\n";
+ }
+
+ print TMP <<EOF;
+
+ exit (0);
+}
+EOF
+close TMP;
+system @ARGV, '-o', "/tmp/$$-1.cc", '-E', "/tmp/$$.cc";
+system 'g++', '-o', "/tmp/$$.a.out", "/tmp/$$-1.cc" and
+($? == 127 && system 'c++', '-o', "/tmp/$$.a.out", "/tmp/$$-1.cc") and
+die "$0: couldn't generate executable for offset calculation \"/tmp/$$.a.out\" - $!\n";
+open(TLS_OUT, '>', $tls_out) or die "$0: couldn't open tls index file \"tls_out\" - $!\n";
+open(OFFS, "/tmp/$$.a.out|") or die "$0: couldn't run \"/tmp/$$.a.out\" - $!\n";
+print TLS_OUT <OFFS>;
+close OFFS;
+close TLS_OUT;
+unlink "/tmp/$$.cc", "/tmp/$$.a.out";
+exit(0);
diff --git a/winsup/cygwin/include/cygwin/signal.h b/winsup/cygwin/include/cygwin/signal.h
new file mode 100644
index 00000000000..5e26bf42ff3
--- /dev/null
+++ b/winsup/cygwin/include/cygwin/signal.h
@@ -0,0 +1,187 @@
+#ifndef _CYGWIN_SIGNAL_H
+#define _CYGWIN_SIGNAL_H
+
+#if 0
+struct ucontext
+{
+ unsigned long uc_flags;
+ void *uc_link;
+ stack_t uc_stack;
+ struct sigcontext uc_mcontext;
+ sigset_t uc_sigmask;
+};
+#endif
+
+typedef union sigval
+{
+ int sival_int; /* integer signal value */
+ void *sival_ptr; /* pointer signal value */
+} sigval_t;
+
+#pragma pack(push,4)
+typedef struct
+{
+ int si_signo; /* signal number */
+ int si_code; /* signal code */
+ pid_t si_pid; /* sender's pid */
+ uid_t si_uid; /* sender's uid */
+ int si_errno; /* errno associated with signal */
+
+ union
+ {
+ __uint32_t __pad[120]; /* plan for future growth */
+ union
+ {
+ /* timers */
+ struct
+ {
+ union
+ {
+ struct
+ {
+ unsigned int si_tid; /* timer id */
+ unsigned int si_overrun; /* overrun count */
+ };
+ };
+ sigval_t si_sigval; /* signal value */
+ };
+ };
+
+ /* SIGCHLD */
+ struct
+ {
+ int si_status; /* exit code */
+ clock_t si_utime; /* user time */
+ clock_t si_stime; /* system time */
+ };
+
+ /* core dumping signals */
+ void *si_addr; /* faulting address */
+ };
+} siginfo_t;
+#pragma pack(pop)
+
+enum
+{
+ SI_USER = 1, /* sent by kill, raise, pthread_kill */
+ SI_ASYNCIO, /* sent by AIO completion (currently
+ unimplemented) */
+ SI_MESGQ, /* sent by real time mesq state change
+ (currently unimplemented) */
+ SI_TIMER, /* sent by timer expiration */
+ SI_QUEUE, /* sent by sigqueue (currently
+ unimplemented) */
+ SI_KERNEL, /* sent by system */
+
+ ILL_ILLOPC, /* illegal opcode */
+ ILL_ILLOPN, /* illegal operand */
+ ILL_ILLADR, /* illegal addressing mode */
+ ILL_ILLTRP, /* illegal trap*/
+ ILL_PRVOPC, /* privileged opcode */
+ ILL_PRVREG, /* privileged register */
+ ILL_COPROC, /* coprocessor error */
+ ILL_BADSTK, /* internal stack error */
+
+ FPE_INTDIV, /* integer divide by zero */
+ FPE_INTOVF, /* integer overflow */
+ FPE_FLTDIV, /* floating point divide by zero */
+ FPE_FLTOVF, /* floating point overflow */
+ FPE_FLTUND, /* floating point underflow */
+ FPE_FLTRES, /* floating point inexact result */
+ FPE_FLTINV, /* floating point invalid operation */
+ FPE_FLTSUB, /* subscript out of range */
+
+ SEGV_MAPERR, /* address not mapped to object */
+ SEGV_ACCERR, /* invalid permissions for mapped object */
+
+ BUS_ADRALN, /* invalid address alignment. */
+ BUS_ADRERR, /* non-existant physical address. */
+ BUS_OBJERR, /* object specific hardware error. */
+
+ CLD_EXITED, /* child has exited */
+ CLD_KILLED, /* child was killed */
+ CLD_DUMPED, /* child terminated abnormally */
+ CLD_TRAPPED, /* traced child has trapped */
+ CLD_STOPPED, /* child has stopped */
+ CLD_CONTINUED /* stopped child has continued */
+};
+
+typedef struct sigevent
+{
+ sigval_t sigev_value; /* signal value */
+ int sigev_signo; /* signal number */
+ int sigev_notify; /* notification type */
+ void (*sigev_notify_function) (sigval_t); /* notification function */
+ pthread_attr_t *sigev_notify_attributes; /* notification attributes */
+} sigevent_t;
+
+enum
+{
+ SIGEV_SIGNAL = 0, /* a queued signal, with an application
+ defined value, is generated when the
+ event of interest occurs */
+ SIGEV_NONE, /* no asynchronous notification is
+ delivered when the event of interest
+ occurs */
+ SIGEV_THREAD /* a notification function is called to
+ perform notification */
+};
+
+typedef void (*_sig_func_ptr)(int);
+
+struct sigaction
+{
+ union
+ {
+ _sig_func_ptr sa_handler; /* SIG_DFL, SIG_IGN, or pointer to a function */
+ void (*sa_sigaction) ( int, siginfo_t *, void * );
+ };
+ sigset_t sa_mask;
+ int sa_flags;
+};
+
+#define SA_NOCLDSTOP 1 /* Do not generate SIGCHLD when children
+ stop */
+#define SA_SIGINFO 2 /* Invoke the signal catching function
+ with three arguments instead of one
+ */
+#define SA_RESTART 0x10000000 /* Restart syscall on signal return */
+#define SA_NODEFER 0x40000000 /* Don't automatically block the signal
+ when its handler is being executed */
+#define SA_RESETHAND 0x80000000 /* Reset to SIG_DFL on entry to handler */
+
+#define SIGHUP 1 /* hangup */
+#define SIGINT 2 /* interrupt */
+#define SIGQUIT 3 /* quit */
+#define SIGILL 4 /* illegal instruction (not reset when caught) */
+#define SIGTRAP 5 /* trace trap (not reset when caught) */
+#define SIGABRT 6 /* used by abort */
+#define SIGEMT 7 /* EMT instruction */
+#define SIGFPE 8 /* floating point exception */
+#define SIGKILL 9 /* kill (cannot be caught or ignored) */
+#define SIGBUS 10 /* bus error */
+#define SIGSEGV 11 /* segmentation violation */
+#define SIGSYS 12 /* bad argument to system call */
+#define SIGPIPE 13 /* write on a pipe with no one to read it */
+#define SIGALRM 14 /* alarm clock */
+#define SIGTERM 15 /* software termination signal from kill */
+#define SIGURG 16 /* urgent condition on IO channel */
+#define SIGSTOP 17 /* sendable stop signal not from tty */
+#define SIGTSTP 18 /* stop signal from tty */
+#define SIGCONT 19 /* continue a stopped process */
+#define SIGCHLD 20 /* to parent on child stop or exit */
+#define SIGCLD 20 /* System V name for SIGCHLD */
+#define SIGTTIN 21 /* to readers pgrp upon background tty read */
+#define SIGTTOU 22 /* like TTIN for output if (tp->t_local&LTOSTOP) */
+#define SIGIO 23 /* input/output possible signal */
+#define SIGPOLL SIGIO /* System V name for SIGIO */
+#define SIGXCPU 24 /* exceeded CPU time limit */
+#define SIGXFSZ 25 /* exceeded file size limit */
+#define SIGVTALRM 26 /* virtual time alarm */
+#define SIGPROF 27 /* profiling time alarm */
+#define SIGWINCH 28 /* window changed */
+#define SIGLOST 29 /* resource lost (eg, record-lock lost) */
+#define SIGUSR1 30 /* user defined signal 1 */
+#define SIGUSR2 31 /* user defined signal 2 */
+#define NSIG 32 /* signal 0 implied */
+#endif /*_CYGWIN_SIGNAL_H*/
diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc
new file mode 100644
index 00000000000..492ca3b24da
--- /dev/null
+++ b/winsup/cygwin/signal.cc
@@ -0,0 +1,507 @@
+/* signal.cc
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+
+ Written by Steve Chamberlain of Cygnus Support, sac@cygnus.com
+ Significant changes by Sergey Okhapkin <sos@prospect.com.ru>
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <stdlib.h>
+#include "cygerrno.h"
+#include <sys/cygwin.h>
+#include "pinfo.h"
+#include "sigproc.h"
+#include "hires.h"
+#include "security.h"
+#include "cygtls.h"
+
+int sigcatchers; /* FIXME: Not thread safe. */
+
+#define sigtrapped(func) ((func) != SIG_IGN && (func) != SIG_DFL)
+
+static inline void
+set_sigcatchers (void (*oldsig) (int), void (*cursig) (int))
+{
+#ifdef DEBUGGING
+ int last_sigcatchers = sigcatchers;
+#endif
+ if (!sigtrapped (oldsig) && sigtrapped (cursig))
+ sigcatchers++;
+ else if (sigtrapped (oldsig) && !sigtrapped (cursig))
+ sigcatchers--;
+#ifdef DEBUGGING
+ if (last_sigcatchers != sigcatchers)
+ sigproc_printf ("last %d, old %d, cur %p, cur %p", last_sigcatchers,
+ sigcatchers, oldsig, cursig);
+#endif
+}
+
+extern "C" _sig_func_ptr
+signal (int sig, _sig_func_ptr func)
+{
+ sig_dispatch_pending ();
+ _sig_func_ptr prev;
+
+ /* check that sig is in right range */
+ if (sig < 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP)
+ {
+ set_errno (EINVAL);
+ syscall_printf ("SIG_ERR = signal (%d, %p)", sig, func);
+ return (_sig_func_ptr) SIG_ERR;
+ }
+
+ prev = global_sigs[sig].sa_handler;
+ global_sigs[sig].sa_handler = func;
+ global_sigs[sig].sa_mask = 0;
+ /* SA_RESTART is set to maintain BSD compatible signal behaviour by default.
+ This is also compatible with the behaviour of signal(2) in Linux. */
+ global_sigs[sig].sa_flags |= SA_RESTART;
+ set_sigcatchers (prev, func);
+
+ syscall_printf ("%p = signal (%d, %p)", prev, sig, func);
+ return prev;
+}
+
+extern "C" int
+nanosleep (const struct timespec *rqtp, struct timespec *rmtp)
+{
+ int res = 0;
+ sig_dispatch_pending ();
+ pthread_testcancel ();
+
+ if ((unsigned int) rqtp->tv_sec > (HIRES_DELAY_MAX / 1000 - 1)
+ || (unsigned int) rqtp->tv_nsec > 999999999)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ DWORD resolution = gtod.resolution ();
+ DWORD req = ((rqtp->tv_sec * 1000 + (rqtp->tv_nsec + 999999) / 1000000
+ + resolution - 1) / resolution) * resolution;
+ DWORD end_time = gtod.dmsecs () + req;
+ syscall_printf ("nanosleep (%ld)", req);
+
+ int rc = pthread::cancelable_wait (signal_arrived, req);
+ DWORD rem;
+ if ((rem = end_time - gtod.dmsecs ()) > HIRES_DELAY_MAX)
+ rem = 0;
+ if (rc == WAIT_OBJECT_0)
+ {
+ (void) call_signal_handler_now ();
+ set_errno (EINTR);
+ res = -1;
+ }
+
+ if (rmtp)
+ {
+ rmtp->tv_sec = rem / 1000;
+ rmtp->tv_nsec = (rem % 1000) * 1000000;
+ }
+
+ syscall_printf ("%d = nanosleep (%ld, %ld)", res, req, rem);
+ return res;
+}
+
+extern "C" unsigned int
+sleep (unsigned int seconds)
+{
+ struct timespec req, rem;
+ req.tv_sec = seconds;
+ req.tv_nsec = 0;
+ nanosleep (&req, &rem);
+ return rem.tv_sec + (rem.tv_nsec > 0);
+}
+
+extern "C" unsigned int
+usleep (unsigned int useconds)
+{
+ struct timespec req;
+ req.tv_sec = useconds / 1000000;
+ req.tv_nsec = (useconds % 1000000) * 1000;
+ int res = nanosleep (&req, 0);
+ return res;
+}
+
+extern "C" int
+sigprocmask (int sig, const sigset_t *set, sigset_t *oldset)
+{
+ return handle_sigprocmask (sig, set, oldset, myself->getsigmask ());
+}
+
+int __stdcall
+handle_sigprocmask (int sig, const sigset_t *set, sigset_t *oldset, sigset_t& opmask)
+{
+ sig_dispatch_pending ();
+ /* check that sig is in right range */
+ if (sig < 0 || sig >= NSIG)
+ {
+ set_errno (ESRCH);
+ syscall_printf ("SIG_ERR = sigprocmask signal %d out of range", sig);
+ return -1;
+ }
+
+ if (oldset)
+ {
+ if (check_null_invalid_struct_errno (oldset))
+ return -1;
+ *oldset = opmask;
+ }
+
+ if (set)
+ {
+ if (check_invalid_read_struct_errno (set))
+ return -1;
+ sigset_t newmask = opmask;
+ switch (sig)
+ {
+ case SIG_BLOCK:
+ /* add set to current mask */
+ newmask |= *set;
+ break;
+ case SIG_UNBLOCK:
+ /* remove set from current mask */
+ newmask &= ~*set;
+ break;
+ case SIG_SETMASK:
+ /* just set it */
+ newmask = *set;
+ break;
+ default:
+ set_errno (EINVAL);
+ return -1;
+ }
+ (void) set_signal_mask (newmask, opmask);
+ }
+ return 0;
+}
+
+static int
+kill_worker (pid_t pid, siginfo_t& si)
+{
+ sig_dispatch_pending ();
+
+ int res = 0;
+ pinfo dest (pid);
+ bool sendSIGCONT;
+
+ if (!dest)
+ {
+ set_errno (ESRCH);
+ return -1;
+ }
+
+ if ((sendSIGCONT = (si.si_signo < 0)))
+ si.si_signo = -si.si_signo;
+
+ DWORD process_state = dest->process_state;
+ if (si.si_signo == 0)
+ {
+ res = proc_exists (dest) ? 0 : -1;
+ if (res < 0)
+ set_errno (ESRCH);
+ }
+ else if ((res = sig_send (dest, si)))
+ {
+ sigproc_printf ("%d = sig_send, %E ", res);
+ res = -1;
+ }
+ else if (sendSIGCONT)
+ {
+ siginfo_t si2;
+ si2.si_signo = SIGCONT;
+ si2.si_code = SI_KERNEL;
+ si2.si_pid = si2.si_uid = si2.si_errno = 0;
+ (void) sig_send (dest, si2);
+ }
+
+ syscall_printf ("%d = kill_worker (%d, %d), process_state %p", res, pid,
+ si.si_signo, process_state);
+ return res;
+}
+
+int
+raise (int sig)
+{
+ return kill (myself->pid, sig);
+}
+
+static int
+kill0 (pid_t pid, siginfo_t& si)
+{
+ syscall_printf ("kill (%d, %d)", pid, si.si_signo);
+ /* check that sig is in right range */
+ if (si.si_signo < 0 || si.si_signo >= NSIG)
+ {
+ set_errno (EINVAL);
+ syscall_printf ("signal %d out of range", si.si_signo);
+ return -1;
+ }
+
+ /* Silently ignore stop signals from a member of orphaned process group.
+ FIXME: Why??? */
+ if (ISSTATE (myself, PID_ORPHANED) &&
+ (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU))
+ si.si_signo = 0;
+
+ return (pid > 0) ? kill_worker (pid, si) : kill_pgrp (-pid, si);
+}
+
+int
+killsys (pid_t pid, int sig)
+{
+ siginfo_t si;
+ si.si_signo = sig;
+ si.si_code = SI_KERNEL;
+ si.si_pid = si.si_uid = si.si_errno = 0;
+ return kill0 (pid, si);
+}
+int
+kill (pid_t pid, int sig)
+{
+ siginfo_t si;
+ si.si_signo = sig;
+ si.si_code = SI_USER;
+ si.si_pid = si.si_uid = si.si_errno = 0;
+ return kill0 (pid, si);
+}
+
+int
+kill_pgrp (pid_t pid, siginfo_t& si)
+{
+ int res = 0;
+ int found = 0;
+ int killself = 0;
+
+ sigproc_printf ("pid %d, signal %d", pid, si.si_signo);
+
+ winpids pids ((DWORD) PID_MAP_RW);
+ for (unsigned i = 0; i < pids.npids; i++)
+ {
+ _pinfo *p = pids[i];
+
+ if (!proc_exists (p))
+ continue;
+
+ /* Is it a process we want to kill? */
+ if ((pid == 0 && (p->pgid != myself->pgid || p->ctty != myself->ctty)) ||
+ (pid > 1 && p->pgid != pid) ||
+ (si.si_signo < 0 && NOTSTATE (p, PID_STOPPED)))
+ continue;
+ sigproc_printf ("killing pid %d, pgrp %d, p->ctty %d, myself->ctty %d",
+ p->pid, p->pgid, p->ctty, myself->ctty);
+ if (p == myself)
+ killself++;
+ else if (kill_worker (p->pid, si))
+ res = -1;
+ found++;
+ }
+
+ if (killself && kill_worker (myself->pid, si))
+ res = -1;
+
+ if (!found)
+ {
+ set_errno (ESRCH);
+ res = -1;
+ }
+ syscall_printf ("%d = kill (%d, %d)", res, pid, si.si_signo);
+ return res;
+}
+
+extern "C" int
+killpg (pid_t pgrp, int sig)
+{
+ return kill (-pgrp, sig);
+}
+
+extern "C" void
+abort (void)
+{
+ sig_dispatch_pending ();
+ /* Flush all streams as per SUSv2.
+ From my reading of this document, this isn't strictly correct.
+ The streams are supposed to be flushed prior to exit. However,
+ if there is I/O in any signal handler that will not necessarily
+ be flushed.
+ However this is the way FreeBSD does it, and it is much easier to
+ do things this way, so... */
+ if (_REENT->__cleanup)
+ _REENT->__cleanup (_REENT);
+
+ /* Ensure that SIGABRT can be caught regardless of blockage. */
+ sigset_t sig_mask;
+ sigfillset (&sig_mask);
+ sigdelset (&sig_mask, SIGABRT);
+ set_signal_mask (sig_mask);
+
+ raise (SIGABRT);
+ (void) call_signal_handler_now (); /* Call any signal handler */
+ do_exit (1); /* signal handler didn't exit. Goodbye. */
+}
+
+extern "C" int
+sigaction (int sig, const struct sigaction *newact, struct sigaction *oldact)
+{
+ sig_dispatch_pending ();
+ sigproc_printf ("signal %d, newact %p, oldact %p", sig, newact, oldact);
+ /* check that sig is in right range */
+ if (sig < 0 || sig >= NSIG)
+ {
+ set_errno (EINVAL);
+ syscall_printf ("SIG_ERR = sigaction signal %d out of range", sig);
+ return -1;
+ }
+
+ struct sigaction oa = global_sigs[sig];
+
+ if (newact)
+ {
+ if (sig == SIGKILL || sig == SIGSTOP)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ global_sigs[sig] = *newact;
+ if (newact->sa_handler == SIG_IGN)
+ sig_clear (sig);
+ if (newact->sa_handler == SIG_DFL && sig == SIGCHLD)
+ sig_clear (sig);
+ set_sigcatchers (oa.sa_handler, newact->sa_handler);
+ if (sig == SIGCHLD)
+ {
+ myself->process_state &= ~PID_NOCLDSTOP;
+ if (newact->sa_flags & SA_NOCLDSTOP);
+ myself->process_state |= PID_NOCLDSTOP;
+ }
+ }
+
+ if (oldact)
+ *oldact = oa;
+
+ return 0;
+}
+
+extern "C" int
+sigaddset (sigset_t *set, const int sig)
+{
+ /* check that sig is in right range */
+ if (sig <= 0 || sig >= NSIG)
+ {
+ set_errno (EINVAL);
+ syscall_printf ("SIG_ERR = sigaddset signal %d out of range", sig);
+ return -1;
+ }
+
+ *set |= SIGTOMASK (sig);
+ return 0;
+}
+
+extern "C" int
+sigdelset (sigset_t *set, const int sig)
+{
+ /* check that sig is in right range */
+ if (sig <= 0 || sig >= NSIG)
+ {
+ set_errno (EINVAL);
+ syscall_printf ("SIG_ERR = sigdelset signal %d out of range", sig);
+ return -1;
+ }
+
+ *set &= ~SIGTOMASK (sig);
+ return 0;
+}
+
+extern "C" int
+sigismember (const sigset_t *set, int sig)
+{
+ /* check that sig is in right range */
+ if (sig <= 0 || sig >= NSIG)
+ {
+ set_errno (EINVAL);
+ syscall_printf ("SIG_ERR = sigdelset signal %d out of range", sig);
+ return -1;
+ }
+
+ if (*set & SIGTOMASK (sig))
+ return 1;
+ else
+ return 0;
+}
+
+extern "C" int
+sigemptyset (sigset_t *set)
+{
+ *set = (sigset_t) 0;
+ return 0;
+}
+
+extern "C" int
+sigfillset (sigset_t *set)
+{
+ *set = ~((sigset_t) 0);
+ return 0;
+}
+
+extern "C" int
+sigsuspend (const sigset_t *set)
+{
+ return handle_sigsuspend (*set);
+}
+
+extern "C" int
+sigpause (int signal_mask)
+{
+ return handle_sigsuspend ((sigset_t) signal_mask);
+}
+
+extern "C" int
+pause (void)
+{
+ return handle_sigsuspend (myself->getsigmask ());
+}
+
+extern "C" int
+siginterrupt (int sig, int flag)
+{
+ struct sigaction act;
+ (void) sigaction(sig, NULL, &act);
+ if (flag)
+ act.sa_flags &= ~SA_RESTART;
+ else
+ act.sa_flags |= SA_RESTART;
+ return sigaction (sig, &act, NULL);
+}
+
+
+extern "C" int
+sigwait (const sigset_t *set, int *sig)
+{
+ pthread_testcancel ();
+ _my_tls.event = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
+ if (!_my_tls.event)
+ {
+ __seterrno ();
+ return -1;
+ }
+
+ _my_tls.sigwait_mask = *set;
+
+ switch (WaitForSingleObject (_my_tls.event, INFINITE))
+ {
+ case WAIT_OBJECT_0:
+ CloseHandle (_my_tls.event);
+ _my_tls.event = NULL;
+ *sig = InterlockedExchange ((LONG *) &_my_tls.sig, (LONG) 0);
+ break;
+ default:
+ __seterrno ();
+ return -1;
+ }
+ return 0;
+}
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index e143a823963..70129f6c289 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -48,41 +48,22 @@ details. */
#define NZOMBIES 256
-struct sigelem
-{
- int sig;
- int pid;
- _threadinfo *tls;
- class sigelem *next;
- friend class pending_signals;
- friend int __stdcall sig_dispatch_pending ();
-};
-
class pending_signals
{
- sigelem sigs[NSIG + 1];
- sigelem start;
- sigelem *end;
- sigelem *prev;
- sigelem *curr;
+ sigpacket sigs[NSIG + 1];
+ sigpacket start;
+ sigpacket *end;
+ sigpacket *prev;
+ sigpacket *curr;
int empty;
public:
void reset () {curr = &start; prev = &start;}
- void add (int sig, int pid, _threadinfo *tls);
+ void add (sigpacket&);
void del ();
- sigelem *next ();
+ sigpacket *next ();
friend int __stdcall sig_dispatch_pending ();
};
-struct sigpacket
-{
- int sig;
- pid_t pid;
- HANDLE wakeup;
- sigset_t *mask;
- _threadinfo *tls;
-};
-
static pending_signals sigqueue;
struct sigaction *global_sigs;
@@ -563,9 +544,9 @@ sig_clear (int target_sig)
else
{
sigqueue.reset ();
- sigelem *q;
+ sigpacket *q;
while ((q = sigqueue.next ()))
- if (q->sig == target_sig)
+ if (q->si.si_signo == target_sig)
{
sigqueue.del ();
break;
@@ -670,13 +651,22 @@ sigproc_terminate (void)
return;
}
+int __stdcall
+sig_send (_pinfo *p, int sig)
+{
+ siginfo_t si;
+ si.si_signo = sig;
+ si.si_code = SI_KERNEL;
+ si.si_pid = si.si_uid = si.si_errno = 0;
+ return sig_send (p, si);
+}
+
/* Send a signal to another process by raising its signal semaphore.
- * If pinfo *p == NULL, send to the current process.
- * If sending to this process, wait for notification that a signal has
- * completed before returning.
- */
+ If pinfo *p == NULL, send to the current process.
+ If sending to this process, wait for notification that a signal has
+ completed before returning. */
int __stdcall
-sig_send (_pinfo *p, int sig, void *tls)
+sig_send (_pinfo *p, siginfo_t& si, _threadinfo *tls)
{
int rc = 1;
bool its_me;
@@ -703,11 +693,11 @@ sig_send (_pinfo *p, int sig, void *tls)
if (!proc_can_be_signalled (p)) /* Is the process accepting messages? */
{
sigproc_printf ("invalid pid %d(%x), signal %d",
- p->pid, p->process_state, sig);
+ p->pid, p->process_state, si.si_signo);
goto out;
}
- sigproc_printf ("pid %d, signal %d, its_me %d", p->pid, sig, its_me);
+ sigproc_printf ("pid %d, signal %d, its_me %d", p->pid, si.si_signo, its_me);
if (its_me)
{
@@ -740,14 +730,18 @@ sig_send (_pinfo *p, int sig, void *tls)
sigset_t pending;
if (!its_me)
pack.mask = NULL;
- else if (sig == __SIGPENDING)
+ else if (si.si_signo == __SIGPENDING)
pack.mask = &pending;
- else if (sig == __SIGFLUSH || sig > 0)
+ else if (si.si_signo == __SIGFLUSH || si.si_signo > 0)
pack.mask = &myself->getsigmask ();
else
pack.mask = NULL;
- pack.sig = sig;
+ pack.si = si;
+ if (!pack.si.si_pid)
+ pack.si.si_pid = myself->pid;
+ if (!pack.si.si_uid)
+ pack.si.si_uid = myself->uid;
pack.pid = myself->pid;
pack.tls = (_threadinfo *) tls;
DWORD nb;
@@ -767,7 +761,7 @@ sig_send (_pinfo *p, int sig, void *tls)
sigproc_printf ("I'm going away now");
else
system_printf ("error sending signal %d to pid %d, pipe handle %p, %E",
- sig, p->pid, sendsig);
+ si.si_signo, p->pid, sendsig);
}
goto out;
}
@@ -787,7 +781,8 @@ sig_send (_pinfo *p, int sig, void *tls)
else
{
rc = WAIT_OBJECT_0;
- sigproc_printf ("Not waiting for sigcomplete. its_me %d signal %d", its_me, sig);
+ sigproc_printf ("Not waiting for sigcomplete. its_me %d signal %d",
+ its_me, si.si_signo);
if (!its_me)
ForceCloseHandle (sendsig);
}
@@ -798,7 +793,7 @@ sig_send (_pinfo *p, int sig, void *tls)
{
if (!no_signals_available ())
system_printf ("wait for sig_complete event failed, signal %d, rc %d, %E",
- sig, rc);
+ si.si_signo, rc);
set_errno (ENOSYS);
rc = -1;
}
@@ -807,13 +802,13 @@ sig_send (_pinfo *p, int sig, void *tls)
call_signal_handler_now ();
out:
- if (sig != __SIGPENDING)
+ if (si.si_signo != __SIGPENDING)
/* nothing */;
else if (!rc)
rc = (int) pending;
else
rc = SIG_BAD_MASK;
- sigproc_printf ("returning %p from sending signal %d", rc, sig);
+ sigproc_printf ("returning %p from sending signal %d", rc, si.si_signo);
return rc;
}
@@ -1009,20 +1004,20 @@ talktome ()
has been handled, as per POSIX. */
void
-pending_signals::add (int sig, int pid, _threadinfo *tls)
+pending_signals::add (sigpacket& pack)
{
- sigelem *se;
+ sigpacket *se;
for (se = start.next; se; se = se->next)
- if (se->sig == sig)
+ if (se->si.si_signo == pack.si.si_signo)
return;
- while (sigs[empty].sig)
+ while (sigs[empty].si.si_signo)
if (++empty == NSIG)
empty = 0;
se = sigs + empty;
- se->sig = sig;
+ *se = pack;
+ se->mask_storage = *(pack.mask);
+ se->mask = &se->mask_storage;
se->next = NULL;
- se->tls = tls;
- se->pid = pid;
if (end)
end->next = se;
end = se;
@@ -1034,9 +1029,9 @@ pending_signals::add (int sig, int pid, _threadinfo *tls)
void
pending_signals::del ()
{
- sigelem *next = curr->next;
+ sigpacket *next = curr->next;
prev->next = next;
- curr->sig = 0;
+ curr->si.si_signo = 0;
#ifdef DEBUGGING
curr->next = NULL;
#endif
@@ -1046,10 +1041,10 @@ pending_signals::del ()
curr = next;
}
-sigelem *
+sigpacket *
pending_signals::next ()
{
- sigelem *res;
+ sigpacket *res;
prev = curr;
if (!curr || !(curr = curr->next))
res = NULL;
@@ -1125,7 +1120,7 @@ wait_sig (VOID *self)
continue;
}
- if (!pack.sig)
+ if (!pack.si.si_signo)
{
#ifdef DEBUGGING
system_printf ("zero signal?");
@@ -1140,8 +1135,8 @@ wait_sig (VOID *self)
pack.mask = &dummy_mask;
}
- sigelem *q;
- switch (pack.sig)
+ sigpacket *q;
+ switch (pack.si.si_signo)
{
case __SIGCOMMUNE:
talktome ();
@@ -1154,30 +1149,30 @@ wait_sig (VOID *self)
unsigned bit;
sigqueue.reset ();
while ((q = sigqueue.next ()))
- if (myself->getsigmask () & (bit = SIGTOMASK (q->sig)))
+ if (myself->getsigmask () & (bit = SIGTOMASK (q->si.si_signo)))
*pack.mask |= bit;
break;
case __SIGFLUSH:
sigqueue.reset ();
while ((q = sigqueue.next ()))
- if (sig_handle (q->sig, *pack.mask, q->pid, q->tls) > 0)
+ if (q->process () > 0)
sigqueue.del ();
break;
default:
- if (pack.sig < 0)
- sig_clear (-pack.sig);
+ if (pack.si.si_signo < 0)
+ sig_clear (-pack.si.si_signo);
else
{
- int sigres = sig_handle (pack.sig, *pack.mask, pack.pid, pack.tls);
+ int sigres = pack.process ();
if (sigres <= 0)
{
#ifdef DEBUGGING2
if (!sigres)
system_printf ("Failed to arm signal %d from pid %d", pack.sig, pack.pid);
#endif
- sigqueue.add (pack.sig, pack.pid, pack.tls);// FIXME: Shouldn't add this in !sh condition
+ sigqueue.add (pack); // FIXME: Shouldn't add this in !sh condition
}
- if (pack.sig == SIGCHLD)
+ if (pack.si.si_signo == SIGCHLD)
proc_subproc (PROC_CLEARWAIT, 0);
}
break;
@@ -1245,6 +1240,13 @@ wait_subproc (VOID *)
rc -= WAIT_OBJECT_0;
if (rc-- != 0)
{
+ siginfo_t si;
+ si.si_signo = SIGCHLD;
+ si.si_code = SI_KERNEL;
+ si.si_pid = pchildren[rc]->pid;
+ si.si_uid = pchildren[rc]->uid;
+ si.si_errno = 0;
+ si.si_status = si.si_utime = si.si_stime = 0; // FIXME fill these in someday
rc = proc_subproc (PROC_CHILDTERMINATED, rc);
if (!proc_loop_wait) // Don't bother if wait_subproc is
break; // exiting
@@ -1253,7 +1255,7 @@ wait_subproc (VOID *)
to avoid the proc_subproc lock since the signal thread will eventually
be calling proc_subproc and could unnecessarily block. */
if (rc)
- sig_send (myself_nowait, SIGCHLD);
+ sig_send (myself_nowait, si);
}
sigproc_printf ("looping");
}
diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h
new file mode 100644
index 00000000000..03ee1b89b1f
--- /dev/null
+++ b/winsup/cygwin/sigproc.h
@@ -0,0 +1,110 @@
+/* sigproc.h
+
+ Copyright 1997, 1998, 2000, 2001, 2002, 2003 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _SIGPROC_H
+#define _SIGPROC_H
+#include <signal.h>
+
+#define EXIT_SIGNAL 0x010000
+#define EXIT_REPARENTING 0x020000
+#define EXIT_NOCLOSEALL 0x040000
+
+#ifdef NSIG
+enum
+{
+ __SIGFLUSH = -(NSIG + 1),
+ __SIGSTRACE = -(NSIG + 2),
+ __SIGCOMMUNE = -(NSIG + 3),
+ __SIGPENDING = -(NSIG + 4)
+};
+#endif
+
+#define SIG_BAD_MASK (1 << (SIGKILL - 1))
+
+enum procstuff
+{
+ PROC_ADDCHILD = 1, // add a new subprocess to list
+ PROC_CHILDTERMINATED = 2, // a child died
+ PROC_CLEARWAIT = 3, // clear all waits - signal arrived
+ PROC_WAIT = 4, // setup for wait() for subproc
+ PROC_NOTHING = 5 // nothing, really
+};
+
+typedef struct struct_waitq
+{
+ int pid;
+ int options;
+ int status;
+ HANDLE ev;
+ void *rusage; /* pointer to potential rusage */
+ struct struct_waitq *next;
+ HANDLE thread_ev;
+} waitq;
+
+struct sigpacket
+{
+ siginfo_t si;
+ pid_t pid;
+ class _threadinfo *tls;
+ sigset_t *mask;
+ sigset_t mask_storage;
+ union
+ {
+ HANDLE wakeup;
+ struct sigpacket *next;
+ };
+ int __stdcall process () __attribute__ ((regparm (1)));
+};
+
+extern HANDLE signal_arrived;
+extern HANDLE sigCONT;
+
+bool __stdcall my_parent_is_alive ();
+int __stdcall sig_dispatch_pending ();
+#ifdef _PINFO_H
+extern "C" void __stdcall set_signal_mask (sigset_t newmask, sigset_t = myself->getsigmask ());
+#endif
+int __stdcall handle_sigprocmask (int sig, const sigset_t *set,
+ sigset_t *oldset, sigset_t& opmask)
+ __attribute__ ((regparm (3)));
+
+extern "C" void __stdcall reset_signal_arrived ();
+extern "C" int __stdcall call_signal_handler_now ();
+void __stdcall sig_clear (int) __attribute__ ((regparm (1)));
+void __stdcall sig_set_pending (int) __attribute__ ((regparm (1)));
+int __stdcall handle_sigsuspend (sigset_t);
+
+int __stdcall proc_subproc (DWORD, DWORD) __attribute__ ((regparm (2)));
+
+class _pinfo;
+void __stdcall proc_terminate ();
+void __stdcall sigproc_init ();
+void __stdcall subproc_init ();
+void __stdcall sigproc_terminate ();
+bool __stdcall proc_exists (_pinfo *) __attribute__ ((regparm(1)));
+bool __stdcall pid_exists (pid_t) __attribute__ ((regparm(1)));
+int __stdcall sig_send (_pinfo *, siginfo_t&, class _threadinfo *tls = NULL) __attribute__ ((regparm (3)));
+int __stdcall sig_send (_pinfo *, int) __attribute__ ((regparm (2)));
+void __stdcall signal_fixup_after_fork ();
+void __stdcall signal_fixup_after_exec ();
+void __stdcall wait_for_sigthread ();
+void __stdcall sigalloc ();
+
+int kill_pgrp (pid_t, siginfo_t&);
+int killsys (pid_t, int);
+
+extern char myself_nowait_dummy[];
+
+extern struct sigaction *global_sigs;
+
+#define WAIT_SIG_PRIORITY THREAD_PRIORITY_TIME_CRITICAL
+
+#define myself_nowait ((_pinfo *)myself_nowait_dummy)
+#endif /*_SIGPROC_H*/
diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc
index ae03dc6266b..0b1782530fb 100644
--- a/winsup/cygwin/thread.cc
+++ b/winsup/cygwin/thread.cc
@@ -2736,7 +2736,11 @@ pthread_kill (pthread_t thread, int sig)
if (!pthread::is_good_object (&thread))
return EINVAL;
- int rval = sig ? sig_send (NULL, sig, thread->cygtls) : 0;
+ siginfo_t si;
+ si.si_signo = sig;
+ si.si_code = SI_USER;
+ si.si_pid = si.si_uid = si.si_errno = 0;
+ int rval = sig ? sig_send (NULL, si, thread->cygtls) : 0;
// unlock myself
return rval;
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index 6c2e58fafa6..f8bb9ec94be 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -318,10 +318,6 @@ int cygwin_select (int , fd_set *, fd_set *, fd_set *,
struct timeval *to);
int cygwin_gethostname (char *__name, size_t __len);
-int kill_pgrp (pid_t, int);
-int _kill (int, int);
-int _raise (int sig);
-
extern DWORD binmode;
extern char _data_start__, _data_end__, _bss_start__, _bss_end__;
extern void (*__CTOR_LIST__) (void);