summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/fhandler.h30
-rw-r--r--winsup/cygwin/fhandler_tty.cc154
2 files changed, 128 insertions, 56 deletions
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index a0c6645fb..e1829e28f 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2274,8 +2274,9 @@ class fhandler_pty_common: public fhandler_termios
void resize_pseudo_console (struct winsize *);
protected:
- BOOL process_opost_output (HANDLE h,
- const void *ptr, ssize_t& len, bool is_echo);
+ static BOOL process_opost_output (HANDLE h, const void *ptr, ssize_t& len,
+ bool is_echo, tty *ttyp,
+ bool is_nonblocking);
};
class fhandler_pty_slave: public fhandler_pty_common
@@ -2352,6 +2353,24 @@ class fhandler_pty_slave: public fhandler_pty_common
#define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
class fhandler_pty_master: public fhandler_pty_common
{
+public:
+ /* Parameter set for the static function pty_master_thread() */
+ struct master_thread_param_t {
+ HANDLE from_master;
+ HANDLE from_master_cyg;
+ HANDLE to_master;
+ HANDLE to_master_cyg;
+ HANDLE master_ctl;
+ HANDLE input_available_event;
+ };
+ /* Parameter set for the static function pty_master_fwd_thread() */
+ struct master_fwd_thread_param_t {
+ HANDLE to_master_cyg;
+ HANDLE from_slave;
+ HANDLE output_mutex;
+ tty *ttyp;
+ };
+private:
int pktmode; // non-zero if pty in a packet mode.
HANDLE master_ctl; // Control socket for handle duplication
cygthread *master_thread; // Master control thread
@@ -2360,14 +2379,15 @@ class fhandler_pty_master: public fhandler_pty_common
DWORD dwProcessId; // Owner of master handles
HANDLE to_master_cyg, from_master_cyg;
cygthread *master_fwd_thread; // Master forwarding thread
+ HANDLE thread_param_copied_event;
public:
HANDLE get_echo_handle () const { return echo_r; }
/* Constructor */
fhandler_pty_master (int);
- DWORD pty_master_thread ();
- DWORD pty_master_fwd_thread ();
+ static DWORD pty_master_thread (const master_thread_param_t *p);
+ static DWORD pty_master_fwd_thread (const master_fwd_thread_param_t *p);
int process_slave_output (char *buf, size_t len, int pktmode_on);
void doecho (const void *str, DWORD len);
int accept_input ();
@@ -2410,6 +2430,8 @@ public:
return fh;
}
bool to_be_read_from_pcon (void);
+ void get_master_thread_param (master_thread_param_t *p);
+ void get_master_fwd_thread_param (master_fwd_thread_param_t *p);
};
class fhandler_dev_null: public fhandler_base
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 1ed6e2ac6..29870c779 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -293,7 +293,8 @@ fhandler_pty_master::doecho (const void *str, DWORD len)
{
ssize_t towrite = len;
acquire_output_mutex (INFINITE);
- if (!process_opost_output (echo_w, str, towrite, true))
+ if (!process_opost_output (echo_w, str, towrite, true,
+ get_ttyp (), is_nonblocking ()))
termios_printf ("Write to echo pipe failed, %E");
release_output_mutex ();
}
@@ -866,7 +867,8 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
reset_switch_to_pcon ();
acquire_output_mutex (INFINITE);
- if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false))
+ if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false,
+ get_ttyp (), is_nonblocking ()))
{
DWORD err = GetLastError ();
termios_printf ("WriteFile failed, %E");
@@ -1947,8 +1949,15 @@ fhandler_pty_slave::fixup_after_exec ()
calls to CallNamedPipe should have a big enough timeout value. For now this
is 500ms. Hope that's enough. */
+/* The function pty_master_thread() should be static because the instance
+ is deleted if the master is dup()'ed and the original is closed. In
+ this case, dup()'ed instance still exists, therefore, master thread
+ is also still alive even though the instance has been deleted. As a
+ result, accesing member variables in this function causes access
+ violation. */
+
DWORD
-fhandler_pty_master::pty_master_thread ()
+fhandler_pty_master::pty_master_thread (const master_thread_param_t *p)
{
bool exit = false;
GENERIC_MAPPING map = { EVENT_QUERY_STATE, EVENT_MODIFY_STATE, 0,
@@ -1962,7 +1971,7 @@ fhandler_pty_master::pty_master_thread ()
NTSTATUS status;
termios_printf ("Entered");
- while (!exit && (ConnectNamedPipe (master_ctl, NULL)
+ while (!exit && (ConnectNamedPipe (p->master_ctl, NULL)
|| GetLastError () == ERROR_PIPE_CONNECTED))
{
pipe_reply repl = { NULL, NULL, NULL, NULL, 0 };
@@ -1971,21 +1980,21 @@ fhandler_pty_master::pty_master_thread ()
ACCESS_MASK access = EVENT_MODIFY_STATE;
HANDLE client = NULL;
- if (!ReadFile (master_ctl, &req, sizeof req, &len, NULL))
+ if (!ReadFile (p->master_ctl, &req, sizeof req, &len, NULL))
{
termios_printf ("ReadFile, %E");
goto reply;
}
- if (!GetNamedPipeClientProcessId (master_ctl, &pid))
+ if (!GetNamedPipeClientProcessId (p->master_ctl, &pid))
pid = req.pid;
- if (get_object_sd (input_available_event, sd))
+ if (get_object_sd (p->input_available_event, sd))
{
termios_printf ("get_object_sd, %E");
goto reply;
}
cygheap->user.deimpersonate ();
deimp = true;
- if (!ImpersonateNamedPipeClient (master_ctl))
+ if (!ImpersonateNamedPipeClient (p->master_ctl))
{
termios_printf ("ImpersonateNamedPipeClient, %E");
goto reply;
@@ -2028,28 +2037,28 @@ fhandler_pty_master::pty_master_thread ()
termios_printf ("OpenProcess, %E");
goto reply;
}
- if (!DuplicateHandle (GetCurrentProcess (), from_master,
+ if (!DuplicateHandle (GetCurrentProcess (), p->from_master,
client, &repl.from_master,
0, TRUE, DUPLICATE_SAME_ACCESS))
{
termios_printf ("DuplicateHandle (from_master), %E");
goto reply;
}
- if (!DuplicateHandle (GetCurrentProcess (), from_master_cyg,
+ if (!DuplicateHandle (GetCurrentProcess (), p->from_master_cyg,
client, &repl.from_master_cyg,
0, TRUE, DUPLICATE_SAME_ACCESS))
{
termios_printf ("DuplicateHandle (from_master_cyg), %E");
goto reply;
}
- if (!DuplicateHandle (GetCurrentProcess (), to_master,
+ if (!DuplicateHandle (GetCurrentProcess (), p->to_master,
client, &repl.to_master,
0, TRUE, DUPLICATE_SAME_ACCESS))
{
termios_printf ("DuplicateHandle (to_master), %E");
goto reply;
}
- if (!DuplicateHandle (GetCurrentProcess (), to_master_cyg,
+ if (!DuplicateHandle (GetCurrentProcess (), p->to_master_cyg,
client, &repl.to_master_cyg,
0, TRUE, DUPLICATE_SAME_ACCESS))
{
@@ -2066,9 +2075,9 @@ reply:
sd.free ();
termios_printf ("Reply: from %p, to %p, error %u",
repl.from_master, repl.to_master, repl.error );
- if (!WriteFile (master_ctl, &repl, sizeof repl, &len, NULL))
+ if (!WriteFile (p->master_ctl, &repl, sizeof repl, &len, NULL))
termios_printf ("WriteFile, %E");
- if (!DisconnectNamedPipe (master_ctl))
+ if (!DisconnectNamedPipe (p->master_ctl))
termios_printf ("DisconnectNamedPipe, %E");
}
termios_printf ("Leaving");
@@ -2078,11 +2087,20 @@ reply:
static DWORD WINAPI
pty_master_thread (VOID *arg)
{
- return ((fhandler_pty_master *) arg)->pty_master_thread ();
+ fhandler_pty_master::master_thread_param_t p;
+ ((fhandler_pty_master *) arg)->get_master_thread_param (&p);
+ return fhandler_pty_master::pty_master_thread (&p);
}
+/* The function pty_master_fwd_thread() should be static because the
+ instance is deleted if the master is dup()'ed and the original is
+ closed. In this case, dup()'ed instance still exists, therefore,
+ master forwarding thread is also still alive even though the instance
+ has been deleted. As a result, accesing member variables in this
+ function causes access violation. */
+
DWORD
-fhandler_pty_master::pty_master_fwd_thread ()
+fhandler_pty_master::pty_master_fwd_thread (const master_fwd_thread_param_t *p)
{
DWORD rlen;
tmp_pathbuf tp;
@@ -2093,17 +2111,17 @@ fhandler_pty_master::pty_master_fwd_thread ()
termios_printf ("Started.");
for (;;)
{
- get_ttyp ()->pcon_last_time = GetTickCount ();
- if (!ReadFile (from_slave, outbuf, NT_MAX_PATH, &rlen, NULL))
+ p->ttyp->pcon_last_time = GetTickCount ();
+ if (!ReadFile (p->from_slave, outbuf, NT_MAX_PATH, &rlen, NULL))
{
termios_printf ("ReadFile for forwarding failed, %E");
break;
}
ssize_t wlen = rlen;
char *ptr = outbuf;
- if (get_ttyp ()->h_pseudo_console)
+ if (p->ttyp->h_pseudo_console)
{
- if (!get_ttyp ()->has_set_title)
+ if (!p->ttyp->has_set_title)
{
/* Remove Set title sequence */
char *p0, *p1;
@@ -2175,10 +2193,10 @@ fhandler_pty_master::pty_master_fwd_thread ()
else
state = 0;
- if (get_ttyp ()->term_code_page != CP_UTF8)
+ if (p->ttyp->term_code_page != CP_UTF8)
{
size_t nlen = NT_MAX_PATH;
- convert_mb_str (get_ttyp ()->term_code_page, mbbuf, &nlen,
+ convert_mb_str (p->ttyp->term_code_page, mbbuf, &nlen,
CP_UTF8, ptr, wlen, &mbp);
ptr = mbbuf;
@@ -2190,7 +2208,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
DWORD written;
while (rlen>0)
{
- if (!WriteFile (to_master_cyg, ptr, wlen, &written, NULL))
+ if (!WriteFile (p->to_master_cyg, ptr, wlen, &written, NULL))
{
termios_printf ("WriteFile for forwarding failed, %E");
break;
@@ -2202,7 +2220,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
}
UINT cp_from;
- pinfo pinfo_target = pinfo (get_ttyp ()->invisible_console_pid);
+ pinfo pinfo_target = pinfo (p->ttyp->invisible_console_pid);
DWORD target_pid = 0;
if (pinfo_target)
target_pid = pinfo_target->dwProcessId;
@@ -2227,20 +2245,21 @@ fhandler_pty_master::pty_master_fwd_thread ()
else
cp_from = GetConsoleOutputCP ();
- if (get_ttyp ()->term_code_page != cp_from)
+ if (p->ttyp->term_code_page != cp_from)
{
size_t nlen = NT_MAX_PATH;
- convert_mb_str (get_ttyp ()->term_code_page, mbbuf, &nlen,
+ convert_mb_str (p->ttyp->term_code_page, mbbuf, &nlen,
cp_from, ptr, wlen, &mbp);
ptr = mbbuf;
wlen = rlen = nlen;
}
- acquire_output_mutex (INFINITE);
+ WaitForSingleObject (p->output_mutex, INFINITE);
while (rlen>0)
{
- if (!process_opost_output (to_master_cyg, ptr, wlen, false))
+ if (!process_opost_output (p->to_master_cyg, ptr, wlen, false,
+ p->ttyp, false))
{
termios_printf ("WriteFile for forwarding failed, %E");
break;
@@ -2248,7 +2267,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
ptr += wlen;
wlen = (rlen -= wlen);
}
- release_output_mutex ();
+ ReleaseMutex (p->output_mutex);
}
return 0;
}
@@ -2256,7 +2275,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
static DWORD WINAPI
pty_master_fwd_thread (VOID *arg)
{
- return ((fhandler_pty_master *) arg)->pty_master_fwd_thread ();
+ fhandler_pty_master::master_fwd_thread_param_t p;
+ ((fhandler_pty_master *) arg)->get_master_fwd_thread_param (&p);
+ return fhandler_pty_master::pty_master_fwd_thread (&p);
}
bool
@@ -2304,6 +2325,15 @@ fhandler_pty_master::setup ()
goto err;
}
+ __small_sprintf (pipename, "pty%d-to-slave", unit);
+ res = fhandler_pipe::create (&sec_none, &from_master, &to_slave,
+ fhandler_pty_common::pipesize, pipename, 0);
+ if (res)
+ {
+ errstr = "input pipe";
+ goto err;
+ }
+
ProtectHandle1 (from_slave, from_pty);
__small_sprintf (pipename, "pty%d-echoloop", unit);
@@ -2358,27 +2388,23 @@ fhandler_pty_master::setup ()
errstr = "pty master control pipe";
goto err;
}
+
+ thread_param_copied_event = CreateEvent(NULL, FALSE, FALSE, NULL);
master_thread = new cygthread (::pty_master_thread, this, "ptym");
if (!master_thread)
{
errstr = "pty master control thread";
goto err;
}
+ WaitForSingleObject (thread_param_copied_event, INFINITE);
master_fwd_thread = new cygthread (::pty_master_fwd_thread, this, "ptymf");
if (!master_fwd_thread)
{
errstr = "pty master forwarding thread";
goto err;
}
-
- __small_sprintf (pipename, "pty%d-to-slave", unit);
- res = fhandler_pipe::create (&sec_none, &from_master, &to_slave,
- fhandler_pty_common::pipesize, pipename, 0);
- if (res)
- {
- errstr = "input pipe";
- goto err;
- }
+ WaitForSingleObject (thread_param_copied_event, INFINITE);
+ CloseHandle (thread_param_copied_event);
t.set_from_master (from_master);
t.set_from_master_cyg (from_master_cyg);
@@ -2455,7 +2481,9 @@ fhandler_pty_master::fixup_after_exec ()
}
BOOL
-fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& len, bool is_echo)
+fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr,
+ ssize_t& len, bool is_echo,
+ tty *ttyp, bool is_nonblocking)
{
ssize_t towrite = len;
BOOL res = TRUE;
@@ -2463,7 +2491,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
{
if (!is_echo)
{
- if (tc ()->output_stopped && is_nonblocking ())
+ if (ttyp->output_stopped && is_nonblocking)
{
if (towrite < len)
break;
@@ -2474,11 +2502,11 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
return TRUE;
}
}
- while (tc ()->output_stopped)
+ while (ttyp->output_stopped)
cygwait (10);
}
- if (!(get_ttyp ()->ti.c_oflag & OPOST)) // raw output mode
+ if (!(ttyp->ti.c_oflag & OPOST)) // raw output mode
{
DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
res = WriteFile (h, ptr, n, &n, NULL);
@@ -2498,13 +2526,13 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
switch (buf[rc])
{
case '\r':
- if ((get_ttyp ()->ti.c_oflag & ONOCR)
- && get_ttyp ()->column == 0)
+ if ((ttyp->ti.c_oflag & ONOCR)
+ && ttyp->column == 0)
{
rc++;
continue;
}
- if (get_ttyp ()->ti.c_oflag & OCRNL)
+ if (ttyp->ti.c_oflag & OCRNL)
{
outbuf[n++] = '\n';
rc++;
@@ -2512,22 +2540,22 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
else
{
outbuf[n++] = buf[rc++];
- get_ttyp ()->column = 0;
+ ttyp->column = 0;
}
break;
case '\n':
- if (get_ttyp ()->ti.c_oflag & ONLCR)
+ if (ttyp->ti.c_oflag & ONLCR)
{
outbuf[n++] = '\r';
- get_ttyp ()->column = 0;
+ ttyp->column = 0;
}
- if (get_ttyp ()->ti.c_oflag & ONLRET)
- get_ttyp ()->column = 0;
+ if (ttyp->ti.c_oflag & ONLRET)
+ ttyp->column = 0;
outbuf[n++] = buf[rc++];
break;
default:
outbuf[n++] = buf[rc++];
- get_ttyp ()->column++;
+ ttyp->column++;
break;
}
}
@@ -2869,3 +2897,25 @@ fhandler_pty_slave::create_invisible_console ()
this process becomes the primary. */
get_ttyp ()->invisible_console_pid = myself->pid;
}
+
+void
+fhandler_pty_master::get_master_thread_param (master_thread_param_t *p)
+{
+ p->from_master = from_master;
+ p->from_master_cyg = from_master_cyg;
+ p->to_master = to_master;
+ p->to_master_cyg = to_master_cyg;
+ p->master_ctl = master_ctl;
+ p->input_available_event = input_available_event;
+ SetEvent (thread_param_copied_event);
+}
+
+void
+fhandler_pty_master::get_master_fwd_thread_param (master_fwd_thread_param_t *p)
+{
+ p->to_master_cyg = to_master_cyg;
+ p->from_slave = from_slave;
+ p->output_mutex = output_mutex;
+ p->ttyp = get_ttyp ();
+ SetEvent (thread_param_copied_event);
+}