public inbox for cygwin-developers@cygwin.com
 help / color / mirror / Atom feed
* New implementation of pseudo console support (experimental)
@ 2020-05-13 12:16 Takashi Yano
  2020-05-13 12:35 ` Thomas Wolff
  2020-05-14  9:28 ` Takashi Yano
  0 siblings, 2 replies; 73+ messages in thread
From: Takashi Yano @ 2020-05-13 12:16 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 1696 bytes --]

Hello everyone.

This time, I have experimentally implemented a new pseudo console
support. In this implementation, pseudo console is created for each
native console app.

The advantage and disadvantage of this implementation are as follows.

Advantage:
1) No performance degradation in pty output for cygwin process.
    https://sourceware.org/pipermail/cygwin/2020-February/243651.html
2) Free from the problem caused by difference of behaviour of control
   sequences between real terminal and pseudo console.
    https://sourceware.org/pipermail/cygwin/2019-December/243074.html
    https://sourceware.org/pipermail/cygwin/2020-February/243648.html
3) Free from the problem in cgdb and emacs gud.
    https://sourceware.org/pipermail/cygwin/2020-January/243394.html
    https://sourceware.org/pipermail/cygwin/2020-March/243939.html
4) Redrawing screen on executing native console apps is not necessary.
5) cygwin-console-helper is not necessary for the pseudo console
   support.

Disadvantage:
1) Pseudo console is disabled if one of stdin, stdout or stderr is
   redirected.
2) Pseudo console is disabled if the native console app is executed
   in background.
3) The cygwin program which call console API directly does not work.
4) The apps which use console API cannot be debugged with gdb.
5) Type ahead key inputs are discarded while native console app is
   executed.
6) cmd.exe hangs up on typing some keys if cmd.exe is executed in
   background. (same as cygwin 3.0.7)
7) Code page cannot be changed by chcp.com.

The patch attached is for the current git head.

Could you please test? Any comments and suggestions will be
appreciated.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: pcon2.diff --]
[-- Type: text/plain, Size: 15129 bytes --]

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index ae64086df..6da92ce60 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2264,6 +2264,7 @@ class fhandler_pty_common: public fhandler_termios
     return get_ttyp ()->h_pseudo_console;
   }
   bool to_be_read_from_pcon (void);
+  void resize_pseudo_console2 (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2355,6 +2356,9 @@ class fhandler_pty_slave: public fhandler_pty_common
   void wait_pcon_fwd (void);
   void pull_pcon_input (void);
   void update_pcon_input_state (bool need_lock);
+  bool setup_pseudoconsole2 (STARTUPINFOEXW *si);
+  void close_pseudoconsole2 (void);
+  void wait_pcon_fwd2 (void);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 8547ec7c4..11b84d332 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -41,6 +41,8 @@ extern "C" {
   VOID WINAPI ClosePseudoConsole (HPCON);
 }
 
+#define USE_PCON_MODE2 true
+
 #define close_maybe(h) \
   do { \
     if (h && h != INVALID_HANDLE_VALUE) \
@@ -1295,6 +1297,7 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
   get_ttyp ()->switch_to_pcon_in = false;
   get_ttyp ()->switch_to_pcon_out = false;
   init_console_handler (true);
+  get_ttyp ()->h_pseudo_console2 = NULL;
 }
 
 void
@@ -1554,8 +1557,8 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 bool
 fhandler_pty_common::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return !get_ttyp ()->pcon_in_empty || get_ttyp ()->h_pseudo_console2
+    || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
@@ -2059,6 +2062,8 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
 cleanup:
 	  restore_reattach_pcon ();
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
 
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
@@ -2348,6 +2353,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console2 (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2497,11 +2523,57 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	get_ttyp ()->req_flush_pcon_input = true;
 
       DWORD wLen;
-      WriteFile (to_slave, buf, nlen, &wLen, NULL);
+      HANDLE write_to =
+	get_ttyp ()->h_pseudo_console2 ? get_output_handle () : to_slave;
+
+      if (get_ttyp ()->pcon2_start)
+	{
+	  /* Pseudo condole support mode-2 uses "CSI6n" to get cursor
+	     position. If the reply for "CSI6n" is divided into multiple
+	     writes, pseudo console sometimes does not recognize it.
+	     Therefore, put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (write_to, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon2_start = false;
+	    }
+	  else
+	    {
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (write_to, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		  WriteFile (write_to, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (write_to, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
+	    }
+	}
+      /* Workaround for rlwrap. Replace NL to CR. */
+      char *p = (char *) memchr (buf, '\n', nlen);
+      if (p) *p = '\r';
+
+      WriteFile (write_to, buf, nlen, &wLen, NULL);
       get_ttyp ()->pcon_in_empty = false;
 
       ReleaseMutex (input_mutex);
 
+#if !USE_PCON_MODE2
       /* Use line_edit () in order to set input_available_event. */
       bool is_echo = tc ()->ti.c_lflag & ECHO;
       if (!get_ttyp ()->mask_switch_to_pcon_in)
@@ -2527,6 +2599,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	      eat_readahead (-1);
 	      SetEvent (input_available_event);
 	    }
+#endif /* USE_PCON_MODE2 */
 
       mb_str_free (buf);
       return len;
@@ -2608,6 +2681,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
 	  size.Y = ((struct winsize *) arg)->ws_row;
 	  ResizePseudoConsole (get_pseudo_console (), size);
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
@@ -2884,6 +2959,19 @@ fhandler_pty_slave::wait_pcon_fwd (void)
   cygwait (get_ttyp ()->fwd_done, INFINITE);
 }
 
+void
+fhandler_pty_slave::wait_pcon_fwd2 (void)
+{
+  const int sleep_in_pcon = 16;
+  const int time_to_wait = sleep_in_pcon * 2 + 1/* margine */;
+  get_ttyp ()->pcon_last_time = GetTickCount ();
+  while (GetTickCount () - get_ttyp ()->pcon_last_time < time_to_wait)
+    {
+      int tw = time_to_wait - (GetTickCount () - get_ttyp ()->pcon_last_time);
+      cygwait (tw);
+    }
+}
+
 void
 fhandler_pty_slave::trigger_redraw_screen (void)
 {
@@ -3267,6 +3355,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      Sleep (1);
 	    }
 	}
+      if (USE_PCON_MODE2)
+	get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3274,8 +3364,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_pseudo_console () || get_ttyp ()->h_pseudo_console2)
 	{
+#if !USE_PCON_MODE2
 	  /* Avoid duplicating slave output which is already sent to
 	     to_master_cyg */
 	  if (!get_ttyp ()->switch_to_pcon_out)
@@ -3328,6 +3419,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      rlen -= 4;
 	    }
 	  wlen = rlen;
+#endif /* USE_PCON_MODE2 */
 
 	  size_t nlen;
 	  char *buf = convert_mb_str
@@ -3697,7 +3789,8 @@ fhandler_pty_master::setup ()
   t.winsize.ws_col = 80;
   t.winsize.ws_row = 25;
 
-  setup_pseudoconsole ();
+  if (!USE_PCON_MODE2)
+    setup_pseudoconsole ();
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
@@ -3859,3 +3952,100 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole2 (STARTUPINFOEXW *si)
+{
+  if (!USE_PCON_MODE2)
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     1, &get_ttyp ()->h_pseudo_console2);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console2,
+				  sizeof (get_ttyp ()->h_pseudo_console2),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  if (get_ttyp ()->pcon_pid == 0 ||
+      !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+  if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon2_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console2 = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole2 (void)
+{
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console2 = NULL;
+    }
+}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..d9ed8cfc4 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -583,6 +601,9 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       /* Attach to pseudo console if pty salve is used */
       pid_restore = fhandler_console::get_console_process_id
 	(GetCurrentProcessId (), false);
+      int minor = -1;
+      int ptys_cnt = 0;
+      fhandler_pty_slave *ptys = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -590,7 +611,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  fhandler_base *fh = ::cygheap->fdtab[fd];
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
-	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	      ptys = (fhandler_pty_slave *) fh;
+	      if (minor < 0)
+		minor = fh->get_minor ();
+	      if (minor == fh->get_minor ())
+		ptys_cnt++;
 	      if (ptys->get_pseudo_console ())
 		{
 		  DWORD helper_process_id = ptys->get_helper_process_id ();
@@ -632,6 +657,20 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool use_pcon_mode2 = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_cnt == 3 && ptys
+	  && ctty_pgid && ctty_pgid == myself->pgid
+	  && is_console_app (runpath))
+	if (ptys->setup_pseudoconsole2 (&si_pcon))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    use_pcon_mode2 = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +699,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +753,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +766,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (use_pcon_mode2)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +941,12 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (use_pcon_mode2)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys->wait_pcon_fwd2 ();
+	      ptys->close_pseudoconsole2 ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 0663dc5ee..9bc1457d1 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -250,6 +250,8 @@ tty::init ()
   pcon_in_empty = true;
   req_transfer_input_to_pcon = false;
   req_flush_pcon_input = false;
+  h_pseudo_console2 = NULL;
+  pcon2_start = false;
 }
 
 HANDLE
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index a24afad06..a7546715e 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -111,6 +111,9 @@ private:
   bool pcon_in_empty;
   bool req_transfer_input_to_pcon;
   bool req_flush_pcon_input;
+  HPCON h_pseudo_console2;
+  HANDLE h_pcon_write_pipe;
+  bool pcon2_start;
 
 public:
   HANDLE from_master () const { return _from_master; }

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-13 12:16 New implementation of pseudo console support (experimental) Takashi Yano
@ 2020-05-13 12:35 ` Thomas Wolff
  2020-05-14  9:28 ` Takashi Yano
  1 sibling, 0 replies; 73+ messages in thread
From: Thomas Wolff @ 2020-05-13 12:35 UTC (permalink / raw)
  To: Takashi Yano, cygwin-developers

Hi Takashi,

Am 13.05.2020 um 14:16 schrieb Takashi Yano via Cygwin-developers:
> Hello everyone.
>
> This time, I have experimentally implemented a new pseudo console
> support. In this implementation, pseudo console is created for each
> native console app.
>
> The advantage and disadvantage of this implementation are as follows.
>
> Advantage:
> 1) No performance degradation in pty output for cygwin process.
>      https://sourceware.org/pipermail/cygwin/2020-February/243651.html
> 2) Free from the problem caused by difference of behaviour of control
>     sequences between real terminal and pseudo console.
>      https://sourceware.org/pipermail/cygwin/2019-December/243074.html
>      https://sourceware.org/pipermail/cygwin/2020-February/243648.html
> 3) Free from the problem in cgdb and emacs gud.
>      https://sourceware.org/pipermail/cygwin/2020-January/243394.html
>      https://sourceware.org/pipermail/cygwin/2020-March/243939.html
> 4) Redrawing screen on executing native console apps is not necessary.
> 5) cygwin-console-helper is not necessary for the pseudo console support.
Sounds great. I'd like to test that soon (if I could...)

> Disadvantage:
> 1) Pseudo console is disabled if one of stdin, stdout or stderr is
>     redirected.
> 2) Pseudo console is disabled if the native console app is executed
>     in background.
> 3) The cygwin program which call console API directly does not work.
> 4) The apps which use console API cannot be debugged with gdb.
> 5) Type ahead key inputs are discarded while native console app is
>     executed.
> 6) cmd.exe hangs up on typing some keys if cmd.exe is executed in
>     background. (same as cygwin 3.0.7)
> 7) Code page cannot be changed by chcp.com.
About 1), 2), 7): Can you explain this limitation? I'd assume e.g. a 
background process would decide for itself whether to hook in conpty 
before starting the native app, so why does it make a difference?

> The patch attached is for the current git head.
>
> Could you please test? Any comments and suggestions will be appreciated.
Thanks
Thomas

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-13 12:16 New implementation of pseudo console support (experimental) Takashi Yano
  2020-05-13 12:35 ` Thomas Wolff
@ 2020-05-14  9:28 ` Takashi Yano
  2020-05-14  9:34   ` Takashi Yano
  1 sibling, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-05-14  9:28 UTC (permalink / raw)
  To: cygwin-developers

On Wed, 13 May 2020 21:16:09 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> Disadvantage:
> 1) Pseudo console is disabled if one of stdin, stdout or stderr is
>    redirected.
> 2) Pseudo console is disabled if the native console app is executed
>    in background.
> 3) The cygwin program which call console API directly does not work.
> 4) The apps which use console API cannot be debugged with gdb.
> 5) Type ahead key inputs are discarded while native console app is
>    executed.
> 6) cmd.exe hangs up on typing some keys if cmd.exe is executed in
>    background. (same as cygwin 3.0.7)
> 7) Code page cannot be changed by chcp.com.

I have found workaround for 1), 2) and 6).

Please test the new patch attached.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-14  9:28 ` Takashi Yano
@ 2020-05-14  9:34   ` Takashi Yano
  2020-05-16  0:29     ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-05-14  9:34 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 970 bytes --]

On Thu, 14 May 2020 18:28:59 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Wed, 13 May 2020 21:16:09 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > Disadvantage:
> > 1) Pseudo console is disabled if one of stdin, stdout or stderr is
> >    redirected.
> > 2) Pseudo console is disabled if the native console app is executed
> >    in background.
> > 3) The cygwin program which call console API directly does not work.
> > 4) The apps which use console API cannot be debugged with gdb.
> > 5) Type ahead key inputs are discarded while native console app is
> >    executed.
> > 6) cmd.exe hangs up on typing some keys if cmd.exe is executed in
> >    background. (same as cygwin 3.0.7)
> > 7) Code page cannot be changed by chcp.com.
> 
> I have found workaround for 1), 2) and 6).
> 
> Please test the new patch attached.

Sorry, forgot to attach.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: pcon2-20200514-2.diff --]
[-- Type: text/plain, Size: 17519 bytes --]

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index ae64086df..6da92ce60 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2264,6 +2264,7 @@ class fhandler_pty_common: public fhandler_termios
     return get_ttyp ()->h_pseudo_console;
   }
   bool to_be_read_from_pcon (void);
+  void resize_pseudo_console2 (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2355,6 +2356,9 @@ class fhandler_pty_slave: public fhandler_pty_common
   void wait_pcon_fwd (void);
   void pull_pcon_input (void);
   void update_pcon_input_state (bool need_lock);
+  bool setup_pseudoconsole2 (STARTUPINFOEXW *si);
+  void close_pseudoconsole2 (void);
+  void wait_pcon_fwd2 (void);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 8547ec7c4..a9a2fcdb7 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -41,6 +41,8 @@ extern "C" {
   VOID WINAPI ClosePseudoConsole (HPCON);
 }
 
+#define USE_PCON_MODE2 true
+
 #define close_maybe(h) \
   do { \
     if (h && h != INVALID_HANDLE_VALUE) \
@@ -524,22 +526,30 @@ fhandler_pty_master::accept_input ()
 
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
+  pinfo p (get_ttyp ()->pcon_pid);
+  bool pcon2_switch_to_pcon_in =
+    USE_PCON_MODE2 && get_ttyp ()->switch_to_pcon_in
+    && p && p->ctty == get_ttyp ()->ntty && p->pgid == get_ttyp ()->getpgid ();
+  if (pcon2_switch_to_pcon_in)
+    write_to = to_slave;
+
   if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
     }
-  else if (!to_be_read_from_pcon ())
+  else if (!to_be_read_from_pcon () || USE_PCON_MODE2)
     {
       char *p = rabuf ();
       DWORD rc;
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -1295,6 +1305,7 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
   get_ttyp ()->switch_to_pcon_in = false;
   get_ttyp ()->switch_to_pcon_out = false;
   init_console_handler (true);
+  get_ttyp ()->h_pseudo_console2 = NULL;
 }
 
 void
@@ -1554,8 +1565,13 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 bool
 fhandler_pty_common::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  pinfo p (get_ttyp ()->pcon_pid);
+  bool pcon2_switch_to_pcon_in =
+    get_ttyp ()->h_pseudo_console2 && get_ttyp ()->switch_to_pcon_in
+    && p && p->ctty == get_ttyp ()->ntty && p->pgid == get_ttyp ()->getpgid ();
+  return !get_ttyp ()->pcon_in_empty
+    || pcon2_switch_to_pcon_in || get_ttyp ()->pcon2_start
+    || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
@@ -2059,6 +2075,8 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
 cleanup:
 	  restore_reattach_pcon ();
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
 
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
@@ -2348,6 +2366,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console2 (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2485,7 +2524,8 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon ()
+      && (!USE_PCON_MODE2 || get_ttyp ()->h_pseudo_console2))
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2497,11 +2537,52 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	get_ttyp ()->req_flush_pcon_input = true;
 
       DWORD wLen;
+
+      if (get_ttyp ()->pcon2_start)
+	{
+	  /* Pseudo condole support mode-2 uses "CSI6n" to get cursor
+	     position. If the reply for "CSI6n" is divided into multiple
+	     writes, pseudo console sometimes does not recognize it.
+	     Therefore, put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon2_start = false;
+	    }
+	  else
+	    {
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
+	    }
+	}
+
       WriteFile (to_slave, buf, nlen, &wLen, NULL);
       get_ttyp ()->pcon_in_empty = false;
 
       ReleaseMutex (input_mutex);
 
+#if !USE_PCON_MODE2
       /* Use line_edit () in order to set input_available_event. */
       bool is_echo = tc ()->ti.c_lflag & ECHO;
       if (!get_ttyp ()->mask_switch_to_pcon_in)
@@ -2527,6 +2608,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	      eat_readahead (-1);
 	      SetEvent (input_available_event);
 	    }
+#endif /* USE_PCON_MODE2 */
 
       mb_str_free (buf);
       return len;
@@ -2608,6 +2690,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
 	  size.Y = ((struct winsize *) arg)->ws_row;
 	  ResizePseudoConsole (get_pseudo_console (), size);
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
@@ -2884,6 +2968,19 @@ fhandler_pty_slave::wait_pcon_fwd (void)
   cygwait (get_ttyp ()->fwd_done, INFINITE);
 }
 
+void
+fhandler_pty_slave::wait_pcon_fwd2 (void)
+{
+  const int sleep_in_pcon = 16;
+  const int time_to_wait = sleep_in_pcon * 2 + 1/* margine */;
+  get_ttyp ()->pcon_last_time = GetTickCount ();
+  while (GetTickCount () - get_ttyp ()->pcon_last_time < time_to_wait)
+    {
+      int tw = time_to_wait - (GetTickCount () - get_ttyp ()->pcon_last_time);
+      cygwait (tw);
+    }
+}
+
 void
 fhandler_pty_slave::trigger_redraw_screen (void)
 {
@@ -3267,6 +3364,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      Sleep (1);
 	    }
 	}
+      if (USE_PCON_MODE2)
+	get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3274,8 +3373,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_pseudo_console () || get_ttyp ()->h_pseudo_console2)
 	{
+#if !USE_PCON_MODE2
 	  /* Avoid duplicating slave output which is already sent to
 	     to_master_cyg */
 	  if (!get_ttyp ()->switch_to_pcon_out)
@@ -3328,6 +3428,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      rlen -= 4;
 	    }
 	  wlen = rlen;
+#endif /* USE_PCON_MODE2 */
 
 	  size_t nlen;
 	  char *buf = convert_mb_str
@@ -3697,7 +3798,10 @@ fhandler_pty_master::setup ()
   t.winsize.ws_col = 80;
   t.winsize.ws_row = 25;
 
-  setup_pseudoconsole ();
+  if (!USE_PCON_MODE2)
+    setup_pseudoconsole ();
+  else
+    CreatePipe (&from_master, &to_slave, &sec_none, 0);
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
@@ -3859,3 +3963,126 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole2 (STARTUPINFOEXW *si)
+{
+  if (USE_PCON_MODE2)
+    {
+      fhandler_pty_slave *p0 = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+      if (p0 && p0->get_device () == get_device ())
+	get_ttyp ()->switch_to_pcon_in = true;
+      if (get_ttyp ()->pcon_pid == 0 ||
+	  !pinfo (get_ttyp ()->pcon_pid))
+	get_ttyp ()->pcon_pid = myself->pid;
+    }
+  if (!USE_PCON_MODE2)
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     1, &get_ttyp ()->h_pseudo_console2);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console2,
+				  sizeof (get_ttyp ()->h_pseudo_console2),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_pty_slave *p0 = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+    if (p0 && p0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = p0->get_handle ();
+    fhandler_pty_slave *p1 = (fhandler_pty_slave *) ::cygheap->fdtab[1];
+    if (p1 && p1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = p1->get_output_handle ();
+    fhandler_pty_slave *p2 = (fhandler_pty_slave *) ::cygheap->fdtab[2];
+    if (p2 && p2->get_device () != get_device ())
+      si->StartupInfo.hStdError = p2->get_output_handle ();
+  }
+#if 0
+  get_ttyp ()->switch_to_pcon_in = (si->StartupInfo.hStdInput == NULL);
+
+  if (get_ttyp ()->pcon_pid == 0 ||
+      !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+#endif
+  if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon2_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console2 = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole2 (void)
+{
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console2 = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+    }
+}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..03999e7ff 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -583,6 +601,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       /* Attach to pseudo console if pty salve is used */
       pid_restore = fhandler_console::get_console_process_id
 	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -590,7 +609,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  fhandler_base *fh = ::cygheap->fdtab[fd];
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
-	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	      ptys = (fhandler_pty_slave *) fh;
 	      if (ptys->get_pseudo_console ())
 		{
 		  DWORD helper_process_id = ptys->get_helper_process_id ();
@@ -632,6 +651,18 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool use_pcon_mode2 = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys && is_console_app (runpath))
+	if (ptys->setup_pseudoconsole2 (&si_pcon))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    use_pcon_mode2 = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +691,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +745,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +758,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (use_pcon_mode2)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +933,12 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (use_pcon_mode2)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys->wait_pcon_fwd2 ();
+	      ptys->close_pseudoconsole2 ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 0663dc5ee..9bc1457d1 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -250,6 +250,8 @@ tty::init ()
   pcon_in_empty = true;
   req_transfer_input_to_pcon = false;
   req_flush_pcon_input = false;
+  h_pseudo_console2 = NULL;
+  pcon2_start = false;
 }
 
 HANDLE
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index a24afad06..a7546715e 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -111,6 +111,9 @@ private:
   bool pcon_in_empty;
   bool req_transfer_input_to_pcon;
   bool req_flush_pcon_input;
+  HPCON h_pseudo_console2;
+  HANDLE h_pcon_write_pipe;
+  bool pcon2_start;
 
 public:
   HANDLE from_master () const { return _from_master; }

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-14  9:34   ` Takashi Yano
@ 2020-05-16  0:29     ` Takashi Yano
  2020-05-16  7:47       ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-05-16  0:29 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 109 bytes --]

Fix a small bug caused when stdio is redirected to another pty.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: pcon2-20200516.diff --]
[-- Type: text/plain, Size: 17529 bytes --]

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index ae64086df..6da92ce60 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2264,6 +2264,7 @@ class fhandler_pty_common: public fhandler_termios
     return get_ttyp ()->h_pseudo_console;
   }
   bool to_be_read_from_pcon (void);
+  void resize_pseudo_console2 (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2355,6 +2356,9 @@ class fhandler_pty_slave: public fhandler_pty_common
   void wait_pcon_fwd (void);
   void pull_pcon_input (void);
   void update_pcon_input_state (bool need_lock);
+  bool setup_pseudoconsole2 (STARTUPINFOEXW *si);
+  void close_pseudoconsole2 (void);
+  void wait_pcon_fwd2 (void);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 8547ec7c4..a9a2fcdb7 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -41,6 +41,8 @@ extern "C" {
   VOID WINAPI ClosePseudoConsole (HPCON);
 }
 
+#define USE_PCON_MODE2 true
+
 #define close_maybe(h) \
   do { \
     if (h && h != INVALID_HANDLE_VALUE) \
@@ -524,22 +526,30 @@ fhandler_pty_master::accept_input ()
 
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
+  pinfo p (get_ttyp ()->pcon_pid);
+  bool pcon2_switch_to_pcon_in =
+    USE_PCON_MODE2 && get_ttyp ()->switch_to_pcon_in
+    && p && p->ctty == get_ttyp ()->ntty && p->pgid == get_ttyp ()->getpgid ();
+  if (pcon2_switch_to_pcon_in)
+    write_to = to_slave;
+
   if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
     }
-  else if (!to_be_read_from_pcon ())
+  else if (!to_be_read_from_pcon () || USE_PCON_MODE2)
     {
       char *p = rabuf ();
       DWORD rc;
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -1295,6 +1305,7 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
   get_ttyp ()->switch_to_pcon_in = false;
   get_ttyp ()->switch_to_pcon_out = false;
   init_console_handler (true);
+  get_ttyp ()->h_pseudo_console2 = NULL;
 }
 
 void
@@ -1554,8 +1565,13 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 bool
 fhandler_pty_common::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  pinfo p (get_ttyp ()->pcon_pid);
+  bool pcon2_switch_to_pcon_in =
+    get_ttyp ()->h_pseudo_console2 && get_ttyp ()->switch_to_pcon_in
+    && p && p->ctty == get_ttyp ()->ntty && p->pgid == get_ttyp ()->getpgid ();
+  return !get_ttyp ()->pcon_in_empty
+    || pcon2_switch_to_pcon_in || get_ttyp ()->pcon2_start
+    || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
@@ -2059,6 +2075,8 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
 cleanup:
 	  restore_reattach_pcon ();
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
 
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
@@ -2348,6 +2366,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console2 (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2485,7 +2524,8 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon ()
+      && (!USE_PCON_MODE2 || get_ttyp ()->h_pseudo_console2))
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2497,11 +2537,52 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	get_ttyp ()->req_flush_pcon_input = true;
 
       DWORD wLen;
+
+      if (get_ttyp ()->pcon2_start)
+	{
+	  /* Pseudo condole support mode-2 uses "CSI6n" to get cursor
+	     position. If the reply for "CSI6n" is divided into multiple
+	     writes, pseudo console sometimes does not recognize it.
+	     Therefore, put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon2_start = false;
+	    }
+	  else
+	    {
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
+	    }
+	}
+
       WriteFile (to_slave, buf, nlen, &wLen, NULL);
       get_ttyp ()->pcon_in_empty = false;
 
       ReleaseMutex (input_mutex);
 
+#if !USE_PCON_MODE2
       /* Use line_edit () in order to set input_available_event. */
       bool is_echo = tc ()->ti.c_lflag & ECHO;
       if (!get_ttyp ()->mask_switch_to_pcon_in)
@@ -2527,6 +2608,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	      eat_readahead (-1);
 	      SetEvent (input_available_event);
 	    }
+#endif /* USE_PCON_MODE2 */
 
       mb_str_free (buf);
       return len;
@@ -2608,6 +2690,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
 	  size.Y = ((struct winsize *) arg)->ws_row;
 	  ResizePseudoConsole (get_pseudo_console (), size);
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
@@ -2884,6 +2968,19 @@ fhandler_pty_slave::wait_pcon_fwd (void)
   cygwait (get_ttyp ()->fwd_done, INFINITE);
 }
 
+void
+fhandler_pty_slave::wait_pcon_fwd2 (void)
+{
+  const int sleep_in_pcon = 16;
+  const int time_to_wait = sleep_in_pcon * 2 + 1/* margine */;
+  get_ttyp ()->pcon_last_time = GetTickCount ();
+  while (GetTickCount () - get_ttyp ()->pcon_last_time < time_to_wait)
+    {
+      int tw = time_to_wait - (GetTickCount () - get_ttyp ()->pcon_last_time);
+      cygwait (tw);
+    }
+}
+
 void
 fhandler_pty_slave::trigger_redraw_screen (void)
 {
@@ -3267,6 +3364,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      Sleep (1);
 	    }
 	}
+      if (USE_PCON_MODE2)
+	get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3274,8 +3373,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_pseudo_console () || get_ttyp ()->h_pseudo_console2)
 	{
+#if !USE_PCON_MODE2
 	  /* Avoid duplicating slave output which is already sent to
 	     to_master_cyg */
 	  if (!get_ttyp ()->switch_to_pcon_out)
@@ -3328,6 +3428,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      rlen -= 4;
 	    }
 	  wlen = rlen;
+#endif /* USE_PCON_MODE2 */
 
 	  size_t nlen;
 	  char *buf = convert_mb_str
@@ -3697,7 +3798,10 @@ fhandler_pty_master::setup ()
   t.winsize.ws_col = 80;
   t.winsize.ws_row = 25;
 
-  setup_pseudoconsole ();
+  if (!USE_PCON_MODE2)
+    setup_pseudoconsole ();
+  else
+    CreatePipe (&from_master, &to_slave, &sec_none, 0);
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
@@ -3859,3 +3963,126 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole2 (STARTUPINFOEXW *si)
+{
+  if (USE_PCON_MODE2)
+    {
+      fhandler_pty_slave *p0 = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+      if (p0 && p0->get_device () == get_device ())
+	get_ttyp ()->switch_to_pcon_in = true;
+      if (get_ttyp ()->pcon_pid == 0 ||
+	  !pinfo (get_ttyp ()->pcon_pid))
+	get_ttyp ()->pcon_pid = myself->pid;
+    }
+  if (!USE_PCON_MODE2)
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     1, &get_ttyp ()->h_pseudo_console2);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console2,
+				  sizeof (get_ttyp ()->h_pseudo_console2),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_pty_slave *p0 = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+    if (p0 && p0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = p0->get_handle ();
+    fhandler_pty_slave *p1 = (fhandler_pty_slave *) ::cygheap->fdtab[1];
+    if (p1 && p1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = p1->get_output_handle ();
+    fhandler_pty_slave *p2 = (fhandler_pty_slave *) ::cygheap->fdtab[2];
+    if (p2 && p2->get_device () != get_device ())
+      si->StartupInfo.hStdError = p2->get_output_handle ();
+  }
+#if 0
+  get_ttyp ()->switch_to_pcon_in = (si->StartupInfo.hStdInput == NULL);
+
+  if (get_ttyp ()->pcon_pid == 0 ||
+      !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+#endif
+  if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon2_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console2 = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole2 (void)
+{
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console2 = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+    }
+}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..514125072 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -583,6 +601,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       /* Attach to pseudo console if pty salve is used */
       pid_restore = fhandler_console::get_console_process_id
 	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -591,6 +610,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	      if (ptys->get_pseudo_console ())
 		{
 		  DWORD helper_process_id = ptys->get_helper_process_id ();
@@ -632,6 +653,18 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool use_pcon_mode2 = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole2 (&si_pcon))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    use_pcon_mode2 = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +693,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +747,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +760,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (use_pcon_mode2)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +935,12 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (use_pcon_mode2)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->wait_pcon_fwd2 ();
+	      ptys_primary->close_pseudoconsole2 ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 0663dc5ee..9bc1457d1 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -250,6 +250,8 @@ tty::init ()
   pcon_in_empty = true;
   req_transfer_input_to_pcon = false;
   req_flush_pcon_input = false;
+  h_pseudo_console2 = NULL;
+  pcon2_start = false;
 }
 
 HANDLE
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index a24afad06..a7546715e 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -111,6 +111,9 @@ private:
   bool pcon_in_empty;
   bool req_transfer_input_to_pcon;
   bool req_flush_pcon_input;
+  HPCON h_pseudo_console2;
+  HANDLE h_pcon_write_pipe;
+  bool pcon2_start;
 
 public:
   HANDLE from_master () const { return _from_master; }

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-16  0:29     ` Takashi Yano
@ 2020-05-16  7:47       ` Takashi Yano
  2020-05-19 13:40         ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-05-16  7:47 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 284 bytes --]

On Sat, 16 May 2020 09:29:56 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> Fix a small bug caused when stdio is redirected to another pty.

Fix another bug caused when stdio is redirected to another pty.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: pcon2-20200516-2.diff --]
[-- Type: text/plain, Size: 17089 bytes --]

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index ae64086df..6da92ce60 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2264,6 +2264,7 @@ class fhandler_pty_common: public fhandler_termios
     return get_ttyp ()->h_pseudo_console;
   }
   bool to_be_read_from_pcon (void);
+  void resize_pseudo_console2 (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2355,6 +2356,9 @@ class fhandler_pty_slave: public fhandler_pty_common
   void wait_pcon_fwd (void);
   void pull_pcon_input (void);
   void update_pcon_input_state (bool need_lock);
+  bool setup_pseudoconsole2 (STARTUPINFOEXW *si);
+  void close_pseudoconsole2 (void);
+  void wait_pcon_fwd2 (void);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 8547ec7c4..8120745b9 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -41,6 +41,8 @@ extern "C" {
   VOID WINAPI ClosePseudoConsole (HPCON);
 }
 
+#define USE_PCON_MODE2 true
+
 #define close_maybe(h) \
   do { \
     if (h && h != INVALID_HANDLE_VALUE) \
@@ -524,22 +526,26 @@ fhandler_pty_master::accept_input ()
 
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
+  if (to_be_read_from_pcon () && USE_PCON_MODE2)
+    write_to = to_slave;
+
   if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
     }
-  else if (!to_be_read_from_pcon ())
+  else if (!to_be_read_from_pcon () || USE_PCON_MODE2)
     {
       char *p = rabuf ();
       DWORD rc;
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -1295,6 +1301,7 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
   get_ttyp ()->switch_to_pcon_in = false;
   get_ttyp ()->switch_to_pcon_out = false;
   init_console_handler (true);
+  get_ttyp ()->h_pseudo_console2 = NULL;
 }
 
 void
@@ -1554,8 +1561,9 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 bool
 fhandler_pty_common::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return !get_ttyp ()->pcon_in_empty || get_ttyp ()->pcon2_start
+    || (get_ttyp ()->switch_to_pcon_in
+	&& !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
@@ -2059,6 +2067,8 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
 cleanup:
 	  restore_reattach_pcon ();
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
 
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
@@ -2348,6 +2358,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console2 (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2485,7 +2516,8 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon ()
+      && (!USE_PCON_MODE2 || get_ttyp ()->h_pseudo_console2))
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2497,11 +2529,52 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	get_ttyp ()->req_flush_pcon_input = true;
 
       DWORD wLen;
+
+      if (get_ttyp ()->pcon2_start)
+	{
+	  /* Pseudo condole support mode-2 uses "CSI6n" to get cursor
+	     position. If the reply for "CSI6n" is divided into multiple
+	     writes, pseudo console sometimes does not recognize it.
+	     Therefore, put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon2_start = false;
+	    }
+	  else
+	    {
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
+	    }
+	}
+
       WriteFile (to_slave, buf, nlen, &wLen, NULL);
       get_ttyp ()->pcon_in_empty = false;
 
       ReleaseMutex (input_mutex);
 
+#if !USE_PCON_MODE2
       /* Use line_edit () in order to set input_available_event. */
       bool is_echo = tc ()->ti.c_lflag & ECHO;
       if (!get_ttyp ()->mask_switch_to_pcon_in)
@@ -2527,6 +2600,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	      eat_readahead (-1);
 	      SetEvent (input_available_event);
 	    }
+#endif /* USE_PCON_MODE2 */
 
       mb_str_free (buf);
       return len;
@@ -2608,6 +2682,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
 	  size.Y = ((struct winsize *) arg)->ws_row;
 	  ResizePseudoConsole (get_pseudo_console (), size);
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
@@ -2884,6 +2960,19 @@ fhandler_pty_slave::wait_pcon_fwd (void)
   cygwait (get_ttyp ()->fwd_done, INFINITE);
 }
 
+void
+fhandler_pty_slave::wait_pcon_fwd2 (void)
+{
+  const int sleep_in_pcon = 16;
+  const int time_to_wait = sleep_in_pcon * 2 + 1/* margine */;
+  get_ttyp ()->pcon_last_time = GetTickCount ();
+  while (GetTickCount () - get_ttyp ()->pcon_last_time < time_to_wait)
+    {
+      int tw = time_to_wait - (GetTickCount () - get_ttyp ()->pcon_last_time);
+      cygwait (tw);
+    }
+}
+
 void
 fhandler_pty_slave::trigger_redraw_screen (void)
 {
@@ -3267,6 +3356,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      Sleep (1);
 	    }
 	}
+      if (USE_PCON_MODE2)
+	get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3274,8 +3365,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_pseudo_console () || get_ttyp ()->h_pseudo_console2)
 	{
+#if !USE_PCON_MODE2
 	  /* Avoid duplicating slave output which is already sent to
 	     to_master_cyg */
 	  if (!get_ttyp ()->switch_to_pcon_out)
@@ -3328,6 +3420,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      rlen -= 4;
 	    }
 	  wlen = rlen;
+#endif /* USE_PCON_MODE2 */
 
 	  size_t nlen;
 	  char *buf = convert_mb_str
@@ -3697,7 +3790,10 @@ fhandler_pty_master::setup ()
   t.winsize.ws_col = 80;
   t.winsize.ws_row = 25;
 
-  setup_pseudoconsole ();
+  if (!USE_PCON_MODE2)
+    setup_pseudoconsole ();
+  else
+    CreatePipe (&from_master, &to_slave, &sec_none, 0);
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
@@ -3859,3 +3955,126 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole2 (STARTUPINFOEXW *si)
+{
+  if (USE_PCON_MODE2)
+    {
+      fhandler_base *fh = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+	{
+	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	  ptys->get_ttyp ()->switch_to_pcon_in = true;
+	  if (ptys->get_ttyp ()->pcon_pid == 0 ||
+	      !pinfo (ptys->get_ttyp ()->pcon_pid))
+	    ptys->get_ttyp ()->pcon_pid = myself->pid;
+	}
+    }
+  if (!USE_PCON_MODE2)
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     1, &get_ttyp ()->h_pseudo_console2);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console2,
+				  sizeof (get_ttyp ()->h_pseudo_console2),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_pty_slave *p0 = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+    if (p0 && p0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = p0->get_handle ();
+    fhandler_pty_slave *p1 = (fhandler_pty_slave *) ::cygheap->fdtab[1];
+    if (p1 && p1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = p1->get_output_handle ();
+    fhandler_pty_slave *p2 = (fhandler_pty_slave *) ::cygheap->fdtab[2];
+    if (p2 && p2->get_device () != get_device ())
+      si->StartupInfo.hStdError = p2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon2_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console2 = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole2 (void)
+{
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console2 = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+    }
+}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..514125072 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -583,6 +601,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       /* Attach to pseudo console if pty salve is used */
       pid_restore = fhandler_console::get_console_process_id
 	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -591,6 +610,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	      if (ptys->get_pseudo_console ())
 		{
 		  DWORD helper_process_id = ptys->get_helper_process_id ();
@@ -632,6 +653,18 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool use_pcon_mode2 = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole2 (&si_pcon))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    use_pcon_mode2 = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +693,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +747,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +760,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (use_pcon_mode2)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +935,12 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (use_pcon_mode2)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->wait_pcon_fwd2 ();
+	      ptys_primary->close_pseudoconsole2 ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 0663dc5ee..9bc1457d1 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -250,6 +250,8 @@ tty::init ()
   pcon_in_empty = true;
   req_transfer_input_to_pcon = false;
   req_flush_pcon_input = false;
+  h_pseudo_console2 = NULL;
+  pcon2_start = false;
 }
 
 HANDLE
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index a24afad06..a7546715e 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -111,6 +111,9 @@ private:
   bool pcon_in_empty;
   bool req_transfer_input_to_pcon;
   bool req_flush_pcon_input;
+  HPCON h_pseudo_console2;
+  HANDLE h_pcon_write_pipe;
+  bool pcon2_start;
 
 public:
   HANDLE from_master () const { return _from_master; }

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-16  7:47       ` Takashi Yano
@ 2020-05-19 13:40         ` Takashi Yano
  2020-05-25 10:53           ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-05-19 13:40 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 449 bytes --]

On Sat, 16 May 2020 16:47:35 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Sat, 16 May 2020 09:29:56 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > Fix a small bug caused when stdio is redirected to another pty.
> 
> Fix another bug caused when stdio is redirected to another pty.

Revise the patch to fit the current git head.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: pcon2-20200519.diff --]
[-- Type: text/plain, Size: 17340 bytes --]

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 857f0a4e0..ea89d8f30 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2264,6 +2264,7 @@ class fhandler_pty_common: public fhandler_termios
     return get_ttyp ()->h_pseudo_console;
   }
   bool to_be_read_from_pcon (void);
+  void resize_pseudo_console2 (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2356,6 +2357,9 @@ class fhandler_pty_slave: public fhandler_pty_common
   void wait_pcon_fwd (void);
   void pull_pcon_input (void);
   void update_pcon_input_state (bool need_lock);
+  bool setup_pseudoconsole2 (STARTUPINFOEXW *si);
+  void close_pseudoconsole2 (void);
+  void wait_pcon_fwd2 (void);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 02b78cd2c..c4106273f 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -41,6 +41,8 @@ extern "C" {
   VOID WINAPI ClosePseudoConsole (HPCON);
 }
 
+#define USE_PCON_MODE2 true
+
 #define close_maybe(h) \
   do { \
     if (h && h != INVALID_HANDLE_VALUE) \
@@ -534,22 +536,26 @@ fhandler_pty_master::accept_input ()
 
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
+  if (to_be_read_from_pcon () && USE_PCON_MODE2)
+    write_to = to_slave;
+
   if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
     }
-  else if (!to_be_read_from_pcon ())
+  else if (!to_be_read_from_pcon () || USE_PCON_MODE2)
     {
       char *p = rabuf ();
       DWORD rc;
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -1256,6 +1262,8 @@ fhandler_pty_slave::get_readahead_valid (void)
 void
 fhandler_pty_slave::set_switch_to_pcon (int fd_set)
 {
+  if (USE_PCON_MODE2)
+    return;
   if (fd < 0)
     fd = fd_set;
   if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
@@ -1302,6 +1310,7 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
   get_ttyp ()->switch_to_pcon_in = false;
   get_ttyp ()->switch_to_pcon_out = false;
   init_console_handler (true);
+  get_ttyp ()->h_pseudo_console2 = NULL;
 }
 
 void
@@ -1561,8 +1570,9 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 bool
 fhandler_pty_common::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return !get_ttyp ()->pcon_in_empty || get_ttyp ()->pcon2_start
+    || (get_ttyp ()->switch_to_pcon_in
+	&& !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
@@ -2066,6 +2076,8 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
 cleanup:
 	  restore_reattach_pcon ();
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
 
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
@@ -2355,6 +2367,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console2 (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2492,7 +2525,8 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon ()
+      && (!USE_PCON_MODE2 || get_ttyp ()->h_pseudo_console2))
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2504,11 +2538,52 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	get_ttyp ()->req_flush_pcon_input = true;
 
       DWORD wLen;
+
+      if (get_ttyp ()->pcon2_start)
+	{
+	  /* Pseudo condole support mode-2 uses "CSI6n" to get cursor
+	     position. If the reply for "CSI6n" is divided into multiple
+	     writes, pseudo console sometimes does not recognize it.
+	     Therefore, put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon2_start = false;
+	    }
+	  else
+	    {
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
+	    }
+	}
+
       WriteFile (to_slave, buf, nlen, &wLen, NULL);
       get_ttyp ()->pcon_in_empty = false;
 
       ReleaseMutex (input_mutex);
 
+#if !USE_PCON_MODE2
       /* Use line_edit () in order to set input_available_event. */
       bool is_echo = tc ()->ti.c_lflag & ECHO;
       if (!get_ttyp ()->mask_switch_to_pcon_in)
@@ -2534,6 +2609,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	      eat_readahead (-1);
 	      SetEvent (input_available_event);
 	    }
+#endif /* USE_PCON_MODE2 */
 
       mb_str_free (buf);
       return len;
@@ -2615,6 +2691,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
 	  size.Y = ((struct winsize *) arg)->ws_row;
 	  ResizePseudoConsole (get_pseudo_console (), size);
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
@@ -2891,6 +2969,19 @@ fhandler_pty_slave::wait_pcon_fwd (void)
   cygwait (get_ttyp ()->fwd_done, INFINITE);
 }
 
+void
+fhandler_pty_slave::wait_pcon_fwd2 (void)
+{
+  const int sleep_in_pcon = 16;
+  const int time_to_wait = sleep_in_pcon * 2 + 1/* margine */;
+  get_ttyp ()->pcon_last_time = GetTickCount ();
+  while (GetTickCount () - get_ttyp ()->pcon_last_time < time_to_wait)
+    {
+      int tw = time_to_wait - (GetTickCount () - get_ttyp ()->pcon_last_time);
+      cygwait (tw);
+    }
+}
+
 void
 fhandler_pty_slave::trigger_redraw_screen (void)
 {
@@ -3270,6 +3361,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      Sleep (1);
 	    }
 	}
+      if (USE_PCON_MODE2)
+	get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3277,8 +3370,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_pseudo_console () || get_ttyp ()->h_pseudo_console2)
 	{
+#if !USE_PCON_MODE2
 	  /* Avoid duplicating slave output which is already sent to
 	     to_master_cyg */
 	  if (!get_ttyp ()->switch_to_pcon_out)
@@ -3331,6 +3425,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      rlen -= 4;
 	    }
 	  wlen = rlen;
+#endif /* USE_PCON_MODE2 */
 
 	  size_t nlen;
 	  char *buf = convert_mb_str
@@ -3700,7 +3795,10 @@ fhandler_pty_master::setup ()
   t.winsize.ws_col = 80;
   t.winsize.ws_row = 25;
 
-  setup_pseudoconsole ();
+  if (!USE_PCON_MODE2)
+    setup_pseudoconsole ();
+  else
+    CreatePipe (&from_master, &to_slave, &sec_none, 0);
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
@@ -3862,3 +3960,126 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole2 (STARTUPINFOEXW *si)
+{
+  if (USE_PCON_MODE2)
+    {
+      fhandler_base *fh = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+	{
+	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	  ptys->get_ttyp ()->switch_to_pcon_in = true;
+	  if (ptys->get_ttyp ()->pcon_pid == 0 ||
+	      !pinfo (ptys->get_ttyp ()->pcon_pid))
+	    ptys->get_ttyp ()->pcon_pid = myself->pid;
+	}
+    }
+  if (!USE_PCON_MODE2)
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     1, &get_ttyp ()->h_pseudo_console2);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console2,
+				  sizeof (get_ttyp ()->h_pseudo_console2),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_pty_slave *p0 = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+    if (p0 && p0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = p0->get_handle ();
+    fhandler_pty_slave *p1 = (fhandler_pty_slave *) ::cygheap->fdtab[1];
+    if (p1 && p1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = p1->get_output_handle ();
+    fhandler_pty_slave *p2 = (fhandler_pty_slave *) ::cygheap->fdtab[2];
+    if (p2 && p2->get_device () != get_device ())
+      si->StartupInfo.hStdError = p2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon2_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console2 = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole2 (void)
+{
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console2 = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+    }
+}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..514125072 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -583,6 +601,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       /* Attach to pseudo console if pty salve is used */
       pid_restore = fhandler_console::get_console_process_id
 	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -591,6 +610,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	      if (ptys->get_pseudo_console ())
 		{
 		  DWORD helper_process_id = ptys->get_helper_process_id ();
@@ -632,6 +653,18 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool use_pcon_mode2 = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole2 (&si_pcon))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    use_pcon_mode2 = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +693,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +747,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +760,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (use_pcon_mode2)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +935,12 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (use_pcon_mode2)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->wait_pcon_fwd2 ();
+	      ptys_primary->close_pseudoconsole2 ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 0663dc5ee..9bc1457d1 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -250,6 +250,8 @@ tty::init ()
   pcon_in_empty = true;
   req_transfer_input_to_pcon = false;
   req_flush_pcon_input = false;
+  h_pseudo_console2 = NULL;
+  pcon2_start = false;
 }
 
 HANDLE
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index a24afad06..a7546715e 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -111,6 +111,9 @@ private:
   bool pcon_in_empty;
   bool req_transfer_input_to_pcon;
   bool req_flush_pcon_input;
+  HPCON h_pseudo_console2;
+  HANDLE h_pcon_write_pipe;
+  bool pcon2_start;
 
 public:
   HANDLE from_master () const { return _from_master; }

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-19 13:40         ` Takashi Yano
@ 2020-05-25 10:53           ` Takashi Yano
  2020-05-25 15:22             ` Corinna Vinschen
  2020-05-26  1:09             ` Takashi Yano
  0 siblings, 2 replies; 73+ messages in thread
From: Takashi Yano @ 2020-05-25 10:53 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 628 bytes --]

On Tue, 19 May 2020 22:40:18 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Sat, 16 May 2020 16:47:35 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Sat, 16 May 2020 09:29:56 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > Fix a small bug caused when stdio is redirected to another pty.
> > 
> > Fix another bug caused when stdio is redirected to another pty.
> 
> Revise the patch to fit the current git head.

Revise the patch again to fit the current git head.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: pcon2-20200525.diff --]
[-- Type: text/plain, Size: 17053 bytes --]

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 76ad2aab0..7006aa060 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2264,6 +2264,7 @@ class fhandler_pty_common: public fhandler_termios
     return get_ttyp ()->h_pseudo_console;
   }
   bool to_be_read_from_pcon (void);
+  void resize_pseudo_console2 (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2356,6 +2357,9 @@ class fhandler_pty_slave: public fhandler_pty_common
   void wait_pcon_fwd (void);
   void pull_pcon_input (void);
   void update_pcon_input_state (bool need_lock);
+  bool setup_pseudoconsole2 (STARTUPINFOEXW *si);
+  void close_pseudoconsole2 (void);
+  void wait_pcon_fwd2 (void);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index df08dd20a..03e7f9aaa 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -41,6 +41,8 @@ extern "C" {
   VOID WINAPI ClosePseudoConsole (HPCON);
 }
 
+#define USE_PCON_MODE2 true
+
 #define close_maybe(h) \
   do { \
     if (h && h != INVALID_HANDLE_VALUE) \
@@ -539,22 +541,26 @@ fhandler_pty_master::accept_input ()
 
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
+  if (to_be_read_from_pcon () && USE_PCON_MODE2)
+    write_to = to_slave;
+
   if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
     }
-  else if (!to_be_read_from_pcon ())
+  else if (!to_be_read_from_pcon () || USE_PCON_MODE2)
     {
       char *p = rabuf ();
       DWORD rc;
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -1262,6 +1268,8 @@ fhandler_pty_slave::get_readahead_valid (void)
 void
 fhandler_pty_slave::set_switch_to_pcon (int fd_set)
 {
+  if (USE_PCON_MODE2)
+    return;
   if (fd < 0)
     fd = fd_set;
   if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
@@ -1308,6 +1316,7 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
   get_ttyp ()->switch_to_pcon_in = false;
   get_ttyp ()->switch_to_pcon_out = false;
   init_console_handler (true);
+  get_ttyp ()->h_pseudo_console2 = NULL;
 }
 
 void
@@ -1567,8 +1576,9 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 bool
 fhandler_pty_common::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return !get_ttyp ()->pcon_in_empty || get_ttyp ()->pcon2_start
+    || (get_ttyp ()->switch_to_pcon_in
+	&& !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
@@ -2072,6 +2082,8 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
 cleanup:
 	  restore_reattach_pcon ();
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
 
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
@@ -2361,6 +2373,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console2 (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2498,7 +2531,8 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon ()
+      && (!USE_PCON_MODE2 || get_ttyp ()->h_pseudo_console2))
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2510,11 +2544,52 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	get_ttyp ()->req_flush_pcon_input = true;
 
       DWORD wLen;
+
+      if (get_ttyp ()->pcon2_start)
+	{
+	  /* Pseudo condole support mode-2 uses "CSI6n" to get cursor
+	     position. If the reply for "CSI6n" is divided into multiple
+	     writes, pseudo console sometimes does not recognize it.
+	     Therefore, put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon2_start = false;
+	    }
+	  else
+	    {
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
+	    }
+	}
+
       WriteFile (to_slave, buf, nlen, &wLen, NULL);
       get_ttyp ()->pcon_in_empty = false;
 
       ReleaseMutex (input_mutex);
 
+#if !USE_PCON_MODE2
       /* Use line_edit () in order to set input_available_event. */
       bool is_echo = tc ()->ti.c_lflag & ECHO;
       if (!get_ttyp ()->mask_switch_to_pcon_in)
@@ -2540,6 +2615,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	      eat_readahead (-1);
 	      SetEvent (input_available_event);
 	    }
+#endif /* USE_PCON_MODE2 */
 
       mb_str_free (buf);
       return len;
@@ -2621,6 +2697,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
 	  size.Y = ((struct winsize *) arg)->ws_row;
 	  ResizePseudoConsole (get_pseudo_console (), size);
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
@@ -2898,6 +2976,12 @@ fhandler_pty_slave::wait_pcon_fwd (void)
 	 && cygwait (get_ttyp ()->fwd_done, 1) == WAIT_TIMEOUT);
 }
 
+void
+fhandler_pty_slave::wait_pcon_fwd2 (void)
+{
+  get_ttyp ()->wait_pcon_fwd ();
+}
+
 void
 fhandler_pty_slave::trigger_redraw_screen (void)
 {
@@ -3267,6 +3351,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      Sleep (1);
 	    }
 	}
+      if (USE_PCON_MODE2)
+	get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3274,8 +3360,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_pseudo_console () || get_ttyp ()->h_pseudo_console2)
 	{
+#if !USE_PCON_MODE2
 	  /* Avoid duplicating slave output which is already sent to
 	     to_master_cyg */
 	  if (!get_ttyp ()->switch_to_pcon_out)
@@ -3328,6 +3415,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      rlen -= 4;
 	    }
 	  wlen = rlen;
+#endif /* USE_PCON_MODE2 */
 
 	  size_t nlen;
 	  char *buf = convert_mb_str
@@ -3697,7 +3785,10 @@ fhandler_pty_master::setup ()
   t.winsize.ws_col = 80;
   t.winsize.ws_row = 25;
 
-  setup_pseudoconsole ();
+  if (!USE_PCON_MODE2)
+    setup_pseudoconsole ();
+  else
+    CreatePipe (&from_master, &to_slave, &sec_none, 0);
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
@@ -3859,3 +3950,126 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole2 (STARTUPINFOEXW *si)
+{
+  if (USE_PCON_MODE2)
+    {
+      fhandler_base *fh = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+	{
+	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	  ptys->get_ttyp ()->switch_to_pcon_in = true;
+	  if (ptys->get_ttyp ()->pcon_pid == 0 ||
+	      !pinfo (ptys->get_ttyp ()->pcon_pid))
+	    ptys->get_ttyp ()->pcon_pid = myself->pid;
+	}
+    }
+  if (!USE_PCON_MODE2)
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     1, &get_ttyp ()->h_pseudo_console2);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console2,
+				  sizeof (get_ttyp ()->h_pseudo_console2),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_pty_slave *p0 = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+    if (p0 && p0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = p0->get_handle ();
+    fhandler_pty_slave *p1 = (fhandler_pty_slave *) ::cygheap->fdtab[1];
+    if (p1 && p1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = p1->get_output_handle ();
+    fhandler_pty_slave *p2 = (fhandler_pty_slave *) ::cygheap->fdtab[2];
+    if (p2 && p2->get_device () != get_device ())
+      si->StartupInfo.hStdError = p2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon2_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console2 = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole2 (void)
+{
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console2 = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+    }
+}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..514125072 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -583,6 +601,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       /* Attach to pseudo console if pty salve is used */
       pid_restore = fhandler_console::get_console_process_id
 	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -591,6 +610,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	      if (ptys->get_pseudo_console ())
 		{
 		  DWORD helper_process_id = ptys->get_helper_process_id ();
@@ -632,6 +653,18 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool use_pcon_mode2 = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole2 (&si_pcon))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    use_pcon_mode2 = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +693,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +747,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +760,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (use_pcon_mode2)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +935,12 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (use_pcon_mode2)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->wait_pcon_fwd2 ();
+	      ptys_primary->close_pseudoconsole2 ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index efdae4697..28316ba6a 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -249,6 +249,8 @@ tty::init ()
   pcon_in_empty = true;
   req_transfer_input_to_pcon = false;
   req_flush_pcon_input = false;
+  h_pseudo_console2 = NULL;
+  pcon2_start = false;
 }
 
 HANDLE
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 7d6fc8fef..52f3872e2 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -110,6 +110,9 @@ private:
   bool pcon_in_empty;
   bool req_transfer_input_to_pcon;
   bool req_flush_pcon_input;
+  HPCON h_pseudo_console2;
+  HANDLE h_pcon_write_pipe;
+  bool pcon2_start;
 
 public:
   HANDLE from_master () const { return _from_master; }

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-25 10:53           ` Takashi Yano
@ 2020-05-25 15:22             ` Corinna Vinschen
  2020-05-25 19:16               ` Thomas Wolff
  2020-05-26  1:00               ` Takashi Yano
  2020-05-26  1:09             ` Takashi Yano
  1 sibling, 2 replies; 73+ messages in thread
From: Corinna Vinschen @ 2020-05-25 15:22 UTC (permalink / raw)
  To: cygwin-developers

On May 25 19:53, Takashi Yano via Cygwin-developers wrote:
> On Tue, 19 May 2020 22:40:18 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Sat, 16 May 2020 16:47:35 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Sat, 16 May 2020 09:29:56 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > Fix a small bug caused when stdio is redirected to another pty.
> > > 
> > > Fix another bug caused when stdio is redirected to another pty.
> > 
> > Revise the patch to fit the current git head.
> 
> Revise the patch again to fit the current git head.

Works fine for me, but I have only a limited test scenario.

Thomas, do you have any input so far?

In terms of the remaining disadvantages:

3) The cygwin program which call console API directly does not work.

  I don't see a problem here.

4) The apps which use console API cannot be debugged with gdb.

  Do you mean Cygwin apps or native apps?  I assume native apps
  because of disadvantage 3...

  Does that mean you can't even debug by attaching (via PID)?

5) Type ahead key inputs are discarded while native console app is
   executed.

  Hmm, not muchg of a problem, I think.

7) Code page cannot be changed by chcp.com.

  I fail to see the exact drawback here.  I don't think a lot of users
  use chcp, but of course I could be wrong.  I'd also be curious why
  chcp doesn't work.


Thanks,
Corinna

-- 
Corinna Vinschen
Cygwin Maintainer

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-25 15:22             ` Corinna Vinschen
@ 2020-05-25 19:16               ` Thomas Wolff
  2020-05-26  1:00               ` Takashi Yano
  1 sibling, 0 replies; 73+ messages in thread
From: Thomas Wolff @ 2020-05-25 19:16 UTC (permalink / raw)
  To: cygwin-developers

Am 25.05.2020 um 17:22 schrieb Corinna Vinschen:
> On May 25 19:53, Takashi Yano via Cygwin-developers wrote:
>> On Tue, 19 May 2020 22:40:18 +0900
>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>> On Sat, 16 May 2020 16:47:35 +0900
>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>>> On Sat, 16 May 2020 09:29:56 +0900
>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>>>> Fix a small bug caused when stdio is redirected to another pty.
>>>> Fix another bug caused when stdio is redirected to another pty.
>>> Revise the patch to fit the current git head.
>> Revise the patch again to fit the current git head.
> Works fine for me, but I have only a limited test scenario.
>
> Thomas, do you have any input so far?
I had a test suite which I plan to run on the patch. I cannot promise to 
make it this week, though, sorry.
Thomas

> In terms of the remaining disadvantages:
>
> 3) The cygwin program which call console API directly does not work.
>
>    I don't see a problem here.
>
> 4) The apps which use console API cannot be debugged with gdb.
>
>    Do you mean Cygwin apps or native apps?  I assume native apps
>    because of disadvantage 3...
>
>    Does that mean you can't even debug by attaching (via PID)?
>
> 5) Type ahead key inputs are discarded while native console app is
>     executed.
>
>    Hmm, not muchg of a problem, I think.
>
> 7) Code page cannot be changed by chcp.com.
>
>    I fail to see the exact drawback here.  I don't think a lot of users
>    use chcp, but of course I could be wrong.  I'd also be curious why
>    chcp doesn't work.
>
>
> Thanks,
> Corinna
>


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-25 15:22             ` Corinna Vinschen
  2020-05-25 19:16               ` Thomas Wolff
@ 2020-05-26  1:00               ` Takashi Yano
  2020-05-26  7:14                 ` Thomas Wolff
  2020-05-26  8:33                 ` Corinna Vinschen
  1 sibling, 2 replies; 73+ messages in thread
From: Takashi Yano @ 2020-05-26  1:00 UTC (permalink / raw)
  To: cygwin-developers

On Mon, 25 May 2020 17:22:04 +0200
Corinna Vinschen wrote:
> Works fine for me, but I have only a limited test scenario.

Thank you very much for testing.

> In terms of the remaining disadvantages:
> 
> 3) The cygwin program which call console API directly does not work.
> 
>   I don't see a problem here.

If the code below is compiled with cygwin gcc, it does not work.

#include <windows.h>
int main()
{
  WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "AAA\r\n", 5, NULL, 0);
  return 0;
}

However, this does not work also in cygwin 3.0.7, so it does not
matter for the app which works in cygwin 3.0.7.

> 4) The apps which use console API cannot be debugged with gdb.
> 
>   Do you mean Cygwin apps or native apps?  I assume native apps
>   because of disadvantage 3...

I mean native apps. If the process is executed by gdb, pseudo
console is not activated since gdb use CreateProcess() rather
than exec().

>   Does that mean you can't even debug by attaching (via PID)?

Attaching gdb to native apps, in which pseudo console is
already activated, should work.

> 5) Type ahead key inputs are discarded while native console app is
>    executed.
> 
>   Hmm, not muchg of a problem, I think.
> 
> 7) Code page cannot be changed by chcp.com.
> 
>   I fail to see the exact drawback here.  I don't think a lot of users
>   use chcp, but of course I could be wrong.  I'd also be curious why
>   chcp doesn't work.

Please note that pseudo console is created for each native 
console app in this implementation. Acctually, chcp works
itself and changes code page of its own pseudo console.
However, since pseudo console is recreated for another
process, which does not inherit the code page.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-25 10:53           ` Takashi Yano
  2020-05-25 15:22             ` Corinna Vinschen
@ 2020-05-26  1:09             ` Takashi Yano
  2020-05-28 15:40               ` Takashi Yano
  1 sibling, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-05-26  1:09 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 808 bytes --]

On Mon, 25 May 2020 19:53:32 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Tue, 19 May 2020 22:40:18 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Sat, 16 May 2020 16:47:35 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Sat, 16 May 2020 09:29:56 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > Fix a small bug caused when stdio is redirected to another pty.
> > > 
> > > Fix another bug caused when stdio is redirected to another pty.
> > 
> > Revise the patch to fit the current git head.
> 
> Revise the patch again to fit the current git head.

Make app, which reads stdin, work under gdb.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: pcon2-20200526.diff --]
[-- Type: text/plain, Size: 20311 bytes --]

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 76ad2aab0..7006aa060 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2264,6 +2264,7 @@ class fhandler_pty_common: public fhandler_termios
     return get_ttyp ()->h_pseudo_console;
   }
   bool to_be_read_from_pcon (void);
+  void resize_pseudo_console2 (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2356,6 +2357,9 @@ class fhandler_pty_slave: public fhandler_pty_common
   void wait_pcon_fwd (void);
   void pull_pcon_input (void);
   void update_pcon_input_state (bool need_lock);
+  bool setup_pseudoconsole2 (STARTUPINFOEXW *si);
+  void close_pseudoconsole2 (void);
+  void wait_pcon_fwd2 (void);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index df08dd20a..34c432370 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -41,6 +41,8 @@ extern "C" {
   VOID WINAPI ClosePseudoConsole (HPCON);
 }
 
+#define USE_PCON_MODE2 true
+
 #define close_maybe(h) \
   do { \
     if (h && h != INVALID_HANDLE_VALUE) \
@@ -73,7 +75,7 @@ clear_pcon_attached_to (void)
 }
 
 static void
-set_switch_to_pcon (void)
+set_switch_to_pcon (HANDLE h)
 {
   cygheap_fdenum cfd (false);
   int fd;
@@ -90,6 +92,8 @@ set_switch_to_pcon (void)
 	      ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
 	    SetConsoleMode (ptys->get_handle (), mode);
 	  }
+	else if (USE_PCON_MODE2 && h == ptys->get_handle ())
+	  ptys->set_switch_to_pcon (fd);
 	return;
       }
   /* No pty slave opened */
@@ -180,7 +184,7 @@ set_ishybrid_and_switch_to_pcon (HANDLE h)
 			|| GetLastError () != ERROR_INVALID_HANDLE))
 	{
 	  isHybrid = true;
-	  set_switch_to_pcon ();
+	  set_switch_to_pcon (h);
 	}
     }
 }
@@ -360,11 +364,25 @@ CreateProcessA_Hooked
       LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
+  if (USE_PCON_MODE2)
+    {
+      if (!isHybrid)
+	{
+	  if (si->dwFlags & STARTF_USESTDHANDLES)
+	    h = si->hStdInput;
+	  else
+	    h = GetStdHandle (STD_INPUT_HANDLE);
+	  set_switch_to_pcon (h);
+	}
+    }
   else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdOutput;
+      else
+	h = GetStdHandle (STD_OUTPUT_HANDLE);
+      set_ishybrid_and_switch_to_pcon (h);
+    }
   return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 static BOOL WINAPI
@@ -374,11 +392,25 @@ CreateProcessW_Hooked
       LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
+  if (USE_PCON_MODE2)
+    {
+      if (!isHybrid)
+	{
+	  if (si->dwFlags & STARTF_USESTDHANDLES)
+	    h = si->hStdInput;
+	  else
+	    h = GetStdHandle (STD_INPUT_HANDLE);
+	  set_switch_to_pcon (h);
+	}
+    }
   else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdOutput;
+      else
+	h = GetStdHandle (STD_OUTPUT_HANDLE);
+      set_ishybrid_and_switch_to_pcon (h);
+    }
   return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 
@@ -539,22 +571,26 @@ fhandler_pty_master::accept_input ()
 
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
+  if (to_be_read_from_pcon () && USE_PCON_MODE2)
+    write_to = to_slave;
+
   if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
     }
-  else if (!to_be_read_from_pcon ())
+  else if (!to_be_read_from_pcon () || USE_PCON_MODE2)
     {
       char *p = rabuf ();
       DWORD rc;
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -1264,6 +1300,18 @@ fhandler_pty_slave::set_switch_to_pcon (int fd_set)
 {
   if (fd < 0)
     fd = fd_set;
+  if (USE_PCON_MODE2)
+    {
+      if (!get_ttyp ()->switch_to_pcon_in)
+	{
+	  isHybrid = true;
+	  if (get_ttyp ()->pcon_pid == 0 ||
+	      !pinfo (get_ttyp ()->pcon_pid))
+	    get_ttyp ()->pcon_pid = myself->pid;
+	  get_ttyp ()->switch_to_pcon_in = true;
+	}
+      return;
+    }
   if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
     {
       pull_pcon_input ();
@@ -1308,6 +1356,7 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
   get_ttyp ()->switch_to_pcon_in = false;
   get_ttyp ()->switch_to_pcon_out = false;
   init_console_handler (true);
+  get_ttyp ()->h_pseudo_console2 = NULL;
 }
 
 void
@@ -1567,8 +1616,9 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 bool
 fhandler_pty_common::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return !get_ttyp ()->pcon_in_empty || get_ttyp ()->pcon2_start
+    || (get_ttyp ()->switch_to_pcon_in
+	&& !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
@@ -2072,6 +2122,8 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
 cleanup:
 	  restore_reattach_pcon ();
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
 
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
@@ -2361,6 +2413,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console2 (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2498,7 +2571,8 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon ()
+      && (!USE_PCON_MODE2 || get_ttyp ()->h_pseudo_console2))
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2510,11 +2584,52 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	get_ttyp ()->req_flush_pcon_input = true;
 
       DWORD wLen;
+
+      if (get_ttyp ()->pcon2_start)
+	{
+	  /* Pseudo condole support mode-2 uses "CSI6n" to get cursor
+	     position. If the reply for "CSI6n" is divided into multiple
+	     writes, pseudo console sometimes does not recognize it.
+	     Therefore, put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon2_start = false;
+	    }
+	  else
+	    {
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
+	    }
+	}
+
       WriteFile (to_slave, buf, nlen, &wLen, NULL);
       get_ttyp ()->pcon_in_empty = false;
 
       ReleaseMutex (input_mutex);
 
+#if !USE_PCON_MODE2
       /* Use line_edit () in order to set input_available_event. */
       bool is_echo = tc ()->ti.c_lflag & ECHO;
       if (!get_ttyp ()->mask_switch_to_pcon_in)
@@ -2540,6 +2655,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	      eat_readahead (-1);
 	      SetEvent (input_available_event);
 	    }
+#endif /* USE_PCON_MODE2 */
 
       mb_str_free (buf);
       return len;
@@ -2621,6 +2737,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
 	  size.Y = ((struct winsize *) arg)->ws_row;
 	  ResizePseudoConsole (get_pseudo_console (), size);
 	}
+      if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	resize_pseudo_console2 ((struct winsize *) arg);
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
@@ -2898,6 +3016,12 @@ fhandler_pty_slave::wait_pcon_fwd (void)
 	 && cygwait (get_ttyp ()->fwd_done, 1) == WAIT_TIMEOUT);
 }
 
+void
+fhandler_pty_slave::wait_pcon_fwd2 (void)
+{
+  get_ttyp ()->wait_pcon_fwd ();
+}
+
 void
 fhandler_pty_slave::trigger_redraw_screen (void)
 {
@@ -3051,6 +3175,12 @@ fhandler_pty_slave::fixup_after_exec ()
       DO_HOOK (NULL, CreateProcessA);
       DO_HOOK (NULL, CreateProcessW);
     }
+  if (USE_PCON_MODE2)
+    {
+      /* CreateProcess() is hooked for GDB etc. */
+      DO_HOOK (NULL, CreateProcessA);
+      DO_HOOK (NULL, CreateProcessW);
+    }
 }
 
 /* This thread function handles the master control pipe.  It waits for a
@@ -3267,6 +3397,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      Sleep (1);
 	    }
 	}
+      if (USE_PCON_MODE2)
+	get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3274,8 +3406,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_pseudo_console () || get_ttyp ()->h_pseudo_console2)
 	{
+#if !USE_PCON_MODE2
 	  /* Avoid duplicating slave output which is already sent to
 	     to_master_cyg */
 	  if (!get_ttyp ()->switch_to_pcon_out)
@@ -3328,6 +3461,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      rlen -= 4;
 	    }
 	  wlen = rlen;
+#endif /* USE_PCON_MODE2 */
 
 	  size_t nlen;
 	  char *buf = convert_mb_str
@@ -3697,7 +3831,19 @@ fhandler_pty_master::setup ()
   t.winsize.ws_col = 80;
   t.winsize.ws_row = 25;
 
-  setup_pseudoconsole ();
+  if (!USE_PCON_MODE2)
+    setup_pseudoconsole ();
+  else
+    {
+      __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;
+	}
+    }
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
@@ -3715,6 +3861,7 @@ fhandler_pty_master::setup ()
 err:
   __seterrno ();
   close_maybe (from_slave);
+  close_maybe (to_slave);
   close_maybe (get_handle ());
   close_maybe (get_output_handle ());
   close_maybe (input_available_event);
@@ -3859,3 +4006,126 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole2 (STARTUPINFOEXW *si)
+{
+  if (USE_PCON_MODE2)
+    {
+      fhandler_base *fh = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+	{
+	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	  ptys->get_ttyp ()->switch_to_pcon_in = true;
+	  if (ptys->get_ttyp ()->pcon_pid == 0 ||
+	      !pinfo (ptys->get_ttyp ()->pcon_pid))
+	    ptys->get_ttyp ()->pcon_pid = myself->pid;
+	}
+    }
+  if (!USE_PCON_MODE2)
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     1, &get_ttyp ()->h_pseudo_console2);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console2,
+				  sizeof (get_ttyp ()->h_pseudo_console2),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_pty_slave *p0 = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+    if (p0 && p0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = p0->get_handle ();
+    fhandler_pty_slave *p1 = (fhandler_pty_slave *) ::cygheap->fdtab[1];
+    if (p1 && p1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = p1->get_output_handle ();
+    fhandler_pty_slave *p2 = (fhandler_pty_slave *) ::cygheap->fdtab[2];
+    if (p2 && p2->get_device () != get_device ())
+      si->StartupInfo.hStdError = p2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon2_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console2 = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole2 (void)
+{
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console2 = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+    }
+}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..514125072 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -583,6 +601,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       /* Attach to pseudo console if pty salve is used */
       pid_restore = fhandler_console::get_console_process_id
 	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -591,6 +610,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	      if (ptys->get_pseudo_console ())
 		{
 		  DWORD helper_process_id = ptys->get_helper_process_id ();
@@ -632,6 +653,18 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool use_pcon_mode2 = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole2 (&si_pcon))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    use_pcon_mode2 = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +693,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +747,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +760,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (use_pcon_mode2)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +935,12 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (use_pcon_mode2)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->wait_pcon_fwd2 ();
+	      ptys_primary->close_pseudoconsole2 ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index efdae4697..28316ba6a 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -249,6 +249,8 @@ tty::init ()
   pcon_in_empty = true;
   req_transfer_input_to_pcon = false;
   req_flush_pcon_input = false;
+  h_pseudo_console2 = NULL;
+  pcon2_start = false;
 }
 
 HANDLE
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 7d6fc8fef..52f3872e2 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -110,6 +110,9 @@ private:
   bool pcon_in_empty;
   bool req_transfer_input_to_pcon;
   bool req_flush_pcon_input;
+  HPCON h_pseudo_console2;
+  HANDLE h_pcon_write_pipe;
+  bool pcon2_start;
 
 public:
   HANDLE from_master () const { return _from_master; }

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-26  1:00               ` Takashi Yano
@ 2020-05-26  7:14                 ` Thomas Wolff
  2020-05-26  9:21                   ` Takashi Yano
  2020-05-26  8:33                 ` Corinna Vinschen
  1 sibling, 1 reply; 73+ messages in thread
From: Thomas Wolff @ 2020-05-26  7:14 UTC (permalink / raw)
  To: cygwin-developers

Am 26.05.2020 um 03:00 schrieb Takashi Yano via Cygwin-developers:
> On Mon, 25 May 2020 17:22:04 +0200
> Corinna Vinschen wrote:
>> Works fine for me, but I have only a limited test scenario.
> Thank you very much for testing.
>
>> In terms of the remaining disadvantages:
>>
>> 3) The cygwin program which call console API directly does not work.
>>
>>    I don't see a problem here.
> If the code below is compiled with cygwin gcc, it does not work.
>
> #include <windows.h>
> int main()
> {
>    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "AAA\r\n", 5, NULL, 0);
>    return 0;
> }
This works for me.

> However, this does not work also in cygwin 3.0.7, so it does not
> matter for the app which works in cygwin 3.0.7.
>
>> 4) The apps which use console API cannot be debugged with gdb.
>>
>>    Do you mean Cygwin apps or native apps?  I assume native apps
>>    because of disadvantage 3...
> I mean native apps. If the process is executed by gdb, pseudo
> console is not activated since gdb use CreateProcess() rather
> than exec().
>
>>    Does that mean you can't even debug by attaching (via PID)?
> Attaching gdb to native apps, in which pseudo console is
> already activated, should work.
>
>> 5) Type ahead key inputs are discarded while native console app is
>>     executed.
>>
>>    Hmm, not muchg of a problem, I think.
>>
>> 7) Code page cannot be changed by chcp.com.
>>
>>    I fail to see the exact drawback here.  I don't think a lot of users
>>    use chcp, but of course I could be wrong.  I'd also be curious why
>>    chcp doesn't work.
> Please note that pseudo console is created for each native
> console app in this implementation. Acctually, chcp works
> itself and changes code page of its own pseudo console.
> However, since pseudo console is recreated for another
> process, which does not inherit the code page.
>


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-26  1:00               ` Takashi Yano
  2020-05-26  7:14                 ` Thomas Wolff
@ 2020-05-26  8:33                 ` Corinna Vinschen
  1 sibling, 0 replies; 73+ messages in thread
From: Corinna Vinschen @ 2020-05-26  8:33 UTC (permalink / raw)
  To: cygwin-developers

On May 26 10:00, Takashi Yano via Cygwin-developers wrote:
> On Mon, 25 May 2020 17:22:04 +0200
> Corinna Vinschen wrote:
> > Works fine for me, but I have only a limited test scenario.
> 
> Thank you very much for testing.
> 
> > In terms of the remaining disadvantages:
> > 
> > 3) The cygwin program which call console API directly does not work.
> > 
> >   I don't see a problem here.
> 
> If the code below is compiled with cygwin gcc, it does not work.
> 
> #include <windows.h>
> int main()
> {
>   WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "AAA\r\n", 5, NULL, 0);
>   return 0;
> }
> 
> However, this does not work also in cygwin 3.0.7, so it does not
> matter for the app which works in cygwin 3.0.7.

Cygwin apps are not supposed to use these functions anyway.  If Thomas
and mintty are fine with that, I'm totally relaxed.

> > 4) The apps which use console API cannot be debugged with gdb.
> > 
> >   Do you mean Cygwin apps or native apps?  I assume native apps
> >   because of disadvantage 3...
> 
> I mean native apps. If the process is executed by gdb, pseudo
> console is not activated since gdb use CreateProcess() rather
> than exec().

Ah, that makes sense.

> >   Does that mean you can't even debug by attaching (via PID)?
> 
> Attaching gdb to native apps, in which pseudo console is
> already activated, should work.

Great.

> > 5) Type ahead key inputs are discarded while native console app is
> >    executed.
> > 
> >   Hmm, not muchg of a problem, I think.
> > 
> > 7) Code page cannot be changed by chcp.com.
> > 
> >   I fail to see the exact drawback here.  I don't think a lot of users
> >   use chcp, but of course I could be wrong.  I'd also be curious why
> >   chcp doesn't work.
> 
> Please note that pseudo console is created for each native 
> console app in this implementation. Acctually, chcp works
> itself and changes code page of its own pseudo console.
> However, since pseudo console is recreated for another
> process, which does not inherit the code page.

Thanks, now I get it.  Not a show-stopper.


Corinna

-- 
Corinna Vinschen
Cygwin Maintainer

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-26  7:14                 ` Thomas Wolff
@ 2020-05-26  9:21                   ` Takashi Yano
  2020-05-26  9:32                     ` Thomas Wolff
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-05-26  9:21 UTC (permalink / raw)
  To: cygwin-developers

On Tue, 26 May 2020 09:14:39 +0200
Thomas Wolff wrote:
> Am 26.05.2020 um 03:00 schrieb Takashi Yano via Cygwin-developers:
> > If the code below is compiled with cygwin gcc, it does not work.
> >
> > #include <windows.h>
> > int main()
> > {
> >    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "AAA\r\n", 5, NULL, 0);
> >    return 0;
> > }
> This works for me.

That's strange. WriteFile() works but WriteConsole() should
not work. I meant cygwin native gcc by "gcc", but not
cygwin mingw gcc "x86_64-w64-mingw32-gcc".

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-26  9:21                   ` Takashi Yano
@ 2020-05-26  9:32                     ` Thomas Wolff
  0 siblings, 0 replies; 73+ messages in thread
From: Thomas Wolff @ 2020-05-26  9:32 UTC (permalink / raw)
  To: cygwin-developers

Am 26.05.2020 um 11:21 schrieb Takashi Yano via Cygwin-developers:
> On Tue, 26 May 2020 09:14:39 +0200
> Thomas Wolff wrote:
>> Am 26.05.2020 um 03:00 schrieb Takashi Yano via Cygwin-developers:
>>> If the code below is compiled with cygwin gcc, it does not work.
>>>
>>> #include <windows.h>
>>> int main()
>>> {
>>>     WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "AAA\r\n", 5, NULL, 0);
>>>     return 0;
>>> }
>> This works for me.
> That's strange. WriteFile() works but WriteConsole() should
> not work. I meant cygwin native gcc by "gcc", but not
> cygwin mingw gcc "x86_64-w64-mingw32-gcc".
Oh well, I seem to have confused the test setup. So it works in cygwin 
console but not in mintty with your new patch.
Works in mintty with 3.1.4. Also works with your patch if compiled with 
mingw-gcc, as expected.
With cygwin 3.0.7 in mintty, neither gcc nor mingw-compiled versions 
work for me.
Thomas

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-26  1:09             ` Takashi Yano
@ 2020-05-28 15:40               ` Takashi Yano
  2020-05-29 15:30                 ` Corinna Vinschen
  2020-07-01 11:47                 ` Takashi Yano
  0 siblings, 2 replies; 73+ messages in thread
From: Takashi Yano @ 2020-05-28 15:40 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 1064 bytes --]

On Tue, 26 May 2020 10:09:55 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Mon, 25 May 2020 19:53:32 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Tue, 19 May 2020 22:40:18 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Sat, 16 May 2020 16:47:35 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Sat, 16 May 2020 09:29:56 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > Fix a small bug caused when stdio is redirected to another pty.
> > > > 
> > > > Fix another bug caused when stdio is redirected to another pty.
> > > 
> > > Revise the patch to fit the current git head.
> > 
> > Revise the patch again to fit the current git head.
> 
> Make app, which reads stdin, work under gdb.

* Prevent ResizePseudoConsole() calls unless the pty is resized.
* Revise the patch to fit the current git head.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: pcon2-20200528.diff --]
[-- Type: text/plain, Size: 20327 bytes --]

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 76ad2aab0..7006aa060 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2264,6 +2264,7 @@ class fhandler_pty_common: public fhandler_termios
     return get_ttyp ()->h_pseudo_console;
   }
   bool to_be_read_from_pcon (void);
+  void resize_pseudo_console2 (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2356,6 +2357,9 @@ class fhandler_pty_slave: public fhandler_pty_common
   void wait_pcon_fwd (void);
   void pull_pcon_input (void);
   void update_pcon_input_state (bool need_lock);
+  bool setup_pseudoconsole2 (STARTUPINFOEXW *si);
+  void close_pseudoconsole2 (void);
+  void wait_pcon_fwd2 (void);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index b091765b3..6c042409a 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -41,6 +41,8 @@ extern "C" {
   VOID WINAPI ClosePseudoConsole (HPCON);
 }
 
+#define USE_PCON_MODE2 true
+
 #define close_maybe(h) \
   do { \
     if (h && h != INVALID_HANDLE_VALUE) \
@@ -73,7 +75,7 @@ clear_pcon_attached_to (void)
 }
 
 static void
-set_switch_to_pcon (void)
+set_switch_to_pcon (HANDLE h)
 {
   cygheap_fdenum cfd (false);
   int fd;
@@ -90,6 +92,8 @@ set_switch_to_pcon (void)
 	      ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
 	    SetConsoleMode (ptys->get_handle (), mode);
 	  }
+	else if (USE_PCON_MODE2 && h == ptys->get_handle ())
+	  ptys->set_switch_to_pcon (fd);
 	return;
       }
   /* No pty slave opened */
@@ -180,7 +184,7 @@ set_ishybrid_and_switch_to_pcon (HANDLE h)
 			|| GetLastError () != ERROR_INVALID_HANDLE))
 	{
 	  isHybrid = true;
-	  set_switch_to_pcon ();
+	  set_switch_to_pcon (h);
 	}
     }
 }
@@ -363,11 +367,25 @@ CreateProcessA_Hooked
       LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
+  if (USE_PCON_MODE2)
+    {
+      if (!isHybrid)
+	{
+	  if (si->dwFlags & STARTF_USESTDHANDLES)
+	    h = si->hStdInput;
+	  else
+	    h = GetStdHandle (STD_INPUT_HANDLE);
+	  set_switch_to_pcon (h);
+	}
+    }
   else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdOutput;
+      else
+	h = GetStdHandle (STD_OUTPUT_HANDLE);
+      set_ishybrid_and_switch_to_pcon (h);
+    }
   return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 static BOOL WINAPI
@@ -377,11 +395,25 @@ CreateProcessW_Hooked
       LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
+  if (USE_PCON_MODE2)
+    {
+      if (!isHybrid)
+	{
+	  if (si->dwFlags & STARTF_USESTDHANDLES)
+	    h = si->hStdInput;
+	  else
+	    h = GetStdHandle (STD_INPUT_HANDLE);
+	  set_switch_to_pcon (h);
+	}
+    }
   else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdOutput;
+      else
+	h = GetStdHandle (STD_OUTPUT_HANDLE);
+      set_ishybrid_and_switch_to_pcon (h);
+    }
   return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 
@@ -542,22 +574,26 @@ fhandler_pty_master::accept_input ()
 
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
+  if (to_be_read_from_pcon () && USE_PCON_MODE2)
+    write_to = to_slave;
+
   if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
     }
-  else if (!to_be_read_from_pcon ())
+  else if (!to_be_read_from_pcon () || USE_PCON_MODE2)
     {
       char *p = rabuf ();
       DWORD rc;
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -1267,6 +1303,18 @@ fhandler_pty_slave::set_switch_to_pcon (int fd_set)
 {
   if (fd < 0)
     fd = fd_set;
+  if (USE_PCON_MODE2)
+    {
+      if (!get_ttyp ()->switch_to_pcon_in)
+	{
+	  isHybrid = true;
+	  if (get_ttyp ()->pcon_pid == 0 ||
+	      !pinfo (get_ttyp ()->pcon_pid))
+	    get_ttyp ()->pcon_pid = myself->pid;
+	  get_ttyp ()->switch_to_pcon_in = true;
+	}
+      return;
+    }
   if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
     {
       pull_pcon_input ();
@@ -1311,6 +1359,7 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
   get_ttyp ()->switch_to_pcon_in = false;
   get_ttyp ()->switch_to_pcon_out = false;
   init_console_handler (true);
+  get_ttyp ()->h_pseudo_console2 = NULL;
 }
 
 void
@@ -1570,8 +1619,9 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 bool
 fhandler_pty_common::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return !get_ttyp ()->pcon_in_empty || get_ttyp ()->pcon2_start
+    || (get_ttyp ()->switch_to_pcon_in
+	&& !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
@@ -2079,6 +2129,8 @@ cleanup:
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
+	  if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console2 ((struct winsize *) arg);
 	  get_ttyp ()->arg.winsize = *(struct winsize *) arg;
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
@@ -2364,6 +2416,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console2 (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2501,7 +2574,8 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon ()
+      && (!USE_PCON_MODE2 || get_ttyp ()->h_pseudo_console2))
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2513,11 +2587,52 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	get_ttyp ()->req_flush_pcon_input = true;
 
       DWORD wLen;
+
+      if (get_ttyp ()->pcon2_start)
+	{
+	  /* Pseudo condole support mode-2 uses "CSI6n" to get cursor
+	     position. If the reply for "CSI6n" is divided into multiple
+	     writes, pseudo console sometimes does not recognize it.
+	     Therefore, put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon2_start = false;
+	    }
+	  else
+	    {
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
+	    }
+	}
+
       WriteFile (to_slave, buf, nlen, &wLen, NULL);
       get_ttyp ()->pcon_in_empty = false;
 
       ReleaseMutex (input_mutex);
 
+#if !USE_PCON_MODE2
       /* Use line_edit () in order to set input_available_event. */
       bool is_echo = tc ()->ti.c_lflag & ECHO;
       if (!get_ttyp ()->mask_switch_to_pcon_in)
@@ -2543,6 +2658,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	      eat_readahead (-1);
 	      SetEvent (input_available_event);
 	    }
+#endif /* USE_PCON_MODE2 */
 
       mb_str_free (buf);
       return len;
@@ -2627,6 +2743,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
 	      size.Y = ((struct winsize *) arg)->ws_row;
 	      ResizePseudoConsole (get_pseudo_console (), size);
 	    }
+	  if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console2 ((struct winsize *) arg);
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
 	}
@@ -2901,6 +3019,12 @@ fhandler_pty_slave::wait_pcon_fwd (void)
 	 && cygwait (get_ttyp ()->fwd_done, 1) == WAIT_TIMEOUT);
 }
 
+void
+fhandler_pty_slave::wait_pcon_fwd2 (void)
+{
+  get_ttyp ()->wait_pcon_fwd ();
+}
+
 void
 fhandler_pty_slave::trigger_redraw_screen (void)
 {
@@ -3054,6 +3178,12 @@ fhandler_pty_slave::fixup_after_exec ()
       DO_HOOK (NULL, CreateProcessA);
       DO_HOOK (NULL, CreateProcessW);
     }
+  if (USE_PCON_MODE2)
+    {
+      /* CreateProcess() is hooked for GDB etc. */
+      DO_HOOK (NULL, CreateProcessA);
+      DO_HOOK (NULL, CreateProcessW);
+    }
 }
 
 /* This thread function handles the master control pipe.  It waits for a
@@ -3270,6 +3400,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      Sleep (1);
 	    }
 	}
+      if (USE_PCON_MODE2)
+	get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3277,8 +3409,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_pseudo_console () || get_ttyp ()->h_pseudo_console2)
 	{
+#if !USE_PCON_MODE2
 	  /* Avoid duplicating slave output which is already sent to
 	     to_master_cyg */
 	  if (!get_ttyp ()->switch_to_pcon_out)
@@ -3331,6 +3464,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      rlen -= 4;
 	    }
 	  wlen = rlen;
+#endif /* USE_PCON_MODE2 */
 
 	  size_t nlen;
 	  char *buf = convert_mb_str
@@ -3700,7 +3834,19 @@ fhandler_pty_master::setup ()
   t.winsize.ws_col = 80;
   t.winsize.ws_row = 25;
 
-  setup_pseudoconsole ();
+  if (!USE_PCON_MODE2)
+    setup_pseudoconsole ();
+  else
+    {
+      __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;
+	}
+    }
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
@@ -3718,6 +3864,7 @@ fhandler_pty_master::setup ()
 err:
   __seterrno ();
   close_maybe (from_slave);
+  close_maybe (to_slave);
   close_maybe (get_handle ());
   close_maybe (get_output_handle ());
   close_maybe (input_available_event);
@@ -3862,3 +4009,126 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole2 (STARTUPINFOEXW *si)
+{
+  if (USE_PCON_MODE2)
+    {
+      fhandler_base *fh = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+	{
+	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	  ptys->get_ttyp ()->switch_to_pcon_in = true;
+	  if (ptys->get_ttyp ()->pcon_pid == 0 ||
+	      !pinfo (ptys->get_ttyp ()->pcon_pid))
+	    ptys->get_ttyp ()->pcon_pid = myself->pid;
+	}
+    }
+  if (!USE_PCON_MODE2)
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     1, &get_ttyp ()->h_pseudo_console2);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console2,
+				  sizeof (get_ttyp ()->h_pseudo_console2),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_pty_slave *p0 = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+    if (p0 && p0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = p0->get_handle ();
+    fhandler_pty_slave *p1 = (fhandler_pty_slave *) ::cygheap->fdtab[1];
+    if (p1 && p1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = p1->get_output_handle ();
+    fhandler_pty_slave *p2 = (fhandler_pty_slave *) ::cygheap->fdtab[2];
+    if (p2 && p2->get_device () != get_device ())
+      si->StartupInfo.hStdError = p2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon2_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console2 = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole2 (void)
+{
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console2 = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+    }
+}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..514125072 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -583,6 +601,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       /* Attach to pseudo console if pty salve is used */
       pid_restore = fhandler_console::get_console_process_id
 	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -591,6 +610,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	      if (ptys->get_pseudo_console ())
 		{
 		  DWORD helper_process_id = ptys->get_helper_process_id ();
@@ -632,6 +653,18 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool use_pcon_mode2 = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole2 (&si_pcon))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    use_pcon_mode2 = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +693,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +747,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +760,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (use_pcon_mode2)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +935,12 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (use_pcon_mode2)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->wait_pcon_fwd2 ();
+	      ptys_primary->close_pseudoconsole2 ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index efdae4697..28316ba6a 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -249,6 +249,8 @@ tty::init ()
   pcon_in_empty = true;
   req_transfer_input_to_pcon = false;
   req_flush_pcon_input = false;
+  h_pseudo_console2 = NULL;
+  pcon2_start = false;
 }
 
 HANDLE
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 7d6fc8fef..52f3872e2 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -110,6 +110,9 @@ private:
   bool pcon_in_empty;
   bool req_transfer_input_to_pcon;
   bool req_flush_pcon_input;
+  HPCON h_pseudo_console2;
+  HANDLE h_pcon_write_pipe;
+  bool pcon2_start;
 
 public:
   HANDLE from_master () const { return _from_master; }

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-28 15:40               ` Takashi Yano
@ 2020-05-29 15:30                 ` Corinna Vinschen
  2020-05-30  7:36                   ` Takashi Yano
  2020-07-01 11:47                 ` Takashi Yano
  1 sibling, 1 reply; 73+ messages in thread
From: Corinna Vinschen @ 2020-05-29 15:30 UTC (permalink / raw)
  To: Takashi Yano; +Cc: cygwin-developers

Hi Takashi,

On May 29 00:40, Takashi Yano via Cygwin-developers wrote:
> On Tue, 26 May 2020 10:09:55 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Mon, 25 May 2020 19:53:32 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Tue, 19 May 2020 22:40:18 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Sat, 16 May 2020 16:47:35 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > On Sat, 16 May 2020 09:29:56 +0900
> > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > Fix a small bug caused when stdio is redirected to another pty.
> > > > > 
> > > > > Fix another bug caused when stdio is redirected to another pty.
> > > > 
> > > > Revise the patch to fit the current git head.
> > > 
> > > Revise the patch again to fit the current git head.
> > 
> > Make app, which reads stdin, work under gdb.
> 
> * Prevent ResizePseudoConsole() calls unless the pty is resized.
> * Revise the patch to fit the current git head.
> [...]

I assume this should only go into the next Cygwin release after 3.1.5,
right?

Ken and I are planning to release 3.1.5 this weekend or Monday at the
latest.  Do you have any more patches in the loop which should go into
3.1.5?


Thanks,
Corinna

-- 
Corinna Vinschen
Cygwin Maintainer

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-29 15:30                 ` Corinna Vinschen
@ 2020-05-30  7:36                   ` Takashi Yano
  2020-05-30 13:14                     ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-05-30  7:36 UTC (permalink / raw)
  To: cygwin-developers

On Fri, 29 May 2020 17:30:29 +0200
Corinna Vinschen wrote:
> On May 29 00:40, Takashi Yano via Cygwin-developers wrote:
> > On Tue, 26 May 2020 10:09:55 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Mon, 25 May 2020 19:53:32 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Tue, 19 May 2020 22:40:18 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > On Sat, 16 May 2020 16:47:35 +0900
> > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > On Sat, 16 May 2020 09:29:56 +0900
> > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > Fix a small bug caused when stdio is redirected to another pty.
> > > > > > 
> > > > > > Fix another bug caused when stdio is redirected to another pty.
> > > > > 
> > > > > Revise the patch to fit the current git head.
> > > > 
> > > > Revise the patch again to fit the current git head.
> > > 
> > > Make app, which reads stdin, work under gdb.
> > 
> > * Prevent ResizePseudoConsole() calls unless the pty is resized.
> > * Revise the patch to fit the current git head.
> > [...]
> 
> I assume this should only go into the next Cygwin release after 3.1.5,
> right?

I think this experimental implementation needs more tests and
discussions. So I don't think it should not go into 3.1.5.

> Ken and I are planning to release 3.1.5 this weekend or Monday at the
> latest.  Do you have any more patches in the loop which should go into
> 3.1.5?

I have one patch for a ConEmu specific issue. I will submit it
within a few hours.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-30  7:36                   ` Takashi Yano
@ 2020-05-30 13:14                     ` Takashi Yano
  2020-05-30 17:43                       ` Corinna Vinschen
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-05-30 13:14 UTC (permalink / raw)
  To: cygwin-developers

On Sat, 30 May 2020 16:36:28 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Fri, 29 May 2020 17:30:29 +0200
> Corinna Vinschen wrote:
> > On May 29 00:40, Takashi Yano via Cygwin-developers wrote:
> > > On Tue, 26 May 2020 10:09:55 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Mon, 25 May 2020 19:53:32 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > On Tue, 19 May 2020 22:40:18 +0900
> > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > On Sat, 16 May 2020 16:47:35 +0900
> > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > On Sat, 16 May 2020 09:29:56 +0900
> > > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > > Fix a small bug caused when stdio is redirected to another pty.
> > > > > > > 
> > > > > > > Fix another bug caused when stdio is redirected to another pty.
> > > > > > 
> > > > > > Revise the patch to fit the current git head.
> > > > > 
> > > > > Revise the patch again to fit the current git head.
> > > > 
> > > > Make app, which reads stdin, work under gdb.
> > > 
> > > * Prevent ResizePseudoConsole() calls unless the pty is resized.
> > > * Revise the patch to fit the current git head.
> > > [...]
> > 
> > I assume this should only go into the next Cygwin release after 3.1.5,
> > right?
> 
> I think this experimental implementation needs more tests and
> discussions. So I don't think it should not go into 3.1.5.

I mean "I think it should not go into 3.1.5"....

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-30 13:14                     ` Takashi Yano
@ 2020-05-30 17:43                       ` Corinna Vinschen
  2020-05-31  5:52                         ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Corinna Vinschen @ 2020-05-30 17:43 UTC (permalink / raw)
  To: cygwin-developers

On May 30 22:14, Takashi Yano via Cygwin-developers wrote:
> On Sat, 30 May 2020 16:36:28 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Fri, 29 May 2020 17:30:29 +0200
> > Corinna Vinschen wrote:
> > > On May 29 00:40, Takashi Yano via Cygwin-developers wrote:
> > > > On Tue, 26 May 2020 10:09:55 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > On Mon, 25 May 2020 19:53:32 +0900
> > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > On Tue, 19 May 2020 22:40:18 +0900
> > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > On Sat, 16 May 2020 16:47:35 +0900
> > > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > > On Sat, 16 May 2020 09:29:56 +0900
> > > > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > > > Fix a small bug caused when stdio is redirected to another pty.
> > > > > > > > 
> > > > > > > > Fix another bug caused when stdio is redirected to another pty.
> > > > > > > 
> > > > > > > Revise the patch to fit the current git head.
> > > > > > 
> > > > > > Revise the patch again to fit the current git head.
> > > > > 
> > > > > Make app, which reads stdin, work under gdb.
> > > > 
> > > > * Prevent ResizePseudoConsole() calls unless the pty is resized.
> > > > * Revise the patch to fit the current git head.
> > > > [...]
> > > 
> > > I assume this should only go into the next Cygwin release after 3.1.5,
> > > right?
> > 
> > I think this experimental implementation needs more tests and
> > discussions. So I don't think it should not go into 3.1.5.
> 
> I mean "I think it should not go into 3.1.5"....

I guessed so, no worries.  If nothing else crops up I will create the
3.1.5 release probably on Monday (it's a holiday here).


Thanks,
Corinna

-- 
Corinna Vinschen
Cygwin Maintainer

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-30 17:43                       ` Corinna Vinschen
@ 2020-05-31  5:52                         ` Takashi Yano
  0 siblings, 0 replies; 73+ messages in thread
From: Takashi Yano @ 2020-05-31  5:52 UTC (permalink / raw)
  To: cygwin-developers

Hi Corinna,

On Sat, 30 May 2020 19:43:01 +0200
Corinna Vinschen wrote:
> On May 30 22:14, Takashi Yano via Cygwin-developers wrote:
> > On Sat, 30 May 2020 16:36:28 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Fri, 29 May 2020 17:30:29 +0200
> > > Corinna Vinschen wrote:
> > > > On May 29 00:40, Takashi Yano via Cygwin-developers wrote:
> > > > > On Tue, 26 May 2020 10:09:55 +0900
> > > > > * Prevent ResizePseudoConsole() calls unless the pty is resized.
> > > > > * Revise the patch to fit the current git head.
> > > > > [...]
> > > > 
> > > > I assume this should only go into the next Cygwin release after 3.1.5,
> > > > right?
> > > 
> > > I think this experimental implementation needs more tests and
> > > discussions. So I don't think it should not go into 3.1.5.
> > 
> > I mean "I think it should not go into 3.1.5"....
> 
> I guessed so, no worries.  If nothing else crops up I will create the
> 3.1.5 release probably on Monday (it's a holiday here).

I would like to propose four more patches. One is for the issue
https://cygwin.com/pipermail/cygwin/2020-May/245057.html, and
others are for the issues that were noticed during this fix.

I apologize for the submission at the last minute.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-05-28 15:40               ` Takashi Yano
  2020-05-29 15:30                 ` Corinna Vinschen
@ 2020-07-01 11:47                 ` Takashi Yano
  2020-07-17 11:19                   ` Corinna Vinschen
  1 sibling, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-07-01 11:47 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 1263 bytes --]

On Fri, 29 May 2020 00:40:24 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Tue, 26 May 2020 10:09:55 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Mon, 25 May 2020 19:53:32 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Tue, 19 May 2020 22:40:18 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Sat, 16 May 2020 16:47:35 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > On Sat, 16 May 2020 09:29:56 +0900
> > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > Fix a small bug caused when stdio is redirected to another pty.
> > > > > 
> > > > > Fix another bug caused when stdio is redirected to another pty.
> > > > 
> > > > Revise the patch to fit the current git head.
> > > 
> > > Revise the patch again to fit the current git head.
> > 
> > Make app, which reads stdin, work under gdb.
> 
> * Prevent ResizePseudoConsole() calls unless the pty is resized.
> * Revise the patch to fit the current git head.

Revise the patch to fit the current git head.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: pcon2-20200630.diff --]
[-- Type: text/plain, Size: 20340 bytes --]

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index c6ce6d8e1..10ef2ae4a 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2265,6 +2265,7 @@ class fhandler_pty_common: public fhandler_termios
     return get_ttyp ()->h_pseudo_console;
   }
   bool to_be_read_from_pcon (void);
+  void resize_pseudo_console2 (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2356,6 +2357,8 @@ class fhandler_pty_slave: public fhandler_pty_common
   void trigger_redraw_screen (void);
   void pull_pcon_input (void);
   void update_pcon_input_state (bool need_lock);
+  bool setup_pseudoconsole2 (STARTUPINFOEXW *si);
+  void close_pseudoconsole2 (void);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index a61167116..adaf2352c 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -41,6 +41,8 @@ extern "C" {
   VOID WINAPI ClosePseudoConsole (HPCON);
 }
 
+#define USE_PCON_MODE2 true
+
 #define close_maybe(h) \
   do { \
     if (h && h != INVALID_HANDLE_VALUE) \
@@ -73,7 +75,7 @@ clear_pcon_attached_to (void)
 }
 
 static void
-set_switch_to_pcon (void)
+set_switch_to_pcon (HANDLE h)
 {
   cygheap_fdenum cfd (false);
   int fd;
@@ -90,6 +92,8 @@ set_switch_to_pcon (void)
 	      ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
 	    SetConsoleMode (ptys->get_handle (), mode);
 	  }
+	else if (USE_PCON_MODE2 && h == ptys->get_handle ())
+	  ptys->set_switch_to_pcon (fd);
 	return;
       }
   /* No pty slave opened */
@@ -180,7 +184,7 @@ set_ishybrid_and_switch_to_pcon (HANDLE h)
 			|| GetLastError () != ERROR_INVALID_HANDLE))
 	{
 	  isHybrid = true;
-	  set_switch_to_pcon ();
+	  set_switch_to_pcon (h);
 	}
     }
 }
@@ -363,11 +367,25 @@ CreateProcessA_Hooked
       LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
+  if (USE_PCON_MODE2)
+    {
+      if (!isHybrid)
+	{
+	  if (si->dwFlags & STARTF_USESTDHANDLES)
+	    h = si->hStdInput;
+	  else
+	    h = GetStdHandle (STD_INPUT_HANDLE);
+	  set_switch_to_pcon (h);
+	}
+    }
   else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdOutput;
+      else
+	h = GetStdHandle (STD_OUTPUT_HANDLE);
+      set_ishybrid_and_switch_to_pcon (h);
+    }
   return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 static BOOL WINAPI
@@ -377,11 +395,25 @@ CreateProcessW_Hooked
       LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
+  if (USE_PCON_MODE2)
+    {
+      if (!isHybrid)
+	{
+	  if (si->dwFlags & STARTF_USESTDHANDLES)
+	    h = si->hStdInput;
+	  else
+	    h = GetStdHandle (STD_INPUT_HANDLE);
+	  set_switch_to_pcon (h);
+	}
+    }
   else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdOutput;
+      else
+	h = GetStdHandle (STD_OUTPUT_HANDLE);
+      set_ishybrid_and_switch_to_pcon (h);
+    }
   return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 
@@ -535,7 +567,7 @@ fhandler_pty_master::doecho (const void *str, DWORD len)
 int
 fhandler_pty_master::put_readahead (char value)
 {
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon () && !USE_PCON_MODE2)
     return 1;
   return fhandler_base::put_readahead (value);
 }
@@ -551,7 +583,11 @@ fhandler_pty_master::accept_input ()
   char *p = rabuf () + raixget ();
   bytes_left = eat_readahead (-1);
 
-  if (to_be_read_from_pcon ())
+  HANDLE write_to = get_output_handle ();
+  if (to_be_read_from_pcon () && USE_PCON_MODE2)
+    write_to = to_slave;
+
+  if (to_be_read_from_pcon () && !USE_PCON_MODE2)
     ; /* Do nothing */
   else if (!bytes_left)
     {
@@ -564,10 +600,10 @@ fhandler_pty_master::accept_input ()
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -1278,6 +1314,18 @@ fhandler_pty_slave::set_switch_to_pcon (int fd_set)
 {
   if (fd < 0)
     fd = fd_set;
+  if (USE_PCON_MODE2)
+    {
+      if (!get_ttyp ()->switch_to_pcon_in)
+	{
+	  isHybrid = true;
+	  if (get_ttyp ()->pcon_pid == 0 ||
+	      !pinfo (get_ttyp ()->pcon_pid))
+	    get_ttyp ()->pcon_pid = myself->pid;
+	  get_ttyp ()->switch_to_pcon_in = true;
+	}
+      return;
+    }
   acquire_output_mutex (INFINITE);
   if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
     {
@@ -1326,6 +1374,7 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
   get_ttyp ()->switch_to_pcon_out = false;
   release_output_mutex ();
   init_console_handler (true);
+  get_ttyp ()->h_pseudo_console2 = NULL;
 }
 
 void
@@ -1589,8 +1638,9 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 bool
 fhandler_pty_common::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return !get_ttyp ()->pcon_in_empty || get_ttyp ()->pcon2_start
+    || (get_ttyp ()->switch_to_pcon_in
+	&& !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
@@ -2098,6 +2148,8 @@ cleanup:
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
+	  if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console2 ((struct winsize *) arg);
 	  get_ttyp ()->arg.winsize = *(struct winsize *) arg;
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
@@ -2383,6 +2435,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console2 (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2518,7 +2591,8 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon ()
+      && (!USE_PCON_MODE2 || get_ttyp ()->h_pseudo_console2))
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2530,11 +2604,52 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	get_ttyp ()->req_flush_pcon_input = true;
 
       DWORD wLen;
+
+      if (get_ttyp ()->pcon2_start)
+	{
+	  /* Pseudo condole support mode-2 uses "CSI6n" to get cursor
+	     position. If the reply for "CSI6n" is divided into multiple
+	     writes, pseudo console sometimes does not recognize it.
+	     Therefore, put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon2_start = false;
+	    }
+	  else
+	    {
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon2_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
+	    }
+	}
+
       WriteFile (to_slave, buf, nlen, &wLen, NULL);
       get_ttyp ()->pcon_in_empty = false;
 
       ReleaseMutex (input_mutex);
 
+#if !USE_PCON_MODE2
       /* Use line_edit () in order to set input_available_event. */
       bool is_echo = tc ()->ti.c_lflag & ECHO;
       if (!get_ttyp ()->mask_switch_to_pcon_in)
@@ -2560,6 +2675,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	      eat_readahead (-1);
 	      SetEvent (input_available_event);
 	    }
+#endif /* USE_PCON_MODE2 */
 
       mb_str_free (buf);
       return len;
@@ -2644,6 +2760,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
 	      size.Y = ((struct winsize *) arg)->ws_row;
 	      ResizePseudoConsole (get_pseudo_console (), size);
 	    }
+	  if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console2 ((struct winsize *) arg);
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
 	}
@@ -3062,6 +3180,12 @@ fhandler_pty_slave::fixup_after_exec ()
       DO_HOOK (NULL, CreateProcessA);
       DO_HOOK (NULL, CreateProcessW);
     }
+  if (USE_PCON_MODE2)
+    {
+      /* CreateProcess() is hooked for GDB etc. */
+      DO_HOOK (NULL, CreateProcessA);
+      DO_HOOK (NULL, CreateProcessW);
+    }
 }
 
 /* This thread function handles the master control pipe.  It waits for a
@@ -3262,6 +3386,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	      Sleep (1);
 	    }
 	}
+      if (USE_PCON_MODE2)
+	get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3269,8 +3395,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_pseudo_console () || get_ttyp ()->h_pseudo_console2)
 	{
+#if !USE_PCON_MODE2
 	  /* Avoid duplicating slave output which is already sent to
 	     to_master_cyg */
 	  if (!get_ttyp ()->switch_to_pcon_out)
@@ -3314,6 +3441,10 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	  /* Remove CSI > Pm m */
 	  state = 0;
 	  start_at = 0;
+#else /* USE_PCON_MODE2 */
+	  int state = 0;
+	  int start_at = 0;
+#endif /* USE_PCON_MODE2 */
 	  for (DWORD i=0; i<rlen; i++)
 	    if (outbuf[i] == '\033')
 	      {
@@ -3704,7 +3835,19 @@ fhandler_pty_master::setup ()
   t.winsize.ws_col = 80;
   t.winsize.ws_row = 25;
 
-  setup_pseudoconsole ();
+  if (!USE_PCON_MODE2)
+    setup_pseudoconsole ();
+  else
+    {
+      __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;
+	}
+    }
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
@@ -3722,6 +3865,7 @@ fhandler_pty_master::setup ()
 err:
   __seterrno ();
   close_maybe (from_slave);
+  close_maybe (to_slave);
   close_maybe (get_handle ());
   close_maybe (get_output_handle ());
   close_maybe (input_available_event);
@@ -3866,3 +4010,124 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole2 (STARTUPINFOEXW *si)
+{
+  if (!USE_PCON_MODE2)
+    return false;
+  fhandler_base *fh = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+    {
+      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+      ptys->get_ttyp ()->switch_to_pcon_in = true;
+      if (ptys->get_ttyp ()->pcon_pid == 0 ||
+	  !pinfo (ptys->get_ttyp ()->pcon_pid))
+	ptys->get_ttyp ()->pcon_pid = myself->pid;
+    }
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     1, &get_ttyp ()->h_pseudo_console2);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console2,
+				  sizeof (get_ttyp ()->h_pseudo_console2),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_pty_slave *p0 = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+    if (p0 && p0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = p0->get_handle ();
+    fhandler_pty_slave *p1 = (fhandler_pty_slave *) ::cygheap->fdtab[1];
+    if (p1 && p1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = p1->get_output_handle ();
+    fhandler_pty_slave *p2 = (fhandler_pty_slave *) ::cygheap->fdtab[2];
+    if (p2 && p2->get_device () != get_device ())
+      si->StartupInfo.hStdError = p2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console2 && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon2_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console2 = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole2 (void)
+{
+  if (get_ttyp ()->h_pseudo_console2)
+    {
+      get_ttyp ()->wait_pcon_fwd ();
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console2;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console2);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console2 = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+    }
+}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..9c4068106 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -583,6 +601,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       /* Attach to pseudo console if pty salve is used */
       pid_restore = fhandler_console::get_console_process_id
 	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -591,6 +610,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	      if (ptys->get_pseudo_console ())
 		{
 		  DWORD helper_process_id = ptys->get_helper_process_id ();
@@ -632,6 +653,18 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool use_pcon_mode2 = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole2 (&si_pcon))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    use_pcon_mode2 = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +693,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +747,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +760,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (use_pcon_mode2)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +935,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (use_pcon_mode2)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->close_pseudoconsole2 ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 4cb68f776..1d296f36e 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -248,6 +248,8 @@ tty::init ()
   pcon_in_empty = true;
   req_transfer_input_to_pcon = false;
   req_flush_pcon_input = false;
+  h_pseudo_console2 = NULL;
+  pcon2_start = false;
 }
 
 HANDLE
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 920e32b16..9372f73b2 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -109,6 +109,9 @@ private:
   bool pcon_in_empty;
   bool req_transfer_input_to_pcon;
   bool req_flush_pcon_input;
+  HPCON h_pseudo_console2;
+  HANDLE h_pcon_write_pipe;
+  bool pcon2_start;
 
 public:
   HANDLE from_master () const { return _from_master; }

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-01 11:47                 ` Takashi Yano
@ 2020-07-17 11:19                   ` Corinna Vinschen
  2020-07-17 12:47                     ` Thomas Wolff
                                       ` (2 more replies)
  0 siblings, 3 replies; 73+ messages in thread
From: Corinna Vinschen @ 2020-07-17 11:19 UTC (permalink / raw)
  To: Takashi Yano; +Cc: cygwin-developers

Hi Takashi,

On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> On Fri, 29 May 2020 00:40:24 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Tue, 26 May 2020 10:09:55 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Mon, 25 May 2020 19:53:32 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Tue, 19 May 2020 22:40:18 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > On Sat, 16 May 2020 16:47:35 +0900
> > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > On Sat, 16 May 2020 09:29:56 +0900
> > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > Fix a small bug caused when stdio is redirected to another pty.
> > > > > > 
> > > > > > Fix another bug caused when stdio is redirected to another pty.
> > > > > 
> > > > > Revise the patch to fit the current git head.
> > > > 
> > > > Revise the patch again to fit the current git head.
> > > 
> > > Make app, which reads stdin, work under gdb.
> > 
> > * Prevent ResizePseudoConsole() calls unless the pty is resized.
> > * Revise the patch to fit the current git head.
> 
> Revise the patch to fit the current git head.

are you satisfied with the code?  If you want to merge it,
I'd bump Cygwin to 3.2.


Thanks,
Corinna

-- 
Corinna Vinschen
Cygwin Maintainer

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-17 11:19                   ` Corinna Vinschen
@ 2020-07-17 12:47                     ` Thomas Wolff
  2020-07-17 14:59                       ` Thomas Wolff
  2020-07-17 12:52                     ` Ken Brown
  2020-07-18  5:30                     ` Takashi Yano
  2 siblings, 1 reply; 73+ messages in thread
From: Thomas Wolff @ 2020-07-17 12:47 UTC (permalink / raw)
  To: cygwin-developers

Am 17.07.2020 um 13:19 schrieb Corinna Vinschen:
> Hi Takashi,
>
> On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
>> On Fri, 29 May 2020 00:40:24 +0900
>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>> On Tue, 26 May 2020 10:09:55 +0900
>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>>> On Mon, 25 May 2020 19:53:32 +0900
>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>>>> On Tue, 19 May 2020 22:40:18 +0900
>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>>>>> On Sat, 16 May 2020 16:47:35 +0900
>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>>>>>> On Sat, 16 May 2020 09:29:56 +0900
>>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>>>>>>> Fix a small bug caused when stdio is redirected to another pty.
>>>>>>> Fix another bug caused when stdio is redirected to another pty.
>>>>>> Revise the patch to fit the current git head.
>>>>> Revise the patch again to fit the current git head.
>>>> Make app, which reads stdin, work under gdb.
>>> * Prevent ResizePseudoConsole() calls unless the pty is resized.
>>> * Revise the patch to fit the current git head.
>> Revise the patch to fit the current git head.
> are you satisfied with the code?  If you want to merge it,
> I'd bump Cygwin to 3.2.
(blush) I apologize, I had promised to run my test cases.
Beginning with it, the first succeeded, the second failed:
run notepad (from mintty), click back into terminal, enter ^Z
It says "Stopped" but the process is gone.

Continuing may test suite soon...
Thomas

>
>
> Thanks,
> Corinna

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-17 11:19                   ` Corinna Vinschen
  2020-07-17 12:47                     ` Thomas Wolff
@ 2020-07-17 12:52                     ` Ken Brown
  2020-07-18  5:07                       ` Takashi Yano
  2020-07-18  5:30                     ` Takashi Yano
  2 siblings, 1 reply; 73+ messages in thread
From: Ken Brown @ 2020-07-17 12:52 UTC (permalink / raw)
  To: cygwin-developers

On 7/17/2020 7:19 AM, Corinna Vinschen wrote:
> Hi Takashi,
> 
> On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
>> On Fri, 29 May 2020 00:40:24 +0900
>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>> On Tue, 26 May 2020 10:09:55 +0900
>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>>> On Mon, 25 May 2020 19:53:32 +0900
>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>>>> On Tue, 19 May 2020 22:40:18 +0900
>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>>>>> On Sat, 16 May 2020 16:47:35 +0900
>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>>>>>> On Sat, 16 May 2020 09:29:56 +0900
>>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>>>>>>> Fix a small bug caused when stdio is redirected to another pty.
>>>>>>>
>>>>>>> Fix another bug caused when stdio is redirected to another pty.
>>>>>>
>>>>>> Revise the patch to fit the current git head.
>>>>>
>>>>> Revise the patch again to fit the current git head.
>>>>
>>>> Make app, which reads stdin, work under gdb.
>>>
>>> * Prevent ResizePseudoConsole() calls unless the pty is resized.
>>> * Revise the patch to fit the current git head.
>>
>> Revise the patch to fit the current git head.
> 
> are you satisfied with the code?  If you want to merge it,
> I'd bump Cygwin to 3.2.

FWIW, I just installed this patch locally and am seeing noticeable speed 
improvements.  For example, here's the result of running 'make -j13 check' in 
the info subdirectory of the texinfo source directory.  [I chose this test 
because it uses both FIFOs and ptys.]

Without the patch:

$ time make -j13 check
[...]
real    0m20.705s
user    0m18.639s
sys     0m40.187s

With the patch:

$ time make -j13 check
[...]
real    0m9.332s
user    0m14.153s
sys     0m30.235s

Ken

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-17 12:47                     ` Thomas Wolff
@ 2020-07-17 14:59                       ` Thomas Wolff
  2020-07-18  5:05                         ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Thomas Wolff @ 2020-07-17 14:59 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 3348 bytes --]

Am 17.07.2020 um 14:47 schrieb Thomas Wolff:
> Am 17.07.2020 um 13:19 schrieb Corinna Vinschen:
>> Hi Takashi,
>>
>> On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
>>> On Fri, 29 May 2020 00:40:24 +0900
>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> 
>>> wrote:
>>>> On Tue, 26 May 2020 10:09:55 +0900
>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> 
>>>> wrote:
>>>>> On Mon, 25 May 2020 19:53:32 +0900
>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> 
>>>>> wrote:
>>>>>> On Tue, 19 May 2020 22:40:18 +0900
>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> 
>>>>>> wrote:
>>>>>>> On Sat, 16 May 2020 16:47:35 +0900
>>>>>>> Takashi Yano via Cygwin-developers 
>>>>>>> <cygwin-developers@cygwin.com> wrote:
>>>>>>>> On Sat, 16 May 2020 09:29:56 +0900
>>>>>>>> Takashi Yano via Cygwin-developers 
>>>>>>>> <cygwin-developers@cygwin.com> wrote:
>>>>>>>>> Fix a small bug caused when stdio is redirected to another pty.
>>>>>>>> Fix another bug caused when stdio is redirected to another pty.
>>>>>>> Revise the patch to fit the current git head.
>>>>>> Revise the patch again to fit the current git head.
>>>>> Make app, which reads stdin, work under gdb.
>>>> * Prevent ResizePseudoConsole() calls unless the pty is resized.
>>>> * Revise the patch to fit the current git head.
>>> Revise the patch to fit the current git head.
>> are you satisfied with the code?  If you want to merge it,
>> I'd bump Cygwin to 3.2.
> (blush) I apologize, I had promised to run my test cases.
> Beginning with it, the first succeeded, the second failed:
> run notepad (from mintty), click back into terminal, enter ^Z
> It says "Stopped" but the process is gone.
>
> Continuing may test suite soon...
OK, so here are finally my updated test results:


resize terminal while running Windows cmd
run cmd, resize, run dir/P:
✓works


terminal reports in response to request escape sequences
("\033[6n", "\033[0c", "\033[>c", '\033[18t', '\033]10;?\033\')
✓works


output to alternate screen
echo -e "\e[?1047h"; cmd
✓works
cmd
from other terminal: echo -e "\e[?1047h" > /dev/pty...
↯no output; weird behaviour on ^C, mintty terminating (also in 3.1.6)


signal handling/mediation; catch SIGTSTP
run notepad, click back into terminal, enter ^Z
↯fails, notepad is terminated
-> this is a regression, ^Z,^C,^\ used to be ignored


character set conversion from Windows cmd line program
run xcopy (Windows system language e.g. German), watch error message
✓works in Unicode terminal
✓works in non-Unicode terminal (e.g. LC_ALL=C.CP850 mintty)


handling non-ASCII characters in non-Unicode terminal + native interworking
LC_ALL=en_US mintty, check locale charmap -> ISO-8859-1
echo ö | od -t x1 -> 0xF6
✓works
cmd /c echo ö | od -t x1 -> 0x94
↯fails (also in cygwin 3.1.6)


using wincon.c, compiled with x86_64-w64-mingw32-gcc
run program, check colour of second output, give non-ASCII input, check echo
✓works in Unicode mintty
✓works in non-Unicode mintty


using attached wincon.c, compiled with gcc
run program, check colour of second output, give non-ASCII input, check echo
↯no output (regression, works in 3.1.6)


using attached program sgr.java
run program, check coloured output of middle characters
✓works (did not in 3.1.6)


[-- Attachment #2: wincon.c --]
[-- Type: text/plain, Size: 492 bytes --]

#include <wchar.h>
#include <windows.h>

void main()
{
  wchar_t * s = u"bäh 3€ 啕\n";
  HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
  DWORD len;

  WriteConsoleW(conout, s, wcslen(s), &len, 0);

  SetConsoleTextAttribute(conout, FOREGROUND_GREEN);
  WriteConsoleW(conout, s, wcslen(s), &len, 0);

  wchar_t buf[99];
  HANDLE conin = GetStdHandle(STD_INPUT_HANDLE);
  ReadConsoleW(conin, buf, 9, &len, 0);
  buf[len] = 0;
  DWORD len1;
  WriteConsoleW(conout, buf, len, &len1, 0);
}

[-- Attachment #3: sgr.java --]
[-- Type: text/plain, Size: 137 bytes --]

import java.io.*;

public class sgr {
    static public void main(String[] args) {
        System.out.println("ab^[[41mCD^[[mef");
    }
}

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-17 14:59                       ` Thomas Wolff
@ 2020-07-18  5:05                         ` Takashi Yano
  2020-07-18 20:57                           ` Thomas Wolff
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-07-18  5:05 UTC (permalink / raw)
  To: cygwin-developers

Hi Thomas,

Thanks for testing.

On Fri, 17 Jul 2020 16:59:56 +0200
Thomas Wolff wrote:
> Am 17.07.2020 um 14:47 schrieb Thomas Wolff:
> > Am 17.07.2020 um 13:19 schrieb Corinna Vinschen:
> >> Hi Takashi,
> >>
> >> On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> >>> On Fri, 29 May 2020 00:40:24 +0900
> >>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> 
> >>> wrote:
> >>>> On Tue, 26 May 2020 10:09:55 +0900
> >>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> 
> >>>> wrote:
> >>>>> On Mon, 25 May 2020 19:53:32 +0900
> >>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> 
> >>>>> wrote:
> >>>>>> On Tue, 19 May 2020 22:40:18 +0900
> >>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> 
> >>>>>> wrote:
> >>>>>>> On Sat, 16 May 2020 16:47:35 +0900
> >>>>>>> Takashi Yano via Cygwin-developers 
> >>>>>>> <cygwin-developers@cygwin.com> wrote:
> >>>>>>>> On Sat, 16 May 2020 09:29:56 +0900
> >>>>>>>> Takashi Yano via Cygwin-developers 
> >>>>>>>> <cygwin-developers@cygwin.com> wrote:
> >>>>>>>>> Fix a small bug caused when stdio is redirected to another pty.
> >>>>>>>> Fix another bug caused when stdio is redirected to another pty.
> >>>>>>> Revise the patch to fit the current git head.
> >>>>>> Revise the patch again to fit the current git head.
> >>>>> Make app, which reads stdin, work under gdb.
> >>>> * Prevent ResizePseudoConsole() calls unless the pty is resized.
> >>>> * Revise the patch to fit the current git head.
> >>> Revise the patch to fit the current git head.
> >> are you satisfied with the code?  If you want to merge it,
> >> I'd bump Cygwin to 3.2.
> > (blush) I apologize, I had promised to run my test cases.
> > Beginning with it, the first succeeded, the second failed:
> > run notepad (from mintty), click back into terminal, enter ^Z
> > It says "Stopped" but the process is gone.
> >
> > Continuing may test suite soon...
> OK, so here are finally my updated test results:
> 
> 
> resize terminal while running Windows cmd
> run cmd, resize, run dir/P:
> ✓works
> 
> 
> terminal reports in response to request escape sequences
> ("\033[6n", "\033[0c", "\033[>c", '\033[18t', '\033]10;?\033\')
> ✓works
> 
> 
> output to alternate screen
> echo -e "\e[?1047h"; cmd
> ✓works
> cmd
> from other terminal: echo -e "\e[?1047h" > /dev/pty...
> ↯no output; weird behaviour on ^C, mintty terminating (also in 3.1.6)

I found this is a bug introduced in commit
0365031ce1347600d854a23f30f1355745a1765c.

I will submit a patch for this issue.

> signal handling/mediation; catch SIGTSTP
> run notepad, click back into terminal, enter ^Z
> ↯fails, notepad is terminated
> -> this is a regression, ^Z,^C,^\ used to be ignored

This behaviour is the same as cygwin 3.0.7. Pseudo console is not
activated for native GUI processes.

> character set conversion from Windows cmd line program
> run xcopy (Windows system language e.g. German), watch error message
> ✓works in Unicode terminal
> ✓works in non-Unicode terminal (e.g. LC_ALL=C.CP850 mintty)
> 
> 
> handling non-ASCII characters in non-Unicode terminal + native interworking
> LC_ALL=en_US mintty, check locale charmap -> ISO-8859-1
> echo ö | od -t x1 -> 0xF6
> ✓works
> cmd /c echo ö | od -t x1 -> 0x94
> ↯fails (also in cygwin 3.1.6)

In this case, stdout is not a pty. So this is not a pty problem.

> using wincon.c, compiled with x86_64-w64-mingw32-gcc
> run program, check colour of second output, give non-ASCII input, check echo
> ✓works in Unicode mintty
> ✓works in non-Unicode mintty
> 
> 
> using attached wincon.c, compiled with gcc
> run program, check colour of second output, give non-ASCII input, check echo
> ↯no output (regression, works in 3.1.6)

This is due to the disadvantage 3) I mentioned in the first post.
Disadvantage:
3) The cygwin program which call console API directly does not work.

> using attached program sgr.java
> run program, check coloured output of middle characters
> ✓works (did not in 3.1.6)

This may work by chance. Escape sequences in native console apps
are supported only with ENABLE_VIRTUAL_TERMINAL_PROCESSING.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-17 12:52                     ` Ken Brown
@ 2020-07-18  5:07                       ` Takashi Yano
  0 siblings, 0 replies; 73+ messages in thread
From: Takashi Yano @ 2020-07-18  5:07 UTC (permalink / raw)
  To: cygwin-developers

Hi Ken,

Thanks for testing.

On Fri, 17 Jul 2020 08:52:15 -0400
Ken Brown via Cygwin-developers <cygwin-developers@cygwin.com> wrote:

> On 7/17/2020 7:19 AM, Corinna Vinschen wrote:
> > Hi Takashi,
> > 
> > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> >> On Fri, 29 May 2020 00:40:24 +0900
> >> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> >>> On Tue, 26 May 2020 10:09:55 +0900
> >>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> >>>> On Mon, 25 May 2020 19:53:32 +0900
> >>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> >>>>> On Tue, 19 May 2020 22:40:18 +0900
> >>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> >>>>>> On Sat, 16 May 2020 16:47:35 +0900
> >>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> >>>>>>> On Sat, 16 May 2020 09:29:56 +0900
> >>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> >>>>>>>> Fix a small bug caused when stdio is redirected to another pty.
> >>>>>>>
> >>>>>>> Fix another bug caused when stdio is redirected to another pty.
> >>>>>>
> >>>>>> Revise the patch to fit the current git head.
> >>>>>
> >>>>> Revise the patch again to fit the current git head.
> >>>>
> >>>> Make app, which reads stdin, work under gdb.
> >>>
> >>> * Prevent ResizePseudoConsole() calls unless the pty is resized.
> >>> * Revise the patch to fit the current git head.
> >>
> >> Revise the patch to fit the current git head.
> > 
> > are you satisfied with the code?  If you want to merge it,
> > I'd bump Cygwin to 3.2.
> 
> FWIW, I just installed this patch locally and am seeing noticeable speed 
> improvements.  For example, here's the result of running 'make -j13 check' in 
> the info subdirectory of the texinfo source directory.  [I chose this test 
> because it uses both FIFOs and ptys.]
> 
> Without the patch:
> 
> $ time make -j13 check
> [...]
> real    0m20.705s
> user    0m18.639s
> sys     0m40.187s
> 
> With the patch:
> 
> $ time make -j13 check
> [...]
> real    0m9.332s
> user    0m14.153s
> sys     0m30.235s

This is the advantage 1) in my first post.
Advantage:
1) No performance degradation in pty output for cygwin process.
    https://sourceware.org/pipermail/cygwin/2020-February/243651.html

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-17 11:19                   ` Corinna Vinschen
  2020-07-17 12:47                     ` Thomas Wolff
  2020-07-17 12:52                     ` Ken Brown
@ 2020-07-18  5:30                     ` Takashi Yano
  2020-07-20  8:06                       ` Corinna Vinschen
  2 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-07-18  5:30 UTC (permalink / raw)
  To: cygwin-developers

Hi Corinna,

On Fri, 17 Jul 2020 13:19:12 +0200
Corinna Vinschen wrote:
> Hi Takashi,
> 
> On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > On Fri, 29 May 2020 00:40:24 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Tue, 26 May 2020 10:09:55 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Mon, 25 May 2020 19:53:32 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > On Tue, 19 May 2020 22:40:18 +0900
> > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > On Sat, 16 May 2020 16:47:35 +0900
> > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > On Sat, 16 May 2020 09:29:56 +0900
> > > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > > Fix a small bug caused when stdio is redirected to another pty.
> > > > > > > 
> > > > > > > Fix another bug caused when stdio is redirected to another pty.
> > > > > > 
> > > > > > Revise the patch to fit the current git head.
> > > > > 
> > > > > Revise the patch again to fit the current git head.
> > > > 
> > > > Make app, which reads stdin, work under gdb.
> > > 
> > > * Prevent ResizePseudoConsole() calls unless the pty is resized.
> > > * Revise the patch to fit the current git head.
> > 
> > Revise the patch to fit the current git head.
> 
> are you satisfied with the code?  If you want to merge it,
> I'd bump Cygwin to 3.2.

Since this new implementation has both advantages and disadvantages,
there might be some options.

1) Default to new implementation and leave the current one as an
  alternative. Switch them using the environment CYGWIN.
2) Default to current implementation and add the new one as an
  alternative. Switch them using the environment CYGWIN.
3) Adopt only new implementation and throw the current one away.

What do you think?

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-18  5:05                         ` Takashi Yano
@ 2020-07-18 20:57                           ` Thomas Wolff
  2020-07-23 17:17                             ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Thomas Wolff @ 2020-07-18 20:57 UTC (permalink / raw)
  To: cygwin-developers

Am 18.07.2020 um 07:05 schrieb Takashi Yano via Cygwin-developers:
> Hi Thomas,
>
> Thanks for testing.
>
> On Fri, 17 Jul 2020 16:59:56 +0200
> Thomas Wolff wrote:
>> Am 17.07.2020 um 14:47 schrieb Thomas Wolff:
>>> Am 17.07.2020 um 13:19 schrieb Corinna Vinschen:
>>>> Hi Takashi,
>>>>
>>>> On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
>>>>> On Fri, 29 May 2020 00:40:24 +0900
>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com>
>>>>> wrote:
>>>>>> On Tue, 26 May 2020 10:09:55 +0900
>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com>
>>>>>> wrote:
>>>>>>> On Mon, 25 May 2020 19:53:32 +0900
>>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com>
>>>>>>> wrote:
>>>>>>>> On Tue, 19 May 2020 22:40:18 +0900
>>>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com>
>>>>>>>> wrote:
>>>>>>>>> On Sat, 16 May 2020 16:47:35 +0900
>>>>>>>>> Takashi Yano via Cygwin-developers
>>>>>>>>> <cygwin-developers@cygwin.com> wrote:
>>>>>>>>>> On Sat, 16 May 2020 09:29:56 +0900
>>>>>>>>>> Takashi Yano via Cygwin-developers
>>>>>>>>>> <cygwin-developers@cygwin.com> wrote:
>>>>>>>>>>> Fix a small bug caused when stdio is redirected to another pty.
>>>>>>>>>> Fix another bug caused when stdio is redirected to another pty.
>>>>>>>>> Revise the patch to fit the current git head.
>>>>>>>> Revise the patch again to fit the current git head.
>>>>>>> Make app, which reads stdin, work under gdb.
>>>>>> * Prevent ResizePseudoConsole() calls unless the pty is resized.
>>>>>> * Revise the patch to fit the current git head.
>>>>> Revise the patch to fit the current git head.
>>>> are you satisfied with the code?  If you want to merge it,
>>>> I'd bump Cygwin to 3.2.
>>> (blush) I apologize, I had promised to run my test cases.
>>> Beginning with it, the first succeeded, the second failed:
>>> run notepad (from mintty), click back into terminal, enter ^Z
>>> It says "Stopped" but the process is gone.
>>>
>>> Continuing may test suite soon...
>> OK, so here are finally my updated test results:
>>
>>
>> resize terminal while running Windows cmd
>> run cmd, resize, run dir/P:
>> ✓works
>>
>>
>> terminal reports in response to request escape sequences
>> ("\033[6n", "\033[0c", "\033[>c", '\033[18t', '\033]10;?\033\')
>> ✓works
>>
>>
>> output to alternate screen
>> echo -e "\e[?1047h"; cmd
>> ✓works
>> cmd
>> from other terminal: echo -e "\e[?1047h" > /dev/pty...
>> ↯no output; weird behaviour on ^C, mintty terminating (also in 3.1.6)
> I found this is a bug introduced in commit
> 0365031ce1347600d854a23f30f1355745a1765c.
>
> I will submit a patch for this issue.
>
>> signal handling/mediation; catch SIGTSTP
>> run notepad, click back into terminal, enter ^Z
>> ↯fails, notepad is terminated
>> -> this is a regression, ^Z,^C,^\ used to be ignored
> This behaviour is the same as cygwin 3.0.7. Pseudo console is not
> activated for native GUI processes.
OK, I understand this is consistent with my own proposal to apply pseudo 
console only for Windows command-line programs. On the other hand, fatal 
signal handling is another nuisance of running Windows programs from 
cygwin, so there was a benefit.
Is it possible to activate the signal interworking without setting up a 
pseudo console? If not, is it maybe worth to set it up also for Windows 
GUI programs just for this purpose? (Modifying my proposal to trigger on 
any Windows program.)

>> character set conversion from Windows cmd line program
>> run xcopy (Windows system language e.g. German), watch error message
>> ✓works in Unicode terminal
>> ✓works in non-Unicode terminal (e.g. LC_ALL=C.CP850 mintty)
>>
>>
>> handling non-ASCII characters in non-Unicode terminal + native interworking
>> LC_ALL=en_US mintty, check locale charmap -> ISO-8859-1
>> echo ö | od -t x1 -> 0xF6
>> ✓works
>> cmd /c echo ö | od -t x1 -> 0x94
>> ↯fails (also in cygwin 3.1.6)
> In this case, stdout is not a pty. So this is not a pty problem.
>
>> using wincon.c, compiled with x86_64-w64-mingw32-gcc
>> run program, check colour of second output, give non-ASCII input, check echo
>> ✓works in Unicode mintty
>> ✓works in non-Unicode mintty
>>
>>
>> using attached wincon.c, compiled with gcc
>> run program, check colour of second output, give non-ASCII input, check echo
>> ↯no output (regression, works in 3.1.6)
> This is due to the disadvantage 3) I mentioned in the first post.
> Disadvantage:
> 3) The cygwin program which call console API directly does not work.
Understood, I think this is an acceptable trade-off.

>> using attached program sgr.java
>> run program, check coloured output of middle characters
>> ✓works (did not in 3.1.6)
> This may work by chance. Escape sequences in native console apps
> are supported only with ENABLE_VIRTUAL_TERMINAL_PROCESSING.
So this seems to be enabled by the Java runtime. Would be nice if there 
were a Windows option (exe file property) to enforce the mode even for 
programs that do not actively invoke it. I've filed an issue 
(https://github.com/microsoft/terminal/issues/6973) to this aim.

Kind regards,
Thomas

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-18  5:30                     ` Takashi Yano
@ 2020-07-20  8:06                       ` Corinna Vinschen
  2020-07-21 18:17                         ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Corinna Vinschen @ 2020-07-20  8:06 UTC (permalink / raw)
  To: Takashi Yano; +Cc: cygwin-developers

On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
> Hi Corinna,
> 
> On Fri, 17 Jul 2020 13:19:12 +0200
> Corinna Vinschen wrote:
> > Hi Takashi,
> > 
> > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > > [...]
> > > Revise the patch to fit the current git head.
> > 
> > are you satisfied with the code?  If you want to merge it,
> > I'd bump Cygwin to 3.2.
> 
> Since this new implementation has both advantages and disadvantages,
> there might be some options.
> 
> 1) Default to new implementation and leave the current one as an
>   alternative. Switch them using the environment CYGWIN.
> 2) Default to current implementation and add the new one as an
>   alternative. Switch them using the environment CYGWIN.
> 3) Adopt only new implementation and throw the current one away.
> 
> What do you think?

Do you really want to maintain twice as much code doing the same stuff
and constantly having to ask users which version of the code they are
running?  The maintenance cost outweighs the advantages, IMHO.
Personally I'd go for option 3.


Corinna

-- 
Corinna Vinschen
Cygwin Maintainer

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-20  8:06                       ` Corinna Vinschen
@ 2020-07-21 18:17                         ` Takashi Yano
  2020-07-22  8:45                           ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-07-21 18:17 UTC (permalink / raw)
  To: cygwin-developers

Hi Corinna,

On Mon, 20 Jul 2020 10:06:13 +0200
Corinna Vinschen wrote:
> On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
> > Hi Corinna,
> > 
> > On Fri, 17 Jul 2020 13:19:12 +0200
> > Corinna Vinschen wrote:
> > > Hi Takashi,
> > > 
> > > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > > > [...]
> > > > Revise the patch to fit the current git head.
> > > 
> > > are you satisfied with the code?  If you want to merge it,
> > > I'd bump Cygwin to 3.2.
> > 
> > Since this new implementation has both advantages and disadvantages,
> > there might be some options.
> > 
> > 1) Default to new implementation and leave the current one as an
> >   alternative. Switch them using the environment CYGWIN.
> > 2) Default to current implementation and add the new one as an
> >   alternative. Switch them using the environment CYGWIN.
> > 3) Adopt only new implementation and throw the current one away.
> > 
> > What do you think?
> 
> Do you really want to maintain twice as much code doing the same stuff
> and constantly having to ask users which version of the code they are
> running?  The maintenance cost outweighs the advantages, IMHO.
> Personally I'd go for option 3.

Personally, I feel a tinge of sadness to discard the current code,
however, your opinion sounds reasonable.

I will submit a new patch in which all the codes specific to the
current implementation are removed.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-21 18:17                         ` Takashi Yano
@ 2020-07-22  8:45                           ` Takashi Yano
  2020-07-22 11:49                             ` Corinna Vinschen
  2020-07-23  0:33                             ` Takashi Yano
  0 siblings, 2 replies; 73+ messages in thread
From: Takashi Yano @ 2020-07-22  8:45 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 1887 bytes --]

On Wed, 22 Jul 2020 03:17:51 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> Hi Corinna,
> 
> On Mon, 20 Jul 2020 10:06:13 +0200
> Corinna Vinschen wrote:
> > On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
> > > Hi Corinna,
> > > 
> > > On Fri, 17 Jul 2020 13:19:12 +0200
> > > Corinna Vinschen wrote:
> > > > Hi Takashi,
> > > > 
> > > > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > > > > [...]
> > > > > Revise the patch to fit the current git head.
> > > > 
> > > > are you satisfied with the code?  If you want to merge it,
> > > > I'd bump Cygwin to 3.2.
> > > 
> > > Since this new implementation has both advantages and disadvantages,
> > > there might be some options.
> > > 
> > > 1) Default to new implementation and leave the current one as an
> > >   alternative. Switch them using the environment CYGWIN.
> > > 2) Default to current implementation and add the new one as an
> > >   alternative. Switch them using the environment CYGWIN.
> > > 3) Adopt only new implementation and throw the current one away.
> > > 
> > > What do you think?
> > 
> > Do you really want to maintain twice as much code doing the same stuff
> > and constantly having to ask users which version of the code they are
> > running?  The maintenance cost outweighs the advantages, IMHO.
> > Personally I'd go for option 3.
> 
> Personally, I feel a tinge of sadness to discard the current code,
> however, your opinion sounds reasonable.
> 
> I will submit a new patch in which all the codes specific to the
> current implementation are removed.

Attached is the patch in git format-patch format.
All the codes specific to the current implementation are removed.

Despite the utmost care, the changes are relatively large, so some
degradation may exist.

I will appreciate if you could test.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-Cygwin-pty-Implement-new-pseudo-console-support.patch --]
[-- Type: application/octet-stream, Size: 86250 bytes --]

From a21b1b27e4b57968e14ffe07177951fd1bc7a06b Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Wed, 22 Jul 2020 12:39:45 +0900
Subject: [PATCH] Cygwin: pty: Implement new pseudo console support.

- In this implementation, pseudo console is created for each native
  console app. Advantages and disadvantages of this implementation
  over the previous implementation are as follows.

  Advantages:
  1) No performance degradation in pty output for cygwin process.
      https://cygwin.com/pipermail/cygwin/2020-February/243858.html
  2) Free from the problem caused by difference of behaviour of control
     sequences between real terminal and pseudo console.
      https://cygwin.com/pipermail/cygwin/2019-December/243281.html
      https://cygwin.com/pipermail/cygwin/2020-February/243855.html
  3) Free from the problem in cgdb and emacs gud.
      https://cygwin.com/pipermail/cygwin/2020-January/243601.html
      https://cygwin.com/pipermail/cygwin/2020-March/244146.html
  4) Redrawing screen on executing native console apps is not necessary.
  5) cygwin-console-helper is not necessary for the pseudo console
     support.
  6) The codes for pseudo console support are much simpler than that
     of the previous one.

  Disadvantages:
  1) The cygwin program which calls console API directly does not work.
  2) The apps which use console API cannot be debugged with gdb. This
     is because pseudo console is not activated since gdb uses
     CreateProcess() rather than exec(). Even with this limitation,
     attaching gdb to native apps, in which pseudo console is already
     activated, works.
  3) Typeahead key inputs are discarded while native console app is
     executed. Simirally, typeahead key inputs while cygwin app is
     executed are not inherited to native console app.
  4) Code page cannot be changed by chcp.com. Acctually, chcp works
     itself and changes code page of its own pseudo console.  However,
     since pseudo console is recreated for another process, it cannot
     inherit the code page.
  5) system_printf() does not work after stderr is closed. (Same with
     cygwin 3.0.7)
  6) Startup time of native console apps is about 3 times slower than
     previous implemenation.
---
 winsup/cygwin/dtable.cc           |   32 -
 winsup/cygwin/fhandler.h          |   51 +-
 winsup/cygwin/fhandler_console.cc |   43 -
 winsup/cygwin/fhandler_tty.cc     | 1733 +++++------------------------
 winsup/cygwin/fork.cc             |   30 -
 winsup/cygwin/select.cc           |    2 -
 winsup/cygwin/smallprint.cc       |    2 -
 winsup/cygwin/spawn.cc            |   87 +-
 winsup/cygwin/strace.cc           |    2 -
 winsup/cygwin/tty.cc              |   20 +-
 winsup/cygwin/tty.h               |   13 +-
 winsup/cygwin/winsup.h            |    3 -
 12 files changed, 317 insertions(+), 1701 deletions(-)

diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index e9e005b08..6a91e33bc 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -147,38 +147,6 @@ dtable::get_debugger_info ()
 void
 dtable::stdio_init ()
 {
-  for (int i = 0; i < 3; i ++)
-    {
-      const int chk_order[] = {1, 0, 2};
-      int fd = chk_order[i];
-      fhandler_base *fh = cygheap->fdtab[fd];
-      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
-	{
-	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	  if (ptys->get_pseudo_console ())
-	    {
-	      bool attached = !!fhandler_console::get_console_process_id
-		(ptys->get_helper_process_id (), true);
-	      if (attached)
-		break;
-	      else
-		{
-		  /* Not attached to pseudo console in fork() or spawn()
-		     by some reason. This happens if the executable is
-		     a windows GUI binary, such as mintty. */
-		  FreeConsole ();
-		  if (AttachConsole (ptys->get_helper_process_id ()))
-		    {
-		      ptys->fixup_after_attach (false, fd);
-		      break;
-		    }
-		}
-	    }
-	}
-      else if (fh && fh->get_major () == DEV_CONS_MAJOR)
-	break;
-    }
-
   if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT))
     {
       tty_min *t = cygwin_shared->tty.get_cttyp ();
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 60bd27e00..544108a23 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -326,16 +326,16 @@ class fhandler_base
   virtual size_t &raixput () { return ra.raixput; };
   virtual size_t &rabuflen () { return ra.rabuflen; };
 
-  virtual bool get_readahead_valid () { return raixget () < ralen (); }
+  bool get_readahead_valid () { return raixget () < ralen (); }
   int puts_readahead (const char *s, size_t len = (size_t) -1);
-  virtual int put_readahead (char value);
+  int put_readahead (char value);
 
   int get_readahead ();
   int peek_readahead (int queryput = 0);
 
   void set_readahead_valid (int val, int ch = -1);
 
-  virtual int get_readahead_into_buffer (char *buf, size_t buflen);
+  int get_readahead_into_buffer (char *buf, size_t buflen);
 
   bool has_acls () const { return pc.has_acls (); }
 
@@ -1909,7 +1909,7 @@ class fhandler_termios: public fhandler_base
   int ioctl (int, void *);
   tty_min *_tc;
   tty *get_ttyp () {return (tty *) tc ();}
-  virtual int eat_readahead (int n);
+  int eat_readahead (int n);
 
  public:
   tty_min*& tc () {return _tc;}
@@ -2188,7 +2188,6 @@ private:
   static bool need_invisible ();
   static void free_console ();
   static const char *get_nonascii_key (INPUT_RECORD& input_rec, char *);
-  static DWORD get_console_process_id (DWORD pid, bool match);
 
   fhandler_console (void *) {}
 
@@ -2268,19 +2267,8 @@ class fhandler_pty_common: public fhandler_termios
     return fh;
   }
 
-  bool attach_pcon_in_fork (void)
-  {
-    return get_ttyp ()->attach_pcon_in_fork;
-  }
-  DWORD get_helper_process_id (void)
-  {
-    return get_ttyp ()->helper_process_id;
-  }
-  HPCON get_pseudo_console (void)
-  {
-    return get_ttyp ()->h_pseudo_console;
-  }
   bool to_be_read_from_pcon (void);
+  void resize_pseudo_console (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2291,23 +2279,15 @@ class fhandler_pty_slave: public fhandler_pty_common
 {
   HANDLE inuse;			// used to indicate that a tty is in use
   HANDLE output_handle_cyg, io_handle_cyg;
-  DWORD pid_restore;
-  int fd;
 
   /* Helper functions for fchmod and fchown. */
   bool fch_open_handles (bool chown);
   int fch_set_sd (security_descriptor &sd, bool chown);
   void fch_close_handles ();
 
-  bool try_reattach_pcon ();
-  void restore_reattach_pcon ();
-  inline void free_attached_console ();
-
  public:
   /* Constructor */
   fhandler_pty_slave (int);
-  /* Destructor */
-  ~fhandler_pty_slave ();
 
   void set_output_handle_cyg (HANDLE h) { output_handle_cyg = h; }
   HANDLE& get_output_handle_cyg () { return output_handle_cyg; }
@@ -2319,9 +2299,6 @@ class fhandler_pty_slave: public fhandler_pty_common
   ssize_t __stdcall write (const void *ptr, size_t len);
   void __reg3 read (void *ptr, size_t& len);
   int init (HANDLE, DWORD, mode_t);
-  int eat_readahead (int n);
-  int get_readahead_into_buffer (char *buf, size_t buflen);
-  bool get_readahead_valid (void);
 
   int tcsetattr (int a, const struct termios *t);
   int tcgetattr (struct termios *t);
@@ -2358,20 +2335,12 @@ class fhandler_pty_slave: public fhandler_pty_common
     copyto (fh);
     return fh;
   }
-  void set_switch_to_pcon (int fd);
+  bool setup_pseudoconsole (STARTUPINFOEXW *si);
+  void close_pseudoconsole (void);
+  void set_switch_to_pcon (void);
   void reset_switch_to_pcon (void);
-  void push_to_pcon_screenbuffer (const char *ptr, size_t len, bool is_echo);
   void mask_switch_to_pcon_in (bool mask);
-  void fixup_after_attach (bool native_maybe, int fd);
-  bool is_line_input (void)
-  {
-    return get_ttyp ()->ti.c_lflag & ICANON;
-  }
   void setup_locale (void);
-  void set_freeconsole_on_close (bool val);
-  void trigger_redraw_screen (void);
-  void pull_pcon_input (void);
-  void update_pcon_input_state (bool need_lock);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
@@ -2396,7 +2365,6 @@ public:
   int process_slave_output (char *buf, size_t len, int pktmode_on);
   void doecho (const void *str, DWORD len);
   int accept_input ();
-  int put_readahead (char value);
   int open (int flags, mode_t mode = 0);
   void open_setup (int flags);
   ssize_t __stdcall write (const void *ptr, size_t len);
@@ -2435,9 +2403,6 @@ public:
     copyto (fh);
     return fh;
   }
-
-  bool setup_pseudoconsole (void);
-  void transfer_input_to_pcon (void);
 };
 
 class fhandler_dev_null: public fhandler_base
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 52741ce8b..02a5996a1 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -1206,18 +1206,6 @@ fhandler_console::close ()
   if (con_ra.rabuf)
     free (con_ra.rabuf);
 
-  /* If already attached to pseudo console, don't call free_console () */
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR ||
-	cfd->get_major () == DEV_PTYS_MAJOR)
-      {
-	fhandler_pty_common *t =
-	  (fhandler_pty_common *) (fhandler_base *) cfd;
-	if (get_console_process_id (t->get_helper_process_id (), true))
-	  return 0;
-      }
-
   if (!have_execed)
     free_console ();
   return 0;
@@ -3611,37 +3599,6 @@ fhandler_console::need_invisible ()
   return b;
 }
 
-DWORD
-fhandler_console::get_console_process_id (DWORD pid, bool match)
-{
-  DWORD tmp;
-  DWORD num, num_req;
-  num = 1;
-  num_req = GetConsoleProcessList (&tmp, num);
-  DWORD *list;
-  while (true)
-    {
-      list = (DWORD *)
-	HeapAlloc (GetProcessHeap (), 0, num_req * sizeof (DWORD));
-      num = num_req;
-      num_req = GetConsoleProcessList (list, num);
-      if (num_req > num)
-	HeapFree (GetProcessHeap (), 0, list);
-      else
-	break;
-    }
-  num = num_req;
-
-  tmp = 0;
-  for (DWORD i=0; i<num; i++)
-    if ((match && list[i] == pid) || (!match && list[i] != pid))
-      /* Last one is the oldest. */
-      /* https://github.com/microsoft/terminal/issues/95 */
-      tmp = list[i];
-  HeapFree (GetProcessHeap (), 0, list);
-  return tmp;
-}
-
 DWORD
 fhandler_console::__acquire_input_mutex (const char *fn, int ln, DWORD ms)
 {
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 6a004f3a5..2cb6d5de0 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -25,7 +25,6 @@ details. */
 #include "child_info.h"
 #include <asm/socket.h>
 #include "cygwait.h"
-#include "tls_pbuf.h"
 #include "registry.h"
 
 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
@@ -33,7 +32,6 @@ details. */
 #endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
 
 extern "C" int sscanf (const char *, const char *, ...);
-extern "C" int ttyname_r (int, char*, size_t);
 
 extern "C" {
   HRESULT WINAPI CreatePseudoConsole (COORD, HANDLE, HANDLE, DWORD, HPCON *);
@@ -60,20 +58,10 @@ struct pipe_reply {
   DWORD error;
 };
 
-static int pcon_attached_to = -1;
 static bool isHybrid;
-static bool do_not_reset_switch_to_pcon;
-static bool freeconsole_on_close = true;
-static tty *last_ttyp = NULL;
-
-void
-clear_pcon_attached_to (void)
-{
-  pcon_attached_to = -1;
-}
 
 static void
-set_switch_to_pcon (void)
+set_switch_to_pcon (HANDLE h)
 {
   cygheap_fdenum cfd (false);
   int fd;
@@ -82,280 +70,17 @@ set_switch_to_pcon (void)
       {
 	fhandler_base *fh = cfd;
 	fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	if (ptys->get_pseudo_console ())
-	  {
-	    ptys->set_switch_to_pcon (fd);
-	    ptys->trigger_redraw_screen ();
-	    DWORD mode =
-	      ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	    SetConsoleMode (ptys->get_handle (), mode);
-	  }
+	if (h == ptys->get_handle ())
+	  ptys->set_switch_to_pcon ();
 	return;
       }
-  /* No pty slave opened */
-  if (last_ttyp) /* Make system_printf() work after closing pty slave */
-    last_ttyp->set_switch_to_pcon_out (true);
-}
-
-static void
-force_attach_to_pcon (HANDLE h)
-{
-  bool attach_done = false;
-  for (int n = 0; n < 2; n ++)
-    {
-      /* First time, attach to the pty whose handle value is match.
-	 Second time, try to attach to any pty. */
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	    if (!ptys->get_pseudo_console ())
-	      continue;
-	    if (n != 0
-		|| h == ptys->get_handle ()
-		|| h == ptys->get_output_handle ())
-	      {
-		if (fhandler_console::get_console_process_id
-				  (ptys->get_helper_process_id (), true))
-		  attach_done = true;
-		else
-		  {
-		    FreeConsole ();
-		    if (AttachConsole (ptys->get_helper_process_id ()))
-		      {
-			pcon_attached_to = ptys->get_minor ();
-			attach_done = true;
-		      }
-		    else
-		      pcon_attached_to = -1;
-		  }
-		break;
-	      }
-	  }
-	else if (cfd->get_major () == DEV_CONS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_console *cons = (fhandler_console *) fh;
-	    if (n != 0
-		|| h == cons->get_handle ()
-		|| h == cons->get_output_handle ())
-	      {
-		/* If the process is running on a console,
-		   the parent process should be attached
-		   to the same console. */
-		DWORD attach_wpid;
-		if (myself->ppid == 1)
-		  attach_wpid = ATTACH_PARENT_PROCESS;
-		else
-		  {
-		    pinfo p (myself->ppid);
-		    attach_wpid = p->dwProcessId;
-		  }
-		FreeConsole ();
-		if (AttachConsole (attach_wpid))
-		  {
-		    pcon_attached_to = -1;
-		    attach_done = true;
-		  }
-		else
-		  pcon_attached_to = -1;
-		break;
-	      }
-	  }
-      if (attach_done)
-	break;
-    }
-}
-
-void
-set_ishybrid_and_switch_to_pcon (HANDLE h)
-{
-  if (GetFileType (h) == FILE_TYPE_CHAR)
-    {
-      force_attach_to_pcon (h);
-      DWORD dummy;
-      if (!isHybrid && (GetConsoleMode (h, &dummy)
-			|| GetLastError () != ERROR_INVALID_HANDLE))
-	{
-	  isHybrid = true;
-	  set_switch_to_pcon ();
-	}
-    }
-}
-
-inline void
-fhandler_pty_slave::free_attached_console ()
-{
-  bool attached = get_ttyp () ?
-    fhandler_console::get_console_process_id (get_helper_process_id (), true)
-    : (get_minor () == pcon_attached_to);
-  if (freeconsole_on_close && attached)
-    {
-      FreeConsole ();
-      pcon_attached_to = -1;
-    }
 }
 
 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
-DEF_HOOK (WriteFile);
-DEF_HOOK (WriteConsoleA);
-DEF_HOOK (WriteConsoleW);
-DEF_HOOK (ReadFile);
-DEF_HOOK (ReadConsoleA);
-DEF_HOOK (ReadConsoleW);
-DEF_HOOK (WriteConsoleOutputA);
-DEF_HOOK (WriteConsoleOutputW);
-DEF_HOOK (WriteConsoleOutputCharacterA);
-DEF_HOOK (WriteConsoleOutputCharacterW);
-DEF_HOOK (WriteConsoleOutputAttribute);
-DEF_HOOK (SetConsoleCursorPosition);
-DEF_HOOK (SetConsoleTextAttribute);
-DEF_HOOK (WriteConsoleInputA);
-DEF_HOOK (WriteConsoleInputW);
-DEF_HOOK (ReadConsoleInputA);
-DEF_HOOK (ReadConsoleInputW);
-DEF_HOOK (PeekConsoleInputA);
-DEF_HOOK (PeekConsoleInputW);
 /* CreateProcess() is hooked for GDB etc. */
 DEF_HOOK (CreateProcessA);
 DEF_HOOK (CreateProcessW);
 
-static BOOL WINAPI
-WriteFile_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleA_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleW_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadFile_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleA_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleW_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleOutputA_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputA_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputW_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputW_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterA_Hooked
-     (HANDLE h, LPCSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterA_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterW_Hooked
-     (HANDLE h, LPCWSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterW_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputAttribute_Hooked
-     (HANDLE h, CONST WORD *a, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputAttribute_Orig (h, a, l, c, n);
-}
-static BOOL WINAPI
-SetConsoleCursorPosition_Hooked
-     (HANDLE h, COORD c)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleCursorPosition_Orig (h, c);
-}
-static BOOL WINAPI
-SetConsoleTextAttribute_Hooked
-     (HANDLE h, WORD a)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleTextAttribute_Orig (h, a);
-}
-static BOOL WINAPI
-WriteConsoleInputA_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-WriteConsoleInputW_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputW_Orig (h, r, l, n);
-}
-/* CreateProcess() is hooked for GDB etc. */
 static BOOL WINAPI
 CreateProcessA_Hooked
      (LPCSTR n, LPSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
@@ -363,11 +88,14 @@ CreateProcessA_Hooked
       LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 static BOOL WINAPI
@@ -377,11 +105,14 @@ CreateProcessW_Hooked
       LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 
@@ -464,10 +195,6 @@ fhandler_pty_master::flush_to_slave ()
 {
   if (get_readahead_valid () && !(get_ttyp ()->ti.c_lflag & ICANON))
     accept_input ();
-  WaitForSingleObject (input_mutex, INFINITE);
-  if (!get_ttyp ()->pcon_in_empty && !(get_ttyp ()->ti.c_lflag & ICANON))
-    SetEvent (input_available_event);
-  ReleaseMutex (input_mutex);
 }
 
 DWORD
@@ -532,14 +259,6 @@ fhandler_pty_master::doecho (const void *str, DWORD len)
   release_output_mutex ();
 }
 
-int
-fhandler_pty_master::put_readahead (char value)
-{
-  if (to_be_read_from_pcon ())
-    return 1;
-  return fhandler_base::put_readahead (value);
-}
-
 int
 fhandler_pty_master::accept_input ()
 {
@@ -551,9 +270,11 @@ fhandler_pty_master::accept_input ()
   char *p = rabuf () + raixget ();
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
   if (to_be_read_from_pcon ())
-    ; /* Do nothing */
-  else if (!bytes_left)
+    write_to = to_slave;
+
+  if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
@@ -564,10 +285,10 @@ fhandler_pty_master::accept_input ()
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -725,52 +446,12 @@ out:
 
 fhandler_pty_slave::fhandler_pty_slave (int unit)
   : fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL),
-  io_handle_cyg (NULL), pid_restore (0), fd (-1)
+  io_handle_cyg (NULL)
 {
   if (unit >= 0)
     dev ().parse (DEV_PTYS_MAJOR, unit);
 }
 
-fhandler_pty_slave::~fhandler_pty_slave ()
-{
-  if (!get_ttyp ())
-    {
-      /* Why comes here? Who clears _tc? */
-      free_attached_console ();
-      return;
-    }
-  if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 0)
-	{
-	  pcon_attached_to = -1;
-	  last_ttyp = get_ttyp ();
-	}
-      if (used == 0)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
-}
-
 int
 fhandler_pty_slave::open (int flags, mode_t)
 {
@@ -950,24 +631,7 @@ fhandler_pty_slave::open (int flags, mode_t)
   set_output_handle (to_master_local);
   set_output_handle_cyg (to_master_cyg_local);
 
-  if (!get_pseudo_console ())
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (!fhandler_console::get_console_process_id
-			       (GetCurrentProcessId (), true))
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (fhandler_console::get_console_process_id
-			       (get_helper_process_id (), true))
-    /* Attached to pcon of this pty */
-    {
-      pcon_attached_to = get_minor ();
-      init_console_handler (true);
-    }
+  fhandler_console::need_invisible ();
 
   set_open_status ();
   return 1;
@@ -1021,8 +685,7 @@ fhandler_pty_slave::close ()
   if (!ForceCloseHandle (get_handle_cyg ()))
     termios_printf ("CloseHandle (get_handle_cyg ()<%p>), %E",
 	get_handle_cyg ());
-  if (!get_pseudo_console () &&
-      (unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
+  if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
     fhandler_console::free_console ();	/* assumes that we are the last pty closer */
   fhandler_pty_common::close ();
   if (!ForceCloseHandle (output_mutex))
@@ -1070,234 +733,17 @@ fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
   return ret;
 }
 
-bool
-fhandler_pty_slave::try_reattach_pcon (void)
-{
-  pid_restore = 0;
-
-  /* Do not detach from the console because re-attaching will
-     fail if helper process is running as service account. */
-  if (get_ttyp()->attach_pcon_in_fork)
-    return false;
-  if (pcon_attached_to >= 0 &&
-      cygwin_shared->tty[pcon_attached_to]->attach_pcon_in_fork)
-    return false;
-
-  pid_restore =
-    fhandler_console::get_console_process_id (GetCurrentProcessId (),
-					      false);
-  /* If pid_restore is not set, give up. */
-  if (!pid_restore)
-    return false;
-
-  FreeConsole ();
-  if (!AttachConsole (get_helper_process_id ()))
-    {
-      system_printf ("pty%d: AttachConsole(helper=%d) failed. 0x%08lx",
-		     get_minor (), get_helper_process_id (), GetLastError ());
-      return false;
-    }
-  return true;
-}
-
 void
-fhandler_pty_slave::restore_reattach_pcon (void)
+fhandler_pty_slave::set_switch_to_pcon (void)
 {
-  if (pid_restore)
+  if (!get_ttyp ()->switch_to_pcon_in)
     {
-      FreeConsole ();
-      if (!AttachConsole (pid_restore))
-	{
-	  system_printf ("pty%d: AttachConsole(restore=%d) failed. 0x%08lx",
-			 get_minor (), pid_restore, GetLastError ());
-	  pcon_attached_to = -1;
-	}
-    }
-  pid_restore = 0;
-}
-
-/* This function requests transfering the input data from the input
-   pipe for cygwin apps to the other input pipe for native apps. */
-void
-fhandler_pty_slave::pull_pcon_input (void)
-{
-  get_ttyp ()->req_transfer_input_to_pcon = true;
-  while (get_ttyp ()->req_transfer_input_to_pcon)
-    Sleep (1);
-}
-
-void
-fhandler_pty_slave::update_pcon_input_state (bool need_lock)
-{
-  if (need_lock)
-    WaitForSingleObject (input_mutex, INFINITE);
-  /* Flush input buffer if it is requested by master.
-     This happens if ^C is pressed in pseudo console side. */
-  if (get_ttyp ()->req_flush_pcon_input)
-    {
-      FlushConsoleInputBuffer (get_handle ());
-      get_ttyp ()->req_flush_pcon_input = false;
-    }
-  /* Peek console input buffer and update state. */
-  INPUT_RECORD inp[INREC_SIZE];
-  DWORD n;
-  BOOL (WINAPI *PeekFunc)
-    (HANDLE, PINPUT_RECORD, DWORD, LPDWORD);
-  PeekFunc =
-    PeekConsoleInputA_Orig ? : PeekConsoleInput;
-  PeekFunc (get_handle (), inp, INREC_SIZE, &n);
-  bool saw_accept = false;
-  bool pipe_empty = true;
-  while (n-- > 0)
-    if (inp[n].EventType == KEY_EVENT && inp[n].Event.KeyEvent.bKeyDown &&
-	inp[n].Event.KeyEvent.uChar.AsciiChar)
-      {
-	pipe_empty = false;
-	char c = inp[n].Event.KeyEvent.uChar.AsciiChar;
-	const char sigs[] = {
-	  (char) get_ttyp ()->ti.c_cc[VINTR],
-	  (char) get_ttyp ()->ti.c_cc[VQUIT],
-	  (char) get_ttyp ()->ti.c_cc[VSUSP],
-	};
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n',
-	  '\r'
-	};
-	if (is_line_input () && c && memchr (eols, c, sizeof (eols)))
-	  saw_accept = true;
-	if ((get_ttyp ()->ti.c_lflag & ISIG)
-	    && c && memchr (sigs, c, sizeof (sigs)))
-	  saw_accept = true;
-      }
-  get_ttyp ()->pcon_in_empty = pipe_empty && !(ralen () > raixget ());
-  if (!get_readahead_valid () &&
-      (pipe_empty || (is_line_input () && !saw_accept)) &&
-      get_ttyp ()->read_retval == 1 && bytes_available (n) && n == 0)
-    ResetEvent (input_available_event);
-  if (need_lock)
-    ReleaseMutex (input_mutex);
-}
-
-int
-fhandler_pty_slave::eat_readahead (int n)
-{
-  int oralen = ralen ();
-  if (n < 0)
-    n = ralen () - raixget ();
-  if (n > 0 && ralen () > raixget ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      while (n > 0 && ralen () > raixget ())
-	{
-	  if (is_line_input () && rabuf ()[ralen ()-1]
-	      && memchr (eols, rabuf ()[ralen ()-1], sizeof (eols)))
-	    break;
-	  -- n;
-	  -- ralen ();
-	}
-
-      /* If IUTF8 is set, the terminal is in UTF-8 mode.  If so, we erase
-	 a complete UTF-8 multibyte sequence on VERASE/VWERASE.  Otherwise,
-	 if we only erase a single byte, invalid unicode chars are left in
-	 the input. */
-      if (get_ttyp ()->ti.c_iflag & IUTF8)
-	while (ralen () > raixget () &&
-	       ((unsigned char) rabuf ()[ralen ()] & 0xc0) == 0x80)
-	  --ralen ();
-    }
-  oralen = oralen - ralen ();
-  if (raixget () >= ralen ())
-    raixget () = raixput () = ralen () = 0;
-  else if (raixput () > ralen ())
-    raixput () = ralen ();
-
-  return oralen;
-}
-
-int
-fhandler_pty_slave::get_readahead_into_buffer (char *buf, size_t buflen)
-{
-  int ch;
-  int copied_chars = 0;
-
-  while (buflen)
-    if ((ch = get_readahead ()) < 0)
-      break;
-    else
-      {
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n'
-	};
-	buf[copied_chars++] = (unsigned char)(ch & 0xff);
-	buflen--;
-	if (is_line_input () && ch && memchr (eols, ch & 0xff, sizeof (eols)))
-	  break;
-      }
-
-  return copied_chars;
-}
-
-bool
-fhandler_pty_slave::get_readahead_valid (void)
-{
-  if (is_line_input ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      for (size_t i=raixget (); i<ralen (); i++)
-	if (rabuf ()[i] && memchr (eols, rabuf ()[i], sizeof (eols)))
-	  return true;
-      return false;
-    }
-  else
-    return ralen () > raixget ();
-}
-
-void
-fhandler_pty_slave::set_switch_to_pcon (int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  acquire_output_mutex (INFINITE);
-  if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
-    {
-      pull_pcon_input ();
+      isHybrid = true;
       if (get_ttyp ()->pcon_pid == 0 ||
 	  !pinfo (get_ttyp ()->pcon_pid))
 	get_ttyp ()->pcon_pid = myself->pid;
       get_ttyp ()->switch_to_pcon_in = true;
-      if (isHybrid && !get_ttyp ()->switch_to_pcon_out)
-	{
-	  get_ttyp ()->wait_pcon_fwd ();
-	  get_ttyp ()->switch_to_pcon_out = true;
-	}
     }
-  else if ((fd == 1 || fd == 2) && !get_ttyp ()->switch_to_pcon_out)
-    {
-      get_ttyp ()->wait_pcon_fwd ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
-	get_ttyp ()->pcon_pid = myself->pid;
-      get_ttyp ()->switch_to_pcon_out = true;
-      if (isHybrid)
-	get_ttyp ()->switch_to_pcon_in = true;
-    }
-  release_output_mutex ();
 }
 
 void
@@ -1310,183 +756,10 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
     return;
   if (isHybrid)
     return;
-  if (do_not_reset_switch_to_pcon)
-    return;
-  acquire_output_mutex (INFINITE);
-  if (get_ttyp ()->switch_to_pcon_out)
-    /* Wait for pty_master_fwd_thread() */
-    get_ttyp ()->wait_pcon_fwd ();
   get_ttyp ()->pcon_pid = 0;
   get_ttyp ()->switch_to_pcon_in = false;
-  get_ttyp ()->switch_to_pcon_out = false;
-  release_output_mutex ();
-  init_console_handler (true);
-}
-
-void
-fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len,
-					       bool is_echo)
-{
-  bool attached =
-    !!fhandler_console::get_console_process_id (get_helper_process_id (), true);
-  if (!attached && pcon_attached_to == get_minor ())
-    {
-      for (DWORD t0 = GetTickCount (); GetTickCount () - t0 < 100; )
-	{
-	  Sleep (1);
-	  attached = fhandler_console::get_console_process_id
-				      (get_helper_process_id (), true);
-	  if (attached)
-	    break;
-	}
-      if (!attached)
-	{
-	  system_printf ("pty%d: pcon_attach_to mismatch??????", get_minor ());
-	  return;
-	}
-    }
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  if (pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      goto detach;
-
-  char *buf;
-  size_t nlen;
-  DWORD origCP;
-  origCP = GetConsoleOutputCP ();
-  SetConsoleOutputCP (get_ttyp ()->term_code_page);
-  /* Just copy */
-  buf = (char *) HeapAlloc (GetProcessHeap (), 0, len);
-  memcpy (buf, (char *)ptr, len);
-  nlen = len;
-  char *p0, *p1;
-  p0 = p1 = buf;
-  /* Remove alternate screen buffer drawing */
-  while (p0 && p1)
-    {
-      if (!get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to alternate screen buffer */
-	  p0 = (char *) memmem (p1, nlen - (p1-buf), "\033[?1049h", 8);
-	  if (p0)
-	    {
-	      //p0 += 8;
-	      get_ttyp ()->screen_alternated = true;
-	      if (get_ttyp ()->switch_to_pcon_out)
-		do_not_reset_switch_to_pcon = true;
-	    }
-	}
-      if (get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to main screen buffer */
-	  p1 = (char *) memmem (p0, nlen - (p0-buf), "\033[?1049l", 8);
-	  if (p1)
-	    {
-	      p1 += 8;
-	      get_ttyp ()->screen_alternated = false;
-	      do_not_reset_switch_to_pcon = false;
-	      memmove (p0, p1, buf+nlen - p1);
-	      nlen -= p1 - p0;
-	    }
-	  else
-	    nlen = p0 - buf;
-	}
-    }
-  if (!nlen) /* Nothing to be synchronized */
-    goto cleanup;
-  if (get_ttyp ()->switch_to_pcon_out && !is_echo)
-    goto cleanup;
-  /* Remove ESC sequence which returns results to console
-     input buffer. Without this, cursor position report
-     is put into the input buffer as a garbage. */
-  /* Remove ESC sequence to report cursor position. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[6n", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-  /* Remove ESC sequence to report terminal identity. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[0c", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-
-  /* If the ESC sequence ESC[?3h or ESC[?3l which clears console screen
-     buffer is pushed, set need_redraw_screen to trigger redraw screen. */
-  p0 = buf;
-  while ((p0 = (char *) memmem (p0, nlen - (p0 - buf), "\033[?", 3)))
-    {
-      p0 += 3;
-      bool exist_arg_3 = false;
-      while (p0 < buf + nlen && (isdigit (*p0) || *p0 == ';'))
-	{
-	  int arg = 0;
-	  while (p0 < buf + nlen && isdigit (*p0))
-	    arg = arg * 10 + (*p0 ++) - '0';
-	  if (arg == 3)
-	    exist_arg_3 = true;
-	  if (p0 < buf + nlen && *p0 == ';')
-	    p0 ++;
-	}
-      if (p0 < buf + nlen && exist_arg_3 && (*p0 == 'h' || *p0 == 'l'))
-	get_ttyp ()->need_redraw_screen = true;
-      p0 ++;
-      if (p0 >= buf + nlen)
-	break;
-    }
-
-  int retry_count;
-  retry_count = 0;
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  while (!GetConsoleMode (get_output_handle (), &dwMode))
-    {
-      termios_printf ("GetConsoleMode failed, %E");
-      int errno_save = errno;
-      /* Re-open handles */
-      this->open (0, 0);
-      /* Fix pseudo console window size */
-      this->ioctl (TIOCSWINSZ, &get_ttyp ()->winsize);
-      if (errno != errno_save)
-	set_errno (errno_save);
-      if (++retry_count > 3)
-	goto cleanup;
-    }
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-  char *p;
-  p = buf;
-  DWORD wLen, written;
-  written = 0;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
-  while (written <  nlen)
-    {
-      if (!WriteFunc (get_output_handle (), p, nlen - written, &wLen, NULL))
-	{
-	  termios_printf ("WriteFile failed, %E");
-	  break;
-	}
-      else
-	{
-	  written += wLen;
-	  p += wLen;
-	}
-    }
-  /* Detach from pseudo console and resume. */
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-cleanup:
-  SetConsoleOutputCP (origCP);
-  HeapFree (GetProcessHeap (), 0, buf);
-detach:
-  restore_reattach_pcon ();
+  get_ttyp ()->h_pseudo_console = NULL;
+  get_ttyp ()->pcon_start = false;
 }
 
 ssize_t __stdcall
@@ -1505,44 +778,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
   reset_switch_to_pcon ();
 
   acquire_output_mutex (INFINITE);
-  bool output_to_pcon = get_ttyp ()->switch_to_pcon_out;
-  release_output_mutex ();
-
-  UINT target_code_page = output_to_pcon ?
-    GetConsoleOutputCP () : get_ttyp ()->term_code_page;
-  ssize_t nlen;
-  char *buf = convert_mb_str (target_code_page, (size_t *) &nlen,
-		 get_ttyp ()->term_code_page, (const char *) ptr, len);
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  bool fallback = false;
-  if (output_to_pcon && pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      fallback = true;
-
-  if (output_to_pcon && !fallback &&
-      (memmem (buf, nlen, "\033[6n", 4) || memmem (buf, nlen, "\033[0c", 4)))
-    {
-      get_ttyp ()->pcon_in_empty = false;
-      if (!is_line_input ())
-	SetEvent (input_available_event);
-    }
-
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  if (output_to_pcon && !fallback)
-    {
-      GetConsoleMode (get_output_handle (), &dwMode);
-      SetConsoleMode (get_output_handle (), dwMode | flags);
-    }
-  HANDLE to = (output_to_pcon && !fallback) ?
-    get_output_handle () : get_output_handle_cyg ();
-  acquire_output_mutex (INFINITE);
-  if (!process_opost_output (to, buf, nlen, false))
+  if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false))
     {
       DWORD err = GetLastError ();
       termios_printf ("WriteFile failed, %E");
@@ -1557,20 +793,6 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
       towrite = -1;
     }
   release_output_mutex ();
-  mb_str_free (buf);
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (output_to_pcon && !fallback)
-    SetConsoleMode (get_output_handle (), dwMode | flags);
-
-  restore_reattach_pcon ();
-
-  /* Push slave output to pseudo console screen buffer */
-  if (get_pseudo_console ())
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer ((char *)ptr, len, false);
-      release_output_mutex ();
-    }
 
   return towrite;
 }
@@ -1584,14 +806,13 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 bool
 fhandler_pty_common::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return get_ttyp ()->pcon_start
+    || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
 fhandler_pty_slave::read (void *ptr, size_t& len)
 {
-  char *ptr0 = (char *)ptr;
   ssize_t totalread = 0;
   int vmin = 0;
   int vtime = 0;	/* Initialized to prevent -Wuninitialized warning */
@@ -1616,8 +837,6 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
       mask_switch_to_pcon_in (true);
       reset_switch_to_pcon ();
     }
-  if (to_be_read_from_pcon ())
-    update_pcon_input_state (true);
 
   if (is_nonblocking () || !ptr) /* Indicating tcflush(). */
     time_to_wait = 0;
@@ -1700,101 +919,24 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 	     is an infinitely blocking read, restart the loop. */
 	  if (time_to_wait != INFINITE)
 	    {
-	      if (!totalread)
-		{
-		  set_sig_errno (EAGAIN);
-		  totalread = -1;
-		}
-	      goto out;
-	    }
-	  continue;
-	default:
-	  termios_printf ("wait for input mutex failed, %E");
-	  if (!totalread)
-	    {
-	      __seterrno ();
-	      totalread = -1;
-	    }
-	  goto out;
-	}
-      if (ptr && to_be_read_from_pcon ())
-	{
-	  if (get_readahead_valid ())
-	    {
-	      ReleaseMutex (input_mutex);
-	      totalread = get_readahead_into_buffer ((char *) ptr, len);
-	    }
-	  else
-	    {
-	      if (!try_reattach_pcon ())
-		{
-		  restore_reattach_pcon ();
-		  goto do_read_cyg;
-		}
-
-	      DWORD dwMode;
-	      GetConsoleMode (get_handle (), &dwMode);
-	      DWORD flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
-	      if (dwMode != flags)
-		SetConsoleMode (get_handle (), flags);
-	      /* Read get_handle() instad of get_handle_cyg() */
-	      BOOL (WINAPI *ReadFunc)
-		(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID);
-	      ReadFunc = ReadConsoleA_Orig ? ReadConsoleA_Orig : ReadConsoleA;
-	      DWORD rlen;
-	      readlen = MIN (len, sizeof (buf));
-	      if (!ReadFunc (get_handle (), buf, readlen, &rlen, NULL))
-		{
-		  termios_printf ("read failed, %E");
-		  SetConsoleMode (get_handle (), dwMode);
-		  restore_reattach_pcon ();
-		  ReleaseMutex (input_mutex);
-		  set_errno (EIO);
-		  totalread = -1;
-		  goto out;
-		}
-	      SetConsoleMode (get_handle (), dwMode);
-	      restore_reattach_pcon ();
-	      ReleaseMutex (input_mutex);
-
-	      ssize_t nlen;
-	      char *nbuf = convert_mb_str (get_ttyp ()->term_code_page,
-			     (size_t *) &nlen, GetConsoleCP (), buf, rlen);
-
-	      ssize_t ret;
-	      line_edit_status res =
-		line_edit (nbuf, nlen, get_ttyp ()->ti, &ret);
-
-	      mb_str_free (nbuf);
-
-	      if (res == line_edit_input_done || res == line_edit_ok)
-		totalread = get_readahead_into_buffer ((char *) ptr, len);
-	      else if (res > line_edit_signalled)
+	      if (!totalread)
 		{
-		  set_sig_errno (EINTR);
+		  set_sig_errno (EAGAIN);
 		  totalread = -1;
 		}
-	      else
-		{
-		  update_pcon_input_state (true);
-		  continue;
-		}
+	      goto out;
+	    }
+	  continue;
+	default:
+	  termios_printf ("wait for input mutex failed, %E");
+	  if (!totalread)
+	    {
+	      __seterrno ();
+	      totalread = -1;
 	    }
-
-	  update_pcon_input_state (true);
-	  mask_switch_to_pcon_in (false);
 	  goto out;
 	}
-      if (!ptr && len == UINT_MAX && !get_ttyp ()->pcon_in_empty)
-	{
-	  FlushConsoleInputBuffer (get_handle ());
-	  get_ttyp ()->pcon_in_empty = true;
-	  DWORD n;
-	  if (bytes_available (n) && n == 0)
-	    ResetEvent (input_available_event);
-	}
 
-do_read_cyg:
       if (!bytes_available (bytes_in_pipe))
 	{
 	  ReleaseMutex (input_mutex);
@@ -1911,16 +1053,6 @@ do_read_cyg:
 out:
   termios_printf ("%d = read(%p, %lu)", totalread, ptr, len);
   len = (size_t) totalread;
-  /* Push slave read as echo to pseudo console screen buffer. */
-  if (get_pseudo_console () && ptr0 && totalread > 0 &&
-      (get_ttyp ()->ti.c_lflag & ECHO))
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer (ptr0, len, true);
-      if (get_ttyp ()->switch_to_pcon_out)
-	trigger_redraw_screen ();
-      release_output_mutex ();
-    }
   mask_switch_to_pcon_in (false);
 }
 
@@ -2061,38 +1193,11 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
       get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
       break;
     case TIOCSWINSZ:
-      if (get_pseudo_console ())
-	{
-	  /* If not attached to this pseudo console,
-	     try to attach temporarily. */
-	  pid_restore = 0;
-	  if (pcon_attached_to != get_minor ())
-	    if (!try_reattach_pcon ())
-	      goto cleanup;
-
-	  COORD size;
-	  size.X = ((struct winsize *) arg)->ws_col;
-	  size.Y = ((struct winsize *) arg)->ws_row;
-	  CONSOLE_SCREEN_BUFFER_INFO csbi;
-	  if (GetConsoleScreenBufferInfo (get_output_handle (), &csbi))
-	    if (size.X == csbi.srWindow.Right - csbi.srWindow.Left + 1 &&
-		size.Y == csbi.srWindow.Bottom - csbi.srWindow.Top + 1)
-	      goto cleanup;
-	  if (!SetConsoleScreenBufferSize (get_output_handle (), size))
-	    goto cleanup;
-	  SMALL_RECT rect;
-	  rect.Left = 0;
-	  rect.Top = 0;
-	  rect.Right = size.X-1;
-	  rect.Bottom = size.Y-1;
-	  SetConsoleWindowInfo (get_output_handle (), TRUE, &rect);
-cleanup:
-	  restore_reattach_pcon ();
-	}
-
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->arg.winsize = *(struct winsize *) arg;
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
@@ -2378,6 +1483,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2393,7 +1519,6 @@ fhandler_pty_master::close ()
 {
   OBJECT_BASIC_INFORMATION obi;
   NTSTATUS status;
-  pid_t master_pid_tmp = get_ttyp ()->master_pid;
 
   termios_printf ("closing from_master(%p)/from_master_cyg(%p)/to_master(%p)/to_master_cyg(%p) since we own them(%u)",
 		  from_master, from_master_cyg,
@@ -2438,30 +1563,6 @@ fhandler_pty_master::close ()
   else if (obi.HandleCount == 1)
     {
       termios_printf ("Closing last master of pty%d", get_minor ());
-      /* Close Pseudo Console */
-      if (get_pseudo_console ())
-	{
-	  /* Terminate helper process */
-	  SetEvent (get_ttyp ()->h_helper_goodbye);
-	  WaitForSingleObject (get_ttyp ()->h_helper_process, INFINITE);
-	  CloseHandle (get_ttyp ()->h_helper_goodbye);
-	  CloseHandle (get_ttyp ()->h_helper_process);
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (master_pid_tmp == myself->pid)
-	    {
-	      /* ClosePseudoConsole() seems to have a bug that one
-		 internal handle remains opened. This causes handle leak.
-		 This is a workaround for this problem. */
-	      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_pseudo_console ();
-	      HANDLE tmp = hp->hConHostProcess;
-	      /* Release pseudo console */
-	      ClosePseudoConsole (get_pseudo_console ());
-	      CloseHandle (tmp);
-	    }
-	  get_ttyp ()->switch_to_pcon_in = false;
-	  get_ttyp ()->switch_to_pcon_out = false;
-	}
       if (get_ttyp ()->getsid () > 0)
 	kill (get_ttyp ()->getsid (), SIGHUP);
       SetEvent (input_available_event);
@@ -2469,9 +1570,8 @@ fhandler_pty_master::close ()
 
   if (!ForceCloseHandle (from_master))
     termios_printf ("error closing from_master %p, %E", from_master);
-  if (from_master_cyg != from_master) /* Avoid double close. */
-    if (!ForceCloseHandle (from_master_cyg))
-      termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
+  if (!ForceCloseHandle (from_master_cyg))
+    termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
   if (!ForceCloseHandle (to_master))
     termios_printf ("error closing to_master %p, %E", to_master);
   from_master = to_master = NULL;
@@ -2513,7 +1613,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon () && get_ttyp ()->h_pseudo_console)
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2521,40 +1621,50 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
       WaitForSingleObject (input_mutex, INFINITE);
 
-      if (memchr (buf, '\003', nlen)) /* ^C intr key in pcon */
-	get_ttyp ()->req_flush_pcon_input = true;
-
       DWORD wLen;
-      WriteFile (to_slave, buf, nlen, &wLen, NULL);
-      get_ttyp ()->pcon_in_empty = false;
-
-      ReleaseMutex (input_mutex);
 
-      /* Use line_edit () in order to set input_available_event. */
-      bool is_echo = tc ()->ti.c_lflag & ECHO;
-      if (!get_ttyp ()->mask_switch_to_pcon_in)
+      if (get_ttyp ()->pcon_start)
 	{
-	  tc ()->ti.c_lflag &= ~ECHO;
-	  ti.c_lflag &= ~ECHO;
-	}
-      ti.c_lflag &= ~ISIG;
-      line_edit (buf, nlen, ti, &ret);
-      if (is_echo)
-	tc ()->ti.c_lflag |= ECHO;
-      get_ttyp ()->read_retval = 1;
-
-      const char sigs[] = {
-	(char) ti.c_cc[VINTR],
-	(char) ti.c_cc[VQUIT],
-	(char) ti.c_cc[VSUSP],
-      };
-      if (tc ()->ti.c_lflag & ISIG)
-	for (size_t i=0; i<sizeof (sigs); i++)
-	  if (sigs[i] && memchr (buf, sigs[i], nlen))
+	  /* Pseudo condole support uses "CSI6n" to get cursor position.
+	     If the reply for "CSI6n" is divided into multiple writes,
+	     pseudo console sometimes does not recognize it.  Therefore,
+	     put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon_start = false;
+	    }
+	  else
 	    {
-	      eat_readahead (-1);
-	      SetEvent (input_available_event);
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
 	    }
+	}
+
+      WriteFile (to_slave, buf, nlen, &wLen, NULL);
+
+      ReleaseMutex (input_mutex);
 
       mb_str_free (buf);
       return len;
@@ -2630,15 +1740,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (get_pseudo_console () && get_ttyp ()->master_pid == myself->pid)
-	    {
-	      COORD size;
-	      size.X = ((struct winsize *) arg)->ws_col;
-	      size.Y = ((struct winsize *) arg)->ws_row;
-	      ResizePseudoConsole (get_pseudo_console (), size);
-	    }
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
 	}
@@ -2763,7 +1866,7 @@ get_locale_from_env (char *locale)
   strcpy (locale, env);
 }
 
-static LCID
+static void
 get_langinfo (char *locale_out, char *charset_out)
 {
   /* Get locale from environment */
@@ -2776,11 +1879,6 @@ get_langinfo (char *locale_out, char *charset_out)
   if (!locale)
     locale = "C";
 
-  char tmp_locale[ENCODING_LEN + 1];
-  char *ret = __set_locale_from_locale_alias (locale, tmp_locale);
-  if (ret)
-    locale = tmp_locale;
-
   const char *charset;
   struct lc_ctype_T *lc_ctype = (struct lc_ctype_T *) loc.lc_cat[LC_CTYPE].ptr;
   if (!lc_ctype)
@@ -2830,23 +1928,9 @@ get_langinfo (char *locale_out, char *charset_out)
       charset = "CP932";
     }
 
-  wchar_t lc[ENCODING_LEN + 1];
-  wchar_t *p;
-  mbstowcs (lc, locale, ENCODING_LEN);
-  p = wcschr (lc, L'.');
-  if (p)
-    *p = L'\0';
-  p = wcschr (lc, L'_');
-  if (p)
-    *p = L'-';
-  LCID lcid = LocaleNameToLCID (lc, 0);
-  if (!lcid && !strcmp (charset, "ASCII"))
-    return 0;
-
   /* Set results */
   strcpy (locale_out, new_locale);
   strcpy (charset_out, charset);
-  return lcid;
 }
 
 void
@@ -2854,21 +1938,7 @@ fhandler_pty_slave::setup_locale (void)
 {
   char locale[ENCODING_LEN + 1] = "C";
   char charset[ENCODING_LEN + 1] = "ASCII";
-  LCID lcid = get_langinfo (locale, charset);
-
-  /* Set console code page form locale */
-  if (get_pseudo_console ())
-    {
-      UINT code_page;
-      if (lcid == 0 || lcid == (LCID) -1)
-	code_page = 20127; /* ASCII */
-      else if (!GetLocaleInfo (lcid,
-			       LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
-			       (char *) &code_page, sizeof (code_page)))
-	code_page = 20127; /* ASCII */
-      SetConsoleCP (code_page);
-      SetConsoleOutputCP (code_page);
-    }
+  get_langinfo (locale, charset);
 
   /* Set terminal code page from locale */
   /* This code is borrowed from mintty: charset.c */
@@ -2896,90 +1966,9 @@ fhandler_pty_slave::setup_locale (void)
 	}
 }
 
-void
-fhandler_pty_slave::set_freeconsole_on_close (bool val)
-{
-  freeconsole_on_close = val;
-}
-
-void
-fhandler_pty_slave::trigger_redraw_screen (void)
-{
-  /* Forcibly redraw screen based on console screen buffer. */
-  /* The following code triggers redrawing the screen. */
-  CONSOLE_SCREEN_BUFFER_INFO sbi;
-  GetConsoleScreenBufferInfo (get_output_handle (), &sbi);
-  SMALL_RECT rect = {0, 0,
-    (SHORT) (sbi.dwSize.X -1), (SHORT) (sbi.dwSize.Y - 1)};
-  COORD dest = {0, 0};
-  CHAR_INFO fill = {' ', 0};
-  ScrollConsoleScreenBuffer (get_output_handle (), &rect, NULL, dest, &fill);
-  get_ttyp ()->need_redraw_screen = false;
-}
-
-void
-fhandler_pty_slave::fixup_after_attach (bool native_maybe, int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  if (get_pseudo_console ())
-    {
-      if (fhandler_console::get_console_process_id (get_helper_process_id (),
-						    true))
-	if (pcon_attached_to != get_minor ())
-	  {
-	    pcon_attached_to = get_minor ();
-	    init_console_handler (true);
-	  }
-
-#if 0 /* This is for debug only. */
-      isHybrid = true;
-      get_ttyp ()->switch_to_pcon_in = true;
-      get_ttyp ()->switch_to_pcon_out = true;
-#endif
-
-      if (pcon_attached_to == get_minor () && native_maybe)
-	{
-	  if (fd == 0)
-	    {
-	      pull_pcon_input ();
-	      DWORD mode =
-		ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	      SetConsoleMode (get_handle (), mode);
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_in = true;
-	    }
-	  else if (fd == 1 || fd == 2)
-	    {
-	      DWORD mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
-	      SetConsoleMode (get_output_handle (), mode);
-	      acquire_output_mutex (INFINITE);
-	      if (!get_ttyp ()->switch_to_pcon_out)
-		get_ttyp ()->wait_pcon_fwd ();
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_out = true;
-	      release_output_mutex ();
-
-	      if (get_ttyp ()->need_redraw_screen)
-		trigger_redraw_screen ();
-	    }
-	  init_console_handler (false);
-	}
-      else if (fd == 0 && native_maybe)
-	/* Read from unattached pseudo console cause freeze,
-	   therefore, fallback to legacy pty. */
-	set_handle (get_handle_cyg ());
-    }
-}
-
 void
 fhandler_pty_slave::fixup_after_fork (HANDLE parent)
 {
-  fixup_after_attach (false, -1);
   // fork_fixup (parent, inuse, "inuse");
   // fhandler_pty_common::fixup_after_fork (parent);
   report_tty_counts (this, "inherited", "");
@@ -2992,71 +1981,22 @@ fhandler_pty_slave::fixup_after_exec ()
 
   if (!close_on_exec ())
     fixup_after_fork (NULL);	/* No parent handle required. */
-  else if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 1 && get_minor () == pcon_attached_to)
-	pcon_attached_to = -1;
-      if (used == 1 /* About to close this tty */)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
 
   /* Set locale */
   if (get_ttyp ()->term_code_page == 0)
     setup_locale ();
 
   /* Hook Console API */
-  if (get_pseudo_console ())
-    {
 #define DO_HOOK(module, name) \
-      if (!name##_Orig) \
-	{ \
-	  void *api = hook_api (module, #name, (void *) name##_Hooked); \
-	  name##_Orig = (__typeof__ (name) *) api; \
-	  /*if (api) system_printf (#name " hooked.");*/ \
-	}
-      DO_HOOK (NULL, WriteFile);
-      DO_HOOK (NULL, WriteConsoleA);
-      DO_HOOK (NULL, WriteConsoleW);
-      DO_HOOK (NULL, ReadFile);
-      DO_HOOK (NULL, ReadConsoleA);
-      DO_HOOK (NULL, ReadConsoleW);
-      DO_HOOK (NULL, WriteConsoleOutputA);
-      DO_HOOK (NULL, WriteConsoleOutputW);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterA);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterW);
-      DO_HOOK (NULL, WriteConsoleOutputAttribute);
-      DO_HOOK (NULL, SetConsoleCursorPosition);
-      DO_HOOK (NULL, SetConsoleTextAttribute);
-      DO_HOOK (NULL, WriteConsoleInputA);
-      DO_HOOK (NULL, WriteConsoleInputW);
-      DO_HOOK (NULL, ReadConsoleInputA);
-      DO_HOOK (NULL, ReadConsoleInputW);
-      DO_HOOK (NULL, PeekConsoleInputA);
-      DO_HOOK (NULL, PeekConsoleInputW);
-      /* CreateProcess() is hooked for GDB etc. */
-      DO_HOOK (NULL, CreateProcessA);
-      DO_HOOK (NULL, CreateProcessW);
+  if (!name##_Orig) \
+    { \
+      void *api = hook_api (module, #name, (void *) name##_Hooked); \
+      name##_Orig = (__typeof__ (name) *) api; \
+      /*if (api) system_printf (#name " hooked.");*/ \
     }
+  /* CreateProcess() is hooked for GDB etc. */
+  DO_HOOK (NULL, CreateProcessA);
+  DO_HOOK (NULL, CreateProcessW);
 }
 
 /* This thread function handles the master control pipe.  It waits for a
@@ -3204,27 +2144,6 @@ reply:
   return 0;
 }
 
-void
-fhandler_pty_master::transfer_input_to_pcon (void)
-{
-  WaitForSingleObject (input_mutex, INFINITE);
-  DWORD n;
-  size_t transfered = 0;
-  while (::bytes_available (n, from_master_cyg) && n)
-    {
-      char buf[1024];
-      ReadFile (from_master_cyg, buf, sizeof (buf), &n, 0);
-      char *p = buf;
-      while ((p = (char *) memchr (p, '\n', n - (p - buf))))
-	*p = '\r';
-      if (WriteFile (to_slave, buf, n, &n, 0))
-	transfered += n;
-    }
-  if (transfered)
-    get_ttyp ()->pcon_in_empty = false;
-  ReleaseMutex (input_mutex);
-}
-
 static DWORD WINAPI
 pty_master_thread (VOID *arg)
 {
@@ -3240,23 +2159,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
   termios_printf ("Started.");
   for (;;)
     {
-      if (get_pseudo_console ())
-	{
-	  get_ttyp ()->pcon_last_time = GetTickCount ();
-	  while (::bytes_available (rlen, from_slave) && rlen == 0)
-	    {
-	      /* Forcibly transfer input if it is requested by slave.
-		 This happens when input data should be transfered
-		 from the input pipe for cygwin apps to the input pipe
-		 for native apps. */
-	      if (get_ttyp ()->req_transfer_input_to_pcon)
-		{
-		  transfer_input_to_pcon ();
-		  get_ttyp ()->req_transfer_input_to_pcon = false;
-		}
-	      Sleep (1);
-	    }
-	}
+      get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3264,51 +2167,11 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_ttyp ()->h_pseudo_console)
 	{
-	  /* Avoid duplicating slave output which is already sent to
-	     to_master_cyg */
-	  if (!get_ttyp ()->switch_to_pcon_out)
-	    continue;
-
-	  /* Avoid setting window title to "cygwin-console-helper.exe" */
+	  /* Remove CSI > Pm m */
 	  int state = 0;
 	  int start_at = 0;
-	  for (DWORD i=0; i<rlen; i++)
-	    if (outbuf[i] == '\033')
-	      {
-		start_at = i;
-		state = 1;
-		continue;
-	      }
-	    else if ((state == 1 && outbuf[i] == ']') ||
-		     (state == 2 && outbuf[i] == '0') ||
-		     (state == 3 && outbuf[i] == ';'))
-	      {
-		state ++;
-		continue;
-	      }
-	    else if (state == 4 && outbuf[i] == '\a')
-	      {
-		const char *helper_str = "\\bin\\cygwin-console-helper.exe";
-		if (memmem (&outbuf[start_at], i + 1 - start_at,
-			    helper_str, strlen (helper_str)))
-		  {
-		    memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
-		    rlen = wlen = start_at + rlen - i - 1;
-		  }
-		state = 0;
-		continue;
-	      }
-	    else if (outbuf[i] == '\a')
-	      {
-		state = 0;
-		continue;
-	      }
-
-	  /* Remove CSI > Pm m */
-	  state = 0;
-	  start_at = 0;
 	  for (DWORD i=0; i<rlen; i++)
 	    if (outbuf[i] == '\033')
 	      {
@@ -3386,201 +2249,6 @@ pty_master_fwd_thread (VOID *arg)
   return ((fhandler_pty_master *) arg)->pty_master_fwd_thread ();
 }
 
-/* If master process is running as service, attaching to
-   pseudo console should be done in fork. If attaching
-   is done in spawn for inetd or sshd, it fails because
-   the helper process is running as privileged user while
-   slave process is not. This function is used to determine
-   if the process is running as a srvice or not. */
-inline static bool
-is_running_as_service (void)
-{
-  return check_token_membership (well_known_service_sid)
-    || cygheap->user.saved_sid () == well_known_system_sid;
-}
-
-bool
-fhandler_pty_master::setup_pseudoconsole ()
-{
-  if (disable_pcon)
-    return false;
-  /* If the legacy console mode is enabled, pseudo console seems
-     not to work as expected. To determine console mode, registry
-     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
-  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
-  if (reg.error ())
-    return false;
-  if (reg.get_dword (L"ForceV2", 1) == 0)
-    {
-      termios_printf ("Pseudo console is disabled "
-		      "because the legacy console mode is enabled.");
-      return false;
-    }
-
-  /* Pseudo console supprot is realized using a tricky technic.
-     PTY need the pseudo console handles, however, they cannot
-     be retrieved by normal procedure. Therefore, run a helper
-     process in a pseudo console and get them from the helper.
-     Slave process will attach to the pseudo console in the
-     helper process using AttachConsole(). */
-  COORD size = {
-    (SHORT) get_ttyp ()->winsize.ws_col,
-    (SHORT) get_ttyp ()->winsize.ws_row
-  };
-  CreatePipe (&from_master, &to_slave, &sec_none, 0);
-  SetLastError (ERROR_SUCCESS);
-  HRESULT res = CreatePseudoConsole (size, from_master, to_master,
-				     0, &get_ttyp ()->h_pseudo_console);
-  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
-    {
-      if (res != S_OK)
-	system_printf ("CreatePseudoConsole() failed. %08x\n",
-		       GetLastError ());
-      goto fallback;
-    }
-
-  /* If master process is running as service, attaching to
-     pseudo console should be done in fork. If attaching
-     is done in spawn for inetd or sshd, it fails because
-     the helper process is running as privileged user while
-     slave process is not. */
-  if (is_running_as_service ())
-    get_ttyp ()->attach_pcon_in_fork = true;
-
-  STARTUPINFOEXW si_helper;
-  HANDLE hello, goodbye;
-  HANDLE hr, hw;
-  PROCESS_INFORMATION pi_helper;
-  HANDLE hpConIn, hpConOut;
-  {
-    SIZE_T bytesRequired;
-    InitializeProcThreadAttributeList (NULL, 2, 0, &bytesRequired);
-    ZeroMemory (&si_helper, sizeof (si_helper));
-    si_helper.StartupInfo.cb = sizeof (STARTUPINFOEXW);
-    si_helper.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
-      HeapAlloc (GetProcessHeap (), 0, bytesRequired);
-    if (si_helper.lpAttributeList == NULL)
-      goto cleanup_pseudo_console;
-    if (!InitializeProcThreadAttributeList (si_helper.lpAttributeList,
-					    2, 0, &bytesRequired))
-      goto cleanup_heap;
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
-				    get_ttyp ()->h_pseudo_console,
-				    sizeof (get_ttyp ()->h_pseudo_console),
-				    NULL, NULL))
-      goto cleanup_heap;
-    /* Create events for start/stop helper process. */
-    hello = CreateEvent (&sec_none, true, false, NULL);
-    goodbye = CreateEvent (&sec_none, true, false, NULL);
-    /* Create a pipe for receiving pseudo console handles */
-    CreatePipe (&hr, &hw, &sec_none, 0);
-    /* Inherit only handles which are needed by helper. */
-    HANDLE handles_to_inherit[] = {hello, goodbye, hw};
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
-				    handles_to_inherit,
-				    sizeof (handles_to_inherit),
-				    NULL, NULL))
-      goto cleanup_event_and_pipes;
-    /* Create helper process */
-    WCHAR cmd[MAX_PATH];
-    path_conv helper ("/bin/cygwin-console-helper.exe");
-    size_t len = helper.get_wide_win32_path_len ();
-    helper.get_wide_win32_path (cmd);
-    __small_swprintf (cmd + len, L" %p %p %p", hello, goodbye, hw);
-    si_helper.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
-    si_helper.StartupInfo.hStdInput = NULL;
-    si_helper.StartupInfo.hStdOutput = NULL;
-    si_helper.StartupInfo.hStdError = NULL;
-    if (!CreateProcessW (NULL, cmd, &sec_none, &sec_none,
-			 TRUE, EXTENDED_STARTUPINFO_PRESENT,
-			 NULL, NULL, &si_helper.StartupInfo, &pi_helper))
-      goto cleanup_event_and_pipes;
-    for (;;)
-      {
-        DWORD wait_result = WaitForSingleObject (hello, 500);
-	if (wait_result == WAIT_OBJECT_0)
-	  break;
-	if (wait_result != WAIT_TIMEOUT)
-	  goto cleanup_helper_process;
-	DWORD exit_code;
-	if (!GetExitCodeProcess(pi_helper.hProcess, &exit_code))
-	  goto cleanup_helper_process;
-	if (exit_code == STILL_ACTIVE)
-	  continue;
-	if (exit_code != 0 ||
-	    WaitForSingleObject (hello, 500) != WAIT_OBJECT_0)
-	  goto cleanup_helper_process;
-	break;
-      }
-    CloseHandle (hello);
-    CloseHandle (pi_helper.hThread);
-    /* Retrieve pseudo console handles */
-    DWORD rLen;
-    char buf[64];
-    if (!ReadFile (hr, buf, sizeof (buf), &rLen, NULL))
-      goto cleanup_helper_process;
-    buf[rLen] = '\0';
-    sscanf (buf, "StdHandles=%p,%p", &hpConIn, &hpConOut);
-    if (!DuplicateHandle (pi_helper.hProcess, hpConIn,
-			  GetCurrentProcess (), &hpConIn, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_helper_process;
-    if (!DuplicateHandle (pi_helper.hProcess, hpConOut,
-			  GetCurrentProcess (), &hpConOut, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_pcon_in;
-    CloseHandle (hr);
-    CloseHandle (hw);
-    /* Clean up */
-    DeleteProcThreadAttributeList (si_helper.lpAttributeList);
-    HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-  }
-  /* Setting information of stuffs regarding pseudo console */
-  get_ttyp ()->h_helper_goodbye = goodbye;
-  get_ttyp ()->h_helper_process = pi_helper.hProcess;
-  get_ttyp ()->helper_process_id = pi_helper.dwProcessId;
-  CloseHandle (from_master);
-  CloseHandle (to_master);
-  from_master = hpConIn;
-  to_master = hpConOut;
-  ResizePseudoConsole (get_ttyp ()->h_pseudo_console, size);
-  return true;
-
-cleanup_pcon_in:
-  CloseHandle (hpConIn);
-cleanup_helper_process:
-  SetEvent (goodbye);
-  WaitForSingleObject (pi_helper.hProcess, INFINITE);
-  CloseHandle (pi_helper.hProcess);
-  goto skip_close_hello;
-cleanup_event_and_pipes:
-  CloseHandle (hello);
-skip_close_hello:
-  CloseHandle (goodbye);
-  CloseHandle (hr);
-  CloseHandle (hw);
-cleanup_heap:
-  HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-cleanup_pseudo_console:
-  {
-    HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
-    HANDLE tmp = hp->hConHostProcess;
-    ClosePseudoConsole (get_pseudo_console ());
-    CloseHandle (tmp);
-  }
-fallback:
-  CloseHandle (from_master);
-  CloseHandle (to_slave);
-  from_master = from_master_cyg;
-  to_slave = NULL;
-  get_ttyp ()->h_pseudo_console = NULL;
-  return false;
-}
-
 bool
 fhandler_pty_master::setup ()
 {
@@ -3593,11 +2261,6 @@ fhandler_pty_master::setup ()
   if (unit < 0)
     return false;
 
-  /* from_master should be used for pseudo console.
-     Just copy from_master_cyg here for the case that
-     pseudo console is not available. */
-  from_master = from_master_cyg;
-
   ProtectHandle1 (get_output_handle (), to_pty);
 
   tty& t = *cygwin_shared->tty[unit];
@@ -3696,15 +2359,21 @@ fhandler_pty_master::setup ()
       goto err;
     }
 
-  t.winsize.ws_col = 80;
-  t.winsize.ws_row = 25;
-
-  setup_pseudoconsole ();
+  __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;
+    }
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
   t.set_to_master (to_master);
   t.set_to_master_cyg (to_master_cyg);
+  t.winsize.ws_col = 80;
+  t.winsize.ws_row = 25;
   t.master_pid = myself->pid;
 
   dev ().parse (DEV_PTYM_MAJOR, unit);
@@ -3717,6 +2386,7 @@ fhandler_pty_master::setup ()
 err:
   __seterrno ();
   close_maybe (from_slave);
+  close_maybe (to_slave);
   close_maybe (get_handle ());
   close_maybe (get_output_handle ());
   close_maybe (input_available_event);
@@ -3776,9 +2446,6 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 {
   ssize_t towrite = len;
   BOOL res = TRUE;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
   while (towrite)
     {
       if (!is_echo)
@@ -3801,7 +2468,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
       if (!(get_ttyp ()->ti.c_oflag & OPOST))	// raw output mode
 	{
 	  DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
-	  res = WriteFunc (h, ptr, n, &n, NULL);
+	  res = WriteFile (h, ptr, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + n;
@@ -3851,7 +2518,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 		  break;
 		}
 	    }
-	  res = WriteFunc (h, outbuf, n, &n, NULL);
+	  res = WriteFile (h, outbuf, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + rc;
@@ -3861,3 +2528,123 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole (STARTUPINFOEXW *si)
+{
+  fhandler_base *fh = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+    {
+      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+      ptys->get_ttyp ()->switch_to_pcon_in = true;
+      if (ptys->get_ttyp ()->pcon_pid == 0 ||
+	  !pinfo (ptys->get_ttyp ()->pcon_pid))
+	ptys->get_ttyp ()->pcon_pid = myself->pid;
+    }
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     1, &get_ttyp ()->h_pseudo_console);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console,
+				  sizeof (get_ttyp ()->h_pseudo_console),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_pty_slave *p0 = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+    if (p0 && p0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = p0->get_handle ();
+    fhandler_pty_slave *p1 = (fhandler_pty_slave *) ::cygheap->fdtab[1];
+    if (p1 && p1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = p1->get_output_handle ();
+    fhandler_pty_slave *p2 = (fhandler_pty_slave *) ::cygheap->fdtab[2];
+    if (p2 && p2->get_device () != get_device ())
+      si->StartupInfo.hStdError = p2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole (void)
+{
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      get_ttyp ()->wait_pcon_fwd ();
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+      get_ttyp ()->pcon_start = false;
+    }
+}
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 691d08137..6ca4b5f29 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -134,36 +134,6 @@ child_info::prefork (bool detached)
 int __stdcall
 frok::child (volatile char * volatile here)
 {
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR)
-      {
-	fhandler_base *fh = cfd;
-	fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
-	if (ptym->get_pseudo_console ())
-	  {
-	    debug_printf ("found a PTY master %d: helper_PID=%d",
-			  ptym->get_minor (), ptym->get_helper_process_id ());
-	    if (fhandler_console::get_console_process_id (
-				ptym->get_helper_process_id (), true))
-	      /* Already attached */
-	      break;
-	    else
-	      {
-		if (ptym->attach_pcon_in_fork ())
-		  {
-		    FreeConsole ();
-		    if (!AttachConsole (ptym->get_helper_process_id ()))
-		      /* Error */;
-		    else
-		      break;
-		  }
-	      }
-	  }
-      }
-  extern void clear_pcon_attached_to (void); /* fhandler_tty.cc */
-  clear_pcon_attached_to ();
-
   HANDLE& hParent = ch.parent;
 
   sync_with_parent ("after longjmp", true);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 3f3f33fb5..56e6390af 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1227,8 +1227,6 @@ peek_pty_slave (select_record *s, bool from_select)
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
 
   ptys->reset_switch_to_pcon ();
-  if (ptys->to_be_read_from_pcon ())
-    ptys->update_pcon_input_state (true);
 
   if (s->read_selected)
     {
diff --git a/winsup/cygwin/smallprint.cc b/winsup/cygwin/smallprint.cc
index 26d34d9e4..f208a057a 100644
--- a/winsup/cygwin/smallprint.cc
+++ b/winsup/cygwin/smallprint.cc
@@ -405,7 +405,6 @@ small_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
   WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, NULL);
   FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
 }
@@ -432,7 +431,6 @@ console_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (console_handle);
   WriteFile (console_handle, buf, count, &done, NULL);
   FlushFileBuffers (console_handle);
 }
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..a3071884e 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -259,8 +277,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 {
   bool rc;
   int res = -1;
-  DWORD pid_restore = 0;
-  bool attach_to_console = false;
   pid_t ctty_pgid = 0;
 
   /* Search for CTTY and retrieve its PGID */
@@ -580,9 +596,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			 PROCESS_QUERY_LIMITED_INFORMATION))
 	sa = &sec_none_nih;
 
-      /* Attach to pseudo console if pty salve is used */
-      pid_restore = fhandler_console::get_console_process_id
-	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -591,29 +605,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	      if (ptys->get_pseudo_console ())
-		{
-		  DWORD helper_process_id = ptys->get_helper_process_id ();
-		  debug_printf ("found a PTY slave %d: helper_PID=%d",
-				    fh->get_minor (), helper_process_id);
-		  if (fhandler_console::get_console_process_id
-					      (helper_process_id, true))
-		    /* Already attached */
-		    attach_to_console = true;
-		  else if (!attach_to_console)
-		    {
-		      FreeConsole ();
-		      if (AttachConsole (helper_process_id))
-			attach_to_console = true;
-		    }
-		  ptys->fixup_after_attach (!iscygwin (), fd);
-		  if (mode == _P_OVERLAY)
-		    ptys->set_freeconsole_on_close (iscygwin ());
-		}
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	    }
 	  else if (fh && fh->get_major () == DEV_CONS_MAJOR)
 	    {
-	      attach_to_console = true;
 	      fhandler_console *cons = (fhandler_console *) fh;
 	      if (wincap.has_con_24bit_colors () && !iscygwin ())
 		if (fd == 1 || fd == 2)
@@ -632,6 +628,18 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool enable_pcon = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole (&si_pcon))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    enable_pcon = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +668,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +722,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +735,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (enable_pcon)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +910,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (enable_pcon)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->close_pseudoconsole ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
@@ -930,21 +948,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
   if (envblock)
     free (envblock);
 
-  if (attach_to_console && pid_restore)
-    {
-      FreeConsole ();
-      AttachConsole (pid_restore);
-      cygheap_fdenum cfd (false);
-      int fd;
-      while ((fd = cfd.next ()) >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_pty_slave *ptys =
-	      (fhandler_pty_slave *) (fhandler_base *) cfd;
-	    ptys->fixup_after_attach (false, fd);
-	  }
-    }
-
   return (int) res;
 }
 
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index f0aef3a36..35f8a59ae 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -264,7 +264,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
   if (category & _STRACE_SYSTEM)
     {
       DWORD done;
-      set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
       WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
       FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
       /* Make sure that the message shows up on the screen, too, since this is
@@ -276,7 +275,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
 				 &sec_none, OPEN_EXISTING, 0, 0);
 	  if (h != INVALID_HANDLE_VALUE)
 	    {
-	      set_ishybrid_and_switch_to_pcon (h);
 	      WriteFile (h, buf, len, &done, 0);
 	      CloseHandle (h);
 	    }
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 4cb68f776..d60f27545 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -234,20 +234,14 @@ tty::init ()
   was_opened = false;
   master_pid = 0;
   is_console = false;
-  attach_pcon_in_fork = false;
-  h_pseudo_console = NULL;
   column = 0;
+  h_pseudo_console = NULL;
   switch_to_pcon_in = false;
-  switch_to_pcon_out = false;
-  screen_alternated = false;
   mask_switch_to_pcon_in = false;
   pcon_pid = 0;
   term_code_page = 0;
-  need_redraw_screen = true;
   pcon_last_time = 0;
-  pcon_in_empty = true;
-  req_transfer_input_to_pcon = false;
-  req_flush_pcon_input = false;
+  pcon_start = false;
 }
 
 HANDLE
@@ -293,16 +287,6 @@ tty_min::ttyname ()
   return d.name ();
 }
 
-void
-tty::set_switch_to_pcon_out (bool v)
-{
-  if (switch_to_pcon_out != v)
-    {
-      wait_pcon_fwd ();
-      switch_to_pcon_out = v;
-    }
-}
-
 void
 tty::wait_pcon_fwd (void)
 {
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 920e32b16..c491d3891 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -94,21 +94,13 @@ private:
   HANDLE _to_master;
   HANDLE _to_master_cyg;
   HPCON h_pseudo_console;
-  HANDLE h_helper_process;
-  DWORD helper_process_id;
-  HANDLE h_helper_goodbye;
-  bool attach_pcon_in_fork;
+  bool pcon_start;
   bool switch_to_pcon_in;
-  bool switch_to_pcon_out;
-  bool screen_alternated;
   bool mask_switch_to_pcon_in;
   pid_t pcon_pid;
   UINT term_code_page;
-  bool need_redraw_screen;
   DWORD pcon_last_time;
-  bool pcon_in_empty;
-  bool req_transfer_input_to_pcon;
-  bool req_flush_pcon_input;
+  HANDLE h_pcon_write_pipe;
 
 public:
   HANDLE from_master () const { return _from_master; }
@@ -138,7 +130,6 @@ public:
   void set_master_ctl_closed () {master_pid = -1;}
   static void __stdcall create_master (int);
   static void __stdcall init_session ();
-  void set_switch_to_pcon_out (bool v);
   void wait_pcon_fwd (void);
   friend class fhandler_pty_common;
   friend class fhandler_pty_master;
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index fff7d18f3..458fb2a23 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -222,9 +222,6 @@ void init_console_handler (bool);
 
 extern bool wsock_started;
 
-/* PTY related */
-void set_ishybrid_and_switch_to_pcon (HANDLE h);
-
 /* Printf type functions */
 extern "C" void vapi_fatal (const char *, va_list ap) __attribute__ ((noreturn));
 extern "C" void api_fatal (const char *, ...) __attribute__ ((noreturn));
-- 
2.27.0


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-22  8:45                           ` Takashi Yano
@ 2020-07-22 11:49                             ` Corinna Vinschen
  2020-07-22 12:13                               ` Ken Brown
  2020-07-23  0:33                             ` Takashi Yano
  1 sibling, 1 reply; 73+ messages in thread
From: Corinna Vinschen @ 2020-07-22 11:49 UTC (permalink / raw)
  To: cygwin-developers

On Jul 22 17:45, Takashi Yano via Cygwin-developers wrote:
> On Wed, 22 Jul 2020 03:17:51 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > Hi Corinna,
> > 
> > On Mon, 20 Jul 2020 10:06:13 +0200
> > Corinna Vinschen wrote:
> > > On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
> > > > Hi Corinna,
> > > > 
> > > > On Fri, 17 Jul 2020 13:19:12 +0200
> > > > Corinna Vinschen wrote:
> > > > > Hi Takashi,
> > > > > 
> > > > > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > > > > > [...]
> > > > > > Revise the patch to fit the current git head.
> > > > > 
> > > > > are you satisfied with the code?  If you want to merge it,
> > > > > I'd bump Cygwin to 3.2.
> > > > 
> > > > Since this new implementation has both advantages and disadvantages,
> > > > there might be some options.
> > > > 
> > > > 1) Default to new implementation and leave the current one as an
> > > >   alternative. Switch them using the environment CYGWIN.
> > > > 2) Default to current implementation and add the new one as an
> > > >   alternative. Switch them using the environment CYGWIN.
> > > > 3) Adopt only new implementation and throw the current one away.
> > > > 
> > > > What do you think?
> > > 
> > > Do you really want to maintain twice as much code doing the same stuff
> > > and constantly having to ask users which version of the code they are
> > > running?  The maintenance cost outweighs the advantages, IMHO.
> > > Personally I'd go for option 3.
> > 
> > Personally, I feel a tinge of sadness to discard the current code,
> > however, your opinion sounds reasonable.
> > 
> > I will submit a new patch in which all the codes specific to the
> > current implementation are removed.
> 
> Attached is the patch in git format-patch format.
> All the codes specific to the current implementation are removed.
> 
> Despite the utmost care, the changes are relatively large, so some
> degradation may exist.
> 
> I will appreciate if you could test.

I built a new DLL with this patch and this looks pretty good to me so
far.  I'm a bad tester for this stuff, though, using just basic Cygwin
tools usually.

At one point we should probably just apply this patch and create
developer snapshots to broaden the tester base, but for now, maybe
I should upload my test DLL somewhere?  Is anybody besides Thomas
willing to test this new pseudo console stuff?


Thanks,
Corinna



-- 
Corinna Vinschen
Cygwin Maintainer

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-22 11:49                             ` Corinna Vinschen
@ 2020-07-22 12:13                               ` Ken Brown
  0 siblings, 0 replies; 73+ messages in thread
From: Ken Brown @ 2020-07-22 12:13 UTC (permalink / raw)
  To: cygwin-developers

On 7/22/2020 7:49 AM, Corinna Vinschen wrote:
> On Jul 22 17:45, Takashi Yano via Cygwin-developers wrote:
>> On Wed, 22 Jul 2020 03:17:51 +0900
>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
>>> Hi Corinna,
>>>
>>> On Mon, 20 Jul 2020 10:06:13 +0200
>>> Corinna Vinschen wrote:
>>>> On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
>>>>> Hi Corinna,
>>>>>
>>>>> On Fri, 17 Jul 2020 13:19:12 +0200
>>>>> Corinna Vinschen wrote:
>>>>>> Hi Takashi,
>>>>>>
>>>>>> On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
>>>>>>> [...]
>>>>>>> Revise the patch to fit the current git head.
>>>>>>
>>>>>> are you satisfied with the code?  If you want to merge it,
>>>>>> I'd bump Cygwin to 3.2.
>>>>>
>>>>> Since this new implementation has both advantages and disadvantages,
>>>>> there might be some options.
>>>>>
>>>>> 1) Default to new implementation and leave the current one as an
>>>>>    alternative. Switch them using the environment CYGWIN.
>>>>> 2) Default to current implementation and add the new one as an
>>>>>    alternative. Switch them using the environment CYGWIN.
>>>>> 3) Adopt only new implementation and throw the current one away.
>>>>>
>>>>> What do you think?
>>>>
>>>> Do you really want to maintain twice as much code doing the same stuff
>>>> and constantly having to ask users which version of the code they are
>>>> running?  The maintenance cost outweighs the advantages, IMHO.
>>>> Personally I'd go for option 3.
>>>
>>> Personally, I feel a tinge of sadness to discard the current code,
>>> however, your opinion sounds reasonable.
>>>
>>> I will submit a new patch in which all the codes specific to the
>>> current implementation are removed.
>>
>> Attached is the patch in git format-patch format.
>> All the codes specific to the current implementation are removed.
>>
>> Despite the utmost care, the changes are relatively large, so some
>> degradation may exist.
>>
>> I will appreciate if you could test.
> 
> I built a new DLL with this patch and this looks pretty good to me so
> far.  I'm a bad tester for this stuff, though, using just basic Cygwin
> tools usually.
> 
> At one point we should probably just apply this patch and create
> developer snapshots to broaden the tester base, but for now, maybe
> I should upload my test DLL somewhere?  Is anybody besides Thomas
> willing to test this new pseudo console stuff?

I don't have any specific tests for the pseudo console, but I'll install 
Takashi's patch and do some things that have often caught bugs in the past 
(e.g., running through my FIFO test suite).

Ken

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-22  8:45                           ` Takashi Yano
  2020-07-22 11:49                             ` Corinna Vinschen
@ 2020-07-23  0:33                             ` Takashi Yano
  2020-07-24  5:38                               ` Takashi Yano
  1 sibling, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-07-23  0:33 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 2160 bytes --]

On Wed, 22 Jul 2020 17:45:41 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:

> On Wed, 22 Jul 2020 03:17:51 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > Hi Corinna,
> > 
> > On Mon, 20 Jul 2020 10:06:13 +0200
> > Corinna Vinschen wrote:
> > > On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
> > > > Hi Corinna,
> > > > 
> > > > On Fri, 17 Jul 2020 13:19:12 +0200
> > > > Corinna Vinschen wrote:
> > > > > Hi Takashi,
> > > > > 
> > > > > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > > > > > [...]
> > > > > > Revise the patch to fit the current git head.
> > > > > 
> > > > > are you satisfied with the code?  If you want to merge it,
> > > > > I'd bump Cygwin to 3.2.
> > > > 
> > > > Since this new implementation has both advantages and disadvantages,
> > > > there might be some options.
> > > > 
> > > > 1) Default to new implementation and leave the current one as an
> > > >   alternative. Switch them using the environment CYGWIN.
> > > > 2) Default to current implementation and add the new one as an
> > > >   alternative. Switch them using the environment CYGWIN.
> > > > 3) Adopt only new implementation and throw the current one away.
> > > > 
> > > > What do you think?
> > > 
> > > Do you really want to maintain twice as much code doing the same stuff
> > > and constantly having to ask users which version of the code they are
> > > running?  The maintenance cost outweighs the advantages, IMHO.
> > > Personally I'd go for option 3.
> > 
> > Personally, I feel a tinge of sadness to discard the current code,
> > however, your opinion sounds reasonable.
> > 
> > I will submit a new patch in which all the codes specific to the
> > current implementation are removed.
> 
> Attached is the patch in git format-patch format.
> All the codes specific to the current implementation are removed.
> 
> Despite the utmost care, the changes are relatively large, so some
> degradation may exist.
> 
> I will appreciate if you could test.

There were still unused code. Please try attached patch instead.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-Cygwin-pty-Implement-new-pseudo-console-support.patch --]
[-- Type: application/octet-stream, Size: 86804 bytes --]

From 7c76a49c6b0d3b222174c972a0d24fed85ef4a5d Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Thu, 23 Jul 2020 09:27:20 +0900
Subject: [PATCH] Cygwin: pty: Implement new pseudo console support.

- In this implementation, pseudo console is created for each native
  console app. Advantages and disadvantages of this implementation
  over the previous implementation are as follows.

  Advantages:
  1) No performance degradation in pty output for cygwin process.
      https://cygwin.com/pipermail/cygwin/2020-February/243858.html
  2) Free from the problem caused by difference of behaviour of control
     sequences between real terminal and pseudo console.
      https://cygwin.com/pipermail/cygwin/2019-December/243281.html
      https://cygwin.com/pipermail/cygwin/2020-February/243855.html
  3) Free from the problem in cgdb and emacs gud.
      https://cygwin.com/pipermail/cygwin/2020-January/243601.html
      https://cygwin.com/pipermail/cygwin/2020-March/244146.html
  4) Redrawing screen on executing native console apps is not necessary.
  5) cygwin-console-helper is not necessary for the pseudo console
     support.
  6) The codes for pseudo console support are much simpler than that
     of the previous one.

  Disadvantages:
  1) The cygwin program which calls console API directly does not work.
  2) The apps which use console API cannot be debugged with gdb. This
     is because pseudo console is not activated since gdb uses
     CreateProcess() rather than exec(). Even with this limitation,
     attaching gdb to native apps, in which pseudo console is already
     activated, works.
  3) Typeahead key inputs are discarded while native console app is
     executed. Simirally, typeahead key inputs while cygwin app is
     executed are not inherited to native console app.
  4) Code page cannot be changed by chcp.com. Acctually, chcp works
     itself and changes code page of its own pseudo console.  However,
     since pseudo console is recreated for another process, it cannot
     inherit the code page.
  5) system_printf() does not work after stderr is closed. (Same with
     cygwin 3.0.7)
  6) Startup time of native console apps is about 3 times slower than
     previous implemenation.
---
 winsup/cygwin/dtable.cc           |   32 -
 winsup/cygwin/fhandler.h          |   53 +-
 winsup/cygwin/fhandler_console.cc |   43 -
 winsup/cygwin/fhandler_tty.cc     | 1735 +++++------------------------
 winsup/cygwin/fork.cc             |   30 -
 winsup/cygwin/select.cc           |    5 +-
 winsup/cygwin/smallprint.cc       |    2 -
 winsup/cygwin/spawn.cc            |   87 +-
 winsup/cygwin/strace.cc           |    2 -
 winsup/cygwin/tty.cc              |   20 +-
 winsup/cygwin/tty.h               |   13 +-
 winsup/cygwin/winsup.h            |    3 -
 12 files changed, 320 insertions(+), 1705 deletions(-)

diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index e9e005b08..6a91e33bc 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -147,38 +147,6 @@ dtable::get_debugger_info ()
 void
 dtable::stdio_init ()
 {
-  for (int i = 0; i < 3; i ++)
-    {
-      const int chk_order[] = {1, 0, 2};
-      int fd = chk_order[i];
-      fhandler_base *fh = cygheap->fdtab[fd];
-      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
-	{
-	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	  if (ptys->get_pseudo_console ())
-	    {
-	      bool attached = !!fhandler_console::get_console_process_id
-		(ptys->get_helper_process_id (), true);
-	      if (attached)
-		break;
-	      else
-		{
-		  /* Not attached to pseudo console in fork() or spawn()
-		     by some reason. This happens if the executable is
-		     a windows GUI binary, such as mintty. */
-		  FreeConsole ();
-		  if (AttachConsole (ptys->get_helper_process_id ()))
-		    {
-		      ptys->fixup_after_attach (false, fd);
-		      break;
-		    }
-		}
-	    }
-	}
-      else if (fh && fh->get_major () == DEV_CONS_MAJOR)
-	break;
-    }
-
   if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT))
     {
       tty_min *t = cygwin_shared->tty.get_cttyp ();
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 60bd27e00..4604ff2ba 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -326,16 +326,16 @@ class fhandler_base
   virtual size_t &raixput () { return ra.raixput; };
   virtual size_t &rabuflen () { return ra.rabuflen; };
 
-  virtual bool get_readahead_valid () { return raixget () < ralen (); }
+  bool get_readahead_valid () { return raixget () < ralen (); }
   int puts_readahead (const char *s, size_t len = (size_t) -1);
-  virtual int put_readahead (char value);
+  int put_readahead (char value);
 
   int get_readahead ();
   int peek_readahead (int queryput = 0);
 
   void set_readahead_valid (int val, int ch = -1);
 
-  virtual int get_readahead_into_buffer (char *buf, size_t buflen);
+  int get_readahead_into_buffer (char *buf, size_t buflen);
 
   bool has_acls () const { return pc.has_acls (); }
 
@@ -1909,7 +1909,7 @@ class fhandler_termios: public fhandler_base
   int ioctl (int, void *);
   tty_min *_tc;
   tty *get_ttyp () {return (tty *) tc ();}
-  virtual int eat_readahead (int n);
+  int eat_readahead (int n);
 
  public:
   tty_min*& tc () {return _tc;}
@@ -2188,7 +2188,6 @@ private:
   static bool need_invisible ();
   static void free_console ();
   static const char *get_nonascii_key (INPUT_RECORD& input_rec, char *);
-  static DWORD get_console_process_id (DWORD pid, bool match);
 
   fhandler_console (void *) {}
 
@@ -2268,19 +2267,7 @@ class fhandler_pty_common: public fhandler_termios
     return fh;
   }
 
-  bool attach_pcon_in_fork (void)
-  {
-    return get_ttyp ()->attach_pcon_in_fork;
-  }
-  DWORD get_helper_process_id (void)
-  {
-    return get_ttyp ()->helper_process_id;
-  }
-  HPCON get_pseudo_console (void)
-  {
-    return get_ttyp ()->h_pseudo_console;
-  }
-  bool to_be_read_from_pcon (void);
+  void resize_pseudo_console (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2291,23 +2278,15 @@ class fhandler_pty_slave: public fhandler_pty_common
 {
   HANDLE inuse;			// used to indicate that a tty is in use
   HANDLE output_handle_cyg, io_handle_cyg;
-  DWORD pid_restore;
-  int fd;
 
   /* Helper functions for fchmod and fchown. */
   bool fch_open_handles (bool chown);
   int fch_set_sd (security_descriptor &sd, bool chown);
   void fch_close_handles ();
 
-  bool try_reattach_pcon ();
-  void restore_reattach_pcon ();
-  inline void free_attached_console ();
-
  public:
   /* Constructor */
   fhandler_pty_slave (int);
-  /* Destructor */
-  ~fhandler_pty_slave ();
 
   void set_output_handle_cyg (HANDLE h) { output_handle_cyg = h; }
   HANDLE& get_output_handle_cyg () { return output_handle_cyg; }
@@ -2319,9 +2298,6 @@ class fhandler_pty_slave: public fhandler_pty_common
   ssize_t __stdcall write (const void *ptr, size_t len);
   void __reg3 read (void *ptr, size_t& len);
   int init (HANDLE, DWORD, mode_t);
-  int eat_readahead (int n);
-  int get_readahead_into_buffer (char *buf, size_t buflen);
-  bool get_readahead_valid (void);
 
   int tcsetattr (int a, const struct termios *t);
   int tcgetattr (struct termios *t);
@@ -2358,20 +2334,12 @@ class fhandler_pty_slave: public fhandler_pty_common
     copyto (fh);
     return fh;
   }
-  void set_switch_to_pcon (int fd);
+  bool setup_pseudoconsole (STARTUPINFOEXW *si);
+  void close_pseudoconsole (void);
+  void set_switch_to_pcon (void);
   void reset_switch_to_pcon (void);
-  void push_to_pcon_screenbuffer (const char *ptr, size_t len, bool is_echo);
   void mask_switch_to_pcon_in (bool mask);
-  void fixup_after_attach (bool native_maybe, int fd);
-  bool is_line_input (void)
-  {
-    return get_ttyp ()->ti.c_lflag & ICANON;
-  }
   void setup_locale (void);
-  void set_freeconsole_on_close (bool val);
-  void trigger_redraw_screen (void);
-  void pull_pcon_input (void);
-  void update_pcon_input_state (bool need_lock);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
@@ -2396,7 +2364,6 @@ public:
   int process_slave_output (char *buf, size_t len, int pktmode_on);
   void doecho (const void *str, DWORD len);
   int accept_input ();
-  int put_readahead (char value);
   int open (int flags, mode_t mode = 0);
   void open_setup (int flags);
   ssize_t __stdcall write (const void *ptr, size_t len);
@@ -2435,9 +2402,7 @@ public:
     copyto (fh);
     return fh;
   }
-
-  bool setup_pseudoconsole (void);
-  void transfer_input_to_pcon (void);
+  bool to_be_read_from_pcon (void);
 };
 
 class fhandler_dev_null: public fhandler_base
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 52741ce8b..02a5996a1 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -1206,18 +1206,6 @@ fhandler_console::close ()
   if (con_ra.rabuf)
     free (con_ra.rabuf);
 
-  /* If already attached to pseudo console, don't call free_console () */
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR ||
-	cfd->get_major () == DEV_PTYS_MAJOR)
-      {
-	fhandler_pty_common *t =
-	  (fhandler_pty_common *) (fhandler_base *) cfd;
-	if (get_console_process_id (t->get_helper_process_id (), true))
-	  return 0;
-      }
-
   if (!have_execed)
     free_console ();
   return 0;
@@ -3611,37 +3599,6 @@ fhandler_console::need_invisible ()
   return b;
 }
 
-DWORD
-fhandler_console::get_console_process_id (DWORD pid, bool match)
-{
-  DWORD tmp;
-  DWORD num, num_req;
-  num = 1;
-  num_req = GetConsoleProcessList (&tmp, num);
-  DWORD *list;
-  while (true)
-    {
-      list = (DWORD *)
-	HeapAlloc (GetProcessHeap (), 0, num_req * sizeof (DWORD));
-      num = num_req;
-      num_req = GetConsoleProcessList (list, num);
-      if (num_req > num)
-	HeapFree (GetProcessHeap (), 0, list);
-      else
-	break;
-    }
-  num = num_req;
-
-  tmp = 0;
-  for (DWORD i=0; i<num; i++)
-    if ((match && list[i] == pid) || (!match && list[i] != pid))
-      /* Last one is the oldest. */
-      /* https://github.com/microsoft/terminal/issues/95 */
-      tmp = list[i];
-  HeapFree (GetProcessHeap (), 0, list);
-  return tmp;
-}
-
 DWORD
 fhandler_console::__acquire_input_mutex (const char *fn, int ln, DWORD ms)
 {
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 6a004f3a5..7f84ead6d 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -25,7 +25,6 @@ details. */
 #include "child_info.h"
 #include <asm/socket.h>
 #include "cygwait.h"
-#include "tls_pbuf.h"
 #include "registry.h"
 
 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
@@ -33,7 +32,6 @@ details. */
 #endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
 
 extern "C" int sscanf (const char *, const char *, ...);
-extern "C" int ttyname_r (int, char*, size_t);
 
 extern "C" {
   HRESULT WINAPI CreatePseudoConsole (COORD, HANDLE, HANDLE, DWORD, HPCON *);
@@ -60,20 +58,10 @@ struct pipe_reply {
   DWORD error;
 };
 
-static int pcon_attached_to = -1;
 static bool isHybrid;
-static bool do_not_reset_switch_to_pcon;
-static bool freeconsole_on_close = true;
-static tty *last_ttyp = NULL;
-
-void
-clear_pcon_attached_to (void)
-{
-  pcon_attached_to = -1;
-}
 
 static void
-set_switch_to_pcon (void)
+set_switch_to_pcon (HANDLE h)
 {
   cygheap_fdenum cfd (false);
   int fd;
@@ -82,280 +70,17 @@ set_switch_to_pcon (void)
       {
 	fhandler_base *fh = cfd;
 	fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	if (ptys->get_pseudo_console ())
-	  {
-	    ptys->set_switch_to_pcon (fd);
-	    ptys->trigger_redraw_screen ();
-	    DWORD mode =
-	      ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	    SetConsoleMode (ptys->get_handle (), mode);
-	  }
+	if (h == ptys->get_handle ())
+	  ptys->set_switch_to_pcon ();
 	return;
       }
-  /* No pty slave opened */
-  if (last_ttyp) /* Make system_printf() work after closing pty slave */
-    last_ttyp->set_switch_to_pcon_out (true);
-}
-
-static void
-force_attach_to_pcon (HANDLE h)
-{
-  bool attach_done = false;
-  for (int n = 0; n < 2; n ++)
-    {
-      /* First time, attach to the pty whose handle value is match.
-	 Second time, try to attach to any pty. */
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	    if (!ptys->get_pseudo_console ())
-	      continue;
-	    if (n != 0
-		|| h == ptys->get_handle ()
-		|| h == ptys->get_output_handle ())
-	      {
-		if (fhandler_console::get_console_process_id
-				  (ptys->get_helper_process_id (), true))
-		  attach_done = true;
-		else
-		  {
-		    FreeConsole ();
-		    if (AttachConsole (ptys->get_helper_process_id ()))
-		      {
-			pcon_attached_to = ptys->get_minor ();
-			attach_done = true;
-		      }
-		    else
-		      pcon_attached_to = -1;
-		  }
-		break;
-	      }
-	  }
-	else if (cfd->get_major () == DEV_CONS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_console *cons = (fhandler_console *) fh;
-	    if (n != 0
-		|| h == cons->get_handle ()
-		|| h == cons->get_output_handle ())
-	      {
-		/* If the process is running on a console,
-		   the parent process should be attached
-		   to the same console. */
-		DWORD attach_wpid;
-		if (myself->ppid == 1)
-		  attach_wpid = ATTACH_PARENT_PROCESS;
-		else
-		  {
-		    pinfo p (myself->ppid);
-		    attach_wpid = p->dwProcessId;
-		  }
-		FreeConsole ();
-		if (AttachConsole (attach_wpid))
-		  {
-		    pcon_attached_to = -1;
-		    attach_done = true;
-		  }
-		else
-		  pcon_attached_to = -1;
-		break;
-	      }
-	  }
-      if (attach_done)
-	break;
-    }
-}
-
-void
-set_ishybrid_and_switch_to_pcon (HANDLE h)
-{
-  if (GetFileType (h) == FILE_TYPE_CHAR)
-    {
-      force_attach_to_pcon (h);
-      DWORD dummy;
-      if (!isHybrid && (GetConsoleMode (h, &dummy)
-			|| GetLastError () != ERROR_INVALID_HANDLE))
-	{
-	  isHybrid = true;
-	  set_switch_to_pcon ();
-	}
-    }
-}
-
-inline void
-fhandler_pty_slave::free_attached_console ()
-{
-  bool attached = get_ttyp () ?
-    fhandler_console::get_console_process_id (get_helper_process_id (), true)
-    : (get_minor () == pcon_attached_to);
-  if (freeconsole_on_close && attached)
-    {
-      FreeConsole ();
-      pcon_attached_to = -1;
-    }
 }
 
 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
-DEF_HOOK (WriteFile);
-DEF_HOOK (WriteConsoleA);
-DEF_HOOK (WriteConsoleW);
-DEF_HOOK (ReadFile);
-DEF_HOOK (ReadConsoleA);
-DEF_HOOK (ReadConsoleW);
-DEF_HOOK (WriteConsoleOutputA);
-DEF_HOOK (WriteConsoleOutputW);
-DEF_HOOK (WriteConsoleOutputCharacterA);
-DEF_HOOK (WriteConsoleOutputCharacterW);
-DEF_HOOK (WriteConsoleOutputAttribute);
-DEF_HOOK (SetConsoleCursorPosition);
-DEF_HOOK (SetConsoleTextAttribute);
-DEF_HOOK (WriteConsoleInputA);
-DEF_HOOK (WriteConsoleInputW);
-DEF_HOOK (ReadConsoleInputA);
-DEF_HOOK (ReadConsoleInputW);
-DEF_HOOK (PeekConsoleInputA);
-DEF_HOOK (PeekConsoleInputW);
 /* CreateProcess() is hooked for GDB etc. */
 DEF_HOOK (CreateProcessA);
 DEF_HOOK (CreateProcessW);
 
-static BOOL WINAPI
-WriteFile_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleA_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleW_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadFile_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleA_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleW_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleOutputA_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputA_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputW_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputW_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterA_Hooked
-     (HANDLE h, LPCSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterA_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterW_Hooked
-     (HANDLE h, LPCWSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterW_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputAttribute_Hooked
-     (HANDLE h, CONST WORD *a, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputAttribute_Orig (h, a, l, c, n);
-}
-static BOOL WINAPI
-SetConsoleCursorPosition_Hooked
-     (HANDLE h, COORD c)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleCursorPosition_Orig (h, c);
-}
-static BOOL WINAPI
-SetConsoleTextAttribute_Hooked
-     (HANDLE h, WORD a)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleTextAttribute_Orig (h, a);
-}
-static BOOL WINAPI
-WriteConsoleInputA_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-WriteConsoleInputW_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputW_Orig (h, r, l, n);
-}
-/* CreateProcess() is hooked for GDB etc. */
 static BOOL WINAPI
 CreateProcessA_Hooked
      (LPCSTR n, LPSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
@@ -363,11 +88,14 @@ CreateProcessA_Hooked
       LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 static BOOL WINAPI
@@ -377,11 +105,14 @@ CreateProcessW_Hooked
       LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 
@@ -464,10 +195,6 @@ fhandler_pty_master::flush_to_slave ()
 {
   if (get_readahead_valid () && !(get_ttyp ()->ti.c_lflag & ICANON))
     accept_input ();
-  WaitForSingleObject (input_mutex, INFINITE);
-  if (!get_ttyp ()->pcon_in_empty && !(get_ttyp ()->ti.c_lflag & ICANON))
-    SetEvent (input_available_event);
-  ReleaseMutex (input_mutex);
 }
 
 DWORD
@@ -532,14 +259,6 @@ fhandler_pty_master::doecho (const void *str, DWORD len)
   release_output_mutex ();
 }
 
-int
-fhandler_pty_master::put_readahead (char value)
-{
-  if (to_be_read_from_pcon ())
-    return 1;
-  return fhandler_base::put_readahead (value);
-}
-
 int
 fhandler_pty_master::accept_input ()
 {
@@ -551,9 +270,11 @@ fhandler_pty_master::accept_input ()
   char *p = rabuf () + raixget ();
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
   if (to_be_read_from_pcon ())
-    ; /* Do nothing */
-  else if (!bytes_left)
+    write_to = to_slave;
+
+  if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
@@ -564,10 +285,10 @@ fhandler_pty_master::accept_input ()
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -725,52 +446,12 @@ out:
 
 fhandler_pty_slave::fhandler_pty_slave (int unit)
   : fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL),
-  io_handle_cyg (NULL), pid_restore (0), fd (-1)
+  io_handle_cyg (NULL)
 {
   if (unit >= 0)
     dev ().parse (DEV_PTYS_MAJOR, unit);
 }
 
-fhandler_pty_slave::~fhandler_pty_slave ()
-{
-  if (!get_ttyp ())
-    {
-      /* Why comes here? Who clears _tc? */
-      free_attached_console ();
-      return;
-    }
-  if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 0)
-	{
-	  pcon_attached_to = -1;
-	  last_ttyp = get_ttyp ();
-	}
-      if (used == 0)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
-}
-
 int
 fhandler_pty_slave::open (int flags, mode_t)
 {
@@ -950,24 +631,7 @@ fhandler_pty_slave::open (int flags, mode_t)
   set_output_handle (to_master_local);
   set_output_handle_cyg (to_master_cyg_local);
 
-  if (!get_pseudo_console ())
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (!fhandler_console::get_console_process_id
-			       (GetCurrentProcessId (), true))
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (fhandler_console::get_console_process_id
-			       (get_helper_process_id (), true))
-    /* Attached to pcon of this pty */
-    {
-      pcon_attached_to = get_minor ();
-      init_console_handler (true);
-    }
+  fhandler_console::need_invisible ();
 
   set_open_status ();
   return 1;
@@ -1021,8 +685,7 @@ fhandler_pty_slave::close ()
   if (!ForceCloseHandle (get_handle_cyg ()))
     termios_printf ("CloseHandle (get_handle_cyg ()<%p>), %E",
 	get_handle_cyg ());
-  if (!get_pseudo_console () &&
-      (unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
+  if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
     fhandler_console::free_console ();	/* assumes that we are the last pty closer */
   fhandler_pty_common::close ();
   if (!ForceCloseHandle (output_mutex))
@@ -1070,234 +733,17 @@ fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
   return ret;
 }
 
-bool
-fhandler_pty_slave::try_reattach_pcon (void)
-{
-  pid_restore = 0;
-
-  /* Do not detach from the console because re-attaching will
-     fail if helper process is running as service account. */
-  if (get_ttyp()->attach_pcon_in_fork)
-    return false;
-  if (pcon_attached_to >= 0 &&
-      cygwin_shared->tty[pcon_attached_to]->attach_pcon_in_fork)
-    return false;
-
-  pid_restore =
-    fhandler_console::get_console_process_id (GetCurrentProcessId (),
-					      false);
-  /* If pid_restore is not set, give up. */
-  if (!pid_restore)
-    return false;
-
-  FreeConsole ();
-  if (!AttachConsole (get_helper_process_id ()))
-    {
-      system_printf ("pty%d: AttachConsole(helper=%d) failed. 0x%08lx",
-		     get_minor (), get_helper_process_id (), GetLastError ());
-      return false;
-    }
-  return true;
-}
-
 void
-fhandler_pty_slave::restore_reattach_pcon (void)
+fhandler_pty_slave::set_switch_to_pcon (void)
 {
-  if (pid_restore)
+  if (!get_ttyp ()->switch_to_pcon_in)
     {
-      FreeConsole ();
-      if (!AttachConsole (pid_restore))
-	{
-	  system_printf ("pty%d: AttachConsole(restore=%d) failed. 0x%08lx",
-			 get_minor (), pid_restore, GetLastError ());
-	  pcon_attached_to = -1;
-	}
-    }
-  pid_restore = 0;
-}
-
-/* This function requests transfering the input data from the input
-   pipe for cygwin apps to the other input pipe for native apps. */
-void
-fhandler_pty_slave::pull_pcon_input (void)
-{
-  get_ttyp ()->req_transfer_input_to_pcon = true;
-  while (get_ttyp ()->req_transfer_input_to_pcon)
-    Sleep (1);
-}
-
-void
-fhandler_pty_slave::update_pcon_input_state (bool need_lock)
-{
-  if (need_lock)
-    WaitForSingleObject (input_mutex, INFINITE);
-  /* Flush input buffer if it is requested by master.
-     This happens if ^C is pressed in pseudo console side. */
-  if (get_ttyp ()->req_flush_pcon_input)
-    {
-      FlushConsoleInputBuffer (get_handle ());
-      get_ttyp ()->req_flush_pcon_input = false;
-    }
-  /* Peek console input buffer and update state. */
-  INPUT_RECORD inp[INREC_SIZE];
-  DWORD n;
-  BOOL (WINAPI *PeekFunc)
-    (HANDLE, PINPUT_RECORD, DWORD, LPDWORD);
-  PeekFunc =
-    PeekConsoleInputA_Orig ? : PeekConsoleInput;
-  PeekFunc (get_handle (), inp, INREC_SIZE, &n);
-  bool saw_accept = false;
-  bool pipe_empty = true;
-  while (n-- > 0)
-    if (inp[n].EventType == KEY_EVENT && inp[n].Event.KeyEvent.bKeyDown &&
-	inp[n].Event.KeyEvent.uChar.AsciiChar)
-      {
-	pipe_empty = false;
-	char c = inp[n].Event.KeyEvent.uChar.AsciiChar;
-	const char sigs[] = {
-	  (char) get_ttyp ()->ti.c_cc[VINTR],
-	  (char) get_ttyp ()->ti.c_cc[VQUIT],
-	  (char) get_ttyp ()->ti.c_cc[VSUSP],
-	};
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n',
-	  '\r'
-	};
-	if (is_line_input () && c && memchr (eols, c, sizeof (eols)))
-	  saw_accept = true;
-	if ((get_ttyp ()->ti.c_lflag & ISIG)
-	    && c && memchr (sigs, c, sizeof (sigs)))
-	  saw_accept = true;
-      }
-  get_ttyp ()->pcon_in_empty = pipe_empty && !(ralen () > raixget ());
-  if (!get_readahead_valid () &&
-      (pipe_empty || (is_line_input () && !saw_accept)) &&
-      get_ttyp ()->read_retval == 1 && bytes_available (n) && n == 0)
-    ResetEvent (input_available_event);
-  if (need_lock)
-    ReleaseMutex (input_mutex);
-}
-
-int
-fhandler_pty_slave::eat_readahead (int n)
-{
-  int oralen = ralen ();
-  if (n < 0)
-    n = ralen () - raixget ();
-  if (n > 0 && ralen () > raixget ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      while (n > 0 && ralen () > raixget ())
-	{
-	  if (is_line_input () && rabuf ()[ralen ()-1]
-	      && memchr (eols, rabuf ()[ralen ()-1], sizeof (eols)))
-	    break;
-	  -- n;
-	  -- ralen ();
-	}
-
-      /* If IUTF8 is set, the terminal is in UTF-8 mode.  If so, we erase
-	 a complete UTF-8 multibyte sequence on VERASE/VWERASE.  Otherwise,
-	 if we only erase a single byte, invalid unicode chars are left in
-	 the input. */
-      if (get_ttyp ()->ti.c_iflag & IUTF8)
-	while (ralen () > raixget () &&
-	       ((unsigned char) rabuf ()[ralen ()] & 0xc0) == 0x80)
-	  --ralen ();
-    }
-  oralen = oralen - ralen ();
-  if (raixget () >= ralen ())
-    raixget () = raixput () = ralen () = 0;
-  else if (raixput () > ralen ())
-    raixput () = ralen ();
-
-  return oralen;
-}
-
-int
-fhandler_pty_slave::get_readahead_into_buffer (char *buf, size_t buflen)
-{
-  int ch;
-  int copied_chars = 0;
-
-  while (buflen)
-    if ((ch = get_readahead ()) < 0)
-      break;
-    else
-      {
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n'
-	};
-	buf[copied_chars++] = (unsigned char)(ch & 0xff);
-	buflen--;
-	if (is_line_input () && ch && memchr (eols, ch & 0xff, sizeof (eols)))
-	  break;
-      }
-
-  return copied_chars;
-}
-
-bool
-fhandler_pty_slave::get_readahead_valid (void)
-{
-  if (is_line_input ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      for (size_t i=raixget (); i<ralen (); i++)
-	if (rabuf ()[i] && memchr (eols, rabuf ()[i], sizeof (eols)))
-	  return true;
-      return false;
-    }
-  else
-    return ralen () > raixget ();
-}
-
-void
-fhandler_pty_slave::set_switch_to_pcon (int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  acquire_output_mutex (INFINITE);
-  if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
-    {
-      pull_pcon_input ();
+      isHybrid = true;
       if (get_ttyp ()->pcon_pid == 0 ||
 	  !pinfo (get_ttyp ()->pcon_pid))
 	get_ttyp ()->pcon_pid = myself->pid;
       get_ttyp ()->switch_to_pcon_in = true;
-      if (isHybrid && !get_ttyp ()->switch_to_pcon_out)
-	{
-	  get_ttyp ()->wait_pcon_fwd ();
-	  get_ttyp ()->switch_to_pcon_out = true;
-	}
     }
-  else if ((fd == 1 || fd == 2) && !get_ttyp ()->switch_to_pcon_out)
-    {
-      get_ttyp ()->wait_pcon_fwd ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
-	get_ttyp ()->pcon_pid = myself->pid;
-      get_ttyp ()->switch_to_pcon_out = true;
-      if (isHybrid)
-	get_ttyp ()->switch_to_pcon_in = true;
-    }
-  release_output_mutex ();
 }
 
 void
@@ -1310,183 +756,10 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
     return;
   if (isHybrid)
     return;
-  if (do_not_reset_switch_to_pcon)
-    return;
-  acquire_output_mutex (INFINITE);
-  if (get_ttyp ()->switch_to_pcon_out)
-    /* Wait for pty_master_fwd_thread() */
-    get_ttyp ()->wait_pcon_fwd ();
   get_ttyp ()->pcon_pid = 0;
   get_ttyp ()->switch_to_pcon_in = false;
-  get_ttyp ()->switch_to_pcon_out = false;
-  release_output_mutex ();
-  init_console_handler (true);
-}
-
-void
-fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len,
-					       bool is_echo)
-{
-  bool attached =
-    !!fhandler_console::get_console_process_id (get_helper_process_id (), true);
-  if (!attached && pcon_attached_to == get_minor ())
-    {
-      for (DWORD t0 = GetTickCount (); GetTickCount () - t0 < 100; )
-	{
-	  Sleep (1);
-	  attached = fhandler_console::get_console_process_id
-				      (get_helper_process_id (), true);
-	  if (attached)
-	    break;
-	}
-      if (!attached)
-	{
-	  system_printf ("pty%d: pcon_attach_to mismatch??????", get_minor ());
-	  return;
-	}
-    }
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  if (pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      goto detach;
-
-  char *buf;
-  size_t nlen;
-  DWORD origCP;
-  origCP = GetConsoleOutputCP ();
-  SetConsoleOutputCP (get_ttyp ()->term_code_page);
-  /* Just copy */
-  buf = (char *) HeapAlloc (GetProcessHeap (), 0, len);
-  memcpy (buf, (char *)ptr, len);
-  nlen = len;
-  char *p0, *p1;
-  p0 = p1 = buf;
-  /* Remove alternate screen buffer drawing */
-  while (p0 && p1)
-    {
-      if (!get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to alternate screen buffer */
-	  p0 = (char *) memmem (p1, nlen - (p1-buf), "\033[?1049h", 8);
-	  if (p0)
-	    {
-	      //p0 += 8;
-	      get_ttyp ()->screen_alternated = true;
-	      if (get_ttyp ()->switch_to_pcon_out)
-		do_not_reset_switch_to_pcon = true;
-	    }
-	}
-      if (get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to main screen buffer */
-	  p1 = (char *) memmem (p0, nlen - (p0-buf), "\033[?1049l", 8);
-	  if (p1)
-	    {
-	      p1 += 8;
-	      get_ttyp ()->screen_alternated = false;
-	      do_not_reset_switch_to_pcon = false;
-	      memmove (p0, p1, buf+nlen - p1);
-	      nlen -= p1 - p0;
-	    }
-	  else
-	    nlen = p0 - buf;
-	}
-    }
-  if (!nlen) /* Nothing to be synchronized */
-    goto cleanup;
-  if (get_ttyp ()->switch_to_pcon_out && !is_echo)
-    goto cleanup;
-  /* Remove ESC sequence which returns results to console
-     input buffer. Without this, cursor position report
-     is put into the input buffer as a garbage. */
-  /* Remove ESC sequence to report cursor position. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[6n", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-  /* Remove ESC sequence to report terminal identity. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[0c", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-
-  /* If the ESC sequence ESC[?3h or ESC[?3l which clears console screen
-     buffer is pushed, set need_redraw_screen to trigger redraw screen. */
-  p0 = buf;
-  while ((p0 = (char *) memmem (p0, nlen - (p0 - buf), "\033[?", 3)))
-    {
-      p0 += 3;
-      bool exist_arg_3 = false;
-      while (p0 < buf + nlen && (isdigit (*p0) || *p0 == ';'))
-	{
-	  int arg = 0;
-	  while (p0 < buf + nlen && isdigit (*p0))
-	    arg = arg * 10 + (*p0 ++) - '0';
-	  if (arg == 3)
-	    exist_arg_3 = true;
-	  if (p0 < buf + nlen && *p0 == ';')
-	    p0 ++;
-	}
-      if (p0 < buf + nlen && exist_arg_3 && (*p0 == 'h' || *p0 == 'l'))
-	get_ttyp ()->need_redraw_screen = true;
-      p0 ++;
-      if (p0 >= buf + nlen)
-	break;
-    }
-
-  int retry_count;
-  retry_count = 0;
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  while (!GetConsoleMode (get_output_handle (), &dwMode))
-    {
-      termios_printf ("GetConsoleMode failed, %E");
-      int errno_save = errno;
-      /* Re-open handles */
-      this->open (0, 0);
-      /* Fix pseudo console window size */
-      this->ioctl (TIOCSWINSZ, &get_ttyp ()->winsize);
-      if (errno != errno_save)
-	set_errno (errno_save);
-      if (++retry_count > 3)
-	goto cleanup;
-    }
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-  char *p;
-  p = buf;
-  DWORD wLen, written;
-  written = 0;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
-  while (written <  nlen)
-    {
-      if (!WriteFunc (get_output_handle (), p, nlen - written, &wLen, NULL))
-	{
-	  termios_printf ("WriteFile failed, %E");
-	  break;
-	}
-      else
-	{
-	  written += wLen;
-	  p += wLen;
-	}
-    }
-  /* Detach from pseudo console and resume. */
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-cleanup:
-  SetConsoleOutputCP (origCP);
-  HeapFree (GetProcessHeap (), 0, buf);
-detach:
-  restore_reattach_pcon ();
+  get_ttyp ()->h_pseudo_console = NULL;
+  get_ttyp ()->pcon_start = false;
 }
 
 ssize_t __stdcall
@@ -1505,44 +778,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
   reset_switch_to_pcon ();
 
   acquire_output_mutex (INFINITE);
-  bool output_to_pcon = get_ttyp ()->switch_to_pcon_out;
-  release_output_mutex ();
-
-  UINT target_code_page = output_to_pcon ?
-    GetConsoleOutputCP () : get_ttyp ()->term_code_page;
-  ssize_t nlen;
-  char *buf = convert_mb_str (target_code_page, (size_t *) &nlen,
-		 get_ttyp ()->term_code_page, (const char *) ptr, len);
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  bool fallback = false;
-  if (output_to_pcon && pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      fallback = true;
-
-  if (output_to_pcon && !fallback &&
-      (memmem (buf, nlen, "\033[6n", 4) || memmem (buf, nlen, "\033[0c", 4)))
-    {
-      get_ttyp ()->pcon_in_empty = false;
-      if (!is_line_input ())
-	SetEvent (input_available_event);
-    }
-
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  if (output_to_pcon && !fallback)
-    {
-      GetConsoleMode (get_output_handle (), &dwMode);
-      SetConsoleMode (get_output_handle (), dwMode | flags);
-    }
-  HANDLE to = (output_to_pcon && !fallback) ?
-    get_output_handle () : get_output_handle_cyg ();
-  acquire_output_mutex (INFINITE);
-  if (!process_opost_output (to, buf, nlen, false))
+  if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false))
     {
       DWORD err = GetLastError ();
       termios_printf ("WriteFile failed, %E");
@@ -1557,20 +793,6 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
       towrite = -1;
     }
   release_output_mutex ();
-  mb_str_free (buf);
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (output_to_pcon && !fallback)
-    SetConsoleMode (get_output_handle (), dwMode | flags);
-
-  restore_reattach_pcon ();
-
-  /* Push slave output to pseudo console screen buffer */
-  if (get_pseudo_console ())
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer ((char *)ptr, len, false);
-      release_output_mutex ();
-    }
 
   return towrite;
 }
@@ -1582,16 +804,15 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 }
 
 bool
-fhandler_pty_common::to_be_read_from_pcon (void)
+fhandler_pty_master::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return get_ttyp ()->pcon_start
+    || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
 fhandler_pty_slave::read (void *ptr, size_t& len)
 {
-  char *ptr0 = (char *)ptr;
   ssize_t totalread = 0;
   int vmin = 0;
   int vtime = 0;	/* Initialized to prevent -Wuninitialized warning */
@@ -1616,8 +837,6 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
       mask_switch_to_pcon_in (true);
       reset_switch_to_pcon ();
     }
-  if (to_be_read_from_pcon ())
-    update_pcon_input_state (true);
 
   if (is_nonblocking () || !ptr) /* Indicating tcflush(). */
     time_to_wait = 0;
@@ -1700,101 +919,24 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 	     is an infinitely blocking read, restart the loop. */
 	  if (time_to_wait != INFINITE)
 	    {
-	      if (!totalread)
-		{
-		  set_sig_errno (EAGAIN);
-		  totalread = -1;
-		}
-	      goto out;
-	    }
-	  continue;
-	default:
-	  termios_printf ("wait for input mutex failed, %E");
-	  if (!totalread)
-	    {
-	      __seterrno ();
-	      totalread = -1;
-	    }
-	  goto out;
-	}
-      if (ptr && to_be_read_from_pcon ())
-	{
-	  if (get_readahead_valid ())
-	    {
-	      ReleaseMutex (input_mutex);
-	      totalread = get_readahead_into_buffer ((char *) ptr, len);
-	    }
-	  else
-	    {
-	      if (!try_reattach_pcon ())
-		{
-		  restore_reattach_pcon ();
-		  goto do_read_cyg;
-		}
-
-	      DWORD dwMode;
-	      GetConsoleMode (get_handle (), &dwMode);
-	      DWORD flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
-	      if (dwMode != flags)
-		SetConsoleMode (get_handle (), flags);
-	      /* Read get_handle() instad of get_handle_cyg() */
-	      BOOL (WINAPI *ReadFunc)
-		(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID);
-	      ReadFunc = ReadConsoleA_Orig ? ReadConsoleA_Orig : ReadConsoleA;
-	      DWORD rlen;
-	      readlen = MIN (len, sizeof (buf));
-	      if (!ReadFunc (get_handle (), buf, readlen, &rlen, NULL))
-		{
-		  termios_printf ("read failed, %E");
-		  SetConsoleMode (get_handle (), dwMode);
-		  restore_reattach_pcon ();
-		  ReleaseMutex (input_mutex);
-		  set_errno (EIO);
-		  totalread = -1;
-		  goto out;
-		}
-	      SetConsoleMode (get_handle (), dwMode);
-	      restore_reattach_pcon ();
-	      ReleaseMutex (input_mutex);
-
-	      ssize_t nlen;
-	      char *nbuf = convert_mb_str (get_ttyp ()->term_code_page,
-			     (size_t *) &nlen, GetConsoleCP (), buf, rlen);
-
-	      ssize_t ret;
-	      line_edit_status res =
-		line_edit (nbuf, nlen, get_ttyp ()->ti, &ret);
-
-	      mb_str_free (nbuf);
-
-	      if (res == line_edit_input_done || res == line_edit_ok)
-		totalread = get_readahead_into_buffer ((char *) ptr, len);
-	      else if (res > line_edit_signalled)
+	      if (!totalread)
 		{
-		  set_sig_errno (EINTR);
+		  set_sig_errno (EAGAIN);
 		  totalread = -1;
 		}
-	      else
-		{
-		  update_pcon_input_state (true);
-		  continue;
-		}
+	      goto out;
+	    }
+	  continue;
+	default:
+	  termios_printf ("wait for input mutex failed, %E");
+	  if (!totalread)
+	    {
+	      __seterrno ();
+	      totalread = -1;
 	    }
-
-	  update_pcon_input_state (true);
-	  mask_switch_to_pcon_in (false);
 	  goto out;
 	}
-      if (!ptr && len == UINT_MAX && !get_ttyp ()->pcon_in_empty)
-	{
-	  FlushConsoleInputBuffer (get_handle ());
-	  get_ttyp ()->pcon_in_empty = true;
-	  DWORD n;
-	  if (bytes_available (n) && n == 0)
-	    ResetEvent (input_available_event);
-	}
 
-do_read_cyg:
       if (!bytes_available (bytes_in_pipe))
 	{
 	  ReleaseMutex (input_mutex);
@@ -1911,16 +1053,6 @@ do_read_cyg:
 out:
   termios_printf ("%d = read(%p, %lu)", totalread, ptr, len);
   len = (size_t) totalread;
-  /* Push slave read as echo to pseudo console screen buffer. */
-  if (get_pseudo_console () && ptr0 && totalread > 0 &&
-      (get_ttyp ()->ti.c_lflag & ECHO))
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer (ptr0, len, true);
-      if (get_ttyp ()->switch_to_pcon_out)
-	trigger_redraw_screen ();
-      release_output_mutex ();
-    }
   mask_switch_to_pcon_in (false);
 }
 
@@ -2061,38 +1193,11 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
       get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
       break;
     case TIOCSWINSZ:
-      if (get_pseudo_console ())
-	{
-	  /* If not attached to this pseudo console,
-	     try to attach temporarily. */
-	  pid_restore = 0;
-	  if (pcon_attached_to != get_minor ())
-	    if (!try_reattach_pcon ())
-	      goto cleanup;
-
-	  COORD size;
-	  size.X = ((struct winsize *) arg)->ws_col;
-	  size.Y = ((struct winsize *) arg)->ws_row;
-	  CONSOLE_SCREEN_BUFFER_INFO csbi;
-	  if (GetConsoleScreenBufferInfo (get_output_handle (), &csbi))
-	    if (size.X == csbi.srWindow.Right - csbi.srWindow.Left + 1 &&
-		size.Y == csbi.srWindow.Bottom - csbi.srWindow.Top + 1)
-	      goto cleanup;
-	  if (!SetConsoleScreenBufferSize (get_output_handle (), size))
-	    goto cleanup;
-	  SMALL_RECT rect;
-	  rect.Left = 0;
-	  rect.Top = 0;
-	  rect.Right = size.X-1;
-	  rect.Bottom = size.Y-1;
-	  SetConsoleWindowInfo (get_output_handle (), TRUE, &rect);
-cleanup:
-	  restore_reattach_pcon ();
-	}
-
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->arg.winsize = *(struct winsize *) arg;
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
@@ -2378,6 +1483,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2393,7 +1519,6 @@ fhandler_pty_master::close ()
 {
   OBJECT_BASIC_INFORMATION obi;
   NTSTATUS status;
-  pid_t master_pid_tmp = get_ttyp ()->master_pid;
 
   termios_printf ("closing from_master(%p)/from_master_cyg(%p)/to_master(%p)/to_master_cyg(%p) since we own them(%u)",
 		  from_master, from_master_cyg,
@@ -2438,30 +1563,6 @@ fhandler_pty_master::close ()
   else if (obi.HandleCount == 1)
     {
       termios_printf ("Closing last master of pty%d", get_minor ());
-      /* Close Pseudo Console */
-      if (get_pseudo_console ())
-	{
-	  /* Terminate helper process */
-	  SetEvent (get_ttyp ()->h_helper_goodbye);
-	  WaitForSingleObject (get_ttyp ()->h_helper_process, INFINITE);
-	  CloseHandle (get_ttyp ()->h_helper_goodbye);
-	  CloseHandle (get_ttyp ()->h_helper_process);
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (master_pid_tmp == myself->pid)
-	    {
-	      /* ClosePseudoConsole() seems to have a bug that one
-		 internal handle remains opened. This causes handle leak.
-		 This is a workaround for this problem. */
-	      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_pseudo_console ();
-	      HANDLE tmp = hp->hConHostProcess;
-	      /* Release pseudo console */
-	      ClosePseudoConsole (get_pseudo_console ());
-	      CloseHandle (tmp);
-	    }
-	  get_ttyp ()->switch_to_pcon_in = false;
-	  get_ttyp ()->switch_to_pcon_out = false;
-	}
       if (get_ttyp ()->getsid () > 0)
 	kill (get_ttyp ()->getsid (), SIGHUP);
       SetEvent (input_available_event);
@@ -2469,9 +1570,8 @@ fhandler_pty_master::close ()
 
   if (!ForceCloseHandle (from_master))
     termios_printf ("error closing from_master %p, %E", from_master);
-  if (from_master_cyg != from_master) /* Avoid double close. */
-    if (!ForceCloseHandle (from_master_cyg))
-      termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
+  if (!ForceCloseHandle (from_master_cyg))
+    termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
   if (!ForceCloseHandle (to_master))
     termios_printf ("error closing to_master %p, %E", to_master);
   from_master = to_master = NULL;
@@ -2513,7 +1613,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon () && get_ttyp ()->h_pseudo_console)
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2521,40 +1621,50 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
       WaitForSingleObject (input_mutex, INFINITE);
 
-      if (memchr (buf, '\003', nlen)) /* ^C intr key in pcon */
-	get_ttyp ()->req_flush_pcon_input = true;
-
       DWORD wLen;
-      WriteFile (to_slave, buf, nlen, &wLen, NULL);
-      get_ttyp ()->pcon_in_empty = false;
-
-      ReleaseMutex (input_mutex);
 
-      /* Use line_edit () in order to set input_available_event. */
-      bool is_echo = tc ()->ti.c_lflag & ECHO;
-      if (!get_ttyp ()->mask_switch_to_pcon_in)
+      if (get_ttyp ()->pcon_start)
 	{
-	  tc ()->ti.c_lflag &= ~ECHO;
-	  ti.c_lflag &= ~ECHO;
-	}
-      ti.c_lflag &= ~ISIG;
-      line_edit (buf, nlen, ti, &ret);
-      if (is_echo)
-	tc ()->ti.c_lflag |= ECHO;
-      get_ttyp ()->read_retval = 1;
-
-      const char sigs[] = {
-	(char) ti.c_cc[VINTR],
-	(char) ti.c_cc[VQUIT],
-	(char) ti.c_cc[VSUSP],
-      };
-      if (tc ()->ti.c_lflag & ISIG)
-	for (size_t i=0; i<sizeof (sigs); i++)
-	  if (sigs[i] && memchr (buf, sigs[i], nlen))
+	  /* Pseudo condole support uses "CSI6n" to get cursor position.
+	     If the reply for "CSI6n" is divided into multiple writes,
+	     pseudo console sometimes does not recognize it.  Therefore,
+	     put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon_start = false;
+	    }
+	  else
 	    {
-	      eat_readahead (-1);
-	      SetEvent (input_available_event);
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
 	    }
+	}
+
+      WriteFile (to_slave, buf, nlen, &wLen, NULL);
+
+      ReleaseMutex (input_mutex);
 
       mb_str_free (buf);
       return len;
@@ -2630,15 +1740,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (get_pseudo_console () && get_ttyp ()->master_pid == myself->pid)
-	    {
-	      COORD size;
-	      size.X = ((struct winsize *) arg)->ws_col;
-	      size.Y = ((struct winsize *) arg)->ws_row;
-	      ResizePseudoConsole (get_pseudo_console (), size);
-	    }
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
 	}
@@ -2763,7 +1866,7 @@ get_locale_from_env (char *locale)
   strcpy (locale, env);
 }
 
-static LCID
+static void
 get_langinfo (char *locale_out, char *charset_out)
 {
   /* Get locale from environment */
@@ -2776,11 +1879,6 @@ get_langinfo (char *locale_out, char *charset_out)
   if (!locale)
     locale = "C";
 
-  char tmp_locale[ENCODING_LEN + 1];
-  char *ret = __set_locale_from_locale_alias (locale, tmp_locale);
-  if (ret)
-    locale = tmp_locale;
-
   const char *charset;
   struct lc_ctype_T *lc_ctype = (struct lc_ctype_T *) loc.lc_cat[LC_CTYPE].ptr;
   if (!lc_ctype)
@@ -2830,23 +1928,9 @@ get_langinfo (char *locale_out, char *charset_out)
       charset = "CP932";
     }
 
-  wchar_t lc[ENCODING_LEN + 1];
-  wchar_t *p;
-  mbstowcs (lc, locale, ENCODING_LEN);
-  p = wcschr (lc, L'.');
-  if (p)
-    *p = L'\0';
-  p = wcschr (lc, L'_');
-  if (p)
-    *p = L'-';
-  LCID lcid = LocaleNameToLCID (lc, 0);
-  if (!lcid && !strcmp (charset, "ASCII"))
-    return 0;
-
   /* Set results */
   strcpy (locale_out, new_locale);
   strcpy (charset_out, charset);
-  return lcid;
 }
 
 void
@@ -2854,21 +1938,7 @@ fhandler_pty_slave::setup_locale (void)
 {
   char locale[ENCODING_LEN + 1] = "C";
   char charset[ENCODING_LEN + 1] = "ASCII";
-  LCID lcid = get_langinfo (locale, charset);
-
-  /* Set console code page form locale */
-  if (get_pseudo_console ())
-    {
-      UINT code_page;
-      if (lcid == 0 || lcid == (LCID) -1)
-	code_page = 20127; /* ASCII */
-      else if (!GetLocaleInfo (lcid,
-			       LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
-			       (char *) &code_page, sizeof (code_page)))
-	code_page = 20127; /* ASCII */
-      SetConsoleCP (code_page);
-      SetConsoleOutputCP (code_page);
-    }
+  get_langinfo (locale, charset);
 
   /* Set terminal code page from locale */
   /* This code is borrowed from mintty: charset.c */
@@ -2896,90 +1966,9 @@ fhandler_pty_slave::setup_locale (void)
 	}
 }
 
-void
-fhandler_pty_slave::set_freeconsole_on_close (bool val)
-{
-  freeconsole_on_close = val;
-}
-
-void
-fhandler_pty_slave::trigger_redraw_screen (void)
-{
-  /* Forcibly redraw screen based on console screen buffer. */
-  /* The following code triggers redrawing the screen. */
-  CONSOLE_SCREEN_BUFFER_INFO sbi;
-  GetConsoleScreenBufferInfo (get_output_handle (), &sbi);
-  SMALL_RECT rect = {0, 0,
-    (SHORT) (sbi.dwSize.X -1), (SHORT) (sbi.dwSize.Y - 1)};
-  COORD dest = {0, 0};
-  CHAR_INFO fill = {' ', 0};
-  ScrollConsoleScreenBuffer (get_output_handle (), &rect, NULL, dest, &fill);
-  get_ttyp ()->need_redraw_screen = false;
-}
-
-void
-fhandler_pty_slave::fixup_after_attach (bool native_maybe, int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  if (get_pseudo_console ())
-    {
-      if (fhandler_console::get_console_process_id (get_helper_process_id (),
-						    true))
-	if (pcon_attached_to != get_minor ())
-	  {
-	    pcon_attached_to = get_minor ();
-	    init_console_handler (true);
-	  }
-
-#if 0 /* This is for debug only. */
-      isHybrid = true;
-      get_ttyp ()->switch_to_pcon_in = true;
-      get_ttyp ()->switch_to_pcon_out = true;
-#endif
-
-      if (pcon_attached_to == get_minor () && native_maybe)
-	{
-	  if (fd == 0)
-	    {
-	      pull_pcon_input ();
-	      DWORD mode =
-		ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	      SetConsoleMode (get_handle (), mode);
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_in = true;
-	    }
-	  else if (fd == 1 || fd == 2)
-	    {
-	      DWORD mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
-	      SetConsoleMode (get_output_handle (), mode);
-	      acquire_output_mutex (INFINITE);
-	      if (!get_ttyp ()->switch_to_pcon_out)
-		get_ttyp ()->wait_pcon_fwd ();
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_out = true;
-	      release_output_mutex ();
-
-	      if (get_ttyp ()->need_redraw_screen)
-		trigger_redraw_screen ();
-	    }
-	  init_console_handler (false);
-	}
-      else if (fd == 0 && native_maybe)
-	/* Read from unattached pseudo console cause freeze,
-	   therefore, fallback to legacy pty. */
-	set_handle (get_handle_cyg ());
-    }
-}
-
 void
 fhandler_pty_slave::fixup_after_fork (HANDLE parent)
 {
-  fixup_after_attach (false, -1);
   // fork_fixup (parent, inuse, "inuse");
   // fhandler_pty_common::fixup_after_fork (parent);
   report_tty_counts (this, "inherited", "");
@@ -2992,71 +1981,22 @@ fhandler_pty_slave::fixup_after_exec ()
 
   if (!close_on_exec ())
     fixup_after_fork (NULL);	/* No parent handle required. */
-  else if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 1 && get_minor () == pcon_attached_to)
-	pcon_attached_to = -1;
-      if (used == 1 /* About to close this tty */)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
 
   /* Set locale */
   if (get_ttyp ()->term_code_page == 0)
     setup_locale ();
 
   /* Hook Console API */
-  if (get_pseudo_console ())
-    {
 #define DO_HOOK(module, name) \
-      if (!name##_Orig) \
-	{ \
-	  void *api = hook_api (module, #name, (void *) name##_Hooked); \
-	  name##_Orig = (__typeof__ (name) *) api; \
-	  /*if (api) system_printf (#name " hooked.");*/ \
-	}
-      DO_HOOK (NULL, WriteFile);
-      DO_HOOK (NULL, WriteConsoleA);
-      DO_HOOK (NULL, WriteConsoleW);
-      DO_HOOK (NULL, ReadFile);
-      DO_HOOK (NULL, ReadConsoleA);
-      DO_HOOK (NULL, ReadConsoleW);
-      DO_HOOK (NULL, WriteConsoleOutputA);
-      DO_HOOK (NULL, WriteConsoleOutputW);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterA);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterW);
-      DO_HOOK (NULL, WriteConsoleOutputAttribute);
-      DO_HOOK (NULL, SetConsoleCursorPosition);
-      DO_HOOK (NULL, SetConsoleTextAttribute);
-      DO_HOOK (NULL, WriteConsoleInputA);
-      DO_HOOK (NULL, WriteConsoleInputW);
-      DO_HOOK (NULL, ReadConsoleInputA);
-      DO_HOOK (NULL, ReadConsoleInputW);
-      DO_HOOK (NULL, PeekConsoleInputA);
-      DO_HOOK (NULL, PeekConsoleInputW);
-      /* CreateProcess() is hooked for GDB etc. */
-      DO_HOOK (NULL, CreateProcessA);
-      DO_HOOK (NULL, CreateProcessW);
+  if (!name##_Orig) \
+    { \
+      void *api = hook_api (module, #name, (void *) name##_Hooked); \
+      name##_Orig = (__typeof__ (name) *) api; \
+      /*if (api) system_printf (#name " hooked.");*/ \
     }
+  /* CreateProcess() is hooked for GDB etc. */
+  DO_HOOK (NULL, CreateProcessA);
+  DO_HOOK (NULL, CreateProcessW);
 }
 
 /* This thread function handles the master control pipe.  It waits for a
@@ -3204,27 +2144,6 @@ reply:
   return 0;
 }
 
-void
-fhandler_pty_master::transfer_input_to_pcon (void)
-{
-  WaitForSingleObject (input_mutex, INFINITE);
-  DWORD n;
-  size_t transfered = 0;
-  while (::bytes_available (n, from_master_cyg) && n)
-    {
-      char buf[1024];
-      ReadFile (from_master_cyg, buf, sizeof (buf), &n, 0);
-      char *p = buf;
-      while ((p = (char *) memchr (p, '\n', n - (p - buf))))
-	*p = '\r';
-      if (WriteFile (to_slave, buf, n, &n, 0))
-	transfered += n;
-    }
-  if (transfered)
-    get_ttyp ()->pcon_in_empty = false;
-  ReleaseMutex (input_mutex);
-}
-
 static DWORD WINAPI
 pty_master_thread (VOID *arg)
 {
@@ -3240,23 +2159,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
   termios_printf ("Started.");
   for (;;)
     {
-      if (get_pseudo_console ())
-	{
-	  get_ttyp ()->pcon_last_time = GetTickCount ();
-	  while (::bytes_available (rlen, from_slave) && rlen == 0)
-	    {
-	      /* Forcibly transfer input if it is requested by slave.
-		 This happens when input data should be transfered
-		 from the input pipe for cygwin apps to the input pipe
-		 for native apps. */
-	      if (get_ttyp ()->req_transfer_input_to_pcon)
-		{
-		  transfer_input_to_pcon ();
-		  get_ttyp ()->req_transfer_input_to_pcon = false;
-		}
-	      Sleep (1);
-	    }
-	}
+      get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3264,51 +2167,11 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_ttyp ()->h_pseudo_console)
 	{
-	  /* Avoid duplicating slave output which is already sent to
-	     to_master_cyg */
-	  if (!get_ttyp ()->switch_to_pcon_out)
-	    continue;
-
-	  /* Avoid setting window title to "cygwin-console-helper.exe" */
+	  /* Remove CSI > Pm m */
 	  int state = 0;
 	  int start_at = 0;
-	  for (DWORD i=0; i<rlen; i++)
-	    if (outbuf[i] == '\033')
-	      {
-		start_at = i;
-		state = 1;
-		continue;
-	      }
-	    else if ((state == 1 && outbuf[i] == ']') ||
-		     (state == 2 && outbuf[i] == '0') ||
-		     (state == 3 && outbuf[i] == ';'))
-	      {
-		state ++;
-		continue;
-	      }
-	    else if (state == 4 && outbuf[i] == '\a')
-	      {
-		const char *helper_str = "\\bin\\cygwin-console-helper.exe";
-		if (memmem (&outbuf[start_at], i + 1 - start_at,
-			    helper_str, strlen (helper_str)))
-		  {
-		    memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
-		    rlen = wlen = start_at + rlen - i - 1;
-		  }
-		state = 0;
-		continue;
-	      }
-	    else if (outbuf[i] == '\a')
-	      {
-		state = 0;
-		continue;
-	      }
-
-	  /* Remove CSI > Pm m */
-	  state = 0;
-	  start_at = 0;
 	  for (DWORD i=0; i<rlen; i++)
 	    if (outbuf[i] == '\033')
 	      {
@@ -3386,201 +2249,6 @@ pty_master_fwd_thread (VOID *arg)
   return ((fhandler_pty_master *) arg)->pty_master_fwd_thread ();
 }
 
-/* If master process is running as service, attaching to
-   pseudo console should be done in fork. If attaching
-   is done in spawn for inetd or sshd, it fails because
-   the helper process is running as privileged user while
-   slave process is not. This function is used to determine
-   if the process is running as a srvice or not. */
-inline static bool
-is_running_as_service (void)
-{
-  return check_token_membership (well_known_service_sid)
-    || cygheap->user.saved_sid () == well_known_system_sid;
-}
-
-bool
-fhandler_pty_master::setup_pseudoconsole ()
-{
-  if (disable_pcon)
-    return false;
-  /* If the legacy console mode is enabled, pseudo console seems
-     not to work as expected. To determine console mode, registry
-     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
-  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
-  if (reg.error ())
-    return false;
-  if (reg.get_dword (L"ForceV2", 1) == 0)
-    {
-      termios_printf ("Pseudo console is disabled "
-		      "because the legacy console mode is enabled.");
-      return false;
-    }
-
-  /* Pseudo console supprot is realized using a tricky technic.
-     PTY need the pseudo console handles, however, they cannot
-     be retrieved by normal procedure. Therefore, run a helper
-     process in a pseudo console and get them from the helper.
-     Slave process will attach to the pseudo console in the
-     helper process using AttachConsole(). */
-  COORD size = {
-    (SHORT) get_ttyp ()->winsize.ws_col,
-    (SHORT) get_ttyp ()->winsize.ws_row
-  };
-  CreatePipe (&from_master, &to_slave, &sec_none, 0);
-  SetLastError (ERROR_SUCCESS);
-  HRESULT res = CreatePseudoConsole (size, from_master, to_master,
-				     0, &get_ttyp ()->h_pseudo_console);
-  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
-    {
-      if (res != S_OK)
-	system_printf ("CreatePseudoConsole() failed. %08x\n",
-		       GetLastError ());
-      goto fallback;
-    }
-
-  /* If master process is running as service, attaching to
-     pseudo console should be done in fork. If attaching
-     is done in spawn for inetd or sshd, it fails because
-     the helper process is running as privileged user while
-     slave process is not. */
-  if (is_running_as_service ())
-    get_ttyp ()->attach_pcon_in_fork = true;
-
-  STARTUPINFOEXW si_helper;
-  HANDLE hello, goodbye;
-  HANDLE hr, hw;
-  PROCESS_INFORMATION pi_helper;
-  HANDLE hpConIn, hpConOut;
-  {
-    SIZE_T bytesRequired;
-    InitializeProcThreadAttributeList (NULL, 2, 0, &bytesRequired);
-    ZeroMemory (&si_helper, sizeof (si_helper));
-    si_helper.StartupInfo.cb = sizeof (STARTUPINFOEXW);
-    si_helper.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
-      HeapAlloc (GetProcessHeap (), 0, bytesRequired);
-    if (si_helper.lpAttributeList == NULL)
-      goto cleanup_pseudo_console;
-    if (!InitializeProcThreadAttributeList (si_helper.lpAttributeList,
-					    2, 0, &bytesRequired))
-      goto cleanup_heap;
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
-				    get_ttyp ()->h_pseudo_console,
-				    sizeof (get_ttyp ()->h_pseudo_console),
-				    NULL, NULL))
-      goto cleanup_heap;
-    /* Create events for start/stop helper process. */
-    hello = CreateEvent (&sec_none, true, false, NULL);
-    goodbye = CreateEvent (&sec_none, true, false, NULL);
-    /* Create a pipe for receiving pseudo console handles */
-    CreatePipe (&hr, &hw, &sec_none, 0);
-    /* Inherit only handles which are needed by helper. */
-    HANDLE handles_to_inherit[] = {hello, goodbye, hw};
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
-				    handles_to_inherit,
-				    sizeof (handles_to_inherit),
-				    NULL, NULL))
-      goto cleanup_event_and_pipes;
-    /* Create helper process */
-    WCHAR cmd[MAX_PATH];
-    path_conv helper ("/bin/cygwin-console-helper.exe");
-    size_t len = helper.get_wide_win32_path_len ();
-    helper.get_wide_win32_path (cmd);
-    __small_swprintf (cmd + len, L" %p %p %p", hello, goodbye, hw);
-    si_helper.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
-    si_helper.StartupInfo.hStdInput = NULL;
-    si_helper.StartupInfo.hStdOutput = NULL;
-    si_helper.StartupInfo.hStdError = NULL;
-    if (!CreateProcessW (NULL, cmd, &sec_none, &sec_none,
-			 TRUE, EXTENDED_STARTUPINFO_PRESENT,
-			 NULL, NULL, &si_helper.StartupInfo, &pi_helper))
-      goto cleanup_event_and_pipes;
-    for (;;)
-      {
-        DWORD wait_result = WaitForSingleObject (hello, 500);
-	if (wait_result == WAIT_OBJECT_0)
-	  break;
-	if (wait_result != WAIT_TIMEOUT)
-	  goto cleanup_helper_process;
-	DWORD exit_code;
-	if (!GetExitCodeProcess(pi_helper.hProcess, &exit_code))
-	  goto cleanup_helper_process;
-	if (exit_code == STILL_ACTIVE)
-	  continue;
-	if (exit_code != 0 ||
-	    WaitForSingleObject (hello, 500) != WAIT_OBJECT_0)
-	  goto cleanup_helper_process;
-	break;
-      }
-    CloseHandle (hello);
-    CloseHandle (pi_helper.hThread);
-    /* Retrieve pseudo console handles */
-    DWORD rLen;
-    char buf[64];
-    if (!ReadFile (hr, buf, sizeof (buf), &rLen, NULL))
-      goto cleanup_helper_process;
-    buf[rLen] = '\0';
-    sscanf (buf, "StdHandles=%p,%p", &hpConIn, &hpConOut);
-    if (!DuplicateHandle (pi_helper.hProcess, hpConIn,
-			  GetCurrentProcess (), &hpConIn, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_helper_process;
-    if (!DuplicateHandle (pi_helper.hProcess, hpConOut,
-			  GetCurrentProcess (), &hpConOut, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_pcon_in;
-    CloseHandle (hr);
-    CloseHandle (hw);
-    /* Clean up */
-    DeleteProcThreadAttributeList (si_helper.lpAttributeList);
-    HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-  }
-  /* Setting information of stuffs regarding pseudo console */
-  get_ttyp ()->h_helper_goodbye = goodbye;
-  get_ttyp ()->h_helper_process = pi_helper.hProcess;
-  get_ttyp ()->helper_process_id = pi_helper.dwProcessId;
-  CloseHandle (from_master);
-  CloseHandle (to_master);
-  from_master = hpConIn;
-  to_master = hpConOut;
-  ResizePseudoConsole (get_ttyp ()->h_pseudo_console, size);
-  return true;
-
-cleanup_pcon_in:
-  CloseHandle (hpConIn);
-cleanup_helper_process:
-  SetEvent (goodbye);
-  WaitForSingleObject (pi_helper.hProcess, INFINITE);
-  CloseHandle (pi_helper.hProcess);
-  goto skip_close_hello;
-cleanup_event_and_pipes:
-  CloseHandle (hello);
-skip_close_hello:
-  CloseHandle (goodbye);
-  CloseHandle (hr);
-  CloseHandle (hw);
-cleanup_heap:
-  HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-cleanup_pseudo_console:
-  {
-    HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
-    HANDLE tmp = hp->hConHostProcess;
-    ClosePseudoConsole (get_pseudo_console ());
-    CloseHandle (tmp);
-  }
-fallback:
-  CloseHandle (from_master);
-  CloseHandle (to_slave);
-  from_master = from_master_cyg;
-  to_slave = NULL;
-  get_ttyp ()->h_pseudo_console = NULL;
-  return false;
-}
-
 bool
 fhandler_pty_master::setup ()
 {
@@ -3593,11 +2261,6 @@ fhandler_pty_master::setup ()
   if (unit < 0)
     return false;
 
-  /* from_master should be used for pseudo console.
-     Just copy from_master_cyg here for the case that
-     pseudo console is not available. */
-  from_master = from_master_cyg;
-
   ProtectHandle1 (get_output_handle (), to_pty);
 
   tty& t = *cygwin_shared->tty[unit];
@@ -3696,15 +2359,21 @@ fhandler_pty_master::setup ()
       goto err;
     }
 
-  t.winsize.ws_col = 80;
-  t.winsize.ws_row = 25;
-
-  setup_pseudoconsole ();
+  __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;
+    }
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
   t.set_to_master (to_master);
   t.set_to_master_cyg (to_master_cyg);
+  t.winsize.ws_col = 80;
+  t.winsize.ws_row = 25;
   t.master_pid = myself->pid;
 
   dev ().parse (DEV_PTYM_MAJOR, unit);
@@ -3717,6 +2386,7 @@ fhandler_pty_master::setup ()
 err:
   __seterrno ();
   close_maybe (from_slave);
+  close_maybe (to_slave);
   close_maybe (get_handle ());
   close_maybe (get_output_handle ());
   close_maybe (input_available_event);
@@ -3776,9 +2446,6 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 {
   ssize_t towrite = len;
   BOOL res = TRUE;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
   while (towrite)
     {
       if (!is_echo)
@@ -3801,7 +2468,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
       if (!(get_ttyp ()->ti.c_oflag & OPOST))	// raw output mode
 	{
 	  DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
-	  res = WriteFunc (h, ptr, n, &n, NULL);
+	  res = WriteFile (h, ptr, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + n;
@@ -3851,7 +2518,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 		  break;
 		}
 	    }
-	  res = WriteFunc (h, outbuf, n, &n, NULL);
+	  res = WriteFile (h, outbuf, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + rc;
@@ -3861,3 +2528,123 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole (STARTUPINFOEXW *si)
+{
+  fhandler_base *fh = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+    {
+      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+      ptys->get_ttyp ()->switch_to_pcon_in = true;
+      if (ptys->get_ttyp ()->pcon_pid == 0 ||
+	  !pinfo (ptys->get_ttyp ()->pcon_pid))
+	ptys->get_ttyp ()->pcon_pid = myself->pid;
+    }
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     1, &get_ttyp ()->h_pseudo_console);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console,
+				  sizeof (get_ttyp ()->h_pseudo_console),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_pty_slave *p0 = (fhandler_pty_slave *) ::cygheap->fdtab[0];
+    if (p0 && p0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = p0->get_handle ();
+    fhandler_pty_slave *p1 = (fhandler_pty_slave *) ::cygheap->fdtab[1];
+    if (p1 && p1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = p1->get_output_handle ();
+    fhandler_pty_slave *p2 = (fhandler_pty_slave *) ::cygheap->fdtab[2];
+    if (p2 && p2->get_device () != get_device ())
+      si->StartupInfo.hStdError = p2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole (void)
+{
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      get_ttyp ()->wait_pcon_fwd ();
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+      get_ttyp ()->pcon_start = false;
+    }
+}
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 691d08137..6ca4b5f29 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -134,36 +134,6 @@ child_info::prefork (bool detached)
 int __stdcall
 frok::child (volatile char * volatile here)
 {
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR)
-      {
-	fhandler_base *fh = cfd;
-	fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
-	if (ptym->get_pseudo_console ())
-	  {
-	    debug_printf ("found a PTY master %d: helper_PID=%d",
-			  ptym->get_minor (), ptym->get_helper_process_id ());
-	    if (fhandler_console::get_console_process_id (
-				ptym->get_helper_process_id (), true))
-	      /* Already attached */
-	      break;
-	    else
-	      {
-		if (ptym->attach_pcon_in_fork ())
-		  {
-		    FreeConsole ();
-		    if (!AttachConsole (ptym->get_helper_process_id ()))
-		      /* Error */;
-		    else
-		      break;
-		  }
-	      }
-	  }
-      }
-  extern void clear_pcon_attached_to (void); /* fhandler_tty.cc */
-  clear_pcon_attached_to ();
-
   HANDLE& hParent = ch.parent;
 
   sync_with_parent ("after longjmp", true);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 3f3f33fb5..93acdd89a 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1213,8 +1213,7 @@ verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds,
 	   fd_set *exceptfds)
 {
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) me->fh;
-  if (me->read_selected && !ptys->to_be_read_from_pcon () &&
-      IsEventSignalled (ptys->input_available_event))
+  if (me->read_selected && IsEventSignalled (ptys->input_available_event))
     me->read_ready = true;
   return set_bits (me, readfds, writefds, exceptfds);
 }
@@ -1227,8 +1226,6 @@ peek_pty_slave (select_record *s, bool from_select)
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
 
   ptys->reset_switch_to_pcon ();
-  if (ptys->to_be_read_from_pcon ())
-    ptys->update_pcon_input_state (true);
 
   if (s->read_selected)
     {
diff --git a/winsup/cygwin/smallprint.cc b/winsup/cygwin/smallprint.cc
index 26d34d9e4..f208a057a 100644
--- a/winsup/cygwin/smallprint.cc
+++ b/winsup/cygwin/smallprint.cc
@@ -405,7 +405,6 @@ small_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
   WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, NULL);
   FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
 }
@@ -432,7 +431,6 @@ console_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (console_handle);
   WriteFile (console_handle, buf, count, &done, NULL);
   FlushFileBuffers (console_handle);
 }
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..a3071884e 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -259,8 +277,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 {
   bool rc;
   int res = -1;
-  DWORD pid_restore = 0;
-  bool attach_to_console = false;
   pid_t ctty_pgid = 0;
 
   /* Search for CTTY and retrieve its PGID */
@@ -580,9 +596,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			 PROCESS_QUERY_LIMITED_INFORMATION))
 	sa = &sec_none_nih;
 
-      /* Attach to pseudo console if pty salve is used */
-      pid_restore = fhandler_console::get_console_process_id
-	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -591,29 +605,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	      if (ptys->get_pseudo_console ())
-		{
-		  DWORD helper_process_id = ptys->get_helper_process_id ();
-		  debug_printf ("found a PTY slave %d: helper_PID=%d",
-				    fh->get_minor (), helper_process_id);
-		  if (fhandler_console::get_console_process_id
-					      (helper_process_id, true))
-		    /* Already attached */
-		    attach_to_console = true;
-		  else if (!attach_to_console)
-		    {
-		      FreeConsole ();
-		      if (AttachConsole (helper_process_id))
-			attach_to_console = true;
-		    }
-		  ptys->fixup_after_attach (!iscygwin (), fd);
-		  if (mode == _P_OVERLAY)
-		    ptys->set_freeconsole_on_close (iscygwin ());
-		}
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	    }
 	  else if (fh && fh->get_major () == DEV_CONS_MAJOR)
 	    {
-	      attach_to_console = true;
 	      fhandler_console *cons = (fhandler_console *) fh;
 	      if (wincap.has_con_24bit_colors () && !iscygwin ())
 		if (fd == 1 || fd == 2)
@@ -632,6 +628,18 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool enable_pcon = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole (&si_pcon))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    enable_pcon = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +668,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +722,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +735,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (enable_pcon)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +910,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (enable_pcon)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->close_pseudoconsole ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
@@ -930,21 +948,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
   if (envblock)
     free (envblock);
 
-  if (attach_to_console && pid_restore)
-    {
-      FreeConsole ();
-      AttachConsole (pid_restore);
-      cygheap_fdenum cfd (false);
-      int fd;
-      while ((fd = cfd.next ()) >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_pty_slave *ptys =
-	      (fhandler_pty_slave *) (fhandler_base *) cfd;
-	    ptys->fixup_after_attach (false, fd);
-	  }
-    }
-
   return (int) res;
 }
 
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index f0aef3a36..35f8a59ae 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -264,7 +264,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
   if (category & _STRACE_SYSTEM)
     {
       DWORD done;
-      set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
       WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
       FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
       /* Make sure that the message shows up on the screen, too, since this is
@@ -276,7 +275,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
 				 &sec_none, OPEN_EXISTING, 0, 0);
 	  if (h != INVALID_HANDLE_VALUE)
 	    {
-	      set_ishybrid_and_switch_to_pcon (h);
 	      WriteFile (h, buf, len, &done, 0);
 	      CloseHandle (h);
 	    }
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 4cb68f776..d60f27545 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -234,20 +234,14 @@ tty::init ()
   was_opened = false;
   master_pid = 0;
   is_console = false;
-  attach_pcon_in_fork = false;
-  h_pseudo_console = NULL;
   column = 0;
+  h_pseudo_console = NULL;
   switch_to_pcon_in = false;
-  switch_to_pcon_out = false;
-  screen_alternated = false;
   mask_switch_to_pcon_in = false;
   pcon_pid = 0;
   term_code_page = 0;
-  need_redraw_screen = true;
   pcon_last_time = 0;
-  pcon_in_empty = true;
-  req_transfer_input_to_pcon = false;
-  req_flush_pcon_input = false;
+  pcon_start = false;
 }
 
 HANDLE
@@ -293,16 +287,6 @@ tty_min::ttyname ()
   return d.name ();
 }
 
-void
-tty::set_switch_to_pcon_out (bool v)
-{
-  if (switch_to_pcon_out != v)
-    {
-      wait_pcon_fwd ();
-      switch_to_pcon_out = v;
-    }
-}
-
 void
 tty::wait_pcon_fwd (void)
 {
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 920e32b16..c491d3891 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -94,21 +94,13 @@ private:
   HANDLE _to_master;
   HANDLE _to_master_cyg;
   HPCON h_pseudo_console;
-  HANDLE h_helper_process;
-  DWORD helper_process_id;
-  HANDLE h_helper_goodbye;
-  bool attach_pcon_in_fork;
+  bool pcon_start;
   bool switch_to_pcon_in;
-  bool switch_to_pcon_out;
-  bool screen_alternated;
   bool mask_switch_to_pcon_in;
   pid_t pcon_pid;
   UINT term_code_page;
-  bool need_redraw_screen;
   DWORD pcon_last_time;
-  bool pcon_in_empty;
-  bool req_transfer_input_to_pcon;
-  bool req_flush_pcon_input;
+  HANDLE h_pcon_write_pipe;
 
 public:
   HANDLE from_master () const { return _from_master; }
@@ -138,7 +130,6 @@ public:
   void set_master_ctl_closed () {master_pid = -1;}
   static void __stdcall create_master (int);
   static void __stdcall init_session ();
-  void set_switch_to_pcon_out (bool v);
   void wait_pcon_fwd (void);
   friend class fhandler_pty_common;
   friend class fhandler_pty_master;
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index fff7d18f3..458fb2a23 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -222,9 +222,6 @@ void init_console_handler (bool);
 
 extern bool wsock_started;
 
-/* PTY related */
-void set_ishybrid_and_switch_to_pcon (HANDLE h);
-
 /* Printf type functions */
 extern "C" void vapi_fatal (const char *, va_list ap) __attribute__ ((noreturn));
 extern "C" void api_fatal (const char *, ...) __attribute__ ((noreturn));
-- 
2.27.0


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-18 20:57                           ` Thomas Wolff
@ 2020-07-23 17:17                             ` Takashi Yano
  2020-07-27 17:10                               ` Thomas Wolff
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-07-23 17:17 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 3979 bytes --]

Hi Thomas,

On Sat, 18 Jul 2020 22:57:24 +0200
Thomas Wolff wrote:
> Am 18.07.2020 um 07:05 schrieb Takashi Yano via Cygwin-developers:
> > Hi Thomas,
> >
> > Thanks for testing.
> >
> > On Fri, 17 Jul 2020 16:59:56 +0200
> > Thomas Wolff wrote:
> >> Am 17.07.2020 um 14:47 schrieb Thomas Wolff:
> >>> Am 17.07.2020 um 13:19 schrieb Corinna Vinschen:
> >>>> Hi Takashi,
> >>>>
> >>>> On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> >>>>> On Fri, 29 May 2020 00:40:24 +0900
> >>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com>
> >>>>> wrote:
> >>>>>> On Tue, 26 May 2020 10:09:55 +0900
> >>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com>
> >>>>>> wrote:
> >>>>>>> On Mon, 25 May 2020 19:53:32 +0900
> >>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com>
> >>>>>>> wrote:
> >>>>>>>> On Tue, 19 May 2020 22:40:18 +0900
> >>>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com>
> >>>>>>>> wrote:
> >>>>>>>>> On Sat, 16 May 2020 16:47:35 +0900
> >>>>>>>>> Takashi Yano via Cygwin-developers
> >>>>>>>>> <cygwin-developers@cygwin.com> wrote:
> >>>>>>>>>> On Sat, 16 May 2020 09:29:56 +0900
> >>>>>>>>>> Takashi Yano via Cygwin-developers
> >>>>>>>>>> <cygwin-developers@cygwin.com> wrote:
> >>>>>>>>>>> Fix a small bug caused when stdio is redirected to another pty.
> >>>>>>>>>> Fix another bug caused when stdio is redirected to another pty.
> >>>>>>>>> Revise the patch to fit the current git head.
> >>>>>>>> Revise the patch again to fit the current git head.
> >>>>>>> Make app, which reads stdin, work under gdb.
> >>>>>> * Prevent ResizePseudoConsole() calls unless the pty is resized.
> >>>>>> * Revise the patch to fit the current git head.
> >>>>> Revise the patch to fit the current git head.
> >>>> are you satisfied with the code?  If you want to merge it,
> >>>> I'd bump Cygwin to 3.2.
> >>> (blush) I apologize, I had promised to run my test cases.
> >>> Beginning with it, the first succeeded, the second failed:
> >>> run notepad (from mintty), click back into terminal, enter ^Z
> >>> It says "Stopped" but the process is gone.
> >>>
> >>> Continuing may test suite soon...
> >> OK, so here are finally my updated test results:
> >>
> >>
> >> resize terminal while running Windows cmd
> >> run cmd, resize, run dir/P:
> >> ✓works
> >>
> >>
> >> terminal reports in response to request escape sequences
> >> ("\033[6n", "\033[0c", "\033[>c", '\033[18t', '\033]10;?\033\')
> >> ✓works
> >>
> >>
> >> output to alternate screen
> >> echo -e "\e[?1047h"; cmd
> >> ✓works
> >> cmd
> >> from other terminal: echo -e "\e[?1047h" > /dev/pty...
> >> ↯no output; weird behaviour on ^C, mintty terminating (also in 3.1.6)
> > I found this is a bug introduced in commit
> > 0365031ce1347600d854a23f30f1355745a1765c.
> >
> > I will submit a patch for this issue.
> >
> >> signal handling/mediation; catch SIGTSTP
> >> run notepad, click back into terminal, enter ^Z
> >> ↯fails, notepad is terminated
> >> -> this is a regression, ^Z,^C,^\ used to be ignored
> > This behaviour is the same as cygwin 3.0.7. Pseudo console is not
> > activated for native GUI processes.
> OK, I understand this is consistent with my own proposal to apply pseudo 
> console only for Windows command-line programs. On the other hand, fatal 
> signal handling is another nuisance of running Windows programs from 
> cygwin, so there was a benefit.
> Is it possible to activate the signal interworking without setting up a 
> pseudo console? If not, is it maybe worth to set it up also for Windows 
> GUI programs just for this purpose? (Modifying my proposal to trigger on 
> any Windows program.)

When pseudo console is activated for GUI apps, ^C, ^Z and ^\ are
just ignored. Please try additional patch attached with the latest
pseudo console patch. Is this as you expected?

I'm not sure which behaviour is better. Does anyone have opinion?

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: pcon-activate-for-gui-apps.diff --]
[-- Type: text/plain, Size: 1165 bytes --]

diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index a3071884e..4524423b3 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,24 +194,6 @@ handle (int fd, bool writing)
   return h;
 }
 
-static bool
-is_console_app (WCHAR *filename)
-{
-  HANDLE h;
-  const int id_offset = 92;
-  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
-		  NULL, OPEN_EXISTING, 0, NULL);
-  char buf[1024];
-  DWORD n;
-  ReadFile (h, buf, sizeof (buf), &n, 0);
-  CloseHandle (h);
-  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
-  if (p && p + id_offset <= buf + n)
-    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
-  else
-    return false;
-}
-
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -632,7 +614,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       STARTUPINFOEXW si_pcon;
       ZeroMemory (&si_pcon, sizeof (si_pcon));
       STARTUPINFOW *si_tmp = &si;
-      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+      if (!iscygwin () && ptys_primary)
 	if (ptys_primary->setup_pseudoconsole (&si_pcon))
 	  {
 	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-23  0:33                             ` Takashi Yano
@ 2020-07-24  5:38                               ` Takashi Yano
  2020-07-24 11:22                                 ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-07-24  5:38 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 2481 bytes --]

On Thu, 23 Jul 2020 09:33:28 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Wed, 22 Jul 2020 17:45:41 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> 
> > On Wed, 22 Jul 2020 03:17:51 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > Hi Corinna,
> > > 
> > > On Mon, 20 Jul 2020 10:06:13 +0200
> > > Corinna Vinschen wrote:
> > > > On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
> > > > > Hi Corinna,
> > > > > 
> > > > > On Fri, 17 Jul 2020 13:19:12 +0200
> > > > > Corinna Vinschen wrote:
> > > > > > Hi Takashi,
> > > > > > 
> > > > > > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > > > > > > [...]
> > > > > > > Revise the patch to fit the current git head.
> > > > > > 
> > > > > > are you satisfied with the code?  If you want to merge it,
> > > > > > I'd bump Cygwin to 3.2.
> > > > > 
> > > > > Since this new implementation has both advantages and disadvantages,
> > > > > there might be some options.
> > > > > 
> > > > > 1) Default to new implementation and leave the current one as an
> > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > 2) Default to current implementation and add the new one as an
> > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > 3) Adopt only new implementation and throw the current one away.
> > > > > 
> > > > > What do you think?
> > > > 
> > > > Do you really want to maintain twice as much code doing the same stuff
> > > > and constantly having to ask users which version of the code they are
> > > > running?  The maintenance cost outweighs the advantages, IMHO.
> > > > Personally I'd go for option 3.
> > > 
> > > Personally, I feel a tinge of sadness to discard the current code,
> > > however, your opinion sounds reasonable.
> > > 
> > > I will submit a new patch in which all the codes specific to the
> > > current implementation are removed.
> > 
> > Attached is the patch in git format-patch format.
> > All the codes specific to the current implementation are removed.
> > 
> > Despite the utmost care, the changes are relatively large, so some
> > degradation may exist.
> > 
> > I will appreciate if you could test.
> 
> There were still unused code. Please try attached patch instead.

Changes:
* Do not activate pseudo console if it is already activated for
  another process on same pty.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-Cygwin-pty-Implement-new-pseudo-console-support.patch --]
[-- Type: application/octet-stream, Size: 86733 bytes --]

From 1e1c9e93a99162e4baa7cca4ff48ecdaa1b14978 Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Fri, 24 Jul 2020 14:32:58 +0900
Subject: [PATCH] Cygwin: pty: Implement new pseudo console support.

- In this implementation, pseudo console is created for each native
  console app. Advantages and disadvantages of this implementation
  over the previous implementation are as follows.

  Advantages:
  1) No performance degradation in pty output for cygwin process.
      https://cygwin.com/pipermail/cygwin/2020-February/243858.html
  2) Free from the problem caused by difference of behaviour of control
     sequences between real terminal and pseudo console.
      https://cygwin.com/pipermail/cygwin/2019-December/243281.html
      https://cygwin.com/pipermail/cygwin/2020-February/243855.html
  3) Free from the problem in cgdb and emacs gud.
      https://cygwin.com/pipermail/cygwin/2020-January/243601.html
      https://cygwin.com/pipermail/cygwin/2020-March/244146.html
  4) Redrawing screen on executing native console apps is not necessary.
  5) cygwin-console-helper is not necessary for the pseudo console
     support.
  6) The codes for pseudo console support are much simpler than that
     of the previous one.

  Disadvantages:
  1) The cygwin program which calls console API directly does not work.
  2) The apps which use console API cannot be debugged with gdb. This
     is because pseudo console is not activated since gdb uses
     CreateProcess() rather than exec(). Even with this limitation,
     attaching gdb to native apps, in which pseudo console is already
     activated, works.
  3) Typeahead key inputs are discarded while native console app is
     executed. Simirally, typeahead key inputs while cygwin app is
     executed are not inherited to native console app.
  4) Code page cannot be changed by chcp.com. Acctually, chcp works
     itself and changes code page of its own pseudo console.  However,
     since pseudo console is recreated for another process, it cannot
     inherit the code page.
  5) system_printf() does not work after stderr is closed. (Same with
     cygwin 3.0.7)
  6) Startup time of native console apps is about 3 times slower than
     previous implemenation.
  7) Pseudo console cannot be activated if it is already activated for
     another process on same pty.
---
 winsup/cygwin/dtable.cc           |   32 -
 winsup/cygwin/fhandler.h          |   53 +-
 winsup/cygwin/fhandler_console.cc |   43 -
 winsup/cygwin/fhandler_tty.cc     | 1735 +++++------------------------
 winsup/cygwin/fork.cc             |   30 -
 winsup/cygwin/select.cc           |    5 +-
 winsup/cygwin/smallprint.cc       |    2 -
 winsup/cygwin/spawn.cc            |   87 +-
 winsup/cygwin/strace.cc           |    2 -
 winsup/cygwin/tty.cc              |   20 +-
 winsup/cygwin/tty.h               |   13 +-
 winsup/cygwin/winsup.h            |    3 -
 12 files changed, 321 insertions(+), 1704 deletions(-)

diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index e9e005b08..6a91e33bc 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -147,38 +147,6 @@ dtable::get_debugger_info ()
 void
 dtable::stdio_init ()
 {
-  for (int i = 0; i < 3; i ++)
-    {
-      const int chk_order[] = {1, 0, 2};
-      int fd = chk_order[i];
-      fhandler_base *fh = cygheap->fdtab[fd];
-      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
-	{
-	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	  if (ptys->get_pseudo_console ())
-	    {
-	      bool attached = !!fhandler_console::get_console_process_id
-		(ptys->get_helper_process_id (), true);
-	      if (attached)
-		break;
-	      else
-		{
-		  /* Not attached to pseudo console in fork() or spawn()
-		     by some reason. This happens if the executable is
-		     a windows GUI binary, such as mintty. */
-		  FreeConsole ();
-		  if (AttachConsole (ptys->get_helper_process_id ()))
-		    {
-		      ptys->fixup_after_attach (false, fd);
-		      break;
-		    }
-		}
-	    }
-	}
-      else if (fh && fh->get_major () == DEV_CONS_MAJOR)
-	break;
-    }
-
   if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT))
     {
       tty_min *t = cygwin_shared->tty.get_cttyp ();
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 60bd27e00..4604ff2ba 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -326,16 +326,16 @@ class fhandler_base
   virtual size_t &raixput () { return ra.raixput; };
   virtual size_t &rabuflen () { return ra.rabuflen; };
 
-  virtual bool get_readahead_valid () { return raixget () < ralen (); }
+  bool get_readahead_valid () { return raixget () < ralen (); }
   int puts_readahead (const char *s, size_t len = (size_t) -1);
-  virtual int put_readahead (char value);
+  int put_readahead (char value);
 
   int get_readahead ();
   int peek_readahead (int queryput = 0);
 
   void set_readahead_valid (int val, int ch = -1);
 
-  virtual int get_readahead_into_buffer (char *buf, size_t buflen);
+  int get_readahead_into_buffer (char *buf, size_t buflen);
 
   bool has_acls () const { return pc.has_acls (); }
 
@@ -1909,7 +1909,7 @@ class fhandler_termios: public fhandler_base
   int ioctl (int, void *);
   tty_min *_tc;
   tty *get_ttyp () {return (tty *) tc ();}
-  virtual int eat_readahead (int n);
+  int eat_readahead (int n);
 
  public:
   tty_min*& tc () {return _tc;}
@@ -2188,7 +2188,6 @@ private:
   static bool need_invisible ();
   static void free_console ();
   static const char *get_nonascii_key (INPUT_RECORD& input_rec, char *);
-  static DWORD get_console_process_id (DWORD pid, bool match);
 
   fhandler_console (void *) {}
 
@@ -2268,19 +2267,7 @@ class fhandler_pty_common: public fhandler_termios
     return fh;
   }
 
-  bool attach_pcon_in_fork (void)
-  {
-    return get_ttyp ()->attach_pcon_in_fork;
-  }
-  DWORD get_helper_process_id (void)
-  {
-    return get_ttyp ()->helper_process_id;
-  }
-  HPCON get_pseudo_console (void)
-  {
-    return get_ttyp ()->h_pseudo_console;
-  }
-  bool to_be_read_from_pcon (void);
+  void resize_pseudo_console (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2291,23 +2278,15 @@ class fhandler_pty_slave: public fhandler_pty_common
 {
   HANDLE inuse;			// used to indicate that a tty is in use
   HANDLE output_handle_cyg, io_handle_cyg;
-  DWORD pid_restore;
-  int fd;
 
   /* Helper functions for fchmod and fchown. */
   bool fch_open_handles (bool chown);
   int fch_set_sd (security_descriptor &sd, bool chown);
   void fch_close_handles ();
 
-  bool try_reattach_pcon ();
-  void restore_reattach_pcon ();
-  inline void free_attached_console ();
-
  public:
   /* Constructor */
   fhandler_pty_slave (int);
-  /* Destructor */
-  ~fhandler_pty_slave ();
 
   void set_output_handle_cyg (HANDLE h) { output_handle_cyg = h; }
   HANDLE& get_output_handle_cyg () { return output_handle_cyg; }
@@ -2319,9 +2298,6 @@ class fhandler_pty_slave: public fhandler_pty_common
   ssize_t __stdcall write (const void *ptr, size_t len);
   void __reg3 read (void *ptr, size_t& len);
   int init (HANDLE, DWORD, mode_t);
-  int eat_readahead (int n);
-  int get_readahead_into_buffer (char *buf, size_t buflen);
-  bool get_readahead_valid (void);
 
   int tcsetattr (int a, const struct termios *t);
   int tcgetattr (struct termios *t);
@@ -2358,20 +2334,12 @@ class fhandler_pty_slave: public fhandler_pty_common
     copyto (fh);
     return fh;
   }
-  void set_switch_to_pcon (int fd);
+  bool setup_pseudoconsole (STARTUPINFOEXW *si);
+  void close_pseudoconsole (void);
+  void set_switch_to_pcon (void);
   void reset_switch_to_pcon (void);
-  void push_to_pcon_screenbuffer (const char *ptr, size_t len, bool is_echo);
   void mask_switch_to_pcon_in (bool mask);
-  void fixup_after_attach (bool native_maybe, int fd);
-  bool is_line_input (void)
-  {
-    return get_ttyp ()->ti.c_lflag & ICANON;
-  }
   void setup_locale (void);
-  void set_freeconsole_on_close (bool val);
-  void trigger_redraw_screen (void);
-  void pull_pcon_input (void);
-  void update_pcon_input_state (bool need_lock);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
@@ -2396,7 +2364,6 @@ public:
   int process_slave_output (char *buf, size_t len, int pktmode_on);
   void doecho (const void *str, DWORD len);
   int accept_input ();
-  int put_readahead (char value);
   int open (int flags, mode_t mode = 0);
   void open_setup (int flags);
   ssize_t __stdcall write (const void *ptr, size_t len);
@@ -2435,9 +2402,7 @@ public:
     copyto (fh);
     return fh;
   }
-
-  bool setup_pseudoconsole (void);
-  void transfer_input_to_pcon (void);
+  bool to_be_read_from_pcon (void);
 };
 
 class fhandler_dev_null: public fhandler_base
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 52741ce8b..02a5996a1 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -1206,18 +1206,6 @@ fhandler_console::close ()
   if (con_ra.rabuf)
     free (con_ra.rabuf);
 
-  /* If already attached to pseudo console, don't call free_console () */
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR ||
-	cfd->get_major () == DEV_PTYS_MAJOR)
-      {
-	fhandler_pty_common *t =
-	  (fhandler_pty_common *) (fhandler_base *) cfd;
-	if (get_console_process_id (t->get_helper_process_id (), true))
-	  return 0;
-      }
-
   if (!have_execed)
     free_console ();
   return 0;
@@ -3611,37 +3599,6 @@ fhandler_console::need_invisible ()
   return b;
 }
 
-DWORD
-fhandler_console::get_console_process_id (DWORD pid, bool match)
-{
-  DWORD tmp;
-  DWORD num, num_req;
-  num = 1;
-  num_req = GetConsoleProcessList (&tmp, num);
-  DWORD *list;
-  while (true)
-    {
-      list = (DWORD *)
-	HeapAlloc (GetProcessHeap (), 0, num_req * sizeof (DWORD));
-      num = num_req;
-      num_req = GetConsoleProcessList (list, num);
-      if (num_req > num)
-	HeapFree (GetProcessHeap (), 0, list);
-      else
-	break;
-    }
-  num = num_req;
-
-  tmp = 0;
-  for (DWORD i=0; i<num; i++)
-    if ((match && list[i] == pid) || (!match && list[i] != pid))
-      /* Last one is the oldest. */
-      /* https://github.com/microsoft/terminal/issues/95 */
-      tmp = list[i];
-  HeapFree (GetProcessHeap (), 0, list);
-  return tmp;
-}
-
 DWORD
 fhandler_console::__acquire_input_mutex (const char *fn, int ln, DWORD ms)
 {
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 6a004f3a5..4cccc74c7 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -25,7 +25,6 @@ details. */
 #include "child_info.h"
 #include <asm/socket.h>
 #include "cygwait.h"
-#include "tls_pbuf.h"
 #include "registry.h"
 
 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
@@ -33,7 +32,6 @@ details. */
 #endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
 
 extern "C" int sscanf (const char *, const char *, ...);
-extern "C" int ttyname_r (int, char*, size_t);
 
 extern "C" {
   HRESULT WINAPI CreatePseudoConsole (COORD, HANDLE, HANDLE, DWORD, HPCON *);
@@ -60,20 +58,10 @@ struct pipe_reply {
   DWORD error;
 };
 
-static int pcon_attached_to = -1;
 static bool isHybrid;
-static bool do_not_reset_switch_to_pcon;
-static bool freeconsole_on_close = true;
-static tty *last_ttyp = NULL;
-
-void
-clear_pcon_attached_to (void)
-{
-  pcon_attached_to = -1;
-}
 
 static void
-set_switch_to_pcon (void)
+set_switch_to_pcon (HANDLE h)
 {
   cygheap_fdenum cfd (false);
   int fd;
@@ -82,280 +70,17 @@ set_switch_to_pcon (void)
       {
 	fhandler_base *fh = cfd;
 	fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	if (ptys->get_pseudo_console ())
-	  {
-	    ptys->set_switch_to_pcon (fd);
-	    ptys->trigger_redraw_screen ();
-	    DWORD mode =
-	      ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	    SetConsoleMode (ptys->get_handle (), mode);
-	  }
+	if (h == ptys->get_handle ())
+	  ptys->set_switch_to_pcon ();
 	return;
       }
-  /* No pty slave opened */
-  if (last_ttyp) /* Make system_printf() work after closing pty slave */
-    last_ttyp->set_switch_to_pcon_out (true);
-}
-
-static void
-force_attach_to_pcon (HANDLE h)
-{
-  bool attach_done = false;
-  for (int n = 0; n < 2; n ++)
-    {
-      /* First time, attach to the pty whose handle value is match.
-	 Second time, try to attach to any pty. */
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	    if (!ptys->get_pseudo_console ())
-	      continue;
-	    if (n != 0
-		|| h == ptys->get_handle ()
-		|| h == ptys->get_output_handle ())
-	      {
-		if (fhandler_console::get_console_process_id
-				  (ptys->get_helper_process_id (), true))
-		  attach_done = true;
-		else
-		  {
-		    FreeConsole ();
-		    if (AttachConsole (ptys->get_helper_process_id ()))
-		      {
-			pcon_attached_to = ptys->get_minor ();
-			attach_done = true;
-		      }
-		    else
-		      pcon_attached_to = -1;
-		  }
-		break;
-	      }
-	  }
-	else if (cfd->get_major () == DEV_CONS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_console *cons = (fhandler_console *) fh;
-	    if (n != 0
-		|| h == cons->get_handle ()
-		|| h == cons->get_output_handle ())
-	      {
-		/* If the process is running on a console,
-		   the parent process should be attached
-		   to the same console. */
-		DWORD attach_wpid;
-		if (myself->ppid == 1)
-		  attach_wpid = ATTACH_PARENT_PROCESS;
-		else
-		  {
-		    pinfo p (myself->ppid);
-		    attach_wpid = p->dwProcessId;
-		  }
-		FreeConsole ();
-		if (AttachConsole (attach_wpid))
-		  {
-		    pcon_attached_to = -1;
-		    attach_done = true;
-		  }
-		else
-		  pcon_attached_to = -1;
-		break;
-	      }
-	  }
-      if (attach_done)
-	break;
-    }
-}
-
-void
-set_ishybrid_and_switch_to_pcon (HANDLE h)
-{
-  if (GetFileType (h) == FILE_TYPE_CHAR)
-    {
-      force_attach_to_pcon (h);
-      DWORD dummy;
-      if (!isHybrid && (GetConsoleMode (h, &dummy)
-			|| GetLastError () != ERROR_INVALID_HANDLE))
-	{
-	  isHybrid = true;
-	  set_switch_to_pcon ();
-	}
-    }
-}
-
-inline void
-fhandler_pty_slave::free_attached_console ()
-{
-  bool attached = get_ttyp () ?
-    fhandler_console::get_console_process_id (get_helper_process_id (), true)
-    : (get_minor () == pcon_attached_to);
-  if (freeconsole_on_close && attached)
-    {
-      FreeConsole ();
-      pcon_attached_to = -1;
-    }
 }
 
 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
-DEF_HOOK (WriteFile);
-DEF_HOOK (WriteConsoleA);
-DEF_HOOK (WriteConsoleW);
-DEF_HOOK (ReadFile);
-DEF_HOOK (ReadConsoleA);
-DEF_HOOK (ReadConsoleW);
-DEF_HOOK (WriteConsoleOutputA);
-DEF_HOOK (WriteConsoleOutputW);
-DEF_HOOK (WriteConsoleOutputCharacterA);
-DEF_HOOK (WriteConsoleOutputCharacterW);
-DEF_HOOK (WriteConsoleOutputAttribute);
-DEF_HOOK (SetConsoleCursorPosition);
-DEF_HOOK (SetConsoleTextAttribute);
-DEF_HOOK (WriteConsoleInputA);
-DEF_HOOK (WriteConsoleInputW);
-DEF_HOOK (ReadConsoleInputA);
-DEF_HOOK (ReadConsoleInputW);
-DEF_HOOK (PeekConsoleInputA);
-DEF_HOOK (PeekConsoleInputW);
 /* CreateProcess() is hooked for GDB etc. */
 DEF_HOOK (CreateProcessA);
 DEF_HOOK (CreateProcessW);
 
-static BOOL WINAPI
-WriteFile_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleA_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleW_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadFile_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleA_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleW_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleOutputA_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputA_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputW_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputW_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterA_Hooked
-     (HANDLE h, LPCSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterA_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterW_Hooked
-     (HANDLE h, LPCWSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterW_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputAttribute_Hooked
-     (HANDLE h, CONST WORD *a, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputAttribute_Orig (h, a, l, c, n);
-}
-static BOOL WINAPI
-SetConsoleCursorPosition_Hooked
-     (HANDLE h, COORD c)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleCursorPosition_Orig (h, c);
-}
-static BOOL WINAPI
-SetConsoleTextAttribute_Hooked
-     (HANDLE h, WORD a)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleTextAttribute_Orig (h, a);
-}
-static BOOL WINAPI
-WriteConsoleInputA_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-WriteConsoleInputW_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputW_Orig (h, r, l, n);
-}
-/* CreateProcess() is hooked for GDB etc. */
 static BOOL WINAPI
 CreateProcessA_Hooked
      (LPCSTR n, LPSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
@@ -363,11 +88,14 @@ CreateProcessA_Hooked
       LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 static BOOL WINAPI
@@ -377,11 +105,14 @@ CreateProcessW_Hooked
       LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 
@@ -464,10 +195,6 @@ fhandler_pty_master::flush_to_slave ()
 {
   if (get_readahead_valid () && !(get_ttyp ()->ti.c_lflag & ICANON))
     accept_input ();
-  WaitForSingleObject (input_mutex, INFINITE);
-  if (!get_ttyp ()->pcon_in_empty && !(get_ttyp ()->ti.c_lflag & ICANON))
-    SetEvent (input_available_event);
-  ReleaseMutex (input_mutex);
 }
 
 DWORD
@@ -532,14 +259,6 @@ fhandler_pty_master::doecho (const void *str, DWORD len)
   release_output_mutex ();
 }
 
-int
-fhandler_pty_master::put_readahead (char value)
-{
-  if (to_be_read_from_pcon ())
-    return 1;
-  return fhandler_base::put_readahead (value);
-}
-
 int
 fhandler_pty_master::accept_input ()
 {
@@ -551,9 +270,11 @@ fhandler_pty_master::accept_input ()
   char *p = rabuf () + raixget ();
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
   if (to_be_read_from_pcon ())
-    ; /* Do nothing */
-  else if (!bytes_left)
+    write_to = to_slave;
+
+  if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
@@ -564,10 +285,10 @@ fhandler_pty_master::accept_input ()
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -725,52 +446,12 @@ out:
 
 fhandler_pty_slave::fhandler_pty_slave (int unit)
   : fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL),
-  io_handle_cyg (NULL), pid_restore (0), fd (-1)
+  io_handle_cyg (NULL)
 {
   if (unit >= 0)
     dev ().parse (DEV_PTYS_MAJOR, unit);
 }
 
-fhandler_pty_slave::~fhandler_pty_slave ()
-{
-  if (!get_ttyp ())
-    {
-      /* Why comes here? Who clears _tc? */
-      free_attached_console ();
-      return;
-    }
-  if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 0)
-	{
-	  pcon_attached_to = -1;
-	  last_ttyp = get_ttyp ();
-	}
-      if (used == 0)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
-}
-
 int
 fhandler_pty_slave::open (int flags, mode_t)
 {
@@ -950,24 +631,7 @@ fhandler_pty_slave::open (int flags, mode_t)
   set_output_handle (to_master_local);
   set_output_handle_cyg (to_master_cyg_local);
 
-  if (!get_pseudo_console ())
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (!fhandler_console::get_console_process_id
-			       (GetCurrentProcessId (), true))
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (fhandler_console::get_console_process_id
-			       (get_helper_process_id (), true))
-    /* Attached to pcon of this pty */
-    {
-      pcon_attached_to = get_minor ();
-      init_console_handler (true);
-    }
+  fhandler_console::need_invisible ();
 
   set_open_status ();
   return 1;
@@ -1021,8 +685,7 @@ fhandler_pty_slave::close ()
   if (!ForceCloseHandle (get_handle_cyg ()))
     termios_printf ("CloseHandle (get_handle_cyg ()<%p>), %E",
 	get_handle_cyg ());
-  if (!get_pseudo_console () &&
-      (unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
+  if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
     fhandler_console::free_console ();	/* assumes that we are the last pty closer */
   fhandler_pty_common::close ();
   if (!ForceCloseHandle (output_mutex))
@@ -1070,234 +733,17 @@ fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
   return ret;
 }
 
-bool
-fhandler_pty_slave::try_reattach_pcon (void)
-{
-  pid_restore = 0;
-
-  /* Do not detach from the console because re-attaching will
-     fail if helper process is running as service account. */
-  if (get_ttyp()->attach_pcon_in_fork)
-    return false;
-  if (pcon_attached_to >= 0 &&
-      cygwin_shared->tty[pcon_attached_to]->attach_pcon_in_fork)
-    return false;
-
-  pid_restore =
-    fhandler_console::get_console_process_id (GetCurrentProcessId (),
-					      false);
-  /* If pid_restore is not set, give up. */
-  if (!pid_restore)
-    return false;
-
-  FreeConsole ();
-  if (!AttachConsole (get_helper_process_id ()))
-    {
-      system_printf ("pty%d: AttachConsole(helper=%d) failed. 0x%08lx",
-		     get_minor (), get_helper_process_id (), GetLastError ());
-      return false;
-    }
-  return true;
-}
-
-void
-fhandler_pty_slave::restore_reattach_pcon (void)
-{
-  if (pid_restore)
-    {
-      FreeConsole ();
-      if (!AttachConsole (pid_restore))
-	{
-	  system_printf ("pty%d: AttachConsole(restore=%d) failed. 0x%08lx",
-			 get_minor (), pid_restore, GetLastError ());
-	  pcon_attached_to = -1;
-	}
-    }
-  pid_restore = 0;
-}
-
-/* This function requests transfering the input data from the input
-   pipe for cygwin apps to the other input pipe for native apps. */
-void
-fhandler_pty_slave::pull_pcon_input (void)
-{
-  get_ttyp ()->req_transfer_input_to_pcon = true;
-  while (get_ttyp ()->req_transfer_input_to_pcon)
-    Sleep (1);
-}
-
-void
-fhandler_pty_slave::update_pcon_input_state (bool need_lock)
-{
-  if (need_lock)
-    WaitForSingleObject (input_mutex, INFINITE);
-  /* Flush input buffer if it is requested by master.
-     This happens if ^C is pressed in pseudo console side. */
-  if (get_ttyp ()->req_flush_pcon_input)
-    {
-      FlushConsoleInputBuffer (get_handle ());
-      get_ttyp ()->req_flush_pcon_input = false;
-    }
-  /* Peek console input buffer and update state. */
-  INPUT_RECORD inp[INREC_SIZE];
-  DWORD n;
-  BOOL (WINAPI *PeekFunc)
-    (HANDLE, PINPUT_RECORD, DWORD, LPDWORD);
-  PeekFunc =
-    PeekConsoleInputA_Orig ? : PeekConsoleInput;
-  PeekFunc (get_handle (), inp, INREC_SIZE, &n);
-  bool saw_accept = false;
-  bool pipe_empty = true;
-  while (n-- > 0)
-    if (inp[n].EventType == KEY_EVENT && inp[n].Event.KeyEvent.bKeyDown &&
-	inp[n].Event.KeyEvent.uChar.AsciiChar)
-      {
-	pipe_empty = false;
-	char c = inp[n].Event.KeyEvent.uChar.AsciiChar;
-	const char sigs[] = {
-	  (char) get_ttyp ()->ti.c_cc[VINTR],
-	  (char) get_ttyp ()->ti.c_cc[VQUIT],
-	  (char) get_ttyp ()->ti.c_cc[VSUSP],
-	};
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n',
-	  '\r'
-	};
-	if (is_line_input () && c && memchr (eols, c, sizeof (eols)))
-	  saw_accept = true;
-	if ((get_ttyp ()->ti.c_lflag & ISIG)
-	    && c && memchr (sigs, c, sizeof (sigs)))
-	  saw_accept = true;
-      }
-  get_ttyp ()->pcon_in_empty = pipe_empty && !(ralen () > raixget ());
-  if (!get_readahead_valid () &&
-      (pipe_empty || (is_line_input () && !saw_accept)) &&
-      get_ttyp ()->read_retval == 1 && bytes_available (n) && n == 0)
-    ResetEvent (input_available_event);
-  if (need_lock)
-    ReleaseMutex (input_mutex);
-}
-
-int
-fhandler_pty_slave::eat_readahead (int n)
-{
-  int oralen = ralen ();
-  if (n < 0)
-    n = ralen () - raixget ();
-  if (n > 0 && ralen () > raixget ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      while (n > 0 && ralen () > raixget ())
-	{
-	  if (is_line_input () && rabuf ()[ralen ()-1]
-	      && memchr (eols, rabuf ()[ralen ()-1], sizeof (eols)))
-	    break;
-	  -- n;
-	  -- ralen ();
-	}
-
-      /* If IUTF8 is set, the terminal is in UTF-8 mode.  If so, we erase
-	 a complete UTF-8 multibyte sequence on VERASE/VWERASE.  Otherwise,
-	 if we only erase a single byte, invalid unicode chars are left in
-	 the input. */
-      if (get_ttyp ()->ti.c_iflag & IUTF8)
-	while (ralen () > raixget () &&
-	       ((unsigned char) rabuf ()[ralen ()] & 0xc0) == 0x80)
-	  --ralen ();
-    }
-  oralen = oralen - ralen ();
-  if (raixget () >= ralen ())
-    raixget () = raixput () = ralen () = 0;
-  else if (raixput () > ralen ())
-    raixput () = ralen ();
-
-  return oralen;
-}
-
-int
-fhandler_pty_slave::get_readahead_into_buffer (char *buf, size_t buflen)
-{
-  int ch;
-  int copied_chars = 0;
-
-  while (buflen)
-    if ((ch = get_readahead ()) < 0)
-      break;
-    else
-      {
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n'
-	};
-	buf[copied_chars++] = (unsigned char)(ch & 0xff);
-	buflen--;
-	if (is_line_input () && ch && memchr (eols, ch & 0xff, sizeof (eols)))
-	  break;
-      }
-
-  return copied_chars;
-}
-
-bool
-fhandler_pty_slave::get_readahead_valid (void)
-{
-  if (is_line_input ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      for (size_t i=raixget (); i<ralen (); i++)
-	if (rabuf ()[i] && memchr (eols, rabuf ()[i], sizeof (eols)))
-	  return true;
-      return false;
-    }
-  else
-    return ralen () > raixget ();
-}
-
 void
-fhandler_pty_slave::set_switch_to_pcon (int fd_set)
+fhandler_pty_slave::set_switch_to_pcon (void)
 {
-  if (fd < 0)
-    fd = fd_set;
-  acquire_output_mutex (INFINITE);
-  if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
+  if (!get_ttyp ()->switch_to_pcon_in)
     {
-      pull_pcon_input ();
+      isHybrid = true;
       if (get_ttyp ()->pcon_pid == 0 ||
 	  !pinfo (get_ttyp ()->pcon_pid))
 	get_ttyp ()->pcon_pid = myself->pid;
       get_ttyp ()->switch_to_pcon_in = true;
-      if (isHybrid && !get_ttyp ()->switch_to_pcon_out)
-	{
-	  get_ttyp ()->wait_pcon_fwd ();
-	  get_ttyp ()->switch_to_pcon_out = true;
-	}
     }
-  else if ((fd == 1 || fd == 2) && !get_ttyp ()->switch_to_pcon_out)
-    {
-      get_ttyp ()->wait_pcon_fwd ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
-	get_ttyp ()->pcon_pid = myself->pid;
-      get_ttyp ()->switch_to_pcon_out = true;
-      if (isHybrid)
-	get_ttyp ()->switch_to_pcon_in = true;
-    }
-  release_output_mutex ();
 }
 
 void
@@ -1310,183 +756,10 @@ fhandler_pty_slave::reset_switch_to_pcon (void)
     return;
   if (isHybrid)
     return;
-  if (do_not_reset_switch_to_pcon)
-    return;
-  acquire_output_mutex (INFINITE);
-  if (get_ttyp ()->switch_to_pcon_out)
-    /* Wait for pty_master_fwd_thread() */
-    get_ttyp ()->wait_pcon_fwd ();
   get_ttyp ()->pcon_pid = 0;
   get_ttyp ()->switch_to_pcon_in = false;
-  get_ttyp ()->switch_to_pcon_out = false;
-  release_output_mutex ();
-  init_console_handler (true);
-}
-
-void
-fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len,
-					       bool is_echo)
-{
-  bool attached =
-    !!fhandler_console::get_console_process_id (get_helper_process_id (), true);
-  if (!attached && pcon_attached_to == get_minor ())
-    {
-      for (DWORD t0 = GetTickCount (); GetTickCount () - t0 < 100; )
-	{
-	  Sleep (1);
-	  attached = fhandler_console::get_console_process_id
-				      (get_helper_process_id (), true);
-	  if (attached)
-	    break;
-	}
-      if (!attached)
-	{
-	  system_printf ("pty%d: pcon_attach_to mismatch??????", get_minor ());
-	  return;
-	}
-    }
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  if (pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      goto detach;
-
-  char *buf;
-  size_t nlen;
-  DWORD origCP;
-  origCP = GetConsoleOutputCP ();
-  SetConsoleOutputCP (get_ttyp ()->term_code_page);
-  /* Just copy */
-  buf = (char *) HeapAlloc (GetProcessHeap (), 0, len);
-  memcpy (buf, (char *)ptr, len);
-  nlen = len;
-  char *p0, *p1;
-  p0 = p1 = buf;
-  /* Remove alternate screen buffer drawing */
-  while (p0 && p1)
-    {
-      if (!get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to alternate screen buffer */
-	  p0 = (char *) memmem (p1, nlen - (p1-buf), "\033[?1049h", 8);
-	  if (p0)
-	    {
-	      //p0 += 8;
-	      get_ttyp ()->screen_alternated = true;
-	      if (get_ttyp ()->switch_to_pcon_out)
-		do_not_reset_switch_to_pcon = true;
-	    }
-	}
-      if (get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to main screen buffer */
-	  p1 = (char *) memmem (p0, nlen - (p0-buf), "\033[?1049l", 8);
-	  if (p1)
-	    {
-	      p1 += 8;
-	      get_ttyp ()->screen_alternated = false;
-	      do_not_reset_switch_to_pcon = false;
-	      memmove (p0, p1, buf+nlen - p1);
-	      nlen -= p1 - p0;
-	    }
-	  else
-	    nlen = p0 - buf;
-	}
-    }
-  if (!nlen) /* Nothing to be synchronized */
-    goto cleanup;
-  if (get_ttyp ()->switch_to_pcon_out && !is_echo)
-    goto cleanup;
-  /* Remove ESC sequence which returns results to console
-     input buffer. Without this, cursor position report
-     is put into the input buffer as a garbage. */
-  /* Remove ESC sequence to report cursor position. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[6n", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-  /* Remove ESC sequence to report terminal identity. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[0c", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-
-  /* If the ESC sequence ESC[?3h or ESC[?3l which clears console screen
-     buffer is pushed, set need_redraw_screen to trigger redraw screen. */
-  p0 = buf;
-  while ((p0 = (char *) memmem (p0, nlen - (p0 - buf), "\033[?", 3)))
-    {
-      p0 += 3;
-      bool exist_arg_3 = false;
-      while (p0 < buf + nlen && (isdigit (*p0) || *p0 == ';'))
-	{
-	  int arg = 0;
-	  while (p0 < buf + nlen && isdigit (*p0))
-	    arg = arg * 10 + (*p0 ++) - '0';
-	  if (arg == 3)
-	    exist_arg_3 = true;
-	  if (p0 < buf + nlen && *p0 == ';')
-	    p0 ++;
-	}
-      if (p0 < buf + nlen && exist_arg_3 && (*p0 == 'h' || *p0 == 'l'))
-	get_ttyp ()->need_redraw_screen = true;
-      p0 ++;
-      if (p0 >= buf + nlen)
-	break;
-    }
-
-  int retry_count;
-  retry_count = 0;
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  while (!GetConsoleMode (get_output_handle (), &dwMode))
-    {
-      termios_printf ("GetConsoleMode failed, %E");
-      int errno_save = errno;
-      /* Re-open handles */
-      this->open (0, 0);
-      /* Fix pseudo console window size */
-      this->ioctl (TIOCSWINSZ, &get_ttyp ()->winsize);
-      if (errno != errno_save)
-	set_errno (errno_save);
-      if (++retry_count > 3)
-	goto cleanup;
-    }
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-  char *p;
-  p = buf;
-  DWORD wLen, written;
-  written = 0;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
-  while (written <  nlen)
-    {
-      if (!WriteFunc (get_output_handle (), p, nlen - written, &wLen, NULL))
-	{
-	  termios_printf ("WriteFile failed, %E");
-	  break;
-	}
-      else
-	{
-	  written += wLen;
-	  p += wLen;
-	}
-    }
-  /* Detach from pseudo console and resume. */
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-cleanup:
-  SetConsoleOutputCP (origCP);
-  HeapFree (GetProcessHeap (), 0, buf);
-detach:
-  restore_reattach_pcon ();
+  get_ttyp ()->h_pseudo_console = NULL;
+  get_ttyp ()->pcon_start = false;
 }
 
 ssize_t __stdcall
@@ -1505,44 +778,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
   reset_switch_to_pcon ();
 
   acquire_output_mutex (INFINITE);
-  bool output_to_pcon = get_ttyp ()->switch_to_pcon_out;
-  release_output_mutex ();
-
-  UINT target_code_page = output_to_pcon ?
-    GetConsoleOutputCP () : get_ttyp ()->term_code_page;
-  ssize_t nlen;
-  char *buf = convert_mb_str (target_code_page, (size_t *) &nlen,
-		 get_ttyp ()->term_code_page, (const char *) ptr, len);
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  bool fallback = false;
-  if (output_to_pcon && pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      fallback = true;
-
-  if (output_to_pcon && !fallback &&
-      (memmem (buf, nlen, "\033[6n", 4) || memmem (buf, nlen, "\033[0c", 4)))
-    {
-      get_ttyp ()->pcon_in_empty = false;
-      if (!is_line_input ())
-	SetEvent (input_available_event);
-    }
-
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  if (output_to_pcon && !fallback)
-    {
-      GetConsoleMode (get_output_handle (), &dwMode);
-      SetConsoleMode (get_output_handle (), dwMode | flags);
-    }
-  HANDLE to = (output_to_pcon && !fallback) ?
-    get_output_handle () : get_output_handle_cyg ();
-  acquire_output_mutex (INFINITE);
-  if (!process_opost_output (to, buf, nlen, false))
+  if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false))
     {
       DWORD err = GetLastError ();
       termios_printf ("WriteFile failed, %E");
@@ -1557,20 +793,6 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
       towrite = -1;
     }
   release_output_mutex ();
-  mb_str_free (buf);
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (output_to_pcon && !fallback)
-    SetConsoleMode (get_output_handle (), dwMode | flags);
-
-  restore_reattach_pcon ();
-
-  /* Push slave output to pseudo console screen buffer */
-  if (get_pseudo_console ())
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer ((char *)ptr, len, false);
-      release_output_mutex ();
-    }
 
   return towrite;
 }
@@ -1582,16 +804,15 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 }
 
 bool
-fhandler_pty_common::to_be_read_from_pcon (void)
+fhandler_pty_master::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return get_ttyp ()->pcon_start
+    || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
 fhandler_pty_slave::read (void *ptr, size_t& len)
 {
-  char *ptr0 = (char *)ptr;
   ssize_t totalread = 0;
   int vmin = 0;
   int vtime = 0;	/* Initialized to prevent -Wuninitialized warning */
@@ -1616,8 +837,6 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
       mask_switch_to_pcon_in (true);
       reset_switch_to_pcon ();
     }
-  if (to_be_read_from_pcon ())
-    update_pcon_input_state (true);
 
   if (is_nonblocking () || !ptr) /* Indicating tcflush(). */
     time_to_wait = 0;
@@ -1702,99 +921,22 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 	    {
 	      if (!totalread)
 		{
-		  set_sig_errno (EAGAIN);
-		  totalread = -1;
-		}
-	      goto out;
-	    }
-	  continue;
-	default:
-	  termios_printf ("wait for input mutex failed, %E");
-	  if (!totalread)
-	    {
-	      __seterrno ();
-	      totalread = -1;
-	    }
-	  goto out;
-	}
-      if (ptr && to_be_read_from_pcon ())
-	{
-	  if (get_readahead_valid ())
-	    {
-	      ReleaseMutex (input_mutex);
-	      totalread = get_readahead_into_buffer ((char *) ptr, len);
-	    }
-	  else
-	    {
-	      if (!try_reattach_pcon ())
-		{
-		  restore_reattach_pcon ();
-		  goto do_read_cyg;
-		}
-
-	      DWORD dwMode;
-	      GetConsoleMode (get_handle (), &dwMode);
-	      DWORD flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
-	      if (dwMode != flags)
-		SetConsoleMode (get_handle (), flags);
-	      /* Read get_handle() instad of get_handle_cyg() */
-	      BOOL (WINAPI *ReadFunc)
-		(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID);
-	      ReadFunc = ReadConsoleA_Orig ? ReadConsoleA_Orig : ReadConsoleA;
-	      DWORD rlen;
-	      readlen = MIN (len, sizeof (buf));
-	      if (!ReadFunc (get_handle (), buf, readlen, &rlen, NULL))
-		{
-		  termios_printf ("read failed, %E");
-		  SetConsoleMode (get_handle (), dwMode);
-		  restore_reattach_pcon ();
-		  ReleaseMutex (input_mutex);
-		  set_errno (EIO);
-		  totalread = -1;
-		  goto out;
-		}
-	      SetConsoleMode (get_handle (), dwMode);
-	      restore_reattach_pcon ();
-	      ReleaseMutex (input_mutex);
-
-	      ssize_t nlen;
-	      char *nbuf = convert_mb_str (get_ttyp ()->term_code_page,
-			     (size_t *) &nlen, GetConsoleCP (), buf, rlen);
-
-	      ssize_t ret;
-	      line_edit_status res =
-		line_edit (nbuf, nlen, get_ttyp ()->ti, &ret);
-
-	      mb_str_free (nbuf);
-
-	      if (res == line_edit_input_done || res == line_edit_ok)
-		totalread = get_readahead_into_buffer ((char *) ptr, len);
-	      else if (res > line_edit_signalled)
-		{
-		  set_sig_errno (EINTR);
+		  set_sig_errno (EAGAIN);
 		  totalread = -1;
 		}
-	      else
-		{
-		  update_pcon_input_state (true);
-		  continue;
-		}
+	      goto out;
+	    }
+	  continue;
+	default:
+	  termios_printf ("wait for input mutex failed, %E");
+	  if (!totalread)
+	    {
+	      __seterrno ();
+	      totalread = -1;
 	    }
-
-	  update_pcon_input_state (true);
-	  mask_switch_to_pcon_in (false);
 	  goto out;
 	}
-      if (!ptr && len == UINT_MAX && !get_ttyp ()->pcon_in_empty)
-	{
-	  FlushConsoleInputBuffer (get_handle ());
-	  get_ttyp ()->pcon_in_empty = true;
-	  DWORD n;
-	  if (bytes_available (n) && n == 0)
-	    ResetEvent (input_available_event);
-	}
 
-do_read_cyg:
       if (!bytes_available (bytes_in_pipe))
 	{
 	  ReleaseMutex (input_mutex);
@@ -1911,16 +1053,6 @@ do_read_cyg:
 out:
   termios_printf ("%d = read(%p, %lu)", totalread, ptr, len);
   len = (size_t) totalread;
-  /* Push slave read as echo to pseudo console screen buffer. */
-  if (get_pseudo_console () && ptr0 && totalread > 0 &&
-      (get_ttyp ()->ti.c_lflag & ECHO))
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer (ptr0, len, true);
-      if (get_ttyp ()->switch_to_pcon_out)
-	trigger_redraw_screen ();
-      release_output_mutex ();
-    }
   mask_switch_to_pcon_in (false);
 }
 
@@ -2061,38 +1193,11 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
       get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
       break;
     case TIOCSWINSZ:
-      if (get_pseudo_console ())
-	{
-	  /* If not attached to this pseudo console,
-	     try to attach temporarily. */
-	  pid_restore = 0;
-	  if (pcon_attached_to != get_minor ())
-	    if (!try_reattach_pcon ())
-	      goto cleanup;
-
-	  COORD size;
-	  size.X = ((struct winsize *) arg)->ws_col;
-	  size.Y = ((struct winsize *) arg)->ws_row;
-	  CONSOLE_SCREEN_BUFFER_INFO csbi;
-	  if (GetConsoleScreenBufferInfo (get_output_handle (), &csbi))
-	    if (size.X == csbi.srWindow.Right - csbi.srWindow.Left + 1 &&
-		size.Y == csbi.srWindow.Bottom - csbi.srWindow.Top + 1)
-	      goto cleanup;
-	  if (!SetConsoleScreenBufferSize (get_output_handle (), size))
-	    goto cleanup;
-	  SMALL_RECT rect;
-	  rect.Left = 0;
-	  rect.Top = 0;
-	  rect.Right = size.X-1;
-	  rect.Bottom = size.Y-1;
-	  SetConsoleWindowInfo (get_output_handle (), TRUE, &rect);
-cleanup:
-	  restore_reattach_pcon ();
-	}
-
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->arg.winsize = *(struct winsize *) arg;
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
@@ -2378,6 +1483,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2393,7 +1519,6 @@ fhandler_pty_master::close ()
 {
   OBJECT_BASIC_INFORMATION obi;
   NTSTATUS status;
-  pid_t master_pid_tmp = get_ttyp ()->master_pid;
 
   termios_printf ("closing from_master(%p)/from_master_cyg(%p)/to_master(%p)/to_master_cyg(%p) since we own them(%u)",
 		  from_master, from_master_cyg,
@@ -2438,30 +1563,6 @@ fhandler_pty_master::close ()
   else if (obi.HandleCount == 1)
     {
       termios_printf ("Closing last master of pty%d", get_minor ());
-      /* Close Pseudo Console */
-      if (get_pseudo_console ())
-	{
-	  /* Terminate helper process */
-	  SetEvent (get_ttyp ()->h_helper_goodbye);
-	  WaitForSingleObject (get_ttyp ()->h_helper_process, INFINITE);
-	  CloseHandle (get_ttyp ()->h_helper_goodbye);
-	  CloseHandle (get_ttyp ()->h_helper_process);
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (master_pid_tmp == myself->pid)
-	    {
-	      /* ClosePseudoConsole() seems to have a bug that one
-		 internal handle remains opened. This causes handle leak.
-		 This is a workaround for this problem. */
-	      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_pseudo_console ();
-	      HANDLE tmp = hp->hConHostProcess;
-	      /* Release pseudo console */
-	      ClosePseudoConsole (get_pseudo_console ());
-	      CloseHandle (tmp);
-	    }
-	  get_ttyp ()->switch_to_pcon_in = false;
-	  get_ttyp ()->switch_to_pcon_out = false;
-	}
       if (get_ttyp ()->getsid () > 0)
 	kill (get_ttyp ()->getsid (), SIGHUP);
       SetEvent (input_available_event);
@@ -2469,9 +1570,8 @@ fhandler_pty_master::close ()
 
   if (!ForceCloseHandle (from_master))
     termios_printf ("error closing from_master %p, %E", from_master);
-  if (from_master_cyg != from_master) /* Avoid double close. */
-    if (!ForceCloseHandle (from_master_cyg))
-      termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
+  if (!ForceCloseHandle (from_master_cyg))
+    termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
   if (!ForceCloseHandle (to_master))
     termios_printf ("error closing to_master %p, %E", to_master);
   from_master = to_master = NULL;
@@ -2513,7 +1613,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon () && get_ttyp ()->h_pseudo_console)
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2521,40 +1621,50 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
       WaitForSingleObject (input_mutex, INFINITE);
 
-      if (memchr (buf, '\003', nlen)) /* ^C intr key in pcon */
-	get_ttyp ()->req_flush_pcon_input = true;
-
       DWORD wLen;
-      WriteFile (to_slave, buf, nlen, &wLen, NULL);
-      get_ttyp ()->pcon_in_empty = false;
-
-      ReleaseMutex (input_mutex);
 
-      /* Use line_edit () in order to set input_available_event. */
-      bool is_echo = tc ()->ti.c_lflag & ECHO;
-      if (!get_ttyp ()->mask_switch_to_pcon_in)
+      if (get_ttyp ()->pcon_start)
 	{
-	  tc ()->ti.c_lflag &= ~ECHO;
-	  ti.c_lflag &= ~ECHO;
-	}
-      ti.c_lflag &= ~ISIG;
-      line_edit (buf, nlen, ti, &ret);
-      if (is_echo)
-	tc ()->ti.c_lflag |= ECHO;
-      get_ttyp ()->read_retval = 1;
-
-      const char sigs[] = {
-	(char) ti.c_cc[VINTR],
-	(char) ti.c_cc[VQUIT],
-	(char) ti.c_cc[VSUSP],
-      };
-      if (tc ()->ti.c_lflag & ISIG)
-	for (size_t i=0; i<sizeof (sigs); i++)
-	  if (sigs[i] && memchr (buf, sigs[i], nlen))
+	  /* Pseudo condole support uses "CSI6n" to get cursor position.
+	     If the reply for "CSI6n" is divided into multiple writes,
+	     pseudo console sometimes does not recognize it.  Therefore,
+	     put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon_start = false;
+	    }
+	  else
 	    {
-	      eat_readahead (-1);
-	      SetEvent (input_available_event);
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
 	    }
+	}
+
+      WriteFile (to_slave, buf, nlen, &wLen, NULL);
+
+      ReleaseMutex (input_mutex);
 
       mb_str_free (buf);
       return len;
@@ -2630,15 +1740,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (get_pseudo_console () && get_ttyp ()->master_pid == myself->pid)
-	    {
-	      COORD size;
-	      size.X = ((struct winsize *) arg)->ws_col;
-	      size.Y = ((struct winsize *) arg)->ws_row;
-	      ResizePseudoConsole (get_pseudo_console (), size);
-	    }
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
 	}
@@ -2763,7 +1866,7 @@ get_locale_from_env (char *locale)
   strcpy (locale, env);
 }
 
-static LCID
+static void
 get_langinfo (char *locale_out, char *charset_out)
 {
   /* Get locale from environment */
@@ -2776,11 +1879,6 @@ get_langinfo (char *locale_out, char *charset_out)
   if (!locale)
     locale = "C";
 
-  char tmp_locale[ENCODING_LEN + 1];
-  char *ret = __set_locale_from_locale_alias (locale, tmp_locale);
-  if (ret)
-    locale = tmp_locale;
-
   const char *charset;
   struct lc_ctype_T *lc_ctype = (struct lc_ctype_T *) loc.lc_cat[LC_CTYPE].ptr;
   if (!lc_ctype)
@@ -2830,23 +1928,9 @@ get_langinfo (char *locale_out, char *charset_out)
       charset = "CP932";
     }
 
-  wchar_t lc[ENCODING_LEN + 1];
-  wchar_t *p;
-  mbstowcs (lc, locale, ENCODING_LEN);
-  p = wcschr (lc, L'.');
-  if (p)
-    *p = L'\0';
-  p = wcschr (lc, L'_');
-  if (p)
-    *p = L'-';
-  LCID lcid = LocaleNameToLCID (lc, 0);
-  if (!lcid && !strcmp (charset, "ASCII"))
-    return 0;
-
   /* Set results */
   strcpy (locale_out, new_locale);
   strcpy (charset_out, charset);
-  return lcid;
 }
 
 void
@@ -2854,21 +1938,7 @@ fhandler_pty_slave::setup_locale (void)
 {
   char locale[ENCODING_LEN + 1] = "C";
   char charset[ENCODING_LEN + 1] = "ASCII";
-  LCID lcid = get_langinfo (locale, charset);
-
-  /* Set console code page form locale */
-  if (get_pseudo_console ())
-    {
-      UINT code_page;
-      if (lcid == 0 || lcid == (LCID) -1)
-	code_page = 20127; /* ASCII */
-      else if (!GetLocaleInfo (lcid,
-			       LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
-			       (char *) &code_page, sizeof (code_page)))
-	code_page = 20127; /* ASCII */
-      SetConsoleCP (code_page);
-      SetConsoleOutputCP (code_page);
-    }
+  get_langinfo (locale, charset);
 
   /* Set terminal code page from locale */
   /* This code is borrowed from mintty: charset.c */
@@ -2896,90 +1966,9 @@ fhandler_pty_slave::setup_locale (void)
 	}
 }
 
-void
-fhandler_pty_slave::set_freeconsole_on_close (bool val)
-{
-  freeconsole_on_close = val;
-}
-
-void
-fhandler_pty_slave::trigger_redraw_screen (void)
-{
-  /* Forcibly redraw screen based on console screen buffer. */
-  /* The following code triggers redrawing the screen. */
-  CONSOLE_SCREEN_BUFFER_INFO sbi;
-  GetConsoleScreenBufferInfo (get_output_handle (), &sbi);
-  SMALL_RECT rect = {0, 0,
-    (SHORT) (sbi.dwSize.X -1), (SHORT) (sbi.dwSize.Y - 1)};
-  COORD dest = {0, 0};
-  CHAR_INFO fill = {' ', 0};
-  ScrollConsoleScreenBuffer (get_output_handle (), &rect, NULL, dest, &fill);
-  get_ttyp ()->need_redraw_screen = false;
-}
-
-void
-fhandler_pty_slave::fixup_after_attach (bool native_maybe, int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  if (get_pseudo_console ())
-    {
-      if (fhandler_console::get_console_process_id (get_helper_process_id (),
-						    true))
-	if (pcon_attached_to != get_minor ())
-	  {
-	    pcon_attached_to = get_minor ();
-	    init_console_handler (true);
-	  }
-
-#if 0 /* This is for debug only. */
-      isHybrid = true;
-      get_ttyp ()->switch_to_pcon_in = true;
-      get_ttyp ()->switch_to_pcon_out = true;
-#endif
-
-      if (pcon_attached_to == get_minor () && native_maybe)
-	{
-	  if (fd == 0)
-	    {
-	      pull_pcon_input ();
-	      DWORD mode =
-		ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	      SetConsoleMode (get_handle (), mode);
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_in = true;
-	    }
-	  else if (fd == 1 || fd == 2)
-	    {
-	      DWORD mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
-	      SetConsoleMode (get_output_handle (), mode);
-	      acquire_output_mutex (INFINITE);
-	      if (!get_ttyp ()->switch_to_pcon_out)
-		get_ttyp ()->wait_pcon_fwd ();
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_out = true;
-	      release_output_mutex ();
-
-	      if (get_ttyp ()->need_redraw_screen)
-		trigger_redraw_screen ();
-	    }
-	  init_console_handler (false);
-	}
-      else if (fd == 0 && native_maybe)
-	/* Read from unattached pseudo console cause freeze,
-	   therefore, fallback to legacy pty. */
-	set_handle (get_handle_cyg ());
-    }
-}
-
 void
 fhandler_pty_slave::fixup_after_fork (HANDLE parent)
 {
-  fixup_after_attach (false, -1);
   // fork_fixup (parent, inuse, "inuse");
   // fhandler_pty_common::fixup_after_fork (parent);
   report_tty_counts (this, "inherited", "");
@@ -2992,71 +1981,22 @@ fhandler_pty_slave::fixup_after_exec ()
 
   if (!close_on_exec ())
     fixup_after_fork (NULL);	/* No parent handle required. */
-  else if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 1 && get_minor () == pcon_attached_to)
-	pcon_attached_to = -1;
-      if (used == 1 /* About to close this tty */)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
 
   /* Set locale */
   if (get_ttyp ()->term_code_page == 0)
     setup_locale ();
 
   /* Hook Console API */
-  if (get_pseudo_console ())
-    {
 #define DO_HOOK(module, name) \
-      if (!name##_Orig) \
-	{ \
-	  void *api = hook_api (module, #name, (void *) name##_Hooked); \
-	  name##_Orig = (__typeof__ (name) *) api; \
-	  /*if (api) system_printf (#name " hooked.");*/ \
-	}
-      DO_HOOK (NULL, WriteFile);
-      DO_HOOK (NULL, WriteConsoleA);
-      DO_HOOK (NULL, WriteConsoleW);
-      DO_HOOK (NULL, ReadFile);
-      DO_HOOK (NULL, ReadConsoleA);
-      DO_HOOK (NULL, ReadConsoleW);
-      DO_HOOK (NULL, WriteConsoleOutputA);
-      DO_HOOK (NULL, WriteConsoleOutputW);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterA);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterW);
-      DO_HOOK (NULL, WriteConsoleOutputAttribute);
-      DO_HOOK (NULL, SetConsoleCursorPosition);
-      DO_HOOK (NULL, SetConsoleTextAttribute);
-      DO_HOOK (NULL, WriteConsoleInputA);
-      DO_HOOK (NULL, WriteConsoleInputW);
-      DO_HOOK (NULL, ReadConsoleInputA);
-      DO_HOOK (NULL, ReadConsoleInputW);
-      DO_HOOK (NULL, PeekConsoleInputA);
-      DO_HOOK (NULL, PeekConsoleInputW);
-      /* CreateProcess() is hooked for GDB etc. */
-      DO_HOOK (NULL, CreateProcessA);
-      DO_HOOK (NULL, CreateProcessW);
+  if (!name##_Orig) \
+    { \
+      void *api = hook_api (module, #name, (void *) name##_Hooked); \
+      name##_Orig = (__typeof__ (name) *) api; \
+      /*if (api) system_printf (#name " hooked.");*/ \
     }
+  /* CreateProcess() is hooked for GDB etc. */
+  DO_HOOK (NULL, CreateProcessA);
+  DO_HOOK (NULL, CreateProcessW);
 }
 
 /* This thread function handles the master control pipe.  It waits for a
@@ -3204,27 +2144,6 @@ reply:
   return 0;
 }
 
-void
-fhandler_pty_master::transfer_input_to_pcon (void)
-{
-  WaitForSingleObject (input_mutex, INFINITE);
-  DWORD n;
-  size_t transfered = 0;
-  while (::bytes_available (n, from_master_cyg) && n)
-    {
-      char buf[1024];
-      ReadFile (from_master_cyg, buf, sizeof (buf), &n, 0);
-      char *p = buf;
-      while ((p = (char *) memchr (p, '\n', n - (p - buf))))
-	*p = '\r';
-      if (WriteFile (to_slave, buf, n, &n, 0))
-	transfered += n;
-    }
-  if (transfered)
-    get_ttyp ()->pcon_in_empty = false;
-  ReleaseMutex (input_mutex);
-}
-
 static DWORD WINAPI
 pty_master_thread (VOID *arg)
 {
@@ -3240,23 +2159,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
   termios_printf ("Started.");
   for (;;)
     {
-      if (get_pseudo_console ())
-	{
-	  get_ttyp ()->pcon_last_time = GetTickCount ();
-	  while (::bytes_available (rlen, from_slave) && rlen == 0)
-	    {
-	      /* Forcibly transfer input if it is requested by slave.
-		 This happens when input data should be transfered
-		 from the input pipe for cygwin apps to the input pipe
-		 for native apps. */
-	      if (get_ttyp ()->req_transfer_input_to_pcon)
-		{
-		  transfer_input_to_pcon ();
-		  get_ttyp ()->req_transfer_input_to_pcon = false;
-		}
-	      Sleep (1);
-	    }
-	}
+      get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3264,51 +2167,11 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_ttyp ()->h_pseudo_console)
 	{
-	  /* Avoid duplicating slave output which is already sent to
-	     to_master_cyg */
-	  if (!get_ttyp ()->switch_to_pcon_out)
-	    continue;
-
-	  /* Avoid setting window title to "cygwin-console-helper.exe" */
+	  /* Remove CSI > Pm m */
 	  int state = 0;
 	  int start_at = 0;
-	  for (DWORD i=0; i<rlen; i++)
-	    if (outbuf[i] == '\033')
-	      {
-		start_at = i;
-		state = 1;
-		continue;
-	      }
-	    else if ((state == 1 && outbuf[i] == ']') ||
-		     (state == 2 && outbuf[i] == '0') ||
-		     (state == 3 && outbuf[i] == ';'))
-	      {
-		state ++;
-		continue;
-	      }
-	    else if (state == 4 && outbuf[i] == '\a')
-	      {
-		const char *helper_str = "\\bin\\cygwin-console-helper.exe";
-		if (memmem (&outbuf[start_at], i + 1 - start_at,
-			    helper_str, strlen (helper_str)))
-		  {
-		    memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
-		    rlen = wlen = start_at + rlen - i - 1;
-		  }
-		state = 0;
-		continue;
-	      }
-	    else if (outbuf[i] == '\a')
-	      {
-		state = 0;
-		continue;
-	      }
-
-	  /* Remove CSI > Pm m */
-	  state = 0;
-	  start_at = 0;
 	  for (DWORD i=0; i<rlen; i++)
 	    if (outbuf[i] == '\033')
 	      {
@@ -3386,201 +2249,6 @@ pty_master_fwd_thread (VOID *arg)
   return ((fhandler_pty_master *) arg)->pty_master_fwd_thread ();
 }
 
-/* If master process is running as service, attaching to
-   pseudo console should be done in fork. If attaching
-   is done in spawn for inetd or sshd, it fails because
-   the helper process is running as privileged user while
-   slave process is not. This function is used to determine
-   if the process is running as a srvice or not. */
-inline static bool
-is_running_as_service (void)
-{
-  return check_token_membership (well_known_service_sid)
-    || cygheap->user.saved_sid () == well_known_system_sid;
-}
-
-bool
-fhandler_pty_master::setup_pseudoconsole ()
-{
-  if (disable_pcon)
-    return false;
-  /* If the legacy console mode is enabled, pseudo console seems
-     not to work as expected. To determine console mode, registry
-     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
-  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
-  if (reg.error ())
-    return false;
-  if (reg.get_dword (L"ForceV2", 1) == 0)
-    {
-      termios_printf ("Pseudo console is disabled "
-		      "because the legacy console mode is enabled.");
-      return false;
-    }
-
-  /* Pseudo console supprot is realized using a tricky technic.
-     PTY need the pseudo console handles, however, they cannot
-     be retrieved by normal procedure. Therefore, run a helper
-     process in a pseudo console and get them from the helper.
-     Slave process will attach to the pseudo console in the
-     helper process using AttachConsole(). */
-  COORD size = {
-    (SHORT) get_ttyp ()->winsize.ws_col,
-    (SHORT) get_ttyp ()->winsize.ws_row
-  };
-  CreatePipe (&from_master, &to_slave, &sec_none, 0);
-  SetLastError (ERROR_SUCCESS);
-  HRESULT res = CreatePseudoConsole (size, from_master, to_master,
-				     0, &get_ttyp ()->h_pseudo_console);
-  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
-    {
-      if (res != S_OK)
-	system_printf ("CreatePseudoConsole() failed. %08x\n",
-		       GetLastError ());
-      goto fallback;
-    }
-
-  /* If master process is running as service, attaching to
-     pseudo console should be done in fork. If attaching
-     is done in spawn for inetd or sshd, it fails because
-     the helper process is running as privileged user while
-     slave process is not. */
-  if (is_running_as_service ())
-    get_ttyp ()->attach_pcon_in_fork = true;
-
-  STARTUPINFOEXW si_helper;
-  HANDLE hello, goodbye;
-  HANDLE hr, hw;
-  PROCESS_INFORMATION pi_helper;
-  HANDLE hpConIn, hpConOut;
-  {
-    SIZE_T bytesRequired;
-    InitializeProcThreadAttributeList (NULL, 2, 0, &bytesRequired);
-    ZeroMemory (&si_helper, sizeof (si_helper));
-    si_helper.StartupInfo.cb = sizeof (STARTUPINFOEXW);
-    si_helper.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
-      HeapAlloc (GetProcessHeap (), 0, bytesRequired);
-    if (si_helper.lpAttributeList == NULL)
-      goto cleanup_pseudo_console;
-    if (!InitializeProcThreadAttributeList (si_helper.lpAttributeList,
-					    2, 0, &bytesRequired))
-      goto cleanup_heap;
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
-				    get_ttyp ()->h_pseudo_console,
-				    sizeof (get_ttyp ()->h_pseudo_console),
-				    NULL, NULL))
-      goto cleanup_heap;
-    /* Create events for start/stop helper process. */
-    hello = CreateEvent (&sec_none, true, false, NULL);
-    goodbye = CreateEvent (&sec_none, true, false, NULL);
-    /* Create a pipe for receiving pseudo console handles */
-    CreatePipe (&hr, &hw, &sec_none, 0);
-    /* Inherit only handles which are needed by helper. */
-    HANDLE handles_to_inherit[] = {hello, goodbye, hw};
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
-				    handles_to_inherit,
-				    sizeof (handles_to_inherit),
-				    NULL, NULL))
-      goto cleanup_event_and_pipes;
-    /* Create helper process */
-    WCHAR cmd[MAX_PATH];
-    path_conv helper ("/bin/cygwin-console-helper.exe");
-    size_t len = helper.get_wide_win32_path_len ();
-    helper.get_wide_win32_path (cmd);
-    __small_swprintf (cmd + len, L" %p %p %p", hello, goodbye, hw);
-    si_helper.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
-    si_helper.StartupInfo.hStdInput = NULL;
-    si_helper.StartupInfo.hStdOutput = NULL;
-    si_helper.StartupInfo.hStdError = NULL;
-    if (!CreateProcessW (NULL, cmd, &sec_none, &sec_none,
-			 TRUE, EXTENDED_STARTUPINFO_PRESENT,
-			 NULL, NULL, &si_helper.StartupInfo, &pi_helper))
-      goto cleanup_event_and_pipes;
-    for (;;)
-      {
-        DWORD wait_result = WaitForSingleObject (hello, 500);
-	if (wait_result == WAIT_OBJECT_0)
-	  break;
-	if (wait_result != WAIT_TIMEOUT)
-	  goto cleanup_helper_process;
-	DWORD exit_code;
-	if (!GetExitCodeProcess(pi_helper.hProcess, &exit_code))
-	  goto cleanup_helper_process;
-	if (exit_code == STILL_ACTIVE)
-	  continue;
-	if (exit_code != 0 ||
-	    WaitForSingleObject (hello, 500) != WAIT_OBJECT_0)
-	  goto cleanup_helper_process;
-	break;
-      }
-    CloseHandle (hello);
-    CloseHandle (pi_helper.hThread);
-    /* Retrieve pseudo console handles */
-    DWORD rLen;
-    char buf[64];
-    if (!ReadFile (hr, buf, sizeof (buf), &rLen, NULL))
-      goto cleanup_helper_process;
-    buf[rLen] = '\0';
-    sscanf (buf, "StdHandles=%p,%p", &hpConIn, &hpConOut);
-    if (!DuplicateHandle (pi_helper.hProcess, hpConIn,
-			  GetCurrentProcess (), &hpConIn, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_helper_process;
-    if (!DuplicateHandle (pi_helper.hProcess, hpConOut,
-			  GetCurrentProcess (), &hpConOut, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_pcon_in;
-    CloseHandle (hr);
-    CloseHandle (hw);
-    /* Clean up */
-    DeleteProcThreadAttributeList (si_helper.lpAttributeList);
-    HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-  }
-  /* Setting information of stuffs regarding pseudo console */
-  get_ttyp ()->h_helper_goodbye = goodbye;
-  get_ttyp ()->h_helper_process = pi_helper.hProcess;
-  get_ttyp ()->helper_process_id = pi_helper.dwProcessId;
-  CloseHandle (from_master);
-  CloseHandle (to_master);
-  from_master = hpConIn;
-  to_master = hpConOut;
-  ResizePseudoConsole (get_ttyp ()->h_pseudo_console, size);
-  return true;
-
-cleanup_pcon_in:
-  CloseHandle (hpConIn);
-cleanup_helper_process:
-  SetEvent (goodbye);
-  WaitForSingleObject (pi_helper.hProcess, INFINITE);
-  CloseHandle (pi_helper.hProcess);
-  goto skip_close_hello;
-cleanup_event_and_pipes:
-  CloseHandle (hello);
-skip_close_hello:
-  CloseHandle (goodbye);
-  CloseHandle (hr);
-  CloseHandle (hw);
-cleanup_heap:
-  HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-cleanup_pseudo_console:
-  {
-    HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
-    HANDLE tmp = hp->hConHostProcess;
-    ClosePseudoConsole (get_pseudo_console ());
-    CloseHandle (tmp);
-  }
-fallback:
-  CloseHandle (from_master);
-  CloseHandle (to_slave);
-  from_master = from_master_cyg;
-  to_slave = NULL;
-  get_ttyp ()->h_pseudo_console = NULL;
-  return false;
-}
-
 bool
 fhandler_pty_master::setup ()
 {
@@ -3593,11 +2261,6 @@ fhandler_pty_master::setup ()
   if (unit < 0)
     return false;
 
-  /* from_master should be used for pseudo console.
-     Just copy from_master_cyg here for the case that
-     pseudo console is not available. */
-  from_master = from_master_cyg;
-
   ProtectHandle1 (get_output_handle (), to_pty);
 
   tty& t = *cygwin_shared->tty[unit];
@@ -3696,15 +2359,21 @@ fhandler_pty_master::setup ()
       goto err;
     }
 
-  t.winsize.ws_col = 80;
-  t.winsize.ws_row = 25;
-
-  setup_pseudoconsole ();
+  __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;
+    }
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
   t.set_to_master (to_master);
   t.set_to_master_cyg (to_master_cyg);
+  t.winsize.ws_col = 80;
+  t.winsize.ws_row = 25;
   t.master_pid = myself->pid;
 
   dev ().parse (DEV_PTYM_MAJOR, unit);
@@ -3717,6 +2386,7 @@ fhandler_pty_master::setup ()
 err:
   __seterrno ();
   close_maybe (from_slave);
+  close_maybe (to_slave);
   close_maybe (get_handle ());
   close_maybe (get_output_handle ());
   close_maybe (input_available_event);
@@ -3776,9 +2446,6 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 {
   ssize_t towrite = len;
   BOOL res = TRUE;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
   while (towrite)
     {
       if (!is_echo)
@@ -3801,7 +2468,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
       if (!(get_ttyp ()->ti.c_oflag & OPOST))	// raw output mode
 	{
 	  DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
-	  res = WriteFunc (h, ptr, n, &n, NULL);
+	  res = WriteFile (h, ptr, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + n;
@@ -3851,7 +2518,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 		  break;
 		}
 	    }
-	  res = WriteFunc (h, outbuf, n, &n, NULL);
+	  res = WriteFile (h, outbuf, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + rc;
@@ -3861,3 +2528,125 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole (STARTUPINFOEXW *si)
+{
+  if (get_ttyp ()->pcon_pid && pinfo (get_ttyp ()->pcon_pid))
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     1, &get_ttyp ()->h_pseudo_console);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console,
+				  sizeof (get_ttyp ()->h_pseudo_console),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_base *fh0 = ::cygheap->fdtab[0];
+    if (fh0 && fh0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = fh0->get_handle ();
+    fhandler_base *fh1 = ::cygheap->fdtab[1];
+    if (fh1 && fh1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = fh1->get_output_handle ();
+    fhandler_base *fh2 = ::cygheap->fdtab[2];
+    if (fh2 && fh2->get_device () != get_device ())
+      si->StartupInfo.hStdError = fh2->get_output_handle ();
+
+    if (fh0 && fh0->get_major () == DEV_PTYS_MAJOR)
+      {
+	fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh0;
+	ptys->get_ttyp ()->switch_to_pcon_in = true;
+	if (ptys->get_ttyp ()->pcon_pid == 0 ||
+	    !pinfo (ptys->get_ttyp ()->pcon_pid))
+	  ptys->get_ttyp ()->pcon_pid = myself->pid;
+      }
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole (void)
+{
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      get_ttyp ()->wait_pcon_fwd ();
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+      get_ttyp ()->pcon_start = false;
+    }
+}
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 691d08137..6ca4b5f29 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -134,36 +134,6 @@ child_info::prefork (bool detached)
 int __stdcall
 frok::child (volatile char * volatile here)
 {
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR)
-      {
-	fhandler_base *fh = cfd;
-	fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
-	if (ptym->get_pseudo_console ())
-	  {
-	    debug_printf ("found a PTY master %d: helper_PID=%d",
-			  ptym->get_minor (), ptym->get_helper_process_id ());
-	    if (fhandler_console::get_console_process_id (
-				ptym->get_helper_process_id (), true))
-	      /* Already attached */
-	      break;
-	    else
-	      {
-		if (ptym->attach_pcon_in_fork ())
-		  {
-		    FreeConsole ();
-		    if (!AttachConsole (ptym->get_helper_process_id ()))
-		      /* Error */;
-		    else
-		      break;
-		  }
-	      }
-	  }
-      }
-  extern void clear_pcon_attached_to (void); /* fhandler_tty.cc */
-  clear_pcon_attached_to ();
-
   HANDLE& hParent = ch.parent;
 
   sync_with_parent ("after longjmp", true);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 3f3f33fb5..93acdd89a 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1213,8 +1213,7 @@ verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds,
 	   fd_set *exceptfds)
 {
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) me->fh;
-  if (me->read_selected && !ptys->to_be_read_from_pcon () &&
-      IsEventSignalled (ptys->input_available_event))
+  if (me->read_selected && IsEventSignalled (ptys->input_available_event))
     me->read_ready = true;
   return set_bits (me, readfds, writefds, exceptfds);
 }
@@ -1227,8 +1226,6 @@ peek_pty_slave (select_record *s, bool from_select)
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
 
   ptys->reset_switch_to_pcon ();
-  if (ptys->to_be_read_from_pcon ())
-    ptys->update_pcon_input_state (true);
 
   if (s->read_selected)
     {
diff --git a/winsup/cygwin/smallprint.cc b/winsup/cygwin/smallprint.cc
index 26d34d9e4..f208a057a 100644
--- a/winsup/cygwin/smallprint.cc
+++ b/winsup/cygwin/smallprint.cc
@@ -405,7 +405,6 @@ small_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
   WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, NULL);
   FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
 }
@@ -432,7 +431,6 @@ console_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (console_handle);
   WriteFile (console_handle, buf, count, &done, NULL);
   FlushFileBuffers (console_handle);
 }
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..a3071884e 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -259,8 +277,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 {
   bool rc;
   int res = -1;
-  DWORD pid_restore = 0;
-  bool attach_to_console = false;
   pid_t ctty_pgid = 0;
 
   /* Search for CTTY and retrieve its PGID */
@@ -580,9 +596,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			 PROCESS_QUERY_LIMITED_INFORMATION))
 	sa = &sec_none_nih;
 
-      /* Attach to pseudo console if pty salve is used */
-      pid_restore = fhandler_console::get_console_process_id
-	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -591,29 +605,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	      if (ptys->get_pseudo_console ())
-		{
-		  DWORD helper_process_id = ptys->get_helper_process_id ();
-		  debug_printf ("found a PTY slave %d: helper_PID=%d",
-				    fh->get_minor (), helper_process_id);
-		  if (fhandler_console::get_console_process_id
-					      (helper_process_id, true))
-		    /* Already attached */
-		    attach_to_console = true;
-		  else if (!attach_to_console)
-		    {
-		      FreeConsole ();
-		      if (AttachConsole (helper_process_id))
-			attach_to_console = true;
-		    }
-		  ptys->fixup_after_attach (!iscygwin (), fd);
-		  if (mode == _P_OVERLAY)
-		    ptys->set_freeconsole_on_close (iscygwin ());
-		}
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	    }
 	  else if (fh && fh->get_major () == DEV_CONS_MAJOR)
 	    {
-	      attach_to_console = true;
 	      fhandler_console *cons = (fhandler_console *) fh;
 	      if (wincap.has_con_24bit_colors () && !iscygwin ())
 		if (fd == 1 || fd == 2)
@@ -632,6 +628,18 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool enable_pcon = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole (&si_pcon))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    enable_pcon = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +668,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +722,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +735,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (enable_pcon)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +910,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (enable_pcon)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->close_pseudoconsole ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
@@ -930,21 +948,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
   if (envblock)
     free (envblock);
 
-  if (attach_to_console && pid_restore)
-    {
-      FreeConsole ();
-      AttachConsole (pid_restore);
-      cygheap_fdenum cfd (false);
-      int fd;
-      while ((fd = cfd.next ()) >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_pty_slave *ptys =
-	      (fhandler_pty_slave *) (fhandler_base *) cfd;
-	    ptys->fixup_after_attach (false, fd);
-	  }
-    }
-
   return (int) res;
 }
 
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index f0aef3a36..35f8a59ae 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -264,7 +264,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
   if (category & _STRACE_SYSTEM)
     {
       DWORD done;
-      set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
       WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
       FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
       /* Make sure that the message shows up on the screen, too, since this is
@@ -276,7 +275,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
 				 &sec_none, OPEN_EXISTING, 0, 0);
 	  if (h != INVALID_HANDLE_VALUE)
 	    {
-	      set_ishybrid_and_switch_to_pcon (h);
 	      WriteFile (h, buf, len, &done, 0);
 	      CloseHandle (h);
 	    }
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 4cb68f776..d60f27545 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -234,20 +234,14 @@ tty::init ()
   was_opened = false;
   master_pid = 0;
   is_console = false;
-  attach_pcon_in_fork = false;
-  h_pseudo_console = NULL;
   column = 0;
+  h_pseudo_console = NULL;
   switch_to_pcon_in = false;
-  switch_to_pcon_out = false;
-  screen_alternated = false;
   mask_switch_to_pcon_in = false;
   pcon_pid = 0;
   term_code_page = 0;
-  need_redraw_screen = true;
   pcon_last_time = 0;
-  pcon_in_empty = true;
-  req_transfer_input_to_pcon = false;
-  req_flush_pcon_input = false;
+  pcon_start = false;
 }
 
 HANDLE
@@ -293,16 +287,6 @@ tty_min::ttyname ()
   return d.name ();
 }
 
-void
-tty::set_switch_to_pcon_out (bool v)
-{
-  if (switch_to_pcon_out != v)
-    {
-      wait_pcon_fwd ();
-      switch_to_pcon_out = v;
-    }
-}
-
 void
 tty::wait_pcon_fwd (void)
 {
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 920e32b16..c491d3891 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -94,21 +94,13 @@ private:
   HANDLE _to_master;
   HANDLE _to_master_cyg;
   HPCON h_pseudo_console;
-  HANDLE h_helper_process;
-  DWORD helper_process_id;
-  HANDLE h_helper_goodbye;
-  bool attach_pcon_in_fork;
+  bool pcon_start;
   bool switch_to_pcon_in;
-  bool switch_to_pcon_out;
-  bool screen_alternated;
   bool mask_switch_to_pcon_in;
   pid_t pcon_pid;
   UINT term_code_page;
-  bool need_redraw_screen;
   DWORD pcon_last_time;
-  bool pcon_in_empty;
-  bool req_transfer_input_to_pcon;
-  bool req_flush_pcon_input;
+  HANDLE h_pcon_write_pipe;
 
 public:
   HANDLE from_master () const { return _from_master; }
@@ -138,7 +130,6 @@ public:
   void set_master_ctl_closed () {master_pid = -1;}
   static void __stdcall create_master (int);
   static void __stdcall init_session ();
-  void set_switch_to_pcon_out (bool v);
   void wait_pcon_fwd (void);
   friend class fhandler_pty_common;
   friend class fhandler_pty_master;
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index fff7d18f3..458fb2a23 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -222,9 +222,6 @@ void init_console_handler (bool);
 
 extern bool wsock_started;
 
-/* PTY related */
-void set_ishybrid_and_switch_to_pcon (HANDLE h);
-
 /* Printf type functions */
 extern "C" void vapi_fatal (const char *, va_list ap) __attribute__ ((noreturn));
 extern "C" void api_fatal (const char *, ...) __attribute__ ((noreturn));
-- 
2.27.0


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-24  5:38                               ` Takashi Yano
@ 2020-07-24 11:22                                 ` Takashi Yano
  2020-08-02 12:01                                   ` Corinna Vinschen
  2020-08-03  2:11                                   ` Takashi Yano
  0 siblings, 2 replies; 73+ messages in thread
From: Takashi Yano @ 2020-07-24 11:22 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 2748 bytes --]

On Fri, 24 Jul 2020 14:38:42 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Thu, 23 Jul 2020 09:33:28 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Wed, 22 Jul 2020 17:45:41 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Wed, 22 Jul 2020 03:17:51 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > Hi Corinna,
> > > > 
> > > > On Mon, 20 Jul 2020 10:06:13 +0200
> > > > Corinna Vinschen wrote:
> > > > > On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
> > > > > > Hi Corinna,
> > > > > > 
> > > > > > On Fri, 17 Jul 2020 13:19:12 +0200
> > > > > > Corinna Vinschen wrote:
> > > > > > > Hi Takashi,
> > > > > > > 
> > > > > > > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > > > > > > > [...]
> > > > > > > > Revise the patch to fit the current git head.
> > > > > > > 
> > > > > > > are you satisfied with the code?  If you want to merge it,
> > > > > > > I'd bump Cygwin to 3.2.
> > > > > > 
> > > > > > Since this new implementation has both advantages and disadvantages,
> > > > > > there might be some options.
> > > > > > 
> > > > > > 1) Default to new implementation and leave the current one as an
> > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > 2) Default to current implementation and add the new one as an
> > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > 3) Adopt only new implementation and throw the current one away.
> > > > > > 
> > > > > > What do you think?
> > > > > 
> > > > > Do you really want to maintain twice as much code doing the same stuff
> > > > > and constantly having to ask users which version of the code they are
> > > > > running?  The maintenance cost outweighs the advantages, IMHO.
> > > > > Personally I'd go for option 3.
> > > > 
> > > > Personally, I feel a tinge of sadness to discard the current code,
> > > > however, your opinion sounds reasonable.
> > > > 
> > > > I will submit a new patch in which all the codes specific to the
> > > > current implementation are removed.
> > > 
> > > Attached is the patch in git format-patch format.
> > > All the codes specific to the current implementation are removed.
> > > 
> > > Despite the utmost care, the changes are relatively large, so some
> > > degradation may exist.
> > > 
> > > I will appreciate if you could test.
> > 
> > There were still unused code. Please try attached patch instead.
> 
> Changes:
> * Do not activate pseudo console if it is already activated for
>   another process on same pty.

Changes:
* Fix a bug in the latest change.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-Cygwin-pty-Implement-new-pseudo-console-support.patch --]
[-- Type: application/octet-stream, Size: 89197 bytes --]

From e5870f8ffb3963b480963c31bce4049e3e57fdde Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Fri, 24 Jul 2020 20:17:36 +0900
Subject: [PATCH] Cygwin: pty: Implement new pseudo console support.

- In this implementation, pseudo console is created for each native
  console app. Advantages and disadvantages of this implementation
  over the previous implementation are as follows.

  Advantages:
  1) No performance degradation in pty output for cygwin process.
      https://cygwin.com/pipermail/cygwin/2020-February/243858.html
  2) Free from the problem caused by difference of behaviour of control
     sequences between real terminal and pseudo console.
      https://cygwin.com/pipermail/cygwin/2019-December/243281.html
      https://cygwin.com/pipermail/cygwin/2020-February/243855.html
  3) Free from the problem in cgdb and emacs gud.
      https://cygwin.com/pipermail/cygwin/2020-January/243601.html
      https://cygwin.com/pipermail/cygwin/2020-March/244146.html
  4) Redrawing screen on executing native console apps is not necessary.
  5) cygwin-console-helper is not necessary for the pseudo console
     support.
  6) The codes for pseudo console support are much simpler than that
     of the previous one.

  Disadvantages:
  1) The cygwin program which calls console API directly does not work.
  2) The apps which use console API cannot be debugged with gdb. This
     is because pseudo console is not activated since gdb uses
     CreateProcess() rather than exec(). Even with this limitation,
     attaching gdb to native apps, in which pseudo console is already
     activated, works.
  3) Typeahead key inputs are discarded while native console app is
     executed. Simirally, typeahead key inputs while cygwin app is
     executed are not inherited to native console app.
  4) Code page cannot be changed by chcp.com. Acctually, chcp works
     itself and changes code page of its own pseudo console.  However,
     since pseudo console is recreated for another process, it cannot
     inherit the code page.
  5) system_printf() does not work after stderr is closed. (Same with
     cygwin 3.0.7)
  6) Startup time of native console apps is about 3 times slower than
     previous implemenation.
  7) Pseudo console cannot be activated if it is already activated for
     another process on same pty.
---
 winsup/cygwin/dtable.cc           |   32 -
 winsup/cygwin/fhandler.h          |   53 +-
 winsup/cygwin/fhandler_console.cc |   43 -
 winsup/cygwin/fhandler_tty.cc     | 1770 +++++------------------------
 winsup/cygwin/fork.cc             |   30 -
 winsup/cygwin/select.cc           |    5 +-
 winsup/cygwin/smallprint.cc       |    2 -
 winsup/cygwin/spawn.cc            |   87 +-
 winsup/cygwin/strace.cc           |    2 -
 winsup/cygwin/tty.cc              |   20 +-
 winsup/cygwin/tty.h               |   13 +-
 winsup/cygwin/winsup.h            |    3 -
 12 files changed, 341 insertions(+), 1719 deletions(-)

diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index e9e005b08..6a91e33bc 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -147,38 +147,6 @@ dtable::get_debugger_info ()
 void
 dtable::stdio_init ()
 {
-  for (int i = 0; i < 3; i ++)
-    {
-      const int chk_order[] = {1, 0, 2};
-      int fd = chk_order[i];
-      fhandler_base *fh = cygheap->fdtab[fd];
-      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
-	{
-	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	  if (ptys->get_pseudo_console ())
-	    {
-	      bool attached = !!fhandler_console::get_console_process_id
-		(ptys->get_helper_process_id (), true);
-	      if (attached)
-		break;
-	      else
-		{
-		  /* Not attached to pseudo console in fork() or spawn()
-		     by some reason. This happens if the executable is
-		     a windows GUI binary, such as mintty. */
-		  FreeConsole ();
-		  if (AttachConsole (ptys->get_helper_process_id ()))
-		    {
-		      ptys->fixup_after_attach (false, fd);
-		      break;
-		    }
-		}
-	    }
-	}
-      else if (fh && fh->get_major () == DEV_CONS_MAJOR)
-	break;
-    }
-
   if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT))
     {
       tty_min *t = cygwin_shared->tty.get_cttyp ();
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 60bd27e00..4604ff2ba 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -326,16 +326,16 @@ class fhandler_base
   virtual size_t &raixput () { return ra.raixput; };
   virtual size_t &rabuflen () { return ra.rabuflen; };
 
-  virtual bool get_readahead_valid () { return raixget () < ralen (); }
+  bool get_readahead_valid () { return raixget () < ralen (); }
   int puts_readahead (const char *s, size_t len = (size_t) -1);
-  virtual int put_readahead (char value);
+  int put_readahead (char value);
 
   int get_readahead ();
   int peek_readahead (int queryput = 0);
 
   void set_readahead_valid (int val, int ch = -1);
 
-  virtual int get_readahead_into_buffer (char *buf, size_t buflen);
+  int get_readahead_into_buffer (char *buf, size_t buflen);
 
   bool has_acls () const { return pc.has_acls (); }
 
@@ -1909,7 +1909,7 @@ class fhandler_termios: public fhandler_base
   int ioctl (int, void *);
   tty_min *_tc;
   tty *get_ttyp () {return (tty *) tc ();}
-  virtual int eat_readahead (int n);
+  int eat_readahead (int n);
 
  public:
   tty_min*& tc () {return _tc;}
@@ -2188,7 +2188,6 @@ private:
   static bool need_invisible ();
   static void free_console ();
   static const char *get_nonascii_key (INPUT_RECORD& input_rec, char *);
-  static DWORD get_console_process_id (DWORD pid, bool match);
 
   fhandler_console (void *) {}
 
@@ -2268,19 +2267,7 @@ class fhandler_pty_common: public fhandler_termios
     return fh;
   }
 
-  bool attach_pcon_in_fork (void)
-  {
-    return get_ttyp ()->attach_pcon_in_fork;
-  }
-  DWORD get_helper_process_id (void)
-  {
-    return get_ttyp ()->helper_process_id;
-  }
-  HPCON get_pseudo_console (void)
-  {
-    return get_ttyp ()->h_pseudo_console;
-  }
-  bool to_be_read_from_pcon (void);
+  void resize_pseudo_console (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2291,23 +2278,15 @@ class fhandler_pty_slave: public fhandler_pty_common
 {
   HANDLE inuse;			// used to indicate that a tty is in use
   HANDLE output_handle_cyg, io_handle_cyg;
-  DWORD pid_restore;
-  int fd;
 
   /* Helper functions for fchmod and fchown. */
   bool fch_open_handles (bool chown);
   int fch_set_sd (security_descriptor &sd, bool chown);
   void fch_close_handles ();
 
-  bool try_reattach_pcon ();
-  void restore_reattach_pcon ();
-  inline void free_attached_console ();
-
  public:
   /* Constructor */
   fhandler_pty_slave (int);
-  /* Destructor */
-  ~fhandler_pty_slave ();
 
   void set_output_handle_cyg (HANDLE h) { output_handle_cyg = h; }
   HANDLE& get_output_handle_cyg () { return output_handle_cyg; }
@@ -2319,9 +2298,6 @@ class fhandler_pty_slave: public fhandler_pty_common
   ssize_t __stdcall write (const void *ptr, size_t len);
   void __reg3 read (void *ptr, size_t& len);
   int init (HANDLE, DWORD, mode_t);
-  int eat_readahead (int n);
-  int get_readahead_into_buffer (char *buf, size_t buflen);
-  bool get_readahead_valid (void);
 
   int tcsetattr (int a, const struct termios *t);
   int tcgetattr (struct termios *t);
@@ -2358,20 +2334,12 @@ class fhandler_pty_slave: public fhandler_pty_common
     copyto (fh);
     return fh;
   }
-  void set_switch_to_pcon (int fd);
+  bool setup_pseudoconsole (STARTUPINFOEXW *si);
+  void close_pseudoconsole (void);
+  void set_switch_to_pcon (void);
   void reset_switch_to_pcon (void);
-  void push_to_pcon_screenbuffer (const char *ptr, size_t len, bool is_echo);
   void mask_switch_to_pcon_in (bool mask);
-  void fixup_after_attach (bool native_maybe, int fd);
-  bool is_line_input (void)
-  {
-    return get_ttyp ()->ti.c_lflag & ICANON;
-  }
   void setup_locale (void);
-  void set_freeconsole_on_close (bool val);
-  void trigger_redraw_screen (void);
-  void pull_pcon_input (void);
-  void update_pcon_input_state (bool need_lock);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
@@ -2396,7 +2364,6 @@ public:
   int process_slave_output (char *buf, size_t len, int pktmode_on);
   void doecho (const void *str, DWORD len);
   int accept_input ();
-  int put_readahead (char value);
   int open (int flags, mode_t mode = 0);
   void open_setup (int flags);
   ssize_t __stdcall write (const void *ptr, size_t len);
@@ -2435,9 +2402,7 @@ public:
     copyto (fh);
     return fh;
   }
-
-  bool setup_pseudoconsole (void);
-  void transfer_input_to_pcon (void);
+  bool to_be_read_from_pcon (void);
 };
 
 class fhandler_dev_null: public fhandler_base
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 52741ce8b..02a5996a1 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -1206,18 +1206,6 @@ fhandler_console::close ()
   if (con_ra.rabuf)
     free (con_ra.rabuf);
 
-  /* If already attached to pseudo console, don't call free_console () */
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR ||
-	cfd->get_major () == DEV_PTYS_MAJOR)
-      {
-	fhandler_pty_common *t =
-	  (fhandler_pty_common *) (fhandler_base *) cfd;
-	if (get_console_process_id (t->get_helper_process_id (), true))
-	  return 0;
-      }
-
   if (!have_execed)
     free_console ();
   return 0;
@@ -3611,37 +3599,6 @@ fhandler_console::need_invisible ()
   return b;
 }
 
-DWORD
-fhandler_console::get_console_process_id (DWORD pid, bool match)
-{
-  DWORD tmp;
-  DWORD num, num_req;
-  num = 1;
-  num_req = GetConsoleProcessList (&tmp, num);
-  DWORD *list;
-  while (true)
-    {
-      list = (DWORD *)
-	HeapAlloc (GetProcessHeap (), 0, num_req * sizeof (DWORD));
-      num = num_req;
-      num_req = GetConsoleProcessList (list, num);
-      if (num_req > num)
-	HeapFree (GetProcessHeap (), 0, list);
-      else
-	break;
-    }
-  num = num_req;
-
-  tmp = 0;
-  for (DWORD i=0; i<num; i++)
-    if ((match && list[i] == pid) || (!match && list[i] != pid))
-      /* Last one is the oldest. */
-      /* https://github.com/microsoft/terminal/issues/95 */
-      tmp = list[i];
-  HeapFree (GetProcessHeap (), 0, list);
-  return tmp;
-}
-
 DWORD
 fhandler_console::__acquire_input_mutex (const char *fn, int ln, DWORD ms)
 {
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 6a004f3a5..410853550 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -25,7 +25,6 @@ details. */
 #include "child_info.h"
 #include <asm/socket.h>
 #include "cygwait.h"
-#include "tls_pbuf.h"
 #include "registry.h"
 
 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
@@ -33,7 +32,6 @@ details. */
 #endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
 
 extern "C" int sscanf (const char *, const char *, ...);
-extern "C" int ttyname_r (int, char*, size_t);
 
 extern "C" {
   HRESULT WINAPI CreatePseudoConsole (COORD, HANDLE, HANDLE, DWORD, HPCON *);
@@ -60,20 +58,10 @@ struct pipe_reply {
   DWORD error;
 };
 
-static int pcon_attached_to = -1;
 static bool isHybrid;
-static bool do_not_reset_switch_to_pcon;
-static bool freeconsole_on_close = true;
-static tty *last_ttyp = NULL;
-
-void
-clear_pcon_attached_to (void)
-{
-  pcon_attached_to = -1;
-}
 
 static void
-set_switch_to_pcon (void)
+set_switch_to_pcon (HANDLE h)
 {
   cygheap_fdenum cfd (false);
   int fd;
@@ -82,280 +70,17 @@ set_switch_to_pcon (void)
       {
 	fhandler_base *fh = cfd;
 	fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	if (ptys->get_pseudo_console ())
-	  {
-	    ptys->set_switch_to_pcon (fd);
-	    ptys->trigger_redraw_screen ();
-	    DWORD mode =
-	      ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	    SetConsoleMode (ptys->get_handle (), mode);
-	  }
+	if (h == ptys->get_handle ())
+	  ptys->set_switch_to_pcon ();
 	return;
       }
-  /* No pty slave opened */
-  if (last_ttyp) /* Make system_printf() work after closing pty slave */
-    last_ttyp->set_switch_to_pcon_out (true);
-}
-
-static void
-force_attach_to_pcon (HANDLE h)
-{
-  bool attach_done = false;
-  for (int n = 0; n < 2; n ++)
-    {
-      /* First time, attach to the pty whose handle value is match.
-	 Second time, try to attach to any pty. */
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	    if (!ptys->get_pseudo_console ())
-	      continue;
-	    if (n != 0
-		|| h == ptys->get_handle ()
-		|| h == ptys->get_output_handle ())
-	      {
-		if (fhandler_console::get_console_process_id
-				  (ptys->get_helper_process_id (), true))
-		  attach_done = true;
-		else
-		  {
-		    FreeConsole ();
-		    if (AttachConsole (ptys->get_helper_process_id ()))
-		      {
-			pcon_attached_to = ptys->get_minor ();
-			attach_done = true;
-		      }
-		    else
-		      pcon_attached_to = -1;
-		  }
-		break;
-	      }
-	  }
-	else if (cfd->get_major () == DEV_CONS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_console *cons = (fhandler_console *) fh;
-	    if (n != 0
-		|| h == cons->get_handle ()
-		|| h == cons->get_output_handle ())
-	      {
-		/* If the process is running on a console,
-		   the parent process should be attached
-		   to the same console. */
-		DWORD attach_wpid;
-		if (myself->ppid == 1)
-		  attach_wpid = ATTACH_PARENT_PROCESS;
-		else
-		  {
-		    pinfo p (myself->ppid);
-		    attach_wpid = p->dwProcessId;
-		  }
-		FreeConsole ();
-		if (AttachConsole (attach_wpid))
-		  {
-		    pcon_attached_to = -1;
-		    attach_done = true;
-		  }
-		else
-		  pcon_attached_to = -1;
-		break;
-	      }
-	  }
-      if (attach_done)
-	break;
-    }
-}
-
-void
-set_ishybrid_and_switch_to_pcon (HANDLE h)
-{
-  if (GetFileType (h) == FILE_TYPE_CHAR)
-    {
-      force_attach_to_pcon (h);
-      DWORD dummy;
-      if (!isHybrid && (GetConsoleMode (h, &dummy)
-			|| GetLastError () != ERROR_INVALID_HANDLE))
-	{
-	  isHybrid = true;
-	  set_switch_to_pcon ();
-	}
-    }
-}
-
-inline void
-fhandler_pty_slave::free_attached_console ()
-{
-  bool attached = get_ttyp () ?
-    fhandler_console::get_console_process_id (get_helper_process_id (), true)
-    : (get_minor () == pcon_attached_to);
-  if (freeconsole_on_close && attached)
-    {
-      FreeConsole ();
-      pcon_attached_to = -1;
-    }
 }
 
 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
-DEF_HOOK (WriteFile);
-DEF_HOOK (WriteConsoleA);
-DEF_HOOK (WriteConsoleW);
-DEF_HOOK (ReadFile);
-DEF_HOOK (ReadConsoleA);
-DEF_HOOK (ReadConsoleW);
-DEF_HOOK (WriteConsoleOutputA);
-DEF_HOOK (WriteConsoleOutputW);
-DEF_HOOK (WriteConsoleOutputCharacterA);
-DEF_HOOK (WriteConsoleOutputCharacterW);
-DEF_HOOK (WriteConsoleOutputAttribute);
-DEF_HOOK (SetConsoleCursorPosition);
-DEF_HOOK (SetConsoleTextAttribute);
-DEF_HOOK (WriteConsoleInputA);
-DEF_HOOK (WriteConsoleInputW);
-DEF_HOOK (ReadConsoleInputA);
-DEF_HOOK (ReadConsoleInputW);
-DEF_HOOK (PeekConsoleInputA);
-DEF_HOOK (PeekConsoleInputW);
 /* CreateProcess() is hooked for GDB etc. */
 DEF_HOOK (CreateProcessA);
 DEF_HOOK (CreateProcessW);
 
-static BOOL WINAPI
-WriteFile_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleA_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleW_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadFile_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleA_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleW_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleOutputA_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputA_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputW_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputW_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterA_Hooked
-     (HANDLE h, LPCSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterA_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterW_Hooked
-     (HANDLE h, LPCWSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterW_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputAttribute_Hooked
-     (HANDLE h, CONST WORD *a, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputAttribute_Orig (h, a, l, c, n);
-}
-static BOOL WINAPI
-SetConsoleCursorPosition_Hooked
-     (HANDLE h, COORD c)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleCursorPosition_Orig (h, c);
-}
-static BOOL WINAPI
-SetConsoleTextAttribute_Hooked
-     (HANDLE h, WORD a)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleTextAttribute_Orig (h, a);
-}
-static BOOL WINAPI
-WriteConsoleInputA_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-WriteConsoleInputW_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputW_Orig (h, r, l, n);
-}
-/* CreateProcess() is hooked for GDB etc. */
 static BOOL WINAPI
 CreateProcessA_Hooked
      (LPCSTR n, LPSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
@@ -363,11 +88,14 @@ CreateProcessA_Hooked
       LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 static BOOL WINAPI
@@ -377,11 +105,14 @@ CreateProcessW_Hooked
       LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 
@@ -464,10 +195,6 @@ fhandler_pty_master::flush_to_slave ()
 {
   if (get_readahead_valid () && !(get_ttyp ()->ti.c_lflag & ICANON))
     accept_input ();
-  WaitForSingleObject (input_mutex, INFINITE);
-  if (!get_ttyp ()->pcon_in_empty && !(get_ttyp ()->ti.c_lflag & ICANON))
-    SetEvent (input_available_event);
-  ReleaseMutex (input_mutex);
 }
 
 DWORD
@@ -532,14 +259,6 @@ fhandler_pty_master::doecho (const void *str, DWORD len)
   release_output_mutex ();
 }
 
-int
-fhandler_pty_master::put_readahead (char value)
-{
-  if (to_be_read_from_pcon ())
-    return 1;
-  return fhandler_base::put_readahead (value);
-}
-
 int
 fhandler_pty_master::accept_input ()
 {
@@ -551,9 +270,11 @@ fhandler_pty_master::accept_input ()
   char *p = rabuf () + raixget ();
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
   if (to_be_read_from_pcon ())
-    ; /* Do nothing */
-  else if (!bytes_left)
+    write_to = to_slave;
+
+  if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
@@ -564,10 +285,10 @@ fhandler_pty_master::accept_input ()
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -725,52 +446,12 @@ out:
 
 fhandler_pty_slave::fhandler_pty_slave (int unit)
   : fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL),
-  io_handle_cyg (NULL), pid_restore (0), fd (-1)
+  io_handle_cyg (NULL)
 {
   if (unit >= 0)
     dev ().parse (DEV_PTYS_MAJOR, unit);
 }
 
-fhandler_pty_slave::~fhandler_pty_slave ()
-{
-  if (!get_ttyp ())
-    {
-      /* Why comes here? Who clears _tc? */
-      free_attached_console ();
-      return;
-    }
-  if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 0)
-	{
-	  pcon_attached_to = -1;
-	  last_ttyp = get_ttyp ();
-	}
-      if (used == 0)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
-}
-
 int
 fhandler_pty_slave::open (int flags, mode_t)
 {
@@ -833,8 +514,8 @@ fhandler_pty_slave::open (int flags, mode_t)
     release_output_mutex ();
   }
 
-  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg () ||
-      !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
+  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg ()
+      || !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
     {
       errmsg = "pty handles have been closed";
       set_errno (EACCES);
@@ -923,8 +604,8 @@ fhandler_pty_slave::open (int flags, mode_t)
       from_master_cyg_local = repl.from_master_cyg;
       to_master_local = repl.to_master;
       to_master_cyg_local = repl.to_master_cyg;
-      if (!from_master_local || !from_master_cyg_local ||
-	  !to_master_local || !to_master_cyg_local)
+      if (!from_master_local || !from_master_cyg_local
+	  || !to_master_local || !to_master_cyg_local)
 	{
 	  SetLastError (repl.error);
 	  errmsg = "error duplicating pipes, %E";
@@ -950,24 +631,7 @@ fhandler_pty_slave::open (int flags, mode_t)
   set_output_handle (to_master_local);
   set_output_handle_cyg (to_master_cyg_local);
 
-  if (!get_pseudo_console ())
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (!fhandler_console::get_console_process_id
-			       (GetCurrentProcessId (), true))
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (fhandler_console::get_console_process_id
-			       (get_helper_process_id (), true))
-    /* Attached to pcon of this pty */
-    {
-      pcon_attached_to = get_minor ();
-      init_console_handler (true);
-    }
+  fhandler_console::need_invisible ();
 
   set_open_status ();
   return 1;
@@ -1021,8 +685,7 @@ fhandler_pty_slave::close ()
   if (!ForceCloseHandle (get_handle_cyg ()))
     termios_printf ("CloseHandle (get_handle_cyg ()<%p>), %E",
 	get_handle_cyg ());
-  if (!get_pseudo_console () &&
-      (unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
+  if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
     fhandler_console::free_console ();	/* assumes that we are the last pty closer */
   fhandler_pty_common::close ();
   if (!ForceCloseHandle (output_mutex))
@@ -1070,423 +733,31 @@ fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
   return ret;
 }
 
-bool
-fhandler_pty_slave::try_reattach_pcon (void)
-{
-  pid_restore = 0;
-
-  /* Do not detach from the console because re-attaching will
-     fail if helper process is running as service account. */
-  if (get_ttyp()->attach_pcon_in_fork)
-    return false;
-  if (pcon_attached_to >= 0 &&
-      cygwin_shared->tty[pcon_attached_to]->attach_pcon_in_fork)
-    return false;
-
-  pid_restore =
-    fhandler_console::get_console_process_id (GetCurrentProcessId (),
-					      false);
-  /* If pid_restore is not set, give up. */
-  if (!pid_restore)
-    return false;
-
-  FreeConsole ();
-  if (!AttachConsole (get_helper_process_id ()))
-    {
-      system_printf ("pty%d: AttachConsole(helper=%d) failed. 0x%08lx",
-		     get_minor (), get_helper_process_id (), GetLastError ());
-      return false;
-    }
-  return true;
-}
-
-void
-fhandler_pty_slave::restore_reattach_pcon (void)
-{
-  if (pid_restore)
-    {
-      FreeConsole ();
-      if (!AttachConsole (pid_restore))
-	{
-	  system_printf ("pty%d: AttachConsole(restore=%d) failed. 0x%08lx",
-			 get_minor (), pid_restore, GetLastError ());
-	  pcon_attached_to = -1;
-	}
-    }
-  pid_restore = 0;
-}
-
-/* This function requests transfering the input data from the input
-   pipe for cygwin apps to the other input pipe for native apps. */
-void
-fhandler_pty_slave::pull_pcon_input (void)
-{
-  get_ttyp ()->req_transfer_input_to_pcon = true;
-  while (get_ttyp ()->req_transfer_input_to_pcon)
-    Sleep (1);
-}
-
 void
-fhandler_pty_slave::update_pcon_input_state (bool need_lock)
+fhandler_pty_slave::set_switch_to_pcon (void)
 {
-  if (need_lock)
-    WaitForSingleObject (input_mutex, INFINITE);
-  /* Flush input buffer if it is requested by master.
-     This happens if ^C is pressed in pseudo console side. */
-  if (get_ttyp ()->req_flush_pcon_input)
+  if (!get_ttyp ()->switch_to_pcon_in)
     {
-      FlushConsoleInputBuffer (get_handle ());
-      get_ttyp ()->req_flush_pcon_input = false;
-    }
-  /* Peek console input buffer and update state. */
-  INPUT_RECORD inp[INREC_SIZE];
-  DWORD n;
-  BOOL (WINAPI *PeekFunc)
-    (HANDLE, PINPUT_RECORD, DWORD, LPDWORD);
-  PeekFunc =
-    PeekConsoleInputA_Orig ? : PeekConsoleInput;
-  PeekFunc (get_handle (), inp, INREC_SIZE, &n);
-  bool saw_accept = false;
-  bool pipe_empty = true;
-  while (n-- > 0)
-    if (inp[n].EventType == KEY_EVENT && inp[n].Event.KeyEvent.bKeyDown &&
-	inp[n].Event.KeyEvent.uChar.AsciiChar)
-      {
-	pipe_empty = false;
-	char c = inp[n].Event.KeyEvent.uChar.AsciiChar;
-	const char sigs[] = {
-	  (char) get_ttyp ()->ti.c_cc[VINTR],
-	  (char) get_ttyp ()->ti.c_cc[VQUIT],
-	  (char) get_ttyp ()->ti.c_cc[VSUSP],
-	};
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n',
-	  '\r'
-	};
-	if (is_line_input () && c && memchr (eols, c, sizeof (eols)))
-	  saw_accept = true;
-	if ((get_ttyp ()->ti.c_lflag & ISIG)
-	    && c && memchr (sigs, c, sizeof (sigs)))
-	  saw_accept = true;
-      }
-  get_ttyp ()->pcon_in_empty = pipe_empty && !(ralen () > raixget ());
-  if (!get_readahead_valid () &&
-      (pipe_empty || (is_line_input () && !saw_accept)) &&
-      get_ttyp ()->read_retval == 1 && bytes_available (n) && n == 0)
-    ResetEvent (input_available_event);
-  if (need_lock)
-    ReleaseMutex (input_mutex);
-}
-
-int
-fhandler_pty_slave::eat_readahead (int n)
-{
-  int oralen = ralen ();
-  if (n < 0)
-    n = ralen () - raixget ();
-  if (n > 0 && ralen () > raixget ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      while (n > 0 && ralen () > raixget ())
-	{
-	  if (is_line_input () && rabuf ()[ralen ()-1]
-	      && memchr (eols, rabuf ()[ralen ()-1], sizeof (eols)))
-	    break;
-	  -- n;
-	  -- ralen ();
-	}
-
-      /* If IUTF8 is set, the terminal is in UTF-8 mode.  If so, we erase
-	 a complete UTF-8 multibyte sequence on VERASE/VWERASE.  Otherwise,
-	 if we only erase a single byte, invalid unicode chars are left in
-	 the input. */
-      if (get_ttyp ()->ti.c_iflag & IUTF8)
-	while (ralen () > raixget () &&
-	       ((unsigned char) rabuf ()[ralen ()] & 0xc0) == 0x80)
-	  --ralen ();
-    }
-  oralen = oralen - ralen ();
-  if (raixget () >= ralen ())
-    raixget () = raixput () = ralen () = 0;
-  else if (raixput () > ralen ())
-    raixput () = ralen ();
-
-  return oralen;
-}
-
-int
-fhandler_pty_slave::get_readahead_into_buffer (char *buf, size_t buflen)
-{
-  int ch;
-  int copied_chars = 0;
-
-  while (buflen)
-    if ((ch = get_readahead ()) < 0)
-      break;
-    else
-      {
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n'
-	};
-	buf[copied_chars++] = (unsigned char)(ch & 0xff);
-	buflen--;
-	if (is_line_input () && ch && memchr (eols, ch & 0xff, sizeof (eols)))
-	  break;
-      }
-
-  return copied_chars;
-}
-
-bool
-fhandler_pty_slave::get_readahead_valid (void)
-{
-  if (is_line_input ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      for (size_t i=raixget (); i<ralen (); i++)
-	if (rabuf ()[i] && memchr (eols, rabuf ()[i], sizeof (eols)))
-	  return true;
-      return false;
-    }
-  else
-    return ralen () > raixget ();
-}
-
-void
-fhandler_pty_slave::set_switch_to_pcon (int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  acquire_output_mutex (INFINITE);
-  if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
-    {
-      pull_pcon_input ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
+      isHybrid = true;
+      if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
 	get_ttyp ()->pcon_pid = myself->pid;
       get_ttyp ()->switch_to_pcon_in = true;
-      if (isHybrid && !get_ttyp ()->switch_to_pcon_out)
-	{
-	  get_ttyp ()->wait_pcon_fwd ();
-	  get_ttyp ()->switch_to_pcon_out = true;
-	}
-    }
-  else if ((fd == 1 || fd == 2) && !get_ttyp ()->switch_to_pcon_out)
-    {
-      get_ttyp ()->wait_pcon_fwd ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
-	get_ttyp ()->pcon_pid = myself->pid;
-      get_ttyp ()->switch_to_pcon_out = true;
-      if (isHybrid)
-	get_ttyp ()->switch_to_pcon_in = true;
     }
-  release_output_mutex ();
 }
 
 void
 fhandler_pty_slave::reset_switch_to_pcon (void)
 {
-  if (get_ttyp ()->pcon_pid &&
-      get_ttyp ()->pcon_pid != myself->pid &&
-      !!pinfo (get_ttyp ()->pcon_pid))
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
     /* There is a process which is grabbing pseudo console. */
     return;
   if (isHybrid)
     return;
-  if (do_not_reset_switch_to_pcon)
-    return;
-  acquire_output_mutex (INFINITE);
-  if (get_ttyp ()->switch_to_pcon_out)
-    /* Wait for pty_master_fwd_thread() */
-    get_ttyp ()->wait_pcon_fwd ();
   get_ttyp ()->pcon_pid = 0;
   get_ttyp ()->switch_to_pcon_in = false;
-  get_ttyp ()->switch_to_pcon_out = false;
-  release_output_mutex ();
-  init_console_handler (true);
-}
-
-void
-fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len,
-					       bool is_echo)
-{
-  bool attached =
-    !!fhandler_console::get_console_process_id (get_helper_process_id (), true);
-  if (!attached && pcon_attached_to == get_minor ())
-    {
-      for (DWORD t0 = GetTickCount (); GetTickCount () - t0 < 100; )
-	{
-	  Sleep (1);
-	  attached = fhandler_console::get_console_process_id
-				      (get_helper_process_id (), true);
-	  if (attached)
-	    break;
-	}
-      if (!attached)
-	{
-	  system_printf ("pty%d: pcon_attach_to mismatch??????", get_minor ());
-	  return;
-	}
-    }
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  if (pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      goto detach;
-
-  char *buf;
-  size_t nlen;
-  DWORD origCP;
-  origCP = GetConsoleOutputCP ();
-  SetConsoleOutputCP (get_ttyp ()->term_code_page);
-  /* Just copy */
-  buf = (char *) HeapAlloc (GetProcessHeap (), 0, len);
-  memcpy (buf, (char *)ptr, len);
-  nlen = len;
-  char *p0, *p1;
-  p0 = p1 = buf;
-  /* Remove alternate screen buffer drawing */
-  while (p0 && p1)
-    {
-      if (!get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to alternate screen buffer */
-	  p0 = (char *) memmem (p1, nlen - (p1-buf), "\033[?1049h", 8);
-	  if (p0)
-	    {
-	      //p0 += 8;
-	      get_ttyp ()->screen_alternated = true;
-	      if (get_ttyp ()->switch_to_pcon_out)
-		do_not_reset_switch_to_pcon = true;
-	    }
-	}
-      if (get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to main screen buffer */
-	  p1 = (char *) memmem (p0, nlen - (p0-buf), "\033[?1049l", 8);
-	  if (p1)
-	    {
-	      p1 += 8;
-	      get_ttyp ()->screen_alternated = false;
-	      do_not_reset_switch_to_pcon = false;
-	      memmove (p0, p1, buf+nlen - p1);
-	      nlen -= p1 - p0;
-	    }
-	  else
-	    nlen = p0 - buf;
-	}
-    }
-  if (!nlen) /* Nothing to be synchronized */
-    goto cleanup;
-  if (get_ttyp ()->switch_to_pcon_out && !is_echo)
-    goto cleanup;
-  /* Remove ESC sequence which returns results to console
-     input buffer. Without this, cursor position report
-     is put into the input buffer as a garbage. */
-  /* Remove ESC sequence to report cursor position. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[6n", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-  /* Remove ESC sequence to report terminal identity. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[0c", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-
-  /* If the ESC sequence ESC[?3h or ESC[?3l which clears console screen
-     buffer is pushed, set need_redraw_screen to trigger redraw screen. */
-  p0 = buf;
-  while ((p0 = (char *) memmem (p0, nlen - (p0 - buf), "\033[?", 3)))
-    {
-      p0 += 3;
-      bool exist_arg_3 = false;
-      while (p0 < buf + nlen && (isdigit (*p0) || *p0 == ';'))
-	{
-	  int arg = 0;
-	  while (p0 < buf + nlen && isdigit (*p0))
-	    arg = arg * 10 + (*p0 ++) - '0';
-	  if (arg == 3)
-	    exist_arg_3 = true;
-	  if (p0 < buf + nlen && *p0 == ';')
-	    p0 ++;
-	}
-      if (p0 < buf + nlen && exist_arg_3 && (*p0 == 'h' || *p0 == 'l'))
-	get_ttyp ()->need_redraw_screen = true;
-      p0 ++;
-      if (p0 >= buf + nlen)
-	break;
-    }
-
-  int retry_count;
-  retry_count = 0;
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  while (!GetConsoleMode (get_output_handle (), &dwMode))
-    {
-      termios_printf ("GetConsoleMode failed, %E");
-      int errno_save = errno;
-      /* Re-open handles */
-      this->open (0, 0);
-      /* Fix pseudo console window size */
-      this->ioctl (TIOCSWINSZ, &get_ttyp ()->winsize);
-      if (errno != errno_save)
-	set_errno (errno_save);
-      if (++retry_count > 3)
-	goto cleanup;
-    }
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-  char *p;
-  p = buf;
-  DWORD wLen, written;
-  written = 0;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
-  while (written <  nlen)
-    {
-      if (!WriteFunc (get_output_handle (), p, nlen - written, &wLen, NULL))
-	{
-	  termios_printf ("WriteFile failed, %E");
-	  break;
-	}
-      else
-	{
-	  written += wLen;
-	  p += wLen;
-	}
-    }
-  /* Detach from pseudo console and resume. */
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-cleanup:
-  SetConsoleOutputCP (origCP);
-  HeapFree (GetProcessHeap (), 0, buf);
-detach:
-  restore_reattach_pcon ();
+  get_ttyp ()->h_pseudo_console = NULL;
+  get_ttyp ()->pcon_start = false;
 }
 
 ssize_t __stdcall
@@ -1505,44 +776,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
   reset_switch_to_pcon ();
 
   acquire_output_mutex (INFINITE);
-  bool output_to_pcon = get_ttyp ()->switch_to_pcon_out;
-  release_output_mutex ();
-
-  UINT target_code_page = output_to_pcon ?
-    GetConsoleOutputCP () : get_ttyp ()->term_code_page;
-  ssize_t nlen;
-  char *buf = convert_mb_str (target_code_page, (size_t *) &nlen,
-		 get_ttyp ()->term_code_page, (const char *) ptr, len);
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  bool fallback = false;
-  if (output_to_pcon && pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      fallback = true;
-
-  if (output_to_pcon && !fallback &&
-      (memmem (buf, nlen, "\033[6n", 4) || memmem (buf, nlen, "\033[0c", 4)))
-    {
-      get_ttyp ()->pcon_in_empty = false;
-      if (!is_line_input ())
-	SetEvent (input_available_event);
-    }
-
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  if (output_to_pcon && !fallback)
-    {
-      GetConsoleMode (get_output_handle (), &dwMode);
-      SetConsoleMode (get_output_handle (), dwMode | flags);
-    }
-  HANDLE to = (output_to_pcon && !fallback) ?
-    get_output_handle () : get_output_handle_cyg ();
-  acquire_output_mutex (INFINITE);
-  if (!process_opost_output (to, buf, nlen, false))
+  if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false))
     {
       DWORD err = GetLastError ();
       termios_printf ("WriteFile failed, %E");
@@ -1557,20 +791,6 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
       towrite = -1;
     }
   release_output_mutex ();
-  mb_str_free (buf);
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (output_to_pcon && !fallback)
-    SetConsoleMode (get_output_handle (), dwMode | flags);
-
-  restore_reattach_pcon ();
-
-  /* Push slave output to pseudo console screen buffer */
-  if (get_pseudo_console ())
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer ((char *)ptr, len, false);
-      release_output_mutex ();
-    }
 
   return towrite;
 }
@@ -1582,16 +802,15 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 }
 
 bool
-fhandler_pty_common::to_be_read_from_pcon (void)
+fhandler_pty_master::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return get_ttyp ()->pcon_start
+    || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
 fhandler_pty_slave::read (void *ptr, size_t& len)
 {
-  char *ptr0 = (char *)ptr;
   ssize_t totalread = 0;
   int vmin = 0;
   int vtime = 0;	/* Initialized to prevent -Wuninitialized warning */
@@ -1616,8 +835,6 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
       mask_switch_to_pcon_in (true);
       reset_switch_to_pcon ();
     }
-  if (to_be_read_from_pcon ())
-    update_pcon_input_state (true);
 
   if (is_nonblocking () || !ptr) /* Indicating tcflush(). */
     time_to_wait = 0;
@@ -1702,99 +919,22 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 	    {
 	      if (!totalread)
 		{
-		  set_sig_errno (EAGAIN);
-		  totalread = -1;
-		}
-	      goto out;
-	    }
-	  continue;
-	default:
-	  termios_printf ("wait for input mutex failed, %E");
-	  if (!totalread)
-	    {
-	      __seterrno ();
-	      totalread = -1;
-	    }
-	  goto out;
-	}
-      if (ptr && to_be_read_from_pcon ())
-	{
-	  if (get_readahead_valid ())
-	    {
-	      ReleaseMutex (input_mutex);
-	      totalread = get_readahead_into_buffer ((char *) ptr, len);
-	    }
-	  else
-	    {
-	      if (!try_reattach_pcon ())
-		{
-		  restore_reattach_pcon ();
-		  goto do_read_cyg;
-		}
-
-	      DWORD dwMode;
-	      GetConsoleMode (get_handle (), &dwMode);
-	      DWORD flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
-	      if (dwMode != flags)
-		SetConsoleMode (get_handle (), flags);
-	      /* Read get_handle() instad of get_handle_cyg() */
-	      BOOL (WINAPI *ReadFunc)
-		(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID);
-	      ReadFunc = ReadConsoleA_Orig ? ReadConsoleA_Orig : ReadConsoleA;
-	      DWORD rlen;
-	      readlen = MIN (len, sizeof (buf));
-	      if (!ReadFunc (get_handle (), buf, readlen, &rlen, NULL))
-		{
-		  termios_printf ("read failed, %E");
-		  SetConsoleMode (get_handle (), dwMode);
-		  restore_reattach_pcon ();
-		  ReleaseMutex (input_mutex);
-		  set_errno (EIO);
-		  totalread = -1;
-		  goto out;
-		}
-	      SetConsoleMode (get_handle (), dwMode);
-	      restore_reattach_pcon ();
-	      ReleaseMutex (input_mutex);
-
-	      ssize_t nlen;
-	      char *nbuf = convert_mb_str (get_ttyp ()->term_code_page,
-			     (size_t *) &nlen, GetConsoleCP (), buf, rlen);
-
-	      ssize_t ret;
-	      line_edit_status res =
-		line_edit (nbuf, nlen, get_ttyp ()->ti, &ret);
-
-	      mb_str_free (nbuf);
-
-	      if (res == line_edit_input_done || res == line_edit_ok)
-		totalread = get_readahead_into_buffer ((char *) ptr, len);
-	      else if (res > line_edit_signalled)
-		{
-		  set_sig_errno (EINTR);
-		  totalread = -1;
-		}
-	      else
-		{
-		  update_pcon_input_state (true);
-		  continue;
+		  set_sig_errno (EAGAIN);
+		  totalread = -1;
 		}
+	      goto out;
+	    }
+	  continue;
+	default:
+	  termios_printf ("wait for input mutex failed, %E");
+	  if (!totalread)
+	    {
+	      __seterrno ();
+	      totalread = -1;
 	    }
-
-	  update_pcon_input_state (true);
-	  mask_switch_to_pcon_in (false);
 	  goto out;
 	}
-      if (!ptr && len == UINT_MAX && !get_ttyp ()->pcon_in_empty)
-	{
-	  FlushConsoleInputBuffer (get_handle ());
-	  get_ttyp ()->pcon_in_empty = true;
-	  DWORD n;
-	  if (bytes_available (n) && n == 0)
-	    ResetEvent (input_available_event);
-	}
 
-do_read_cyg:
       if (!bytes_available (bytes_in_pipe))
 	{
 	  ReleaseMutex (input_mutex);
@@ -1911,16 +1051,6 @@ do_read_cyg:
 out:
   termios_printf ("%d = read(%p, %lu)", totalread, ptr, len);
   len = (size_t) totalread;
-  /* Push slave read as echo to pseudo console screen buffer. */
-  if (get_pseudo_console () && ptr0 && totalread > 0 &&
-      (get_ttyp ()->ti.c_lflag & ECHO))
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer (ptr0, len, true);
-      if (get_ttyp ()->switch_to_pcon_out)
-	trigger_redraw_screen ();
-      release_output_mutex ();
-    }
   mask_switch_to_pcon_in (false);
 }
 
@@ -2061,38 +1191,11 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
       get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
       break;
     case TIOCSWINSZ:
-      if (get_pseudo_console ())
-	{
-	  /* If not attached to this pseudo console,
-	     try to attach temporarily. */
-	  pid_restore = 0;
-	  if (pcon_attached_to != get_minor ())
-	    if (!try_reattach_pcon ())
-	      goto cleanup;
-
-	  COORD size;
-	  size.X = ((struct winsize *) arg)->ws_col;
-	  size.Y = ((struct winsize *) arg)->ws_row;
-	  CONSOLE_SCREEN_BUFFER_INFO csbi;
-	  if (GetConsoleScreenBufferInfo (get_output_handle (), &csbi))
-	    if (size.X == csbi.srWindow.Right - csbi.srWindow.Left + 1 &&
-		size.Y == csbi.srWindow.Bottom - csbi.srWindow.Top + 1)
-	      goto cleanup;
-	  if (!SetConsoleScreenBufferSize (get_output_handle (), size))
-	    goto cleanup;
-	  SMALL_RECT rect;
-	  rect.Left = 0;
-	  rect.Top = 0;
-	  rect.Right = size.X-1;
-	  rect.Bottom = size.Y-1;
-	  SetConsoleWindowInfo (get_output_handle (), TRUE, &rect);
-cleanup:
-	  restore_reattach_pcon ();
-	}
-
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->arg.winsize = *(struct winsize *) arg;
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
@@ -2378,6 +1481,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2393,7 +1517,6 @@ fhandler_pty_master::close ()
 {
   OBJECT_BASIC_INFORMATION obi;
   NTSTATUS status;
-  pid_t master_pid_tmp = get_ttyp ()->master_pid;
 
   termios_printf ("closing from_master(%p)/from_master_cyg(%p)/to_master(%p)/to_master_cyg(%p) since we own them(%u)",
 		  from_master, from_master_cyg,
@@ -2438,30 +1561,6 @@ fhandler_pty_master::close ()
   else if (obi.HandleCount == 1)
     {
       termios_printf ("Closing last master of pty%d", get_minor ());
-      /* Close Pseudo Console */
-      if (get_pseudo_console ())
-	{
-	  /* Terminate helper process */
-	  SetEvent (get_ttyp ()->h_helper_goodbye);
-	  WaitForSingleObject (get_ttyp ()->h_helper_process, INFINITE);
-	  CloseHandle (get_ttyp ()->h_helper_goodbye);
-	  CloseHandle (get_ttyp ()->h_helper_process);
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (master_pid_tmp == myself->pid)
-	    {
-	      /* ClosePseudoConsole() seems to have a bug that one
-		 internal handle remains opened. This causes handle leak.
-		 This is a workaround for this problem. */
-	      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_pseudo_console ();
-	      HANDLE tmp = hp->hConHostProcess;
-	      /* Release pseudo console */
-	      ClosePseudoConsole (get_pseudo_console ());
-	      CloseHandle (tmp);
-	    }
-	  get_ttyp ()->switch_to_pcon_in = false;
-	  get_ttyp ()->switch_to_pcon_out = false;
-	}
       if (get_ttyp ()->getsid () > 0)
 	kill (get_ttyp ()->getsid (), SIGHUP);
       SetEvent (input_available_event);
@@ -2469,9 +1568,8 @@ fhandler_pty_master::close ()
 
   if (!ForceCloseHandle (from_master))
     termios_printf ("error closing from_master %p, %E", from_master);
-  if (from_master_cyg != from_master) /* Avoid double close. */
-    if (!ForceCloseHandle (from_master_cyg))
-      termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
+  if (!ForceCloseHandle (from_master_cyg))
+    termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
   if (!ForceCloseHandle (to_master))
     termios_printf ("error closing to_master %p, %E", to_master);
   from_master = to_master = NULL;
@@ -2513,7 +1611,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon () && get_ttyp ()->h_pseudo_console)
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2521,40 +1619,50 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
       WaitForSingleObject (input_mutex, INFINITE);
 
-      if (memchr (buf, '\003', nlen)) /* ^C intr key in pcon */
-	get_ttyp ()->req_flush_pcon_input = true;
-
       DWORD wLen;
-      WriteFile (to_slave, buf, nlen, &wLen, NULL);
-      get_ttyp ()->pcon_in_empty = false;
 
-      ReleaseMutex (input_mutex);
-
-      /* Use line_edit () in order to set input_available_event. */
-      bool is_echo = tc ()->ti.c_lflag & ECHO;
-      if (!get_ttyp ()->mask_switch_to_pcon_in)
+      if (get_ttyp ()->pcon_start)
 	{
-	  tc ()->ti.c_lflag &= ~ECHO;
-	  ti.c_lflag &= ~ECHO;
-	}
-      ti.c_lflag &= ~ISIG;
-      line_edit (buf, nlen, ti, &ret);
-      if (is_echo)
-	tc ()->ti.c_lflag |= ECHO;
-      get_ttyp ()->read_retval = 1;
-
-      const char sigs[] = {
-	(char) ti.c_cc[VINTR],
-	(char) ti.c_cc[VQUIT],
-	(char) ti.c_cc[VSUSP],
-      };
-      if (tc ()->ti.c_lflag & ISIG)
-	for (size_t i=0; i<sizeof (sigs); i++)
-	  if (sigs[i] && memchr (buf, sigs[i], nlen))
+	  /* Pseudo condole support uses "CSI6n" to get cursor position.
+	     If the reply for "CSI6n" is divided into multiple writes,
+	     pseudo console sometimes does not recognize it.  Therefore,
+	     put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon_start = false;
+	    }
+	  else
 	    {
-	      eat_readahead (-1);
-	      SetEvent (input_available_event);
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
 	    }
+	}
+
+      WriteFile (to_slave, buf, nlen, &wLen, NULL);
+
+      ReleaseMutex (input_mutex);
 
       mb_str_free (buf);
       return len;
@@ -2630,15 +1738,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (get_pseudo_console () && get_ttyp ()->master_pid == myself->pid)
-	    {
-	      COORD size;
-	      size.X = ((struct winsize *) arg)->ws_col;
-	      size.Y = ((struct winsize *) arg)->ws_row;
-	      ResizePseudoConsole (get_pseudo_console (), size);
-	    }
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
 	}
@@ -2763,7 +1864,7 @@ get_locale_from_env (char *locale)
   strcpy (locale, env);
 }
 
-static LCID
+static void
 get_langinfo (char *locale_out, char *charset_out)
 {
   /* Get locale from environment */
@@ -2776,11 +1877,6 @@ get_langinfo (char *locale_out, char *charset_out)
   if (!locale)
     locale = "C";
 
-  char tmp_locale[ENCODING_LEN + 1];
-  char *ret = __set_locale_from_locale_alias (locale, tmp_locale);
-  if (ret)
-    locale = tmp_locale;
-
   const char *charset;
   struct lc_ctype_T *lc_ctype = (struct lc_ctype_T *) loc.lc_cat[LC_CTYPE].ptr;
   if (!lc_ctype)
@@ -2830,23 +1926,9 @@ get_langinfo (char *locale_out, char *charset_out)
       charset = "CP932";
     }
 
-  wchar_t lc[ENCODING_LEN + 1];
-  wchar_t *p;
-  mbstowcs (lc, locale, ENCODING_LEN);
-  p = wcschr (lc, L'.');
-  if (p)
-    *p = L'\0';
-  p = wcschr (lc, L'_');
-  if (p)
-    *p = L'-';
-  LCID lcid = LocaleNameToLCID (lc, 0);
-  if (!lcid && !strcmp (charset, "ASCII"))
-    return 0;
-
   /* Set results */
   strcpy (locale_out, new_locale);
   strcpy (charset_out, charset);
-  return lcid;
 }
 
 void
@@ -2854,21 +1936,7 @@ fhandler_pty_slave::setup_locale (void)
 {
   char locale[ENCODING_LEN + 1] = "C";
   char charset[ENCODING_LEN + 1] = "ASCII";
-  LCID lcid = get_langinfo (locale, charset);
-
-  /* Set console code page form locale */
-  if (get_pseudo_console ())
-    {
-      UINT code_page;
-      if (lcid == 0 || lcid == (LCID) -1)
-	code_page = 20127; /* ASCII */
-      else if (!GetLocaleInfo (lcid,
-			       LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
-			       (char *) &code_page, sizeof (code_page)))
-	code_page = 20127; /* ASCII */
-      SetConsoleCP (code_page);
-      SetConsoleOutputCP (code_page);
-    }
+  get_langinfo (locale, charset);
 
   /* Set terminal code page from locale */
   /* This code is borrowed from mintty: charset.c */
@@ -2878,9 +1946,9 @@ fhandler_pty_slave::setup_locale (void)
     charset_u[i] = toupper (charset[i]);
   unsigned int iso;
   UINT cp = 20127; /* Default for fallback */
-  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859%u", &iso) == 1)
+  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859%u", &iso) == 1)
     {
       if (iso && iso <= 16 && iso !=12)
 	get_ttyp ()->term_code_page = 28590 + iso;
@@ -2896,90 +1964,9 @@ fhandler_pty_slave::setup_locale (void)
 	}
 }
 
-void
-fhandler_pty_slave::set_freeconsole_on_close (bool val)
-{
-  freeconsole_on_close = val;
-}
-
-void
-fhandler_pty_slave::trigger_redraw_screen (void)
-{
-  /* Forcibly redraw screen based on console screen buffer. */
-  /* The following code triggers redrawing the screen. */
-  CONSOLE_SCREEN_BUFFER_INFO sbi;
-  GetConsoleScreenBufferInfo (get_output_handle (), &sbi);
-  SMALL_RECT rect = {0, 0,
-    (SHORT) (sbi.dwSize.X -1), (SHORT) (sbi.dwSize.Y - 1)};
-  COORD dest = {0, 0};
-  CHAR_INFO fill = {' ', 0};
-  ScrollConsoleScreenBuffer (get_output_handle (), &rect, NULL, dest, &fill);
-  get_ttyp ()->need_redraw_screen = false;
-}
-
-void
-fhandler_pty_slave::fixup_after_attach (bool native_maybe, int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  if (get_pseudo_console ())
-    {
-      if (fhandler_console::get_console_process_id (get_helper_process_id (),
-						    true))
-	if (pcon_attached_to != get_minor ())
-	  {
-	    pcon_attached_to = get_minor ();
-	    init_console_handler (true);
-	  }
-
-#if 0 /* This is for debug only. */
-      isHybrid = true;
-      get_ttyp ()->switch_to_pcon_in = true;
-      get_ttyp ()->switch_to_pcon_out = true;
-#endif
-
-      if (pcon_attached_to == get_minor () && native_maybe)
-	{
-	  if (fd == 0)
-	    {
-	      pull_pcon_input ();
-	      DWORD mode =
-		ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	      SetConsoleMode (get_handle (), mode);
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_in = true;
-	    }
-	  else if (fd == 1 || fd == 2)
-	    {
-	      DWORD mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
-	      SetConsoleMode (get_output_handle (), mode);
-	      acquire_output_mutex (INFINITE);
-	      if (!get_ttyp ()->switch_to_pcon_out)
-		get_ttyp ()->wait_pcon_fwd ();
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_out = true;
-	      release_output_mutex ();
-
-	      if (get_ttyp ()->need_redraw_screen)
-		trigger_redraw_screen ();
-	    }
-	  init_console_handler (false);
-	}
-      else if (fd == 0 && native_maybe)
-	/* Read from unattached pseudo console cause freeze,
-	   therefore, fallback to legacy pty. */
-	set_handle (get_handle_cyg ());
-    }
-}
-
 void
 fhandler_pty_slave::fixup_after_fork (HANDLE parent)
 {
-  fixup_after_attach (false, -1);
   // fork_fixup (parent, inuse, "inuse");
   // fhandler_pty_common::fixup_after_fork (parent);
   report_tty_counts (this, "inherited", "");
@@ -2992,71 +1979,22 @@ fhandler_pty_slave::fixup_after_exec ()
 
   if (!close_on_exec ())
     fixup_after_fork (NULL);	/* No parent handle required. */
-  else if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 1 && get_minor () == pcon_attached_to)
-	pcon_attached_to = -1;
-      if (used == 1 /* About to close this tty */)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
 
   /* Set locale */
   if (get_ttyp ()->term_code_page == 0)
     setup_locale ();
 
   /* Hook Console API */
-  if (get_pseudo_console ())
-    {
 #define DO_HOOK(module, name) \
-      if (!name##_Orig) \
-	{ \
-	  void *api = hook_api (module, #name, (void *) name##_Hooked); \
-	  name##_Orig = (__typeof__ (name) *) api; \
-	  /*if (api) system_printf (#name " hooked.");*/ \
-	}
-      DO_HOOK (NULL, WriteFile);
-      DO_HOOK (NULL, WriteConsoleA);
-      DO_HOOK (NULL, WriteConsoleW);
-      DO_HOOK (NULL, ReadFile);
-      DO_HOOK (NULL, ReadConsoleA);
-      DO_HOOK (NULL, ReadConsoleW);
-      DO_HOOK (NULL, WriteConsoleOutputA);
-      DO_HOOK (NULL, WriteConsoleOutputW);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterA);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterW);
-      DO_HOOK (NULL, WriteConsoleOutputAttribute);
-      DO_HOOK (NULL, SetConsoleCursorPosition);
-      DO_HOOK (NULL, SetConsoleTextAttribute);
-      DO_HOOK (NULL, WriteConsoleInputA);
-      DO_HOOK (NULL, WriteConsoleInputW);
-      DO_HOOK (NULL, ReadConsoleInputA);
-      DO_HOOK (NULL, ReadConsoleInputW);
-      DO_HOOK (NULL, PeekConsoleInputA);
-      DO_HOOK (NULL, PeekConsoleInputW);
-      /* CreateProcess() is hooked for GDB etc. */
-      DO_HOOK (NULL, CreateProcessA);
-      DO_HOOK (NULL, CreateProcessW);
+  if (!name##_Orig) \
+    { \
+      void *api = hook_api (module, #name, (void *) name##_Hooked); \
+      name##_Orig = (__typeof__ (name) *) api; \
+      /*if (api) system_printf (#name " hooked.");*/ \
     }
+  /* CreateProcess() is hooked for GDB etc. */
+  DO_HOOK (NULL, CreateProcessA);
+  DO_HOOK (NULL, CreateProcessW);
 }
 
 /* This thread function handles the master control pipe.  It waits for a
@@ -3204,27 +2142,6 @@ reply:
   return 0;
 }
 
-void
-fhandler_pty_master::transfer_input_to_pcon (void)
-{
-  WaitForSingleObject (input_mutex, INFINITE);
-  DWORD n;
-  size_t transfered = 0;
-  while (::bytes_available (n, from_master_cyg) && n)
-    {
-      char buf[1024];
-      ReadFile (from_master_cyg, buf, sizeof (buf), &n, 0);
-      char *p = buf;
-      while ((p = (char *) memchr (p, '\n', n - (p - buf))))
-	*p = '\r';
-      if (WriteFile (to_slave, buf, n, &n, 0))
-	transfered += n;
-    }
-  if (transfered)
-    get_ttyp ()->pcon_in_empty = false;
-  ReleaseMutex (input_mutex);
-}
-
 static DWORD WINAPI
 pty_master_thread (VOID *arg)
 {
@@ -3240,23 +2157,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
   termios_printf ("Started.");
   for (;;)
     {
-      if (get_pseudo_console ())
-	{
-	  get_ttyp ()->pcon_last_time = GetTickCount ();
-	  while (::bytes_available (rlen, from_slave) && rlen == 0)
-	    {
-	      /* Forcibly transfer input if it is requested by slave.
-		 This happens when input data should be transfered
-		 from the input pipe for cygwin apps to the input pipe
-		 for native apps. */
-	      if (get_ttyp ()->req_transfer_input_to_pcon)
-		{
-		  transfer_input_to_pcon ();
-		  get_ttyp ()->req_transfer_input_to_pcon = false;
-		}
-	      Sleep (1);
-	    }
-	}
+      get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3264,14 +2165,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_ttyp ()->h_pseudo_console)
 	{
-	  /* Avoid duplicating slave output which is already sent to
-	     to_master_cyg */
-	  if (!get_ttyp ()->switch_to_pcon_out)
-	    continue;
-
-	  /* Avoid setting window title to "cygwin-console-helper.exe" */
+	  /* Remove CSI > Pm m */
 	  int state = 0;
 	  int start_at = 0;
 	  for (DWORD i=0; i<rlen; i++)
@@ -3281,43 +2177,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 		state = 1;
 		continue;
 	      }
-	    else if ((state == 1 && outbuf[i] == ']') ||
-		     (state == 2 && outbuf[i] == '0') ||
-		     (state == 3 && outbuf[i] == ';'))
-	      {
-		state ++;
-		continue;
-	      }
-	    else if (state == 4 && outbuf[i] == '\a')
-	      {
-		const char *helper_str = "\\bin\\cygwin-console-helper.exe";
-		if (memmem (&outbuf[start_at], i + 1 - start_at,
-			    helper_str, strlen (helper_str)))
-		  {
-		    memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
-		    rlen = wlen = start_at + rlen - i - 1;
-		  }
-		state = 0;
-		continue;
-	      }
-	    else if (outbuf[i] == '\a')
-	      {
-		state = 0;
-		continue;
-	      }
-
-	  /* Remove CSI > Pm m */
-	  state = 0;
-	  start_at = 0;
-	  for (DWORD i=0; i<rlen; i++)
-	    if (outbuf[i] == '\033')
-	      {
-		start_at = i;
-		state = 1;
-		continue;
-	      }
-	    else if ((state == 1 && outbuf[i] == '[') ||
-		     (state == 2 && outbuf[i] == '>'))
+	    else if ((state == 1 && outbuf[i] == '[')
+		     || (state == 2 && outbuf[i] == '>'))
 	      {
 		state ++;
 		continue;
@@ -3386,201 +2247,6 @@ pty_master_fwd_thread (VOID *arg)
   return ((fhandler_pty_master *) arg)->pty_master_fwd_thread ();
 }
 
-/* If master process is running as service, attaching to
-   pseudo console should be done in fork. If attaching
-   is done in spawn for inetd or sshd, it fails because
-   the helper process is running as privileged user while
-   slave process is not. This function is used to determine
-   if the process is running as a srvice or not. */
-inline static bool
-is_running_as_service (void)
-{
-  return check_token_membership (well_known_service_sid)
-    || cygheap->user.saved_sid () == well_known_system_sid;
-}
-
-bool
-fhandler_pty_master::setup_pseudoconsole ()
-{
-  if (disable_pcon)
-    return false;
-  /* If the legacy console mode is enabled, pseudo console seems
-     not to work as expected. To determine console mode, registry
-     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
-  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
-  if (reg.error ())
-    return false;
-  if (reg.get_dword (L"ForceV2", 1) == 0)
-    {
-      termios_printf ("Pseudo console is disabled "
-		      "because the legacy console mode is enabled.");
-      return false;
-    }
-
-  /* Pseudo console supprot is realized using a tricky technic.
-     PTY need the pseudo console handles, however, they cannot
-     be retrieved by normal procedure. Therefore, run a helper
-     process in a pseudo console and get them from the helper.
-     Slave process will attach to the pseudo console in the
-     helper process using AttachConsole(). */
-  COORD size = {
-    (SHORT) get_ttyp ()->winsize.ws_col,
-    (SHORT) get_ttyp ()->winsize.ws_row
-  };
-  CreatePipe (&from_master, &to_slave, &sec_none, 0);
-  SetLastError (ERROR_SUCCESS);
-  HRESULT res = CreatePseudoConsole (size, from_master, to_master,
-				     0, &get_ttyp ()->h_pseudo_console);
-  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
-    {
-      if (res != S_OK)
-	system_printf ("CreatePseudoConsole() failed. %08x\n",
-		       GetLastError ());
-      goto fallback;
-    }
-
-  /* If master process is running as service, attaching to
-     pseudo console should be done in fork. If attaching
-     is done in spawn for inetd or sshd, it fails because
-     the helper process is running as privileged user while
-     slave process is not. */
-  if (is_running_as_service ())
-    get_ttyp ()->attach_pcon_in_fork = true;
-
-  STARTUPINFOEXW si_helper;
-  HANDLE hello, goodbye;
-  HANDLE hr, hw;
-  PROCESS_INFORMATION pi_helper;
-  HANDLE hpConIn, hpConOut;
-  {
-    SIZE_T bytesRequired;
-    InitializeProcThreadAttributeList (NULL, 2, 0, &bytesRequired);
-    ZeroMemory (&si_helper, sizeof (si_helper));
-    si_helper.StartupInfo.cb = sizeof (STARTUPINFOEXW);
-    si_helper.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
-      HeapAlloc (GetProcessHeap (), 0, bytesRequired);
-    if (si_helper.lpAttributeList == NULL)
-      goto cleanup_pseudo_console;
-    if (!InitializeProcThreadAttributeList (si_helper.lpAttributeList,
-					    2, 0, &bytesRequired))
-      goto cleanup_heap;
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
-				    get_ttyp ()->h_pseudo_console,
-				    sizeof (get_ttyp ()->h_pseudo_console),
-				    NULL, NULL))
-      goto cleanup_heap;
-    /* Create events for start/stop helper process. */
-    hello = CreateEvent (&sec_none, true, false, NULL);
-    goodbye = CreateEvent (&sec_none, true, false, NULL);
-    /* Create a pipe for receiving pseudo console handles */
-    CreatePipe (&hr, &hw, &sec_none, 0);
-    /* Inherit only handles which are needed by helper. */
-    HANDLE handles_to_inherit[] = {hello, goodbye, hw};
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
-				    handles_to_inherit,
-				    sizeof (handles_to_inherit),
-				    NULL, NULL))
-      goto cleanup_event_and_pipes;
-    /* Create helper process */
-    WCHAR cmd[MAX_PATH];
-    path_conv helper ("/bin/cygwin-console-helper.exe");
-    size_t len = helper.get_wide_win32_path_len ();
-    helper.get_wide_win32_path (cmd);
-    __small_swprintf (cmd + len, L" %p %p %p", hello, goodbye, hw);
-    si_helper.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
-    si_helper.StartupInfo.hStdInput = NULL;
-    si_helper.StartupInfo.hStdOutput = NULL;
-    si_helper.StartupInfo.hStdError = NULL;
-    if (!CreateProcessW (NULL, cmd, &sec_none, &sec_none,
-			 TRUE, EXTENDED_STARTUPINFO_PRESENT,
-			 NULL, NULL, &si_helper.StartupInfo, &pi_helper))
-      goto cleanup_event_and_pipes;
-    for (;;)
-      {
-        DWORD wait_result = WaitForSingleObject (hello, 500);
-	if (wait_result == WAIT_OBJECT_0)
-	  break;
-	if (wait_result != WAIT_TIMEOUT)
-	  goto cleanup_helper_process;
-	DWORD exit_code;
-	if (!GetExitCodeProcess(pi_helper.hProcess, &exit_code))
-	  goto cleanup_helper_process;
-	if (exit_code == STILL_ACTIVE)
-	  continue;
-	if (exit_code != 0 ||
-	    WaitForSingleObject (hello, 500) != WAIT_OBJECT_0)
-	  goto cleanup_helper_process;
-	break;
-      }
-    CloseHandle (hello);
-    CloseHandle (pi_helper.hThread);
-    /* Retrieve pseudo console handles */
-    DWORD rLen;
-    char buf[64];
-    if (!ReadFile (hr, buf, sizeof (buf), &rLen, NULL))
-      goto cleanup_helper_process;
-    buf[rLen] = '\0';
-    sscanf (buf, "StdHandles=%p,%p", &hpConIn, &hpConOut);
-    if (!DuplicateHandle (pi_helper.hProcess, hpConIn,
-			  GetCurrentProcess (), &hpConIn, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_helper_process;
-    if (!DuplicateHandle (pi_helper.hProcess, hpConOut,
-			  GetCurrentProcess (), &hpConOut, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_pcon_in;
-    CloseHandle (hr);
-    CloseHandle (hw);
-    /* Clean up */
-    DeleteProcThreadAttributeList (si_helper.lpAttributeList);
-    HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-  }
-  /* Setting information of stuffs regarding pseudo console */
-  get_ttyp ()->h_helper_goodbye = goodbye;
-  get_ttyp ()->h_helper_process = pi_helper.hProcess;
-  get_ttyp ()->helper_process_id = pi_helper.dwProcessId;
-  CloseHandle (from_master);
-  CloseHandle (to_master);
-  from_master = hpConIn;
-  to_master = hpConOut;
-  ResizePseudoConsole (get_ttyp ()->h_pseudo_console, size);
-  return true;
-
-cleanup_pcon_in:
-  CloseHandle (hpConIn);
-cleanup_helper_process:
-  SetEvent (goodbye);
-  WaitForSingleObject (pi_helper.hProcess, INFINITE);
-  CloseHandle (pi_helper.hProcess);
-  goto skip_close_hello;
-cleanup_event_and_pipes:
-  CloseHandle (hello);
-skip_close_hello:
-  CloseHandle (goodbye);
-  CloseHandle (hr);
-  CloseHandle (hw);
-cleanup_heap:
-  HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-cleanup_pseudo_console:
-  {
-    HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
-    HANDLE tmp = hp->hConHostProcess;
-    ClosePseudoConsole (get_pseudo_console ());
-    CloseHandle (tmp);
-  }
-fallback:
-  CloseHandle (from_master);
-  CloseHandle (to_slave);
-  from_master = from_master_cyg;
-  to_slave = NULL;
-  get_ttyp ()->h_pseudo_console = NULL;
-  return false;
-}
-
 bool
 fhandler_pty_master::setup ()
 {
@@ -3593,11 +2259,6 @@ fhandler_pty_master::setup ()
   if (unit < 0)
     return false;
 
-  /* from_master should be used for pseudo console.
-     Just copy from_master_cyg here for the case that
-     pseudo console is not available. */
-  from_master = from_master_cyg;
-
   ProtectHandle1 (get_output_handle (), to_pty);
 
   tty& t = *cygwin_shared->tty[unit];
@@ -3696,15 +2357,21 @@ fhandler_pty_master::setup ()
       goto err;
     }
 
-  t.winsize.ws_col = 80;
-  t.winsize.ws_row = 25;
-
-  setup_pseudoconsole ();
+  __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;
+    }
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
   t.set_to_master (to_master);
   t.set_to_master_cyg (to_master_cyg);
+  t.winsize.ws_col = 80;
+  t.winsize.ws_row = 25;
   t.master_pid = myself->pid;
 
   dev ().parse (DEV_PTYM_MAJOR, unit);
@@ -3717,6 +2384,7 @@ fhandler_pty_master::setup ()
 err:
   __seterrno ();
   close_maybe (from_slave);
+  close_maybe (to_slave);
   close_maybe (get_handle ());
   close_maybe (get_output_handle ());
   close_maybe (input_available_event);
@@ -3776,9 +2444,6 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 {
   ssize_t towrite = len;
   BOOL res = TRUE;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
   while (towrite)
     {
       if (!is_echo)
@@ -3801,7 +2466,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
       if (!(get_ttyp ()->ti.c_oflag & OPOST))	// raw output mode
 	{
 	  DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
-	  res = WriteFunc (h, ptr, n, &n, NULL);
+	  res = WriteFile (h, ptr, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + n;
@@ -3851,7 +2516,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 		  break;
 		}
 	    }
-	  res = WriteFunc (h, outbuf, n, &n, NULL);
+	  res = WriteFile (h, outbuf, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + rc;
@@ -3861,3 +2526,132 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole (STARTUPINFOEXW *si)
+{
+
+  /* Setting switch_to_pcon_in is necessary even if
+     pseudo console will not be activated. */
+  fhandler_base *fh = ::cygheap->fdtab[0];
+  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+    {
+      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+      ptys->get_ttyp ()->switch_to_pcon_in = true;
+      if (ptys->get_ttyp ()->pcon_pid == 0
+	  || !pinfo (ptys->get_ttyp ()->pcon_pid))
+	ptys->get_ttyp ()->pcon_pid = myself->pid;
+    }
+
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  const DWORD inherit_cursor = 1;
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     inherit_cursor,
+				     &get_ttyp ()->h_pseudo_console);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console,
+				  sizeof (get_ttyp ()->h_pseudo_console),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_base *fh0 = ::cygheap->fdtab[0];
+    if (fh0 && fh0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = fh0->get_handle ();
+    fhandler_base *fh1 = ::cygheap->fdtab[1];
+    if (fh1 && fh1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = fh1->get_output_handle ();
+    fhandler_base *fh2 = ::cygheap->fdtab[2];
+    if (fh2 && fh2->get_device () != get_device ())
+      si->StartupInfo.hStdError = fh2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole (void)
+{
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      get_ttyp ()->wait_pcon_fwd ();
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+      get_ttyp ()->pcon_start = false;
+    }
+}
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 691d08137..6ca4b5f29 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -134,36 +134,6 @@ child_info::prefork (bool detached)
 int __stdcall
 frok::child (volatile char * volatile here)
 {
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR)
-      {
-	fhandler_base *fh = cfd;
-	fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
-	if (ptym->get_pseudo_console ())
-	  {
-	    debug_printf ("found a PTY master %d: helper_PID=%d",
-			  ptym->get_minor (), ptym->get_helper_process_id ());
-	    if (fhandler_console::get_console_process_id (
-				ptym->get_helper_process_id (), true))
-	      /* Already attached */
-	      break;
-	    else
-	      {
-		if (ptym->attach_pcon_in_fork ())
-		  {
-		    FreeConsole ();
-		    if (!AttachConsole (ptym->get_helper_process_id ()))
-		      /* Error */;
-		    else
-		      break;
-		  }
-	      }
-	  }
-      }
-  extern void clear_pcon_attached_to (void); /* fhandler_tty.cc */
-  clear_pcon_attached_to ();
-
   HANDLE& hParent = ch.parent;
 
   sync_with_parent ("after longjmp", true);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 3f3f33fb5..93acdd89a 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1213,8 +1213,7 @@ verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds,
 	   fd_set *exceptfds)
 {
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) me->fh;
-  if (me->read_selected && !ptys->to_be_read_from_pcon () &&
-      IsEventSignalled (ptys->input_available_event))
+  if (me->read_selected && IsEventSignalled (ptys->input_available_event))
     me->read_ready = true;
   return set_bits (me, readfds, writefds, exceptfds);
 }
@@ -1227,8 +1226,6 @@ peek_pty_slave (select_record *s, bool from_select)
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
 
   ptys->reset_switch_to_pcon ();
-  if (ptys->to_be_read_from_pcon ())
-    ptys->update_pcon_input_state (true);
 
   if (s->read_selected)
     {
diff --git a/winsup/cygwin/smallprint.cc b/winsup/cygwin/smallprint.cc
index 26d34d9e4..f208a057a 100644
--- a/winsup/cygwin/smallprint.cc
+++ b/winsup/cygwin/smallprint.cc
@@ -405,7 +405,6 @@ small_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
   WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, NULL);
   FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
 }
@@ -432,7 +431,6 @@ console_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (console_handle);
   WriteFile (console_handle, buf, count, &done, NULL);
   FlushFileBuffers (console_handle);
 }
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..a3071884e 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -259,8 +277,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 {
   bool rc;
   int res = -1;
-  DWORD pid_restore = 0;
-  bool attach_to_console = false;
   pid_t ctty_pgid = 0;
 
   /* Search for CTTY and retrieve its PGID */
@@ -580,9 +596,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			 PROCESS_QUERY_LIMITED_INFORMATION))
 	sa = &sec_none_nih;
 
-      /* Attach to pseudo console if pty salve is used */
-      pid_restore = fhandler_console::get_console_process_id
-	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -591,29 +605,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	      if (ptys->get_pseudo_console ())
-		{
-		  DWORD helper_process_id = ptys->get_helper_process_id ();
-		  debug_printf ("found a PTY slave %d: helper_PID=%d",
-				    fh->get_minor (), helper_process_id);
-		  if (fhandler_console::get_console_process_id
-					      (helper_process_id, true))
-		    /* Already attached */
-		    attach_to_console = true;
-		  else if (!attach_to_console)
-		    {
-		      FreeConsole ();
-		      if (AttachConsole (helper_process_id))
-			attach_to_console = true;
-		    }
-		  ptys->fixup_after_attach (!iscygwin (), fd);
-		  if (mode == _P_OVERLAY)
-		    ptys->set_freeconsole_on_close (iscygwin ());
-		}
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	    }
 	  else if (fh && fh->get_major () == DEV_CONS_MAJOR)
 	    {
-	      attach_to_console = true;
 	      fhandler_console *cons = (fhandler_console *) fh;
 	      if (wincap.has_con_24bit_colors () && !iscygwin ())
 		if (fd == 1 || fd == 2)
@@ -632,6 +628,18 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool enable_pcon = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole (&si_pcon))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    enable_pcon = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +668,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +722,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +735,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (enable_pcon)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +910,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (enable_pcon)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->close_pseudoconsole ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
@@ -930,21 +948,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
   if (envblock)
     free (envblock);
 
-  if (attach_to_console && pid_restore)
-    {
-      FreeConsole ();
-      AttachConsole (pid_restore);
-      cygheap_fdenum cfd (false);
-      int fd;
-      while ((fd = cfd.next ()) >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_pty_slave *ptys =
-	      (fhandler_pty_slave *) (fhandler_base *) cfd;
-	    ptys->fixup_after_attach (false, fd);
-	  }
-    }
-
   return (int) res;
 }
 
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index f0aef3a36..35f8a59ae 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -264,7 +264,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
   if (category & _STRACE_SYSTEM)
     {
       DWORD done;
-      set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
       WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
       FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
       /* Make sure that the message shows up on the screen, too, since this is
@@ -276,7 +275,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
 				 &sec_none, OPEN_EXISTING, 0, 0);
 	  if (h != INVALID_HANDLE_VALUE)
 	    {
-	      set_ishybrid_and_switch_to_pcon (h);
 	      WriteFile (h, buf, len, &done, 0);
 	      CloseHandle (h);
 	    }
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 4cb68f776..d60f27545 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -234,20 +234,14 @@ tty::init ()
   was_opened = false;
   master_pid = 0;
   is_console = false;
-  attach_pcon_in_fork = false;
-  h_pseudo_console = NULL;
   column = 0;
+  h_pseudo_console = NULL;
   switch_to_pcon_in = false;
-  switch_to_pcon_out = false;
-  screen_alternated = false;
   mask_switch_to_pcon_in = false;
   pcon_pid = 0;
   term_code_page = 0;
-  need_redraw_screen = true;
   pcon_last_time = 0;
-  pcon_in_empty = true;
-  req_transfer_input_to_pcon = false;
-  req_flush_pcon_input = false;
+  pcon_start = false;
 }
 
 HANDLE
@@ -293,16 +287,6 @@ tty_min::ttyname ()
   return d.name ();
 }
 
-void
-tty::set_switch_to_pcon_out (bool v)
-{
-  if (switch_to_pcon_out != v)
-    {
-      wait_pcon_fwd ();
-      switch_to_pcon_out = v;
-    }
-}
-
 void
 tty::wait_pcon_fwd (void)
 {
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 920e32b16..c491d3891 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -94,21 +94,13 @@ private:
   HANDLE _to_master;
   HANDLE _to_master_cyg;
   HPCON h_pseudo_console;
-  HANDLE h_helper_process;
-  DWORD helper_process_id;
-  HANDLE h_helper_goodbye;
-  bool attach_pcon_in_fork;
+  bool pcon_start;
   bool switch_to_pcon_in;
-  bool switch_to_pcon_out;
-  bool screen_alternated;
   bool mask_switch_to_pcon_in;
   pid_t pcon_pid;
   UINT term_code_page;
-  bool need_redraw_screen;
   DWORD pcon_last_time;
-  bool pcon_in_empty;
-  bool req_transfer_input_to_pcon;
-  bool req_flush_pcon_input;
+  HANDLE h_pcon_write_pipe;
 
 public:
   HANDLE from_master () const { return _from_master; }
@@ -138,7 +130,6 @@ public:
   void set_master_ctl_closed () {master_pid = -1;}
   static void __stdcall create_master (int);
   static void __stdcall init_session ();
-  void set_switch_to_pcon_out (bool v);
   void wait_pcon_fwd (void);
   friend class fhandler_pty_common;
   friend class fhandler_pty_master;
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index fff7d18f3..458fb2a23 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -222,9 +222,6 @@ void init_console_handler (bool);
 
 extern bool wsock_started;
 
-/* PTY related */
-void set_ishybrid_and_switch_to_pcon (HANDLE h);
-
 /* Printf type functions */
 extern "C" void vapi_fatal (const char *, va_list ap) __attribute__ ((noreturn));
 extern "C" void api_fatal (const char *, ...) __attribute__ ((noreturn));
-- 
2.27.0


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-23 17:17                             ` Takashi Yano
@ 2020-07-27 17:10                               ` Thomas Wolff
  0 siblings, 0 replies; 73+ messages in thread
From: Thomas Wolff @ 2020-07-27 17:10 UTC (permalink / raw)
  To: cygwin-developers, Takashi Yano

Hi Takashi,

Am 23.07.2020 um 19:17 schrieb Takashi Yano via Cygwin-developers:
> Hi Thomas,
>
> On Sat, 18 Jul 2020 22:57:24 +0200
> Thomas Wolff wrote:
>> Am 18.07.2020 um 07:05 schrieb Takashi Yano via Cygwin-developers:
>>> Hi Thomas,
>>>
>>> Thanks for testing.
>>>
>>> On Fri, 17 Jul 2020 16:59:56 +0200
>>> Thomas Wolff wrote:
>>>> Am 17.07.2020 um 14:47 schrieb Thomas Wolff:
>>>>> Am 17.07.2020 um 13:19 schrieb Corinna Vinschen:
>>>>>> Hi Takashi,
>>>>>>
>>>>>> On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
>>>>>>> On Fri, 29 May 2020 00:40:24 +0900
>>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com>
>>>>>>> wrote:
>>>>>>>> On Tue, 26 May 2020 10:09:55 +0900
>>>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com>
>>>>>>>> wrote:
>>>>>>>>> On Mon, 25 May 2020 19:53:32 +0900
>>>>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com>
>>>>>>>>> wrote:
>>>>>>>>>> On Tue, 19 May 2020 22:40:18 +0900
>>>>>>>>>> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com>
>>>>>>>>>> wrote:
>>>>>>>>>>> On Sat, 16 May 2020 16:47:35 +0900
>>>>>>>>>>> Takashi Yano via Cygwin-developers
>>>>>>>>>>> <cygwin-developers@cygwin.com> wrote:
>>>>>>>>>>>> On Sat, 16 May 2020 09:29:56 +0900
>>>>>>>>>>>> Takashi Yano via Cygwin-developers
>>>>>>>>>>>> <cygwin-developers@cygwin.com> wrote:
>>>>>>>>>>>>> Fix a small bug caused when stdio is redirected to another pty.
>>>>>>>>>>>> Fix another bug caused when stdio is redirected to another pty.
>>>>>>>>>>> Revise the patch to fit the current git head.
>>>>>>>>>> Revise the patch again to fit the current git head.
>>>>>>>>> Make app, which reads stdin, work under gdb.
>>>>>>>> * Prevent ResizePseudoConsole() calls unless the pty is resized.
>>>>>>>> * Revise the patch to fit the current git head.
>>>>>>> Revise the patch to fit the current git head.
>>>>>> are you satisfied with the code?  If you want to merge it,
>>>>>> I'd bump Cygwin to 3.2.
>>>>> (blush) I apologize, I had promised to run my test cases.
>>>>> Beginning with it, the first succeeded, the second failed:
>>>>> run notepad (from mintty), click back into terminal, enter ^Z
>>>>> It says "Stopped" but the process is gone.
>>>>>
>>>>> Continuing may test suite soon...
>>>> OK, so here are finally my updated test results:
>>>>
>>>>
>>>> resize terminal while running Windows cmd
>>>> run cmd, resize, run dir/P:
>>>> ✓works
>>>>
>>>>
>>>> terminal reports in response to request escape sequences
>>>> ("\033[6n", "\033[0c", "\033[>c", '\033[18t', '\033]10;?\033\')
>>>> ✓works
>>>>
>>>>
>>>> output to alternate screen
>>>> echo -e "\e[?1047h"; cmd
>>>> ✓works
>>>> cmd
>>>> from other terminal: echo -e "\e[?1047h" > /dev/pty...
>>>> ↯no output; weird behaviour on ^C, mintty terminating (also in 3.1.6)
>>> I found this is a bug introduced in commit
>>> 0365031ce1347600d854a23f30f1355745a1765c.
>>>
>>> I will submit a patch for this issue.
>>>
>>>> signal handling/mediation; catch SIGTSTP
>>>> run notepad, click back into terminal, enter ^Z
>>>> ↯fails, notepad is terminated
>>>> -> this is a regression, ^Z,^C,^\ used to be ignored
>>> This behaviour is the same as cygwin 3.0.7. Pseudo console is not
>>> activated for native GUI processes.
>> OK, I understand this is consistent with my own proposal to apply pseudo
>> console only for Windows command-line programs. On the other hand, fatal
>> signal handling is another nuisance of running Windows programs from
>> cygwin, so there was a benefit.
>> Is it possible to activate the signal interworking without setting up a
>> pseudo console? If not, is it maybe worth to set it up also for Windows
>> GUI programs just for this purpose? (Modifying my proposal to trigger on
>> any Windows program.)
> When pseudo console is activated for GUI apps, ^C, ^Z and ^\ are
> just ignored. Please try additional patch attached with the latest
> pseudo console patch. Is this as you expected?
>
> I'm not sure which behaviour is better. Does anyone have opinion?
>
Just noticed this message (after travelling). Yes, killing a GUI 
application on ^Z is surprising and may be fatal for the data in that 
application. Ignoring ^Z, and, if that's the price, ignoring all three 
is better than letting ^Z terminate an application.
That's how it is in 3.1.6; I cannot easily test the new patch as my 
newlib-cygwin builds tend to bitrot. I'm always getting build failures 
if I try to catch up after some weeks. This time it's
configure: error: `CCASFLAGS' was not set in the previous run
configure: error: in `/usr/src/newlib-cygwin/x86_64-pc-cygwin/newlib/libc':
configure: error: changes in the environment can compromise the build
configure: error: run `make distclean' and/or `rm .././config.cache' and 
startver
... which I can do but which takes 1-2hours on a moderately old machine...
Thomas

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-24 11:22                                 ` Takashi Yano
@ 2020-08-02 12:01                                   ` Corinna Vinschen
  2020-08-03  2:05                                     ` Takashi Yano
  2020-08-03  2:11                                   ` Takashi Yano
  1 sibling, 1 reply; 73+ messages in thread
From: Corinna Vinschen @ 2020-08-02 12:01 UTC (permalink / raw)
  To: Takashi Yano; +Cc: cygwin-developers

Hi Takashi,

On Jul 24 20:22, Takashi Yano via Cygwin-developers wrote:
> On Fri, 24 Jul 2020 14:38:42 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Thu, 23 Jul 2020 09:33:28 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Wed, 22 Jul 2020 17:45:41 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > [...]
> > > > Attached is the patch in git format-patch format.
> > > > All the codes specific to the current implementation are removed.
> > > > 
> > > > Despite the utmost care, the changes are relatively large, so some
> > > > degradation may exist.
> > > > 
> > > > I will appreciate if you could test.
> > > 
> > > There were still unused code. Please try attached patch instead.
> > 
> > Changes:
> > * Do not activate pseudo console if it is already activated for
> >   another process on same pty.
> 
> Changes:
> * Fix a bug in the latest change.
> 
> -- 
> Takashi Yano <takashi.yano@nifty.ne.jp>

While hacking on the posix_spawn thingy, I noticed this hunk of yours:

@@ -897,6 +910,11 @@ child_info_spawn::worker (const char *prog_arg, const char
*const *argv,
                  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
                wait_for_myself ();
            }
+         if (enable_pcon)   
+           {
+             WaitForSingleObject (pi.hProcess, INFINITE);
+             ptys_primary->close_pseudoconsole ();
+           }
          myself.exit (EXITCODE_NOSET);
          break;
        case _P_WAIT:

Wait... what?  So the exec'ing process hangs infinitely if the exec'ed
process runs infinitely?  Doesn't that have weird side effects by any
chance?


Thanks,
Corinna

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-02 12:01                                   ` Corinna Vinschen
@ 2020-08-03  2:05                                     ` Takashi Yano
  2020-08-03 10:50                                       ` Corinna Vinschen
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-08-03  2:05 UTC (permalink / raw)
  To: cygwin-developers

Hi Corinna,

On Sun, 2 Aug 2020 14:01:04 +0200
Corinna Vinschen wrote:
> On Jul 24 20:22, Takashi Yano via Cygwin-developers wrote:
> > On Fri, 24 Jul 2020 14:38:42 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Thu, 23 Jul 2020 09:33:28 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Wed, 22 Jul 2020 17:45:41 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > [...]
> > > > > Attached is the patch in git format-patch format.
> > > > > All the codes specific to the current implementation are removed.
> > > > > 
> > > > > Despite the utmost care, the changes are relatively large, so some
> > > > > degradation may exist.
> > > > > 
> > > > > I will appreciate if you could test.
> > > > 
> > > > There were still unused code. Please try attached patch instead.
> > > 
> > > Changes:
> > > * Do not activate pseudo console if it is already activated for
> > >   another process on same pty.
> > 
> > Changes:
> > * Fix a bug in the latest change.
> > 
> > -- 
> > Takashi Yano <takashi.yano@nifty.ne.jp>
> 
> While hacking on the posix_spawn thingy, I noticed this hunk of yours:
> 
> @@ -897,6 +910,11 @@ child_info_spawn::worker (const char *prog_arg, const char
> *const *argv,
>                   && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
>                 wait_for_myself ();
>             }
> +         if (enable_pcon)   
> +           {
> +             WaitForSingleObject (pi.hProcess, INFINITE);
> +             ptys_primary->close_pseudoconsole ();
> +           }
>           myself.exit (EXITCODE_NOSET);
>           break;
>         case _P_WAIT:
> 
> Wait... what?  So the exec'ing process hangs infinitely if the exec'ed
> process runs infinitely?  Doesn't that have weird side effects by any
> chance?

This is needed to close pseudo console when the native console app
is terminated.

exec() call does not return on success. So the caller is not affected.
If mode == _P_OVERLAY, the process is not seen from cygwin, though,
it is seen from windows task manager. I have not noticed any serious
side effects so far.

BTW, I have noticed the current code cause handle leak if mode !=
_P_OVERLAY due to lack of chance to close pseudo console.
I will submit a new patch.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-07-24 11:22                                 ` Takashi Yano
  2020-08-02 12:01                                   ` Corinna Vinschen
@ 2020-08-03  2:11                                   ` Takashi Yano
  2020-08-03 12:23                                     ` Takashi Yano
  1 sibling, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-08-03  2:11 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 3067 bytes --]

On Fri, 24 Jul 2020 20:22:19 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Fri, 24 Jul 2020 14:38:42 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Thu, 23 Jul 2020 09:33:28 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Wed, 22 Jul 2020 17:45:41 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Wed, 22 Jul 2020 03:17:51 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > Hi Corinna,
> > > > > 
> > > > > On Mon, 20 Jul 2020 10:06:13 +0200
> > > > > Corinna Vinschen wrote:
> > > > > > On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
> > > > > > > Hi Corinna,
> > > > > > > 
> > > > > > > On Fri, 17 Jul 2020 13:19:12 +0200
> > > > > > > Corinna Vinschen wrote:
> > > > > > > > Hi Takashi,
> > > > > > > > 
> > > > > > > > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > > > > > > > > [...]
> > > > > > > > > Revise the patch to fit the current git head.
> > > > > > > > 
> > > > > > > > are you satisfied with the code?  If you want to merge it,
> > > > > > > > I'd bump Cygwin to 3.2.
> > > > > > > 
> > > > > > > Since this new implementation has both advantages and disadvantages,
> > > > > > > there might be some options.
> > > > > > > 
> > > > > > > 1) Default to new implementation and leave the current one as an
> > > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > > 2) Default to current implementation and add the new one as an
> > > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > > 3) Adopt only new implementation and throw the current one away.
> > > > > > > 
> > > > > > > What do you think?
> > > > > > 
> > > > > > Do you really want to maintain twice as much code doing the same stuff
> > > > > > and constantly having to ask users which version of the code they are
> > > > > > running?  The maintenance cost outweighs the advantages, IMHO.
> > > > > > Personally I'd go for option 3.
> > > > > 
> > > > > Personally, I feel a tinge of sadness to discard the current code,
> > > > > however, your opinion sounds reasonable.
> > > > > 
> > > > > I will submit a new patch in which all the codes specific to the
> > > > > current implementation are removed.
> > > > 
> > > > Attached is the patch in git format-patch format.
> > > > All the codes specific to the current implementation are removed.
> > > > 
> > > > Despite the utmost care, the changes are relatively large, so some
> > > > degradation may exist.
> > > > 
> > > > I will appreciate if you could test.
> > > 
> > > There were still unused code. Please try attached patch instead.
> > 
> > Changes:
> > * Do not activate pseudo console if it is already activated for
> >   another process on same pty.
> 
> Changes:
> * Fix a bug in the latest change.

Changes:
* Fix a handle leak caused when spawn is called with mode != _P_OVERLAY.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-Cygwin-pty-Implement-new-pseudo-console-support.patch --]
[-- Type: application/octet-stream, Size: 89589 bytes --]

From 87b29c5fdbf8f8b75256755a619efb0975c75b53 Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Mon, 3 Aug 2020 11:02:15 +0900
Subject: [PATCH] Cygwin: pty: Implement new pseudo console support.

- In this implementation, pseudo console is created for each native
  console app. Advantages and disadvantages of this implementation
  over the previous implementation are as follows.

  Advantages:
  1) No performance degradation in pty output for cygwin process.
      https://cygwin.com/pipermail/cygwin/2020-February/243858.html
  2) Free from the problem caused by difference of behaviour of control
     sequences between real terminal and pseudo console.
      https://cygwin.com/pipermail/cygwin/2019-December/243281.html
      https://cygwin.com/pipermail/cygwin/2020-February/243855.html
  3) Free from the problem in cgdb and emacs gud.
      https://cygwin.com/pipermail/cygwin/2020-January/243601.html
      https://cygwin.com/pipermail/cygwin/2020-March/244146.html
  4) Redrawing screen on executing native console apps is not necessary.
  5) cygwin-console-helper is not necessary for the pseudo console
     support.
  6) The codes for pseudo console support are much simpler than that
     of the previous one.

  Disadvantages:
  1) The cygwin program which calls console API directly does not work.
  2) The apps which use console API cannot be debugged with gdb. This
     is because pseudo console is not activated since gdb uses
     CreateProcess() rather than exec(). Even with this limitation,
     attaching gdb to native apps, in which pseudo console is already
     activated, works.
  3) Typeahead key inputs are discarded while native console app is
     executed. Simirally, typeahead key inputs while cygwin app is
     executed are not inherited to native console app.
  4) Code page cannot be changed by chcp.com. Acctually, chcp works
     itself and changes code page of its own pseudo console.  However,
     since pseudo console is recreated for another process, it cannot
     inherit the code page.
  5) system_printf() does not work after stderr is closed. (Same with
     cygwin 3.0.7)
  6) Startup time of native console apps is about 3 times slower than
     previous implemenation.
  7) Pseudo console cannot be activated if it is already activated for
     another process on same pty.
---
 winsup/cygwin/dtable.cc           |   32 -
 winsup/cygwin/fhandler.h          |   53 +-
 winsup/cygwin/fhandler_console.cc |   43 -
 winsup/cygwin/fhandler_tty.cc     | 1770 +++++------------------------
 winsup/cygwin/fork.cc             |   30 -
 winsup/cygwin/select.cc           |    5 +-
 winsup/cygwin/smallprint.cc       |    2 -
 winsup/cygwin/spawn.cc            |   90 +-
 winsup/cygwin/strace.cc           |    2 -
 winsup/cygwin/tty.cc              |   20 +-
 winsup/cygwin/tty.h               |   13 +-
 winsup/cygwin/winsup.h            |    3 -
 12 files changed, 345 insertions(+), 1718 deletions(-)

diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index e9e005b08..6a91e33bc 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -147,38 +147,6 @@ dtable::get_debugger_info ()
 void
 dtable::stdio_init ()
 {
-  for (int i = 0; i < 3; i ++)
-    {
-      const int chk_order[] = {1, 0, 2};
-      int fd = chk_order[i];
-      fhandler_base *fh = cygheap->fdtab[fd];
-      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
-	{
-	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	  if (ptys->get_pseudo_console ())
-	    {
-	      bool attached = !!fhandler_console::get_console_process_id
-		(ptys->get_helper_process_id (), true);
-	      if (attached)
-		break;
-	      else
-		{
-		  /* Not attached to pseudo console in fork() or spawn()
-		     by some reason. This happens if the executable is
-		     a windows GUI binary, such as mintty. */
-		  FreeConsole ();
-		  if (AttachConsole (ptys->get_helper_process_id ()))
-		    {
-		      ptys->fixup_after_attach (false, fd);
-		      break;
-		    }
-		}
-	    }
-	}
-      else if (fh && fh->get_major () == DEV_CONS_MAJOR)
-	break;
-    }
-
   if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT))
     {
       tty_min *t = cygwin_shared->tty.get_cttyp ();
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 60bd27e00..ebaca3bb8 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -326,16 +326,16 @@ class fhandler_base
   virtual size_t &raixput () { return ra.raixput; };
   virtual size_t &rabuflen () { return ra.rabuflen; };
 
-  virtual bool get_readahead_valid () { return raixget () < ralen (); }
+  bool get_readahead_valid () { return raixget () < ralen (); }
   int puts_readahead (const char *s, size_t len = (size_t) -1);
-  virtual int put_readahead (char value);
+  int put_readahead (char value);
 
   int get_readahead ();
   int peek_readahead (int queryput = 0);
 
   void set_readahead_valid (int val, int ch = -1);
 
-  virtual int get_readahead_into_buffer (char *buf, size_t buflen);
+  int get_readahead_into_buffer (char *buf, size_t buflen);
 
   bool has_acls () const { return pc.has_acls (); }
 
@@ -1909,7 +1909,7 @@ class fhandler_termios: public fhandler_base
   int ioctl (int, void *);
   tty_min *_tc;
   tty *get_ttyp () {return (tty *) tc ();}
-  virtual int eat_readahead (int n);
+  int eat_readahead (int n);
 
  public:
   tty_min*& tc () {return _tc;}
@@ -2188,7 +2188,6 @@ private:
   static bool need_invisible ();
   static void free_console ();
   static const char *get_nonascii_key (INPUT_RECORD& input_rec, char *);
-  static DWORD get_console_process_id (DWORD pid, bool match);
 
   fhandler_console (void *) {}
 
@@ -2268,19 +2267,7 @@ class fhandler_pty_common: public fhandler_termios
     return fh;
   }
 
-  bool attach_pcon_in_fork (void)
-  {
-    return get_ttyp ()->attach_pcon_in_fork;
-  }
-  DWORD get_helper_process_id (void)
-  {
-    return get_ttyp ()->helper_process_id;
-  }
-  HPCON get_pseudo_console (void)
-  {
-    return get_ttyp ()->h_pseudo_console;
-  }
-  bool to_be_read_from_pcon (void);
+  void resize_pseudo_console (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2291,23 +2278,15 @@ class fhandler_pty_slave: public fhandler_pty_common
 {
   HANDLE inuse;			// used to indicate that a tty is in use
   HANDLE output_handle_cyg, io_handle_cyg;
-  DWORD pid_restore;
-  int fd;
 
   /* Helper functions for fchmod and fchown. */
   bool fch_open_handles (bool chown);
   int fch_set_sd (security_descriptor &sd, bool chown);
   void fch_close_handles ();
 
-  bool try_reattach_pcon ();
-  void restore_reattach_pcon ();
-  inline void free_attached_console ();
-
  public:
   /* Constructor */
   fhandler_pty_slave (int);
-  /* Destructor */
-  ~fhandler_pty_slave ();
 
   void set_output_handle_cyg (HANDLE h) { output_handle_cyg = h; }
   HANDLE& get_output_handle_cyg () { return output_handle_cyg; }
@@ -2319,9 +2298,6 @@ class fhandler_pty_slave: public fhandler_pty_common
   ssize_t __stdcall write (const void *ptr, size_t len);
   void __reg3 read (void *ptr, size_t& len);
   int init (HANDLE, DWORD, mode_t);
-  int eat_readahead (int n);
-  int get_readahead_into_buffer (char *buf, size_t buflen);
-  bool get_readahead_valid (void);
 
   int tcsetattr (int a, const struct termios *t);
   int tcgetattr (struct termios *t);
@@ -2358,20 +2334,12 @@ class fhandler_pty_slave: public fhandler_pty_common
     copyto (fh);
     return fh;
   }
-  void set_switch_to_pcon (int fd);
+  bool setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon);
+  void close_pseudoconsole (void);
+  void set_switch_to_pcon (void);
   void reset_switch_to_pcon (void);
-  void push_to_pcon_screenbuffer (const char *ptr, size_t len, bool is_echo);
   void mask_switch_to_pcon_in (bool mask);
-  void fixup_after_attach (bool native_maybe, int fd);
-  bool is_line_input (void)
-  {
-    return get_ttyp ()->ti.c_lflag & ICANON;
-  }
   void setup_locale (void);
-  void set_freeconsole_on_close (bool val);
-  void trigger_redraw_screen (void);
-  void pull_pcon_input (void);
-  void update_pcon_input_state (bool need_lock);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
@@ -2396,7 +2364,6 @@ public:
   int process_slave_output (char *buf, size_t len, int pktmode_on);
   void doecho (const void *str, DWORD len);
   int accept_input ();
-  int put_readahead (char value);
   int open (int flags, mode_t mode = 0);
   void open_setup (int flags);
   ssize_t __stdcall write (const void *ptr, size_t len);
@@ -2435,9 +2402,7 @@ public:
     copyto (fh);
     return fh;
   }
-
-  bool setup_pseudoconsole (void);
-  void transfer_input_to_pcon (void);
+  bool to_be_read_from_pcon (void);
 };
 
 class fhandler_dev_null: public fhandler_base
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 52741ce8b..02a5996a1 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -1206,18 +1206,6 @@ fhandler_console::close ()
   if (con_ra.rabuf)
     free (con_ra.rabuf);
 
-  /* If already attached to pseudo console, don't call free_console () */
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR ||
-	cfd->get_major () == DEV_PTYS_MAJOR)
-      {
-	fhandler_pty_common *t =
-	  (fhandler_pty_common *) (fhandler_base *) cfd;
-	if (get_console_process_id (t->get_helper_process_id (), true))
-	  return 0;
-      }
-
   if (!have_execed)
     free_console ();
   return 0;
@@ -3611,37 +3599,6 @@ fhandler_console::need_invisible ()
   return b;
 }
 
-DWORD
-fhandler_console::get_console_process_id (DWORD pid, bool match)
-{
-  DWORD tmp;
-  DWORD num, num_req;
-  num = 1;
-  num_req = GetConsoleProcessList (&tmp, num);
-  DWORD *list;
-  while (true)
-    {
-      list = (DWORD *)
-	HeapAlloc (GetProcessHeap (), 0, num_req * sizeof (DWORD));
-      num = num_req;
-      num_req = GetConsoleProcessList (list, num);
-      if (num_req > num)
-	HeapFree (GetProcessHeap (), 0, list);
-      else
-	break;
-    }
-  num = num_req;
-
-  tmp = 0;
-  for (DWORD i=0; i<num; i++)
-    if ((match && list[i] == pid) || (!match && list[i] != pid))
-      /* Last one is the oldest. */
-      /* https://github.com/microsoft/terminal/issues/95 */
-      tmp = list[i];
-  HeapFree (GetProcessHeap (), 0, list);
-  return tmp;
-}
-
 DWORD
 fhandler_console::__acquire_input_mutex (const char *fn, int ln, DWORD ms)
 {
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 6a004f3a5..37682dc3e 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -25,7 +25,6 @@ details. */
 #include "child_info.h"
 #include <asm/socket.h>
 #include "cygwait.h"
-#include "tls_pbuf.h"
 #include "registry.h"
 
 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
@@ -33,7 +32,6 @@ details. */
 #endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
 
 extern "C" int sscanf (const char *, const char *, ...);
-extern "C" int ttyname_r (int, char*, size_t);
 
 extern "C" {
   HRESULT WINAPI CreatePseudoConsole (COORD, HANDLE, HANDLE, DWORD, HPCON *);
@@ -60,20 +58,10 @@ struct pipe_reply {
   DWORD error;
 };
 
-static int pcon_attached_to = -1;
 static bool isHybrid;
-static bool do_not_reset_switch_to_pcon;
-static bool freeconsole_on_close = true;
-static tty *last_ttyp = NULL;
-
-void
-clear_pcon_attached_to (void)
-{
-  pcon_attached_to = -1;
-}
 
 static void
-set_switch_to_pcon (void)
+set_switch_to_pcon (HANDLE h)
 {
   cygheap_fdenum cfd (false);
   int fd;
@@ -82,280 +70,17 @@ set_switch_to_pcon (void)
       {
 	fhandler_base *fh = cfd;
 	fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	if (ptys->get_pseudo_console ())
-	  {
-	    ptys->set_switch_to_pcon (fd);
-	    ptys->trigger_redraw_screen ();
-	    DWORD mode =
-	      ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	    SetConsoleMode (ptys->get_handle (), mode);
-	  }
+	if (h == ptys->get_handle ())
+	  ptys->set_switch_to_pcon ();
 	return;
       }
-  /* No pty slave opened */
-  if (last_ttyp) /* Make system_printf() work after closing pty slave */
-    last_ttyp->set_switch_to_pcon_out (true);
-}
-
-static void
-force_attach_to_pcon (HANDLE h)
-{
-  bool attach_done = false;
-  for (int n = 0; n < 2; n ++)
-    {
-      /* First time, attach to the pty whose handle value is match.
-	 Second time, try to attach to any pty. */
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	    if (!ptys->get_pseudo_console ())
-	      continue;
-	    if (n != 0
-		|| h == ptys->get_handle ()
-		|| h == ptys->get_output_handle ())
-	      {
-		if (fhandler_console::get_console_process_id
-				  (ptys->get_helper_process_id (), true))
-		  attach_done = true;
-		else
-		  {
-		    FreeConsole ();
-		    if (AttachConsole (ptys->get_helper_process_id ()))
-		      {
-			pcon_attached_to = ptys->get_minor ();
-			attach_done = true;
-		      }
-		    else
-		      pcon_attached_to = -1;
-		  }
-		break;
-	      }
-	  }
-	else if (cfd->get_major () == DEV_CONS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_console *cons = (fhandler_console *) fh;
-	    if (n != 0
-		|| h == cons->get_handle ()
-		|| h == cons->get_output_handle ())
-	      {
-		/* If the process is running on a console,
-		   the parent process should be attached
-		   to the same console. */
-		DWORD attach_wpid;
-		if (myself->ppid == 1)
-		  attach_wpid = ATTACH_PARENT_PROCESS;
-		else
-		  {
-		    pinfo p (myself->ppid);
-		    attach_wpid = p->dwProcessId;
-		  }
-		FreeConsole ();
-		if (AttachConsole (attach_wpid))
-		  {
-		    pcon_attached_to = -1;
-		    attach_done = true;
-		  }
-		else
-		  pcon_attached_to = -1;
-		break;
-	      }
-	  }
-      if (attach_done)
-	break;
-    }
-}
-
-void
-set_ishybrid_and_switch_to_pcon (HANDLE h)
-{
-  if (GetFileType (h) == FILE_TYPE_CHAR)
-    {
-      force_attach_to_pcon (h);
-      DWORD dummy;
-      if (!isHybrid && (GetConsoleMode (h, &dummy)
-			|| GetLastError () != ERROR_INVALID_HANDLE))
-	{
-	  isHybrid = true;
-	  set_switch_to_pcon ();
-	}
-    }
-}
-
-inline void
-fhandler_pty_slave::free_attached_console ()
-{
-  bool attached = get_ttyp () ?
-    fhandler_console::get_console_process_id (get_helper_process_id (), true)
-    : (get_minor () == pcon_attached_to);
-  if (freeconsole_on_close && attached)
-    {
-      FreeConsole ();
-      pcon_attached_to = -1;
-    }
 }
 
 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
-DEF_HOOK (WriteFile);
-DEF_HOOK (WriteConsoleA);
-DEF_HOOK (WriteConsoleW);
-DEF_HOOK (ReadFile);
-DEF_HOOK (ReadConsoleA);
-DEF_HOOK (ReadConsoleW);
-DEF_HOOK (WriteConsoleOutputA);
-DEF_HOOK (WriteConsoleOutputW);
-DEF_HOOK (WriteConsoleOutputCharacterA);
-DEF_HOOK (WriteConsoleOutputCharacterW);
-DEF_HOOK (WriteConsoleOutputAttribute);
-DEF_HOOK (SetConsoleCursorPosition);
-DEF_HOOK (SetConsoleTextAttribute);
-DEF_HOOK (WriteConsoleInputA);
-DEF_HOOK (WriteConsoleInputW);
-DEF_HOOK (ReadConsoleInputA);
-DEF_HOOK (ReadConsoleInputW);
-DEF_HOOK (PeekConsoleInputA);
-DEF_HOOK (PeekConsoleInputW);
 /* CreateProcess() is hooked for GDB etc. */
 DEF_HOOK (CreateProcessA);
 DEF_HOOK (CreateProcessW);
 
-static BOOL WINAPI
-WriteFile_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleA_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleW_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadFile_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleA_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleW_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleOutputA_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputA_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputW_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputW_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterA_Hooked
-     (HANDLE h, LPCSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterA_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterW_Hooked
-     (HANDLE h, LPCWSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterW_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputAttribute_Hooked
-     (HANDLE h, CONST WORD *a, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputAttribute_Orig (h, a, l, c, n);
-}
-static BOOL WINAPI
-SetConsoleCursorPosition_Hooked
-     (HANDLE h, COORD c)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleCursorPosition_Orig (h, c);
-}
-static BOOL WINAPI
-SetConsoleTextAttribute_Hooked
-     (HANDLE h, WORD a)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleTextAttribute_Orig (h, a);
-}
-static BOOL WINAPI
-WriteConsoleInputA_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-WriteConsoleInputW_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputW_Orig (h, r, l, n);
-}
-/* CreateProcess() is hooked for GDB etc. */
 static BOOL WINAPI
 CreateProcessA_Hooked
      (LPCSTR n, LPSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
@@ -363,11 +88,14 @@ CreateProcessA_Hooked
       LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 static BOOL WINAPI
@@ -377,11 +105,14 @@ CreateProcessW_Hooked
       LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 
@@ -464,10 +195,6 @@ fhandler_pty_master::flush_to_slave ()
 {
   if (get_readahead_valid () && !(get_ttyp ()->ti.c_lflag & ICANON))
     accept_input ();
-  WaitForSingleObject (input_mutex, INFINITE);
-  if (!get_ttyp ()->pcon_in_empty && !(get_ttyp ()->ti.c_lflag & ICANON))
-    SetEvent (input_available_event);
-  ReleaseMutex (input_mutex);
 }
 
 DWORD
@@ -532,14 +259,6 @@ fhandler_pty_master::doecho (const void *str, DWORD len)
   release_output_mutex ();
 }
 
-int
-fhandler_pty_master::put_readahead (char value)
-{
-  if (to_be_read_from_pcon ())
-    return 1;
-  return fhandler_base::put_readahead (value);
-}
-
 int
 fhandler_pty_master::accept_input ()
 {
@@ -551,9 +270,11 @@ fhandler_pty_master::accept_input ()
   char *p = rabuf () + raixget ();
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
   if (to_be_read_from_pcon ())
-    ; /* Do nothing */
-  else if (!bytes_left)
+    write_to = to_slave;
+
+  if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
@@ -564,10 +285,10 @@ fhandler_pty_master::accept_input ()
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -725,52 +446,12 @@ out:
 
 fhandler_pty_slave::fhandler_pty_slave (int unit)
   : fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL),
-  io_handle_cyg (NULL), pid_restore (0), fd (-1)
+  io_handle_cyg (NULL)
 {
   if (unit >= 0)
     dev ().parse (DEV_PTYS_MAJOR, unit);
 }
 
-fhandler_pty_slave::~fhandler_pty_slave ()
-{
-  if (!get_ttyp ())
-    {
-      /* Why comes here? Who clears _tc? */
-      free_attached_console ();
-      return;
-    }
-  if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 0)
-	{
-	  pcon_attached_to = -1;
-	  last_ttyp = get_ttyp ();
-	}
-      if (used == 0)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
-}
-
 int
 fhandler_pty_slave::open (int flags, mode_t)
 {
@@ -833,8 +514,8 @@ fhandler_pty_slave::open (int flags, mode_t)
     release_output_mutex ();
   }
 
-  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg () ||
-      !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
+  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg ()
+      || !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
     {
       errmsg = "pty handles have been closed";
       set_errno (EACCES);
@@ -923,8 +604,8 @@ fhandler_pty_slave::open (int flags, mode_t)
       from_master_cyg_local = repl.from_master_cyg;
       to_master_local = repl.to_master;
       to_master_cyg_local = repl.to_master_cyg;
-      if (!from_master_local || !from_master_cyg_local ||
-	  !to_master_local || !to_master_cyg_local)
+      if (!from_master_local || !from_master_cyg_local
+	  || !to_master_local || !to_master_cyg_local)
 	{
 	  SetLastError (repl.error);
 	  errmsg = "error duplicating pipes, %E";
@@ -950,24 +631,7 @@ fhandler_pty_slave::open (int flags, mode_t)
   set_output_handle (to_master_local);
   set_output_handle_cyg (to_master_cyg_local);
 
-  if (!get_pseudo_console ())
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (!fhandler_console::get_console_process_id
-			       (GetCurrentProcessId (), true))
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (fhandler_console::get_console_process_id
-			       (get_helper_process_id (), true))
-    /* Attached to pcon of this pty */
-    {
-      pcon_attached_to = get_minor ();
-      init_console_handler (true);
-    }
+  fhandler_console::need_invisible ();
 
   set_open_status ();
   return 1;
@@ -1021,8 +685,7 @@ fhandler_pty_slave::close ()
   if (!ForceCloseHandle (get_handle_cyg ()))
     termios_printf ("CloseHandle (get_handle_cyg ()<%p>), %E",
 	get_handle_cyg ());
-  if (!get_pseudo_console () &&
-      (unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
+  if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
     fhandler_console::free_console ();	/* assumes that we are the last pty closer */
   fhandler_pty_common::close ();
   if (!ForceCloseHandle (output_mutex))
@@ -1070,423 +733,31 @@ fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
   return ret;
 }
 
-bool
-fhandler_pty_slave::try_reattach_pcon (void)
-{
-  pid_restore = 0;
-
-  /* Do not detach from the console because re-attaching will
-     fail if helper process is running as service account. */
-  if (get_ttyp()->attach_pcon_in_fork)
-    return false;
-  if (pcon_attached_to >= 0 &&
-      cygwin_shared->tty[pcon_attached_to]->attach_pcon_in_fork)
-    return false;
-
-  pid_restore =
-    fhandler_console::get_console_process_id (GetCurrentProcessId (),
-					      false);
-  /* If pid_restore is not set, give up. */
-  if (!pid_restore)
-    return false;
-
-  FreeConsole ();
-  if (!AttachConsole (get_helper_process_id ()))
-    {
-      system_printf ("pty%d: AttachConsole(helper=%d) failed. 0x%08lx",
-		     get_minor (), get_helper_process_id (), GetLastError ());
-      return false;
-    }
-  return true;
-}
-
 void
-fhandler_pty_slave::restore_reattach_pcon (void)
+fhandler_pty_slave::set_switch_to_pcon (void)
 {
-  if (pid_restore)
+  if (!get_ttyp ()->switch_to_pcon_in)
     {
-      FreeConsole ();
-      if (!AttachConsole (pid_restore))
-	{
-	  system_printf ("pty%d: AttachConsole(restore=%d) failed. 0x%08lx",
-			 get_minor (), pid_restore, GetLastError ());
-	  pcon_attached_to = -1;
-	}
-    }
-  pid_restore = 0;
-}
-
-/* This function requests transfering the input data from the input
-   pipe for cygwin apps to the other input pipe for native apps. */
-void
-fhandler_pty_slave::pull_pcon_input (void)
-{
-  get_ttyp ()->req_transfer_input_to_pcon = true;
-  while (get_ttyp ()->req_transfer_input_to_pcon)
-    Sleep (1);
-}
-
-void
-fhandler_pty_slave::update_pcon_input_state (bool need_lock)
-{
-  if (need_lock)
-    WaitForSingleObject (input_mutex, INFINITE);
-  /* Flush input buffer if it is requested by master.
-     This happens if ^C is pressed in pseudo console side. */
-  if (get_ttyp ()->req_flush_pcon_input)
-    {
-      FlushConsoleInputBuffer (get_handle ());
-      get_ttyp ()->req_flush_pcon_input = false;
-    }
-  /* Peek console input buffer and update state. */
-  INPUT_RECORD inp[INREC_SIZE];
-  DWORD n;
-  BOOL (WINAPI *PeekFunc)
-    (HANDLE, PINPUT_RECORD, DWORD, LPDWORD);
-  PeekFunc =
-    PeekConsoleInputA_Orig ? : PeekConsoleInput;
-  PeekFunc (get_handle (), inp, INREC_SIZE, &n);
-  bool saw_accept = false;
-  bool pipe_empty = true;
-  while (n-- > 0)
-    if (inp[n].EventType == KEY_EVENT && inp[n].Event.KeyEvent.bKeyDown &&
-	inp[n].Event.KeyEvent.uChar.AsciiChar)
-      {
-	pipe_empty = false;
-	char c = inp[n].Event.KeyEvent.uChar.AsciiChar;
-	const char sigs[] = {
-	  (char) get_ttyp ()->ti.c_cc[VINTR],
-	  (char) get_ttyp ()->ti.c_cc[VQUIT],
-	  (char) get_ttyp ()->ti.c_cc[VSUSP],
-	};
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n',
-	  '\r'
-	};
-	if (is_line_input () && c && memchr (eols, c, sizeof (eols)))
-	  saw_accept = true;
-	if ((get_ttyp ()->ti.c_lflag & ISIG)
-	    && c && memchr (sigs, c, sizeof (sigs)))
-	  saw_accept = true;
-      }
-  get_ttyp ()->pcon_in_empty = pipe_empty && !(ralen () > raixget ());
-  if (!get_readahead_valid () &&
-      (pipe_empty || (is_line_input () && !saw_accept)) &&
-      get_ttyp ()->read_retval == 1 && bytes_available (n) && n == 0)
-    ResetEvent (input_available_event);
-  if (need_lock)
-    ReleaseMutex (input_mutex);
-}
-
-int
-fhandler_pty_slave::eat_readahead (int n)
-{
-  int oralen = ralen ();
-  if (n < 0)
-    n = ralen () - raixget ();
-  if (n > 0 && ralen () > raixget ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      while (n > 0 && ralen () > raixget ())
-	{
-	  if (is_line_input () && rabuf ()[ralen ()-1]
-	      && memchr (eols, rabuf ()[ralen ()-1], sizeof (eols)))
-	    break;
-	  -- n;
-	  -- ralen ();
-	}
-
-      /* If IUTF8 is set, the terminal is in UTF-8 mode.  If so, we erase
-	 a complete UTF-8 multibyte sequence on VERASE/VWERASE.  Otherwise,
-	 if we only erase a single byte, invalid unicode chars are left in
-	 the input. */
-      if (get_ttyp ()->ti.c_iflag & IUTF8)
-	while (ralen () > raixget () &&
-	       ((unsigned char) rabuf ()[ralen ()] & 0xc0) == 0x80)
-	  --ralen ();
-    }
-  oralen = oralen - ralen ();
-  if (raixget () >= ralen ())
-    raixget () = raixput () = ralen () = 0;
-  else if (raixput () > ralen ())
-    raixput () = ralen ();
-
-  return oralen;
-}
-
-int
-fhandler_pty_slave::get_readahead_into_buffer (char *buf, size_t buflen)
-{
-  int ch;
-  int copied_chars = 0;
-
-  while (buflen)
-    if ((ch = get_readahead ()) < 0)
-      break;
-    else
-      {
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n'
-	};
-	buf[copied_chars++] = (unsigned char)(ch & 0xff);
-	buflen--;
-	if (is_line_input () && ch && memchr (eols, ch & 0xff, sizeof (eols)))
-	  break;
-      }
-
-  return copied_chars;
-}
-
-bool
-fhandler_pty_slave::get_readahead_valid (void)
-{
-  if (is_line_input ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      for (size_t i=raixget (); i<ralen (); i++)
-	if (rabuf ()[i] && memchr (eols, rabuf ()[i], sizeof (eols)))
-	  return true;
-      return false;
-    }
-  else
-    return ralen () > raixget ();
-}
-
-void
-fhandler_pty_slave::set_switch_to_pcon (int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  acquire_output_mutex (INFINITE);
-  if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
-    {
-      pull_pcon_input ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
+      isHybrid = true;
+      if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
 	get_ttyp ()->pcon_pid = myself->pid;
       get_ttyp ()->switch_to_pcon_in = true;
-      if (isHybrid && !get_ttyp ()->switch_to_pcon_out)
-	{
-	  get_ttyp ()->wait_pcon_fwd ();
-	  get_ttyp ()->switch_to_pcon_out = true;
-	}
     }
-  else if ((fd == 1 || fd == 2) && !get_ttyp ()->switch_to_pcon_out)
-    {
-      get_ttyp ()->wait_pcon_fwd ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
-	get_ttyp ()->pcon_pid = myself->pid;
-      get_ttyp ()->switch_to_pcon_out = true;
-      if (isHybrid)
-	get_ttyp ()->switch_to_pcon_in = true;
-    }
-  release_output_mutex ();
 }
 
 void
 fhandler_pty_slave::reset_switch_to_pcon (void)
 {
-  if (get_ttyp ()->pcon_pid &&
-      get_ttyp ()->pcon_pid != myself->pid &&
-      !!pinfo (get_ttyp ()->pcon_pid))
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
     /* There is a process which is grabbing pseudo console. */
     return;
   if (isHybrid)
     return;
-  if (do_not_reset_switch_to_pcon)
-    return;
-  acquire_output_mutex (INFINITE);
-  if (get_ttyp ()->switch_to_pcon_out)
-    /* Wait for pty_master_fwd_thread() */
-    get_ttyp ()->wait_pcon_fwd ();
   get_ttyp ()->pcon_pid = 0;
   get_ttyp ()->switch_to_pcon_in = false;
-  get_ttyp ()->switch_to_pcon_out = false;
-  release_output_mutex ();
-  init_console_handler (true);
-}
-
-void
-fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len,
-					       bool is_echo)
-{
-  bool attached =
-    !!fhandler_console::get_console_process_id (get_helper_process_id (), true);
-  if (!attached && pcon_attached_to == get_minor ())
-    {
-      for (DWORD t0 = GetTickCount (); GetTickCount () - t0 < 100; )
-	{
-	  Sleep (1);
-	  attached = fhandler_console::get_console_process_id
-				      (get_helper_process_id (), true);
-	  if (attached)
-	    break;
-	}
-      if (!attached)
-	{
-	  system_printf ("pty%d: pcon_attach_to mismatch??????", get_minor ());
-	  return;
-	}
-    }
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  if (pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      goto detach;
-
-  char *buf;
-  size_t nlen;
-  DWORD origCP;
-  origCP = GetConsoleOutputCP ();
-  SetConsoleOutputCP (get_ttyp ()->term_code_page);
-  /* Just copy */
-  buf = (char *) HeapAlloc (GetProcessHeap (), 0, len);
-  memcpy (buf, (char *)ptr, len);
-  nlen = len;
-  char *p0, *p1;
-  p0 = p1 = buf;
-  /* Remove alternate screen buffer drawing */
-  while (p0 && p1)
-    {
-      if (!get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to alternate screen buffer */
-	  p0 = (char *) memmem (p1, nlen - (p1-buf), "\033[?1049h", 8);
-	  if (p0)
-	    {
-	      //p0 += 8;
-	      get_ttyp ()->screen_alternated = true;
-	      if (get_ttyp ()->switch_to_pcon_out)
-		do_not_reset_switch_to_pcon = true;
-	    }
-	}
-      if (get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to main screen buffer */
-	  p1 = (char *) memmem (p0, nlen - (p0-buf), "\033[?1049l", 8);
-	  if (p1)
-	    {
-	      p1 += 8;
-	      get_ttyp ()->screen_alternated = false;
-	      do_not_reset_switch_to_pcon = false;
-	      memmove (p0, p1, buf+nlen - p1);
-	      nlen -= p1 - p0;
-	    }
-	  else
-	    nlen = p0 - buf;
-	}
-    }
-  if (!nlen) /* Nothing to be synchronized */
-    goto cleanup;
-  if (get_ttyp ()->switch_to_pcon_out && !is_echo)
-    goto cleanup;
-  /* Remove ESC sequence which returns results to console
-     input buffer. Without this, cursor position report
-     is put into the input buffer as a garbage. */
-  /* Remove ESC sequence to report cursor position. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[6n", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-  /* Remove ESC sequence to report terminal identity. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[0c", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-
-  /* If the ESC sequence ESC[?3h or ESC[?3l which clears console screen
-     buffer is pushed, set need_redraw_screen to trigger redraw screen. */
-  p0 = buf;
-  while ((p0 = (char *) memmem (p0, nlen - (p0 - buf), "\033[?", 3)))
-    {
-      p0 += 3;
-      bool exist_arg_3 = false;
-      while (p0 < buf + nlen && (isdigit (*p0) || *p0 == ';'))
-	{
-	  int arg = 0;
-	  while (p0 < buf + nlen && isdigit (*p0))
-	    arg = arg * 10 + (*p0 ++) - '0';
-	  if (arg == 3)
-	    exist_arg_3 = true;
-	  if (p0 < buf + nlen && *p0 == ';')
-	    p0 ++;
-	}
-      if (p0 < buf + nlen && exist_arg_3 && (*p0 == 'h' || *p0 == 'l'))
-	get_ttyp ()->need_redraw_screen = true;
-      p0 ++;
-      if (p0 >= buf + nlen)
-	break;
-    }
-
-  int retry_count;
-  retry_count = 0;
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  while (!GetConsoleMode (get_output_handle (), &dwMode))
-    {
-      termios_printf ("GetConsoleMode failed, %E");
-      int errno_save = errno;
-      /* Re-open handles */
-      this->open (0, 0);
-      /* Fix pseudo console window size */
-      this->ioctl (TIOCSWINSZ, &get_ttyp ()->winsize);
-      if (errno != errno_save)
-	set_errno (errno_save);
-      if (++retry_count > 3)
-	goto cleanup;
-    }
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-  char *p;
-  p = buf;
-  DWORD wLen, written;
-  written = 0;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
-  while (written <  nlen)
-    {
-      if (!WriteFunc (get_output_handle (), p, nlen - written, &wLen, NULL))
-	{
-	  termios_printf ("WriteFile failed, %E");
-	  break;
-	}
-      else
-	{
-	  written += wLen;
-	  p += wLen;
-	}
-    }
-  /* Detach from pseudo console and resume. */
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-cleanup:
-  SetConsoleOutputCP (origCP);
-  HeapFree (GetProcessHeap (), 0, buf);
-detach:
-  restore_reattach_pcon ();
+  get_ttyp ()->h_pseudo_console = NULL;
+  get_ttyp ()->pcon_start = false;
 }
 
 ssize_t __stdcall
@@ -1505,44 +776,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
   reset_switch_to_pcon ();
 
   acquire_output_mutex (INFINITE);
-  bool output_to_pcon = get_ttyp ()->switch_to_pcon_out;
-  release_output_mutex ();
-
-  UINT target_code_page = output_to_pcon ?
-    GetConsoleOutputCP () : get_ttyp ()->term_code_page;
-  ssize_t nlen;
-  char *buf = convert_mb_str (target_code_page, (size_t *) &nlen,
-		 get_ttyp ()->term_code_page, (const char *) ptr, len);
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  bool fallback = false;
-  if (output_to_pcon && pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      fallback = true;
-
-  if (output_to_pcon && !fallback &&
-      (memmem (buf, nlen, "\033[6n", 4) || memmem (buf, nlen, "\033[0c", 4)))
-    {
-      get_ttyp ()->pcon_in_empty = false;
-      if (!is_line_input ())
-	SetEvent (input_available_event);
-    }
-
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  if (output_to_pcon && !fallback)
-    {
-      GetConsoleMode (get_output_handle (), &dwMode);
-      SetConsoleMode (get_output_handle (), dwMode | flags);
-    }
-  HANDLE to = (output_to_pcon && !fallback) ?
-    get_output_handle () : get_output_handle_cyg ();
-  acquire_output_mutex (INFINITE);
-  if (!process_opost_output (to, buf, nlen, false))
+  if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false))
     {
       DWORD err = GetLastError ();
       termios_printf ("WriteFile failed, %E");
@@ -1557,20 +791,6 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
       towrite = -1;
     }
   release_output_mutex ();
-  mb_str_free (buf);
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (output_to_pcon && !fallback)
-    SetConsoleMode (get_output_handle (), dwMode | flags);
-
-  restore_reattach_pcon ();
-
-  /* Push slave output to pseudo console screen buffer */
-  if (get_pseudo_console ())
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer ((char *)ptr, len, false);
-      release_output_mutex ();
-    }
 
   return towrite;
 }
@@ -1582,16 +802,15 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 }
 
 bool
-fhandler_pty_common::to_be_read_from_pcon (void)
+fhandler_pty_master::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return get_ttyp ()->pcon_start
+    || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
 fhandler_pty_slave::read (void *ptr, size_t& len)
 {
-  char *ptr0 = (char *)ptr;
   ssize_t totalread = 0;
   int vmin = 0;
   int vtime = 0;	/* Initialized to prevent -Wuninitialized warning */
@@ -1616,8 +835,6 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
       mask_switch_to_pcon_in (true);
       reset_switch_to_pcon ();
     }
-  if (to_be_read_from_pcon ())
-    update_pcon_input_state (true);
 
   if (is_nonblocking () || !ptr) /* Indicating tcflush(). */
     time_to_wait = 0;
@@ -1703,98 +920,21 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 	      if (!totalread)
 		{
 		  set_sig_errno (EAGAIN);
-		  totalread = -1;
-		}
-	      goto out;
-	    }
-	  continue;
-	default:
-	  termios_printf ("wait for input mutex failed, %E");
-	  if (!totalread)
-	    {
-	      __seterrno ();
-	      totalread = -1;
-	    }
-	  goto out;
-	}
-      if (ptr && to_be_read_from_pcon ())
-	{
-	  if (get_readahead_valid ())
-	    {
-	      ReleaseMutex (input_mutex);
-	      totalread = get_readahead_into_buffer ((char *) ptr, len);
-	    }
-	  else
-	    {
-	      if (!try_reattach_pcon ())
-		{
-		  restore_reattach_pcon ();
-		  goto do_read_cyg;
-		}
-
-	      DWORD dwMode;
-	      GetConsoleMode (get_handle (), &dwMode);
-	      DWORD flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
-	      if (dwMode != flags)
-		SetConsoleMode (get_handle (), flags);
-	      /* Read get_handle() instad of get_handle_cyg() */
-	      BOOL (WINAPI *ReadFunc)
-		(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID);
-	      ReadFunc = ReadConsoleA_Orig ? ReadConsoleA_Orig : ReadConsoleA;
-	      DWORD rlen;
-	      readlen = MIN (len, sizeof (buf));
-	      if (!ReadFunc (get_handle (), buf, readlen, &rlen, NULL))
-		{
-		  termios_printf ("read failed, %E");
-		  SetConsoleMode (get_handle (), dwMode);
-		  restore_reattach_pcon ();
-		  ReleaseMutex (input_mutex);
-		  set_errno (EIO);
-		  totalread = -1;
-		  goto out;
-		}
-	      SetConsoleMode (get_handle (), dwMode);
-	      restore_reattach_pcon ();
-	      ReleaseMutex (input_mutex);
-
-	      ssize_t nlen;
-	      char *nbuf = convert_mb_str (get_ttyp ()->term_code_page,
-			     (size_t *) &nlen, GetConsoleCP (), buf, rlen);
-
-	      ssize_t ret;
-	      line_edit_status res =
-		line_edit (nbuf, nlen, get_ttyp ()->ti, &ret);
-
-	      mb_str_free (nbuf);
-
-	      if (res == line_edit_input_done || res == line_edit_ok)
-		totalread = get_readahead_into_buffer ((char *) ptr, len);
-	      else if (res > line_edit_signalled)
-		{
-		  set_sig_errno (EINTR);
-		  totalread = -1;
-		}
-	      else
-		{
-		  update_pcon_input_state (true);
-		  continue;
+		  totalread = -1;
 		}
+	      goto out;
+	    }
+	  continue;
+	default:
+	  termios_printf ("wait for input mutex failed, %E");
+	  if (!totalread)
+	    {
+	      __seterrno ();
+	      totalread = -1;
 	    }
-
-	  update_pcon_input_state (true);
-	  mask_switch_to_pcon_in (false);
 	  goto out;
 	}
-      if (!ptr && len == UINT_MAX && !get_ttyp ()->pcon_in_empty)
-	{
-	  FlushConsoleInputBuffer (get_handle ());
-	  get_ttyp ()->pcon_in_empty = true;
-	  DWORD n;
-	  if (bytes_available (n) && n == 0)
-	    ResetEvent (input_available_event);
-	}
 
-do_read_cyg:
       if (!bytes_available (bytes_in_pipe))
 	{
 	  ReleaseMutex (input_mutex);
@@ -1911,16 +1051,6 @@ do_read_cyg:
 out:
   termios_printf ("%d = read(%p, %lu)", totalread, ptr, len);
   len = (size_t) totalread;
-  /* Push slave read as echo to pseudo console screen buffer. */
-  if (get_pseudo_console () && ptr0 && totalread > 0 &&
-      (get_ttyp ()->ti.c_lflag & ECHO))
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer (ptr0, len, true);
-      if (get_ttyp ()->switch_to_pcon_out)
-	trigger_redraw_screen ();
-      release_output_mutex ();
-    }
   mask_switch_to_pcon_in (false);
 }
 
@@ -2061,38 +1191,11 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
       get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
       break;
     case TIOCSWINSZ:
-      if (get_pseudo_console ())
-	{
-	  /* If not attached to this pseudo console,
-	     try to attach temporarily. */
-	  pid_restore = 0;
-	  if (pcon_attached_to != get_minor ())
-	    if (!try_reattach_pcon ())
-	      goto cleanup;
-
-	  COORD size;
-	  size.X = ((struct winsize *) arg)->ws_col;
-	  size.Y = ((struct winsize *) arg)->ws_row;
-	  CONSOLE_SCREEN_BUFFER_INFO csbi;
-	  if (GetConsoleScreenBufferInfo (get_output_handle (), &csbi))
-	    if (size.X == csbi.srWindow.Right - csbi.srWindow.Left + 1 &&
-		size.Y == csbi.srWindow.Bottom - csbi.srWindow.Top + 1)
-	      goto cleanup;
-	  if (!SetConsoleScreenBufferSize (get_output_handle (), size))
-	    goto cleanup;
-	  SMALL_RECT rect;
-	  rect.Left = 0;
-	  rect.Top = 0;
-	  rect.Right = size.X-1;
-	  rect.Bottom = size.Y-1;
-	  SetConsoleWindowInfo (get_output_handle (), TRUE, &rect);
-cleanup:
-	  restore_reattach_pcon ();
-	}
-
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->arg.winsize = *(struct winsize *) arg;
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
@@ -2378,6 +1481,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2393,7 +1517,6 @@ fhandler_pty_master::close ()
 {
   OBJECT_BASIC_INFORMATION obi;
   NTSTATUS status;
-  pid_t master_pid_tmp = get_ttyp ()->master_pid;
 
   termios_printf ("closing from_master(%p)/from_master_cyg(%p)/to_master(%p)/to_master_cyg(%p) since we own them(%u)",
 		  from_master, from_master_cyg,
@@ -2438,30 +1561,6 @@ fhandler_pty_master::close ()
   else if (obi.HandleCount == 1)
     {
       termios_printf ("Closing last master of pty%d", get_minor ());
-      /* Close Pseudo Console */
-      if (get_pseudo_console ())
-	{
-	  /* Terminate helper process */
-	  SetEvent (get_ttyp ()->h_helper_goodbye);
-	  WaitForSingleObject (get_ttyp ()->h_helper_process, INFINITE);
-	  CloseHandle (get_ttyp ()->h_helper_goodbye);
-	  CloseHandle (get_ttyp ()->h_helper_process);
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (master_pid_tmp == myself->pid)
-	    {
-	      /* ClosePseudoConsole() seems to have a bug that one
-		 internal handle remains opened. This causes handle leak.
-		 This is a workaround for this problem. */
-	      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_pseudo_console ();
-	      HANDLE tmp = hp->hConHostProcess;
-	      /* Release pseudo console */
-	      ClosePseudoConsole (get_pseudo_console ());
-	      CloseHandle (tmp);
-	    }
-	  get_ttyp ()->switch_to_pcon_in = false;
-	  get_ttyp ()->switch_to_pcon_out = false;
-	}
       if (get_ttyp ()->getsid () > 0)
 	kill (get_ttyp ()->getsid (), SIGHUP);
       SetEvent (input_available_event);
@@ -2469,9 +1568,8 @@ fhandler_pty_master::close ()
 
   if (!ForceCloseHandle (from_master))
     termios_printf ("error closing from_master %p, %E", from_master);
-  if (from_master_cyg != from_master) /* Avoid double close. */
-    if (!ForceCloseHandle (from_master_cyg))
-      termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
+  if (!ForceCloseHandle (from_master_cyg))
+    termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
   if (!ForceCloseHandle (to_master))
     termios_printf ("error closing to_master %p, %E", to_master);
   from_master = to_master = NULL;
@@ -2513,7 +1611,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon () && get_ttyp ()->h_pseudo_console)
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2521,40 +1619,50 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
       WaitForSingleObject (input_mutex, INFINITE);
 
-      if (memchr (buf, '\003', nlen)) /* ^C intr key in pcon */
-	get_ttyp ()->req_flush_pcon_input = true;
-
       DWORD wLen;
-      WriteFile (to_slave, buf, nlen, &wLen, NULL);
-      get_ttyp ()->pcon_in_empty = false;
-
-      ReleaseMutex (input_mutex);
 
-      /* Use line_edit () in order to set input_available_event. */
-      bool is_echo = tc ()->ti.c_lflag & ECHO;
-      if (!get_ttyp ()->mask_switch_to_pcon_in)
+      if (get_ttyp ()->pcon_start)
 	{
-	  tc ()->ti.c_lflag &= ~ECHO;
-	  ti.c_lflag &= ~ECHO;
-	}
-      ti.c_lflag &= ~ISIG;
-      line_edit (buf, nlen, ti, &ret);
-      if (is_echo)
-	tc ()->ti.c_lflag |= ECHO;
-      get_ttyp ()->read_retval = 1;
-
-      const char sigs[] = {
-	(char) ti.c_cc[VINTR],
-	(char) ti.c_cc[VQUIT],
-	(char) ti.c_cc[VSUSP],
-      };
-      if (tc ()->ti.c_lflag & ISIG)
-	for (size_t i=0; i<sizeof (sigs); i++)
-	  if (sigs[i] && memchr (buf, sigs[i], nlen))
+	  /* Pseudo condole support uses "CSI6n" to get cursor position.
+	     If the reply for "CSI6n" is divided into multiple writes,
+	     pseudo console sometimes does not recognize it.  Therefore,
+	     put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon_start = false;
+	    }
+	  else
 	    {
-	      eat_readahead (-1);
-	      SetEvent (input_available_event);
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
 	    }
+	}
+
+      WriteFile (to_slave, buf, nlen, &wLen, NULL);
+
+      ReleaseMutex (input_mutex);
 
       mb_str_free (buf);
       return len;
@@ -2630,15 +1738,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (get_pseudo_console () && get_ttyp ()->master_pid == myself->pid)
-	    {
-	      COORD size;
-	      size.X = ((struct winsize *) arg)->ws_col;
-	      size.Y = ((struct winsize *) arg)->ws_row;
-	      ResizePseudoConsole (get_pseudo_console (), size);
-	    }
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
 	}
@@ -2763,7 +1864,7 @@ get_locale_from_env (char *locale)
   strcpy (locale, env);
 }
 
-static LCID
+static void
 get_langinfo (char *locale_out, char *charset_out)
 {
   /* Get locale from environment */
@@ -2776,11 +1877,6 @@ get_langinfo (char *locale_out, char *charset_out)
   if (!locale)
     locale = "C";
 
-  char tmp_locale[ENCODING_LEN + 1];
-  char *ret = __set_locale_from_locale_alias (locale, tmp_locale);
-  if (ret)
-    locale = tmp_locale;
-
   const char *charset;
   struct lc_ctype_T *lc_ctype = (struct lc_ctype_T *) loc.lc_cat[LC_CTYPE].ptr;
   if (!lc_ctype)
@@ -2830,23 +1926,9 @@ get_langinfo (char *locale_out, char *charset_out)
       charset = "CP932";
     }
 
-  wchar_t lc[ENCODING_LEN + 1];
-  wchar_t *p;
-  mbstowcs (lc, locale, ENCODING_LEN);
-  p = wcschr (lc, L'.');
-  if (p)
-    *p = L'\0';
-  p = wcschr (lc, L'_');
-  if (p)
-    *p = L'-';
-  LCID lcid = LocaleNameToLCID (lc, 0);
-  if (!lcid && !strcmp (charset, "ASCII"))
-    return 0;
-
   /* Set results */
   strcpy (locale_out, new_locale);
   strcpy (charset_out, charset);
-  return lcid;
 }
 
 void
@@ -2854,21 +1936,7 @@ fhandler_pty_slave::setup_locale (void)
 {
   char locale[ENCODING_LEN + 1] = "C";
   char charset[ENCODING_LEN + 1] = "ASCII";
-  LCID lcid = get_langinfo (locale, charset);
-
-  /* Set console code page form locale */
-  if (get_pseudo_console ())
-    {
-      UINT code_page;
-      if (lcid == 0 || lcid == (LCID) -1)
-	code_page = 20127; /* ASCII */
-      else if (!GetLocaleInfo (lcid,
-			       LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
-			       (char *) &code_page, sizeof (code_page)))
-	code_page = 20127; /* ASCII */
-      SetConsoleCP (code_page);
-      SetConsoleOutputCP (code_page);
-    }
+  get_langinfo (locale, charset);
 
   /* Set terminal code page from locale */
   /* This code is borrowed from mintty: charset.c */
@@ -2878,9 +1946,9 @@ fhandler_pty_slave::setup_locale (void)
     charset_u[i] = toupper (charset[i]);
   unsigned int iso;
   UINT cp = 20127; /* Default for fallback */
-  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859%u", &iso) == 1)
+  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859%u", &iso) == 1)
     {
       if (iso && iso <= 16 && iso !=12)
 	get_ttyp ()->term_code_page = 28590 + iso;
@@ -2896,90 +1964,9 @@ fhandler_pty_slave::setup_locale (void)
 	}
 }
 
-void
-fhandler_pty_slave::set_freeconsole_on_close (bool val)
-{
-  freeconsole_on_close = val;
-}
-
-void
-fhandler_pty_slave::trigger_redraw_screen (void)
-{
-  /* Forcibly redraw screen based on console screen buffer. */
-  /* The following code triggers redrawing the screen. */
-  CONSOLE_SCREEN_BUFFER_INFO sbi;
-  GetConsoleScreenBufferInfo (get_output_handle (), &sbi);
-  SMALL_RECT rect = {0, 0,
-    (SHORT) (sbi.dwSize.X -1), (SHORT) (sbi.dwSize.Y - 1)};
-  COORD dest = {0, 0};
-  CHAR_INFO fill = {' ', 0};
-  ScrollConsoleScreenBuffer (get_output_handle (), &rect, NULL, dest, &fill);
-  get_ttyp ()->need_redraw_screen = false;
-}
-
-void
-fhandler_pty_slave::fixup_after_attach (bool native_maybe, int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  if (get_pseudo_console ())
-    {
-      if (fhandler_console::get_console_process_id (get_helper_process_id (),
-						    true))
-	if (pcon_attached_to != get_minor ())
-	  {
-	    pcon_attached_to = get_minor ();
-	    init_console_handler (true);
-	  }
-
-#if 0 /* This is for debug only. */
-      isHybrid = true;
-      get_ttyp ()->switch_to_pcon_in = true;
-      get_ttyp ()->switch_to_pcon_out = true;
-#endif
-
-      if (pcon_attached_to == get_minor () && native_maybe)
-	{
-	  if (fd == 0)
-	    {
-	      pull_pcon_input ();
-	      DWORD mode =
-		ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	      SetConsoleMode (get_handle (), mode);
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_in = true;
-	    }
-	  else if (fd == 1 || fd == 2)
-	    {
-	      DWORD mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
-	      SetConsoleMode (get_output_handle (), mode);
-	      acquire_output_mutex (INFINITE);
-	      if (!get_ttyp ()->switch_to_pcon_out)
-		get_ttyp ()->wait_pcon_fwd ();
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_out = true;
-	      release_output_mutex ();
-
-	      if (get_ttyp ()->need_redraw_screen)
-		trigger_redraw_screen ();
-	    }
-	  init_console_handler (false);
-	}
-      else if (fd == 0 && native_maybe)
-	/* Read from unattached pseudo console cause freeze,
-	   therefore, fallback to legacy pty. */
-	set_handle (get_handle_cyg ());
-    }
-}
-
 void
 fhandler_pty_slave::fixup_after_fork (HANDLE parent)
 {
-  fixup_after_attach (false, -1);
   // fork_fixup (parent, inuse, "inuse");
   // fhandler_pty_common::fixup_after_fork (parent);
   report_tty_counts (this, "inherited", "");
@@ -2992,71 +1979,22 @@ fhandler_pty_slave::fixup_after_exec ()
 
   if (!close_on_exec ())
     fixup_after_fork (NULL);	/* No parent handle required. */
-  else if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 1 && get_minor () == pcon_attached_to)
-	pcon_attached_to = -1;
-      if (used == 1 /* About to close this tty */)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
 
   /* Set locale */
   if (get_ttyp ()->term_code_page == 0)
     setup_locale ();
 
   /* Hook Console API */
-  if (get_pseudo_console ())
-    {
 #define DO_HOOK(module, name) \
-      if (!name##_Orig) \
-	{ \
-	  void *api = hook_api (module, #name, (void *) name##_Hooked); \
-	  name##_Orig = (__typeof__ (name) *) api; \
-	  /*if (api) system_printf (#name " hooked.");*/ \
-	}
-      DO_HOOK (NULL, WriteFile);
-      DO_HOOK (NULL, WriteConsoleA);
-      DO_HOOK (NULL, WriteConsoleW);
-      DO_HOOK (NULL, ReadFile);
-      DO_HOOK (NULL, ReadConsoleA);
-      DO_HOOK (NULL, ReadConsoleW);
-      DO_HOOK (NULL, WriteConsoleOutputA);
-      DO_HOOK (NULL, WriteConsoleOutputW);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterA);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterW);
-      DO_HOOK (NULL, WriteConsoleOutputAttribute);
-      DO_HOOK (NULL, SetConsoleCursorPosition);
-      DO_HOOK (NULL, SetConsoleTextAttribute);
-      DO_HOOK (NULL, WriteConsoleInputA);
-      DO_HOOK (NULL, WriteConsoleInputW);
-      DO_HOOK (NULL, ReadConsoleInputA);
-      DO_HOOK (NULL, ReadConsoleInputW);
-      DO_HOOK (NULL, PeekConsoleInputA);
-      DO_HOOK (NULL, PeekConsoleInputW);
-      /* CreateProcess() is hooked for GDB etc. */
-      DO_HOOK (NULL, CreateProcessA);
-      DO_HOOK (NULL, CreateProcessW);
+  if (!name##_Orig) \
+    { \
+      void *api = hook_api (module, #name, (void *) name##_Hooked); \
+      name##_Orig = (__typeof__ (name) *) api; \
+      /*if (api) system_printf (#name " hooked.");*/ \
     }
+  /* CreateProcess() is hooked for GDB etc. */
+  DO_HOOK (NULL, CreateProcessA);
+  DO_HOOK (NULL, CreateProcessW);
 }
 
 /* This thread function handles the master control pipe.  It waits for a
@@ -3204,27 +2142,6 @@ reply:
   return 0;
 }
 
-void
-fhandler_pty_master::transfer_input_to_pcon (void)
-{
-  WaitForSingleObject (input_mutex, INFINITE);
-  DWORD n;
-  size_t transfered = 0;
-  while (::bytes_available (n, from_master_cyg) && n)
-    {
-      char buf[1024];
-      ReadFile (from_master_cyg, buf, sizeof (buf), &n, 0);
-      char *p = buf;
-      while ((p = (char *) memchr (p, '\n', n - (p - buf))))
-	*p = '\r';
-      if (WriteFile (to_slave, buf, n, &n, 0))
-	transfered += n;
-    }
-  if (transfered)
-    get_ttyp ()->pcon_in_empty = false;
-  ReleaseMutex (input_mutex);
-}
-
 static DWORD WINAPI
 pty_master_thread (VOID *arg)
 {
@@ -3240,23 +2157,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
   termios_printf ("Started.");
   for (;;)
     {
-      if (get_pseudo_console ())
-	{
-	  get_ttyp ()->pcon_last_time = GetTickCount ();
-	  while (::bytes_available (rlen, from_slave) && rlen == 0)
-	    {
-	      /* Forcibly transfer input if it is requested by slave.
-		 This happens when input data should be transfered
-		 from the input pipe for cygwin apps to the input pipe
-		 for native apps. */
-	      if (get_ttyp ()->req_transfer_input_to_pcon)
-		{
-		  transfer_input_to_pcon ();
-		  get_ttyp ()->req_transfer_input_to_pcon = false;
-		}
-	      Sleep (1);
-	    }
-	}
+      get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3264,14 +2165,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_ttyp ()->h_pseudo_console)
 	{
-	  /* Avoid duplicating slave output which is already sent to
-	     to_master_cyg */
-	  if (!get_ttyp ()->switch_to_pcon_out)
-	    continue;
-
-	  /* Avoid setting window title to "cygwin-console-helper.exe" */
+	  /* Remove CSI > Pm m */
 	  int state = 0;
 	  int start_at = 0;
 	  for (DWORD i=0; i<rlen; i++)
@@ -3281,43 +2177,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 		state = 1;
 		continue;
 	      }
-	    else if ((state == 1 && outbuf[i] == ']') ||
-		     (state == 2 && outbuf[i] == '0') ||
-		     (state == 3 && outbuf[i] == ';'))
-	      {
-		state ++;
-		continue;
-	      }
-	    else if (state == 4 && outbuf[i] == '\a')
-	      {
-		const char *helper_str = "\\bin\\cygwin-console-helper.exe";
-		if (memmem (&outbuf[start_at], i + 1 - start_at,
-			    helper_str, strlen (helper_str)))
-		  {
-		    memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
-		    rlen = wlen = start_at + rlen - i - 1;
-		  }
-		state = 0;
-		continue;
-	      }
-	    else if (outbuf[i] == '\a')
-	      {
-		state = 0;
-		continue;
-	      }
-
-	  /* Remove CSI > Pm m */
-	  state = 0;
-	  start_at = 0;
-	  for (DWORD i=0; i<rlen; i++)
-	    if (outbuf[i] == '\033')
-	      {
-		start_at = i;
-		state = 1;
-		continue;
-	      }
-	    else if ((state == 1 && outbuf[i] == '[') ||
-		     (state == 2 && outbuf[i] == '>'))
+	    else if ((state == 1 && outbuf[i] == '[')
+		     || (state == 2 && outbuf[i] == '>'))
 	      {
 		state ++;
 		continue;
@@ -3386,201 +2247,6 @@ pty_master_fwd_thread (VOID *arg)
   return ((fhandler_pty_master *) arg)->pty_master_fwd_thread ();
 }
 
-/* If master process is running as service, attaching to
-   pseudo console should be done in fork. If attaching
-   is done in spawn for inetd or sshd, it fails because
-   the helper process is running as privileged user while
-   slave process is not. This function is used to determine
-   if the process is running as a srvice or not. */
-inline static bool
-is_running_as_service (void)
-{
-  return check_token_membership (well_known_service_sid)
-    || cygheap->user.saved_sid () == well_known_system_sid;
-}
-
-bool
-fhandler_pty_master::setup_pseudoconsole ()
-{
-  if (disable_pcon)
-    return false;
-  /* If the legacy console mode is enabled, pseudo console seems
-     not to work as expected. To determine console mode, registry
-     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
-  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
-  if (reg.error ())
-    return false;
-  if (reg.get_dword (L"ForceV2", 1) == 0)
-    {
-      termios_printf ("Pseudo console is disabled "
-		      "because the legacy console mode is enabled.");
-      return false;
-    }
-
-  /* Pseudo console supprot is realized using a tricky technic.
-     PTY need the pseudo console handles, however, they cannot
-     be retrieved by normal procedure. Therefore, run a helper
-     process in a pseudo console and get them from the helper.
-     Slave process will attach to the pseudo console in the
-     helper process using AttachConsole(). */
-  COORD size = {
-    (SHORT) get_ttyp ()->winsize.ws_col,
-    (SHORT) get_ttyp ()->winsize.ws_row
-  };
-  CreatePipe (&from_master, &to_slave, &sec_none, 0);
-  SetLastError (ERROR_SUCCESS);
-  HRESULT res = CreatePseudoConsole (size, from_master, to_master,
-				     0, &get_ttyp ()->h_pseudo_console);
-  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
-    {
-      if (res != S_OK)
-	system_printf ("CreatePseudoConsole() failed. %08x\n",
-		       GetLastError ());
-      goto fallback;
-    }
-
-  /* If master process is running as service, attaching to
-     pseudo console should be done in fork. If attaching
-     is done in spawn for inetd or sshd, it fails because
-     the helper process is running as privileged user while
-     slave process is not. */
-  if (is_running_as_service ())
-    get_ttyp ()->attach_pcon_in_fork = true;
-
-  STARTUPINFOEXW si_helper;
-  HANDLE hello, goodbye;
-  HANDLE hr, hw;
-  PROCESS_INFORMATION pi_helper;
-  HANDLE hpConIn, hpConOut;
-  {
-    SIZE_T bytesRequired;
-    InitializeProcThreadAttributeList (NULL, 2, 0, &bytesRequired);
-    ZeroMemory (&si_helper, sizeof (si_helper));
-    si_helper.StartupInfo.cb = sizeof (STARTUPINFOEXW);
-    si_helper.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
-      HeapAlloc (GetProcessHeap (), 0, bytesRequired);
-    if (si_helper.lpAttributeList == NULL)
-      goto cleanup_pseudo_console;
-    if (!InitializeProcThreadAttributeList (si_helper.lpAttributeList,
-					    2, 0, &bytesRequired))
-      goto cleanup_heap;
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
-				    get_ttyp ()->h_pseudo_console,
-				    sizeof (get_ttyp ()->h_pseudo_console),
-				    NULL, NULL))
-      goto cleanup_heap;
-    /* Create events for start/stop helper process. */
-    hello = CreateEvent (&sec_none, true, false, NULL);
-    goodbye = CreateEvent (&sec_none, true, false, NULL);
-    /* Create a pipe for receiving pseudo console handles */
-    CreatePipe (&hr, &hw, &sec_none, 0);
-    /* Inherit only handles which are needed by helper. */
-    HANDLE handles_to_inherit[] = {hello, goodbye, hw};
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
-				    handles_to_inherit,
-				    sizeof (handles_to_inherit),
-				    NULL, NULL))
-      goto cleanup_event_and_pipes;
-    /* Create helper process */
-    WCHAR cmd[MAX_PATH];
-    path_conv helper ("/bin/cygwin-console-helper.exe");
-    size_t len = helper.get_wide_win32_path_len ();
-    helper.get_wide_win32_path (cmd);
-    __small_swprintf (cmd + len, L" %p %p %p", hello, goodbye, hw);
-    si_helper.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
-    si_helper.StartupInfo.hStdInput = NULL;
-    si_helper.StartupInfo.hStdOutput = NULL;
-    si_helper.StartupInfo.hStdError = NULL;
-    if (!CreateProcessW (NULL, cmd, &sec_none, &sec_none,
-			 TRUE, EXTENDED_STARTUPINFO_PRESENT,
-			 NULL, NULL, &si_helper.StartupInfo, &pi_helper))
-      goto cleanup_event_and_pipes;
-    for (;;)
-      {
-        DWORD wait_result = WaitForSingleObject (hello, 500);
-	if (wait_result == WAIT_OBJECT_0)
-	  break;
-	if (wait_result != WAIT_TIMEOUT)
-	  goto cleanup_helper_process;
-	DWORD exit_code;
-	if (!GetExitCodeProcess(pi_helper.hProcess, &exit_code))
-	  goto cleanup_helper_process;
-	if (exit_code == STILL_ACTIVE)
-	  continue;
-	if (exit_code != 0 ||
-	    WaitForSingleObject (hello, 500) != WAIT_OBJECT_0)
-	  goto cleanup_helper_process;
-	break;
-      }
-    CloseHandle (hello);
-    CloseHandle (pi_helper.hThread);
-    /* Retrieve pseudo console handles */
-    DWORD rLen;
-    char buf[64];
-    if (!ReadFile (hr, buf, sizeof (buf), &rLen, NULL))
-      goto cleanup_helper_process;
-    buf[rLen] = '\0';
-    sscanf (buf, "StdHandles=%p,%p", &hpConIn, &hpConOut);
-    if (!DuplicateHandle (pi_helper.hProcess, hpConIn,
-			  GetCurrentProcess (), &hpConIn, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_helper_process;
-    if (!DuplicateHandle (pi_helper.hProcess, hpConOut,
-			  GetCurrentProcess (), &hpConOut, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_pcon_in;
-    CloseHandle (hr);
-    CloseHandle (hw);
-    /* Clean up */
-    DeleteProcThreadAttributeList (si_helper.lpAttributeList);
-    HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-  }
-  /* Setting information of stuffs regarding pseudo console */
-  get_ttyp ()->h_helper_goodbye = goodbye;
-  get_ttyp ()->h_helper_process = pi_helper.hProcess;
-  get_ttyp ()->helper_process_id = pi_helper.dwProcessId;
-  CloseHandle (from_master);
-  CloseHandle (to_master);
-  from_master = hpConIn;
-  to_master = hpConOut;
-  ResizePseudoConsole (get_ttyp ()->h_pseudo_console, size);
-  return true;
-
-cleanup_pcon_in:
-  CloseHandle (hpConIn);
-cleanup_helper_process:
-  SetEvent (goodbye);
-  WaitForSingleObject (pi_helper.hProcess, INFINITE);
-  CloseHandle (pi_helper.hProcess);
-  goto skip_close_hello;
-cleanup_event_and_pipes:
-  CloseHandle (hello);
-skip_close_hello:
-  CloseHandle (goodbye);
-  CloseHandle (hr);
-  CloseHandle (hw);
-cleanup_heap:
-  HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-cleanup_pseudo_console:
-  {
-    HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
-    HANDLE tmp = hp->hConHostProcess;
-    ClosePseudoConsole (get_pseudo_console ());
-    CloseHandle (tmp);
-  }
-fallback:
-  CloseHandle (from_master);
-  CloseHandle (to_slave);
-  from_master = from_master_cyg;
-  to_slave = NULL;
-  get_ttyp ()->h_pseudo_console = NULL;
-  return false;
-}
-
 bool
 fhandler_pty_master::setup ()
 {
@@ -3593,11 +2259,6 @@ fhandler_pty_master::setup ()
   if (unit < 0)
     return false;
 
-  /* from_master should be used for pseudo console.
-     Just copy from_master_cyg here for the case that
-     pseudo console is not available. */
-  from_master = from_master_cyg;
-
   ProtectHandle1 (get_output_handle (), to_pty);
 
   tty& t = *cygwin_shared->tty[unit];
@@ -3696,15 +2357,21 @@ fhandler_pty_master::setup ()
       goto err;
     }
 
-  t.winsize.ws_col = 80;
-  t.winsize.ws_row = 25;
-
-  setup_pseudoconsole ();
+  __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;
+    }
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
   t.set_to_master (to_master);
   t.set_to_master_cyg (to_master_cyg);
+  t.winsize.ws_col = 80;
+  t.winsize.ws_row = 25;
   t.master_pid = myself->pid;
 
   dev ().parse (DEV_PTYM_MAJOR, unit);
@@ -3717,6 +2384,7 @@ fhandler_pty_master::setup ()
 err:
   __seterrno ();
   close_maybe (from_slave);
+  close_maybe (to_slave);
   close_maybe (get_handle ());
   close_maybe (get_output_handle ());
   close_maybe (input_available_event);
@@ -3776,9 +2444,6 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 {
   ssize_t towrite = len;
   BOOL res = TRUE;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
   while (towrite)
     {
       if (!is_echo)
@@ -3801,7 +2466,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
       if (!(get_ttyp ()->ti.c_oflag & OPOST))	// raw output mode
 	{
 	  DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
-	  res = WriteFunc (h, ptr, n, &n, NULL);
+	  res = WriteFile (h, ptr, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + n;
@@ -3851,7 +2516,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 		  break;
 		}
 	    }
-	  res = WriteFunc (h, outbuf, n, &n, NULL);
+	  res = WriteFile (h, outbuf, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + rc;
@@ -3861,3 +2526,134 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon)
+{
+
+  /* Setting switch_to_pcon_in is necessary even if
+     pseudo console will not be activated. */
+  fhandler_base *fh = ::cygheap->fdtab[0];
+  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+    {
+      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+      ptys->get_ttyp ()->switch_to_pcon_in = true;
+      if (ptys->get_ttyp ()->pcon_pid == 0
+	  || !pinfo (ptys->get_ttyp ()->pcon_pid))
+	ptys->get_ttyp ()->pcon_pid = myself->pid;
+    }
+
+  if (nopcon)
+    return false;
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  const DWORD inherit_cursor = 1;
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     inherit_cursor,
+				     &get_ttyp ()->h_pseudo_console);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console,
+				  sizeof (get_ttyp ()->h_pseudo_console),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_base *fh0 = ::cygheap->fdtab[0];
+    if (fh0 && fh0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = fh0->get_handle ();
+    fhandler_base *fh1 = ::cygheap->fdtab[1];
+    if (fh1 && fh1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = fh1->get_output_handle ();
+    fhandler_base *fh2 = ::cygheap->fdtab[2];
+    if (fh2 && fh2->get_device () != get_device ())
+      si->StartupInfo.hStdError = fh2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole (void)
+{
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      get_ttyp ()->wait_pcon_fwd ();
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+      get_ttyp ()->pcon_start = false;
+    }
+}
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 691d08137..6ca4b5f29 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -134,36 +134,6 @@ child_info::prefork (bool detached)
 int __stdcall
 frok::child (volatile char * volatile here)
 {
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR)
-      {
-	fhandler_base *fh = cfd;
-	fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
-	if (ptym->get_pseudo_console ())
-	  {
-	    debug_printf ("found a PTY master %d: helper_PID=%d",
-			  ptym->get_minor (), ptym->get_helper_process_id ());
-	    if (fhandler_console::get_console_process_id (
-				ptym->get_helper_process_id (), true))
-	      /* Already attached */
-	      break;
-	    else
-	      {
-		if (ptym->attach_pcon_in_fork ())
-		  {
-		    FreeConsole ();
-		    if (!AttachConsole (ptym->get_helper_process_id ()))
-		      /* Error */;
-		    else
-		      break;
-		  }
-	      }
-	  }
-      }
-  extern void clear_pcon_attached_to (void); /* fhandler_tty.cc */
-  clear_pcon_attached_to ();
-
   HANDLE& hParent = ch.parent;
 
   sync_with_parent ("after longjmp", true);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 3f3f33fb5..93acdd89a 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1213,8 +1213,7 @@ verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds,
 	   fd_set *exceptfds)
 {
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) me->fh;
-  if (me->read_selected && !ptys->to_be_read_from_pcon () &&
-      IsEventSignalled (ptys->input_available_event))
+  if (me->read_selected && IsEventSignalled (ptys->input_available_event))
     me->read_ready = true;
   return set_bits (me, readfds, writefds, exceptfds);
 }
@@ -1227,8 +1226,6 @@ peek_pty_slave (select_record *s, bool from_select)
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
 
   ptys->reset_switch_to_pcon ();
-  if (ptys->to_be_read_from_pcon ())
-    ptys->update_pcon_input_state (true);
 
   if (s->read_selected)
     {
diff --git a/winsup/cygwin/smallprint.cc b/winsup/cygwin/smallprint.cc
index 26d34d9e4..f208a057a 100644
--- a/winsup/cygwin/smallprint.cc
+++ b/winsup/cygwin/smallprint.cc
@@ -405,7 +405,6 @@ small_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
   WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, NULL);
   FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
 }
@@ -432,7 +431,6 @@ console_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (console_handle);
   WriteFile (console_handle, buf, count, &done, NULL);
   FlushFileBuffers (console_handle);
 }
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 3e8c8367a..61a23a72a 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -259,8 +277,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 {
   bool rc;
   int res = -1;
-  DWORD pid_restore = 0;
-  bool attach_to_console = false;
   pid_t ctty_pgid = 0;
 
   /* Search for CTTY and retrieve its PGID */
@@ -580,9 +596,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			 PROCESS_QUERY_LIMITED_INFORMATION))
 	sa = &sec_none_nih;
 
-      /* Attach to pseudo console if pty salve is used */
-      pid_restore = fhandler_console::get_console_process_id
-	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -591,29 +605,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	      if (ptys->get_pseudo_console ())
-		{
-		  DWORD helper_process_id = ptys->get_helper_process_id ();
-		  debug_printf ("found a PTY slave %d: helper_PID=%d",
-				    fh->get_minor (), helper_process_id);
-		  if (fhandler_console::get_console_process_id
-					      (helper_process_id, true))
-		    /* Already attached */
-		    attach_to_console = true;
-		  else if (!attach_to_console)
-		    {
-		      FreeConsole ();
-		      if (AttachConsole (helper_process_id))
-			attach_to_console = true;
-		    }
-		  ptys->fixup_after_attach (!iscygwin (), fd);
-		  if (mode == _P_OVERLAY)
-		    ptys->set_freeconsole_on_close (iscygwin ());
-		}
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	    }
 	  else if (fh && fh->get_major () == DEV_CONS_MAJOR)
 	    {
-	      attach_to_console = true;
 	      fhandler_console *cons = (fhandler_console *) fh;
 	      if (wincap.has_con_24bit_colors () && !iscygwin ())
 		if (fd == 1 || fd == 2)
@@ -632,6 +628,19 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool enable_pcon = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole (&si_pcon,
+			     mode != _P_OVERLAY && mode != _P_WAIT))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    enable_pcon = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -660,7 +669,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -714,7 +723,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -727,6 +736,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (enable_pcon)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -897,6 +911,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 		  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
 		wait_for_myself ();
 	    }
+	  if (enable_pcon)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->close_pseudoconsole ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
@@ -904,6 +923,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  system_call.arm ();
 	  if (waitpid (cygpid, &res, 0) != cygpid)
 	    res = -1;
+	  if (enable_pcon)
+	    ptys_primary->close_pseudoconsole ();
 	  break;
 	case _P_DETACH:
 	  res = 0;	/* Lost all memory of this child. */
@@ -930,21 +951,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
   if (envblock)
     free (envblock);
 
-  if (attach_to_console && pid_restore)
-    {
-      FreeConsole ();
-      AttachConsole (pid_restore);
-      cygheap_fdenum cfd (false);
-      int fd;
-      while ((fd = cfd.next ()) >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_pty_slave *ptys =
-	      (fhandler_pty_slave *) (fhandler_base *) cfd;
-	    ptys->fixup_after_attach (false, fd);
-	  }
-    }
-
   return (int) res;
 }
 
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index f0aef3a36..35f8a59ae 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -264,7 +264,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
   if (category & _STRACE_SYSTEM)
     {
       DWORD done;
-      set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
       WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
       FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
       /* Make sure that the message shows up on the screen, too, since this is
@@ -276,7 +275,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
 				 &sec_none, OPEN_EXISTING, 0, 0);
 	  if (h != INVALID_HANDLE_VALUE)
 	    {
-	      set_ishybrid_and_switch_to_pcon (h);
 	      WriteFile (h, buf, len, &done, 0);
 	      CloseHandle (h);
 	    }
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 4cb68f776..d60f27545 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -234,20 +234,14 @@ tty::init ()
   was_opened = false;
   master_pid = 0;
   is_console = false;
-  attach_pcon_in_fork = false;
-  h_pseudo_console = NULL;
   column = 0;
+  h_pseudo_console = NULL;
   switch_to_pcon_in = false;
-  switch_to_pcon_out = false;
-  screen_alternated = false;
   mask_switch_to_pcon_in = false;
   pcon_pid = 0;
   term_code_page = 0;
-  need_redraw_screen = true;
   pcon_last_time = 0;
-  pcon_in_empty = true;
-  req_transfer_input_to_pcon = false;
-  req_flush_pcon_input = false;
+  pcon_start = false;
 }
 
 HANDLE
@@ -293,16 +287,6 @@ tty_min::ttyname ()
   return d.name ();
 }
 
-void
-tty::set_switch_to_pcon_out (bool v)
-{
-  if (switch_to_pcon_out != v)
-    {
-      wait_pcon_fwd ();
-      switch_to_pcon_out = v;
-    }
-}
-
 void
 tty::wait_pcon_fwd (void)
 {
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 920e32b16..c491d3891 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -94,21 +94,13 @@ private:
   HANDLE _to_master;
   HANDLE _to_master_cyg;
   HPCON h_pseudo_console;
-  HANDLE h_helper_process;
-  DWORD helper_process_id;
-  HANDLE h_helper_goodbye;
-  bool attach_pcon_in_fork;
+  bool pcon_start;
   bool switch_to_pcon_in;
-  bool switch_to_pcon_out;
-  bool screen_alternated;
   bool mask_switch_to_pcon_in;
   pid_t pcon_pid;
   UINT term_code_page;
-  bool need_redraw_screen;
   DWORD pcon_last_time;
-  bool pcon_in_empty;
-  bool req_transfer_input_to_pcon;
-  bool req_flush_pcon_input;
+  HANDLE h_pcon_write_pipe;
 
 public:
   HANDLE from_master () const { return _from_master; }
@@ -138,7 +130,6 @@ public:
   void set_master_ctl_closed () {master_pid = -1;}
   static void __stdcall create_master (int);
   static void __stdcall init_session ();
-  void set_switch_to_pcon_out (bool v);
   void wait_pcon_fwd (void);
   friend class fhandler_pty_common;
   friend class fhandler_pty_master;
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index fff7d18f3..458fb2a23 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -222,9 +222,6 @@ void init_console_handler (bool);
 
 extern bool wsock_started;
 
-/* PTY related */
-void set_ishybrid_and_switch_to_pcon (HANDLE h);
-
 /* Printf type functions */
 extern "C" void vapi_fatal (const char *, va_list ap) __attribute__ ((noreturn));
 extern "C" void api_fatal (const char *, ...) __attribute__ ((noreturn));
-- 
2.27.0


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-03  2:05                                     ` Takashi Yano
@ 2020-08-03 10:50                                       ` Corinna Vinschen
  0 siblings, 0 replies; 73+ messages in thread
From: Corinna Vinschen @ 2020-08-03 10:50 UTC (permalink / raw)
  To: cygwin-developers

On Aug  3 11:05, Takashi Yano via Cygwin-developers wrote:
> On Sun, 2 Aug 2020 14:01:04 +0200 Corinna Vinschen wrote:
> > Wait... what?  So the exec'ing process hangs infinitely if the exec'ed
> > process runs infinitely?  Doesn't that have weird side effects by any
> > chance?
> 
> This is needed to close pseudo console when the native console app
> is terminated.
> 
> exec() call does not return on success. So the caller is not affected.
> If mode == _P_OVERLAY, the process is not seen from cygwin, though,
> it is seen from windows task manager. I have not noticed any serious
> side effects so far.

Ok, thanks for checking.


Corinna

-- 
Corinna Vinschen
Cygwin Maintainer

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-03  2:11                                   ` Takashi Yano
@ 2020-08-03 12:23                                     ` Takashi Yano
  2020-08-11 11:12                                       ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-08-03 12:23 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 3411 bytes --]

On Mon, 3 Aug 2020 11:11:03 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Fri, 24 Jul 2020 20:22:19 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Fri, 24 Jul 2020 14:38:42 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Thu, 23 Jul 2020 09:33:28 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Wed, 22 Jul 2020 17:45:41 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > On Wed, 22 Jul 2020 03:17:51 +0900
> > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > Hi Corinna,
> > > > > > 
> > > > > > On Mon, 20 Jul 2020 10:06:13 +0200
> > > > > > Corinna Vinschen wrote:
> > > > > > > On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
> > > > > > > > Hi Corinna,
> > > > > > > > 
> > > > > > > > On Fri, 17 Jul 2020 13:19:12 +0200
> > > > > > > > Corinna Vinschen wrote:
> > > > > > > > > Hi Takashi,
> > > > > > > > > 
> > > > > > > > > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > > > > > > > > > [...]
> > > > > > > > > > Revise the patch to fit the current git head.
> > > > > > > > > 
> > > > > > > > > are you satisfied with the code?  If you want to merge it,
> > > > > > > > > I'd bump Cygwin to 3.2.
> > > > > > > > 
> > > > > > > > Since this new implementation has both advantages and disadvantages,
> > > > > > > > there might be some options.
> > > > > > > > 
> > > > > > > > 1) Default to new implementation and leave the current one as an
> > > > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > > > 2) Default to current implementation and add the new one as an
> > > > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > > > 3) Adopt only new implementation and throw the current one away.
> > > > > > > > 
> > > > > > > > What do you think?
> > > > > > > 
> > > > > > > Do you really want to maintain twice as much code doing the same stuff
> > > > > > > and constantly having to ask users which version of the code they are
> > > > > > > running?  The maintenance cost outweighs the advantages, IMHO.
> > > > > > > Personally I'd go for option 3.
> > > > > > 
> > > > > > Personally, I feel a tinge of sadness to discard the current code,
> > > > > > however, your opinion sounds reasonable.
> > > > > > 
> > > > > > I will submit a new patch in which all the codes specific to the
> > > > > > current implementation are removed.
> > > > > 
> > > > > Attached is the patch in git format-patch format.
> > > > > All the codes specific to the current implementation are removed.
> > > > > 
> > > > > Despite the utmost care, the changes are relatively large, so some
> > > > > degradation may exist.
> > > > > 
> > > > > I will appreciate if you could test.
> > > > 
> > > > There were still unused code. Please try attached patch instead.
> > > 
> > > Changes:
> > > * Do not activate pseudo console if it is already activated for
> > >   another process on same pty.
> > 
> > Changes:
> > * Fix a bug in the latest change.
> 
> Changes:
> * Fix a handle leak caused when spawn is called with mode != _P_OVERLAY.

This patch cannot be applied cleanly against current git head.
Please use attached patch instead.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-Cygwin-pty-Implement-new-pseudo-console-support.patch --]
[-- Type: application/octet-stream, Size: 89559 bytes --]

From d28076bfa9b68a88390f46870229375f8d4e6906 Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Mon, 3 Aug 2020 21:08:05 +0900
Subject: [PATCH] Cygwin: pty: Implement new pseudo console support.

- In this implementation, pseudo console is created for each native
  console app. Advantages and disadvantages of this implementation
  over the previous implementation are as follows.

  Advantages:
  1) No performance degradation in pty output for cygwin process.
      https://cygwin.com/pipermail/cygwin/2020-February/243858.html
  2) Free from the problem caused by difference of behaviour of control
     sequences between real terminal and pseudo console.
      https://cygwin.com/pipermail/cygwin/2019-December/243281.html
      https://cygwin.com/pipermail/cygwin/2020-February/243855.html
  3) Free from the problem in cgdb and emacs gud.
      https://cygwin.com/pipermail/cygwin/2020-January/243601.html
      https://cygwin.com/pipermail/cygwin/2020-March/244146.html
  4) Redrawing screen on executing native console apps is not necessary.
  5) cygwin-console-helper is not necessary for the pseudo console
     support.
  6) The codes for pseudo console support are much simpler than that
     of the previous one.

  Disadvantages:
  1) The cygwin program which calls console API directly does not work.
  2) The apps which use console API cannot be debugged with gdb. This
     is because pseudo console is not activated since gdb uses
     CreateProcess() rather than exec(). Even with this limitation,
     attaching gdb to native apps, in which pseudo console is already
     activated, works.
  3) Typeahead key inputs are discarded while native console app is
     executed. Simirally, typeahead key inputs while cygwin app is
     executed are not inherited to native console app.
  4) Code page cannot be changed by chcp.com. Acctually, chcp works
     itself and changes code page of its own pseudo console.  However,
     since pseudo console is recreated for another process, it cannot
     inherit the code page.
  5) system_printf() does not work after stderr is closed. (Same with
     cygwin 3.0.7)
  6) Startup time of native console apps is about 3 times slower than
     previous implemenation.
  7) Pseudo console cannot be activated if it is already activated for
     another process on same pty.
---
 winsup/cygwin/dtable.cc           |   32 -
 winsup/cygwin/fhandler.h          |   53 +-
 winsup/cygwin/fhandler_console.cc |   43 -
 winsup/cygwin/fhandler_tty.cc     | 1770 +++++------------------------
 winsup/cygwin/fork.cc             |   30 -
 winsup/cygwin/select.cc           |    5 +-
 winsup/cygwin/smallprint.cc       |    2 -
 winsup/cygwin/spawn.cc            |   90 +-
 winsup/cygwin/strace.cc           |    2 -
 winsup/cygwin/tty.cc              |   20 +-
 winsup/cygwin/tty.h               |   13 +-
 winsup/cygwin/winsup.h            |    3 -
 12 files changed, 345 insertions(+), 1718 deletions(-)

diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index e9e005b08..6a91e33bc 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -147,38 +147,6 @@ dtable::get_debugger_info ()
 void
 dtable::stdio_init ()
 {
-  for (int i = 0; i < 3; i ++)
-    {
-      const int chk_order[] = {1, 0, 2};
-      int fd = chk_order[i];
-      fhandler_base *fh = cygheap->fdtab[fd];
-      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
-	{
-	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	  if (ptys->get_pseudo_console ())
-	    {
-	      bool attached = !!fhandler_console::get_console_process_id
-		(ptys->get_helper_process_id (), true);
-	      if (attached)
-		break;
-	      else
-		{
-		  /* Not attached to pseudo console in fork() or spawn()
-		     by some reason. This happens if the executable is
-		     a windows GUI binary, such as mintty. */
-		  FreeConsole ();
-		  if (AttachConsole (ptys->get_helper_process_id ()))
-		    {
-		      ptys->fixup_after_attach (false, fd);
-		      break;
-		    }
-		}
-	    }
-	}
-      else if (fh && fh->get_major () == DEV_CONS_MAJOR)
-	break;
-    }
-
   if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT))
     {
       tty_min *t = cygwin_shared->tty.get_cttyp ();
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 60bd27e00..ebaca3bb8 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -326,16 +326,16 @@ class fhandler_base
   virtual size_t &raixput () { return ra.raixput; };
   virtual size_t &rabuflen () { return ra.rabuflen; };
 
-  virtual bool get_readahead_valid () { return raixget () < ralen (); }
+  bool get_readahead_valid () { return raixget () < ralen (); }
   int puts_readahead (const char *s, size_t len = (size_t) -1);
-  virtual int put_readahead (char value);
+  int put_readahead (char value);
 
   int get_readahead ();
   int peek_readahead (int queryput = 0);
 
   void set_readahead_valid (int val, int ch = -1);
 
-  virtual int get_readahead_into_buffer (char *buf, size_t buflen);
+  int get_readahead_into_buffer (char *buf, size_t buflen);
 
   bool has_acls () const { return pc.has_acls (); }
 
@@ -1909,7 +1909,7 @@ class fhandler_termios: public fhandler_base
   int ioctl (int, void *);
   tty_min *_tc;
   tty *get_ttyp () {return (tty *) tc ();}
-  virtual int eat_readahead (int n);
+  int eat_readahead (int n);
 
  public:
   tty_min*& tc () {return _tc;}
@@ -2188,7 +2188,6 @@ private:
   static bool need_invisible ();
   static void free_console ();
   static const char *get_nonascii_key (INPUT_RECORD& input_rec, char *);
-  static DWORD get_console_process_id (DWORD pid, bool match);
 
   fhandler_console (void *) {}
 
@@ -2268,19 +2267,7 @@ class fhandler_pty_common: public fhandler_termios
     return fh;
   }
 
-  bool attach_pcon_in_fork (void)
-  {
-    return get_ttyp ()->attach_pcon_in_fork;
-  }
-  DWORD get_helper_process_id (void)
-  {
-    return get_ttyp ()->helper_process_id;
-  }
-  HPCON get_pseudo_console (void)
-  {
-    return get_ttyp ()->h_pseudo_console;
-  }
-  bool to_be_read_from_pcon (void);
+  void resize_pseudo_console (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2291,23 +2278,15 @@ class fhandler_pty_slave: public fhandler_pty_common
 {
   HANDLE inuse;			// used to indicate that a tty is in use
   HANDLE output_handle_cyg, io_handle_cyg;
-  DWORD pid_restore;
-  int fd;
 
   /* Helper functions for fchmod and fchown. */
   bool fch_open_handles (bool chown);
   int fch_set_sd (security_descriptor &sd, bool chown);
   void fch_close_handles ();
 
-  bool try_reattach_pcon ();
-  void restore_reattach_pcon ();
-  inline void free_attached_console ();
-
  public:
   /* Constructor */
   fhandler_pty_slave (int);
-  /* Destructor */
-  ~fhandler_pty_slave ();
 
   void set_output_handle_cyg (HANDLE h) { output_handle_cyg = h; }
   HANDLE& get_output_handle_cyg () { return output_handle_cyg; }
@@ -2319,9 +2298,6 @@ class fhandler_pty_slave: public fhandler_pty_common
   ssize_t __stdcall write (const void *ptr, size_t len);
   void __reg3 read (void *ptr, size_t& len);
   int init (HANDLE, DWORD, mode_t);
-  int eat_readahead (int n);
-  int get_readahead_into_buffer (char *buf, size_t buflen);
-  bool get_readahead_valid (void);
 
   int tcsetattr (int a, const struct termios *t);
   int tcgetattr (struct termios *t);
@@ -2358,20 +2334,12 @@ class fhandler_pty_slave: public fhandler_pty_common
     copyto (fh);
     return fh;
   }
-  void set_switch_to_pcon (int fd);
+  bool setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon);
+  void close_pseudoconsole (void);
+  void set_switch_to_pcon (void);
   void reset_switch_to_pcon (void);
-  void push_to_pcon_screenbuffer (const char *ptr, size_t len, bool is_echo);
   void mask_switch_to_pcon_in (bool mask);
-  void fixup_after_attach (bool native_maybe, int fd);
-  bool is_line_input (void)
-  {
-    return get_ttyp ()->ti.c_lflag & ICANON;
-  }
   void setup_locale (void);
-  void set_freeconsole_on_close (bool val);
-  void trigger_redraw_screen (void);
-  void pull_pcon_input (void);
-  void update_pcon_input_state (bool need_lock);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
@@ -2396,7 +2364,6 @@ public:
   int process_slave_output (char *buf, size_t len, int pktmode_on);
   void doecho (const void *str, DWORD len);
   int accept_input ();
-  int put_readahead (char value);
   int open (int flags, mode_t mode = 0);
   void open_setup (int flags);
   ssize_t __stdcall write (const void *ptr, size_t len);
@@ -2435,9 +2402,7 @@ public:
     copyto (fh);
     return fh;
   }
-
-  bool setup_pseudoconsole (void);
-  void transfer_input_to_pcon (void);
+  bool to_be_read_from_pcon (void);
 };
 
 class fhandler_dev_null: public fhandler_base
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 52741ce8b..02a5996a1 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -1206,18 +1206,6 @@ fhandler_console::close ()
   if (con_ra.rabuf)
     free (con_ra.rabuf);
 
-  /* If already attached to pseudo console, don't call free_console () */
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR ||
-	cfd->get_major () == DEV_PTYS_MAJOR)
-      {
-	fhandler_pty_common *t =
-	  (fhandler_pty_common *) (fhandler_base *) cfd;
-	if (get_console_process_id (t->get_helper_process_id (), true))
-	  return 0;
-      }
-
   if (!have_execed)
     free_console ();
   return 0;
@@ -3611,37 +3599,6 @@ fhandler_console::need_invisible ()
   return b;
 }
 
-DWORD
-fhandler_console::get_console_process_id (DWORD pid, bool match)
-{
-  DWORD tmp;
-  DWORD num, num_req;
-  num = 1;
-  num_req = GetConsoleProcessList (&tmp, num);
-  DWORD *list;
-  while (true)
-    {
-      list = (DWORD *)
-	HeapAlloc (GetProcessHeap (), 0, num_req * sizeof (DWORD));
-      num = num_req;
-      num_req = GetConsoleProcessList (list, num);
-      if (num_req > num)
-	HeapFree (GetProcessHeap (), 0, list);
-      else
-	break;
-    }
-  num = num_req;
-
-  tmp = 0;
-  for (DWORD i=0; i<num; i++)
-    if ((match && list[i] == pid) || (!match && list[i] != pid))
-      /* Last one is the oldest. */
-      /* https://github.com/microsoft/terminal/issues/95 */
-      tmp = list[i];
-  HeapFree (GetProcessHeap (), 0, list);
-  return tmp;
-}
-
 DWORD
 fhandler_console::__acquire_input_mutex (const char *fn, int ln, DWORD ms)
 {
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 6a004f3a5..37682dc3e 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -25,7 +25,6 @@ details. */
 #include "child_info.h"
 #include <asm/socket.h>
 #include "cygwait.h"
-#include "tls_pbuf.h"
 #include "registry.h"
 
 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
@@ -33,7 +32,6 @@ details. */
 #endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
 
 extern "C" int sscanf (const char *, const char *, ...);
-extern "C" int ttyname_r (int, char*, size_t);
 
 extern "C" {
   HRESULT WINAPI CreatePseudoConsole (COORD, HANDLE, HANDLE, DWORD, HPCON *);
@@ -60,20 +58,10 @@ struct pipe_reply {
   DWORD error;
 };
 
-static int pcon_attached_to = -1;
 static bool isHybrid;
-static bool do_not_reset_switch_to_pcon;
-static bool freeconsole_on_close = true;
-static tty *last_ttyp = NULL;
-
-void
-clear_pcon_attached_to (void)
-{
-  pcon_attached_to = -1;
-}
 
 static void
-set_switch_to_pcon (void)
+set_switch_to_pcon (HANDLE h)
 {
   cygheap_fdenum cfd (false);
   int fd;
@@ -82,280 +70,17 @@ set_switch_to_pcon (void)
       {
 	fhandler_base *fh = cfd;
 	fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	if (ptys->get_pseudo_console ())
-	  {
-	    ptys->set_switch_to_pcon (fd);
-	    ptys->trigger_redraw_screen ();
-	    DWORD mode =
-	      ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	    SetConsoleMode (ptys->get_handle (), mode);
-	  }
+	if (h == ptys->get_handle ())
+	  ptys->set_switch_to_pcon ();
 	return;
       }
-  /* No pty slave opened */
-  if (last_ttyp) /* Make system_printf() work after closing pty slave */
-    last_ttyp->set_switch_to_pcon_out (true);
-}
-
-static void
-force_attach_to_pcon (HANDLE h)
-{
-  bool attach_done = false;
-  for (int n = 0; n < 2; n ++)
-    {
-      /* First time, attach to the pty whose handle value is match.
-	 Second time, try to attach to any pty. */
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	    if (!ptys->get_pseudo_console ())
-	      continue;
-	    if (n != 0
-		|| h == ptys->get_handle ()
-		|| h == ptys->get_output_handle ())
-	      {
-		if (fhandler_console::get_console_process_id
-				  (ptys->get_helper_process_id (), true))
-		  attach_done = true;
-		else
-		  {
-		    FreeConsole ();
-		    if (AttachConsole (ptys->get_helper_process_id ()))
-		      {
-			pcon_attached_to = ptys->get_minor ();
-			attach_done = true;
-		      }
-		    else
-		      pcon_attached_to = -1;
-		  }
-		break;
-	      }
-	  }
-	else if (cfd->get_major () == DEV_CONS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_console *cons = (fhandler_console *) fh;
-	    if (n != 0
-		|| h == cons->get_handle ()
-		|| h == cons->get_output_handle ())
-	      {
-		/* If the process is running on a console,
-		   the parent process should be attached
-		   to the same console. */
-		DWORD attach_wpid;
-		if (myself->ppid == 1)
-		  attach_wpid = ATTACH_PARENT_PROCESS;
-		else
-		  {
-		    pinfo p (myself->ppid);
-		    attach_wpid = p->dwProcessId;
-		  }
-		FreeConsole ();
-		if (AttachConsole (attach_wpid))
-		  {
-		    pcon_attached_to = -1;
-		    attach_done = true;
-		  }
-		else
-		  pcon_attached_to = -1;
-		break;
-	      }
-	  }
-      if (attach_done)
-	break;
-    }
-}
-
-void
-set_ishybrid_and_switch_to_pcon (HANDLE h)
-{
-  if (GetFileType (h) == FILE_TYPE_CHAR)
-    {
-      force_attach_to_pcon (h);
-      DWORD dummy;
-      if (!isHybrid && (GetConsoleMode (h, &dummy)
-			|| GetLastError () != ERROR_INVALID_HANDLE))
-	{
-	  isHybrid = true;
-	  set_switch_to_pcon ();
-	}
-    }
-}
-
-inline void
-fhandler_pty_slave::free_attached_console ()
-{
-  bool attached = get_ttyp () ?
-    fhandler_console::get_console_process_id (get_helper_process_id (), true)
-    : (get_minor () == pcon_attached_to);
-  if (freeconsole_on_close && attached)
-    {
-      FreeConsole ();
-      pcon_attached_to = -1;
-    }
 }
 
 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
-DEF_HOOK (WriteFile);
-DEF_HOOK (WriteConsoleA);
-DEF_HOOK (WriteConsoleW);
-DEF_HOOK (ReadFile);
-DEF_HOOK (ReadConsoleA);
-DEF_HOOK (ReadConsoleW);
-DEF_HOOK (WriteConsoleOutputA);
-DEF_HOOK (WriteConsoleOutputW);
-DEF_HOOK (WriteConsoleOutputCharacterA);
-DEF_HOOK (WriteConsoleOutputCharacterW);
-DEF_HOOK (WriteConsoleOutputAttribute);
-DEF_HOOK (SetConsoleCursorPosition);
-DEF_HOOK (SetConsoleTextAttribute);
-DEF_HOOK (WriteConsoleInputA);
-DEF_HOOK (WriteConsoleInputW);
-DEF_HOOK (ReadConsoleInputA);
-DEF_HOOK (ReadConsoleInputW);
-DEF_HOOK (PeekConsoleInputA);
-DEF_HOOK (PeekConsoleInputW);
 /* CreateProcess() is hooked for GDB etc. */
 DEF_HOOK (CreateProcessA);
 DEF_HOOK (CreateProcessW);
 
-static BOOL WINAPI
-WriteFile_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleA_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleW_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadFile_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleA_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleW_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleOutputA_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputA_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputW_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputW_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterA_Hooked
-     (HANDLE h, LPCSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterA_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterW_Hooked
-     (HANDLE h, LPCWSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterW_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputAttribute_Hooked
-     (HANDLE h, CONST WORD *a, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputAttribute_Orig (h, a, l, c, n);
-}
-static BOOL WINAPI
-SetConsoleCursorPosition_Hooked
-     (HANDLE h, COORD c)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleCursorPosition_Orig (h, c);
-}
-static BOOL WINAPI
-SetConsoleTextAttribute_Hooked
-     (HANDLE h, WORD a)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleTextAttribute_Orig (h, a);
-}
-static BOOL WINAPI
-WriteConsoleInputA_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-WriteConsoleInputW_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputW_Orig (h, r, l, n);
-}
-/* CreateProcess() is hooked for GDB etc. */
 static BOOL WINAPI
 CreateProcessA_Hooked
      (LPCSTR n, LPSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
@@ -363,11 +88,14 @@ CreateProcessA_Hooked
       LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 static BOOL WINAPI
@@ -377,11 +105,14 @@ CreateProcessW_Hooked
       LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 
@@ -464,10 +195,6 @@ fhandler_pty_master::flush_to_slave ()
 {
   if (get_readahead_valid () && !(get_ttyp ()->ti.c_lflag & ICANON))
     accept_input ();
-  WaitForSingleObject (input_mutex, INFINITE);
-  if (!get_ttyp ()->pcon_in_empty && !(get_ttyp ()->ti.c_lflag & ICANON))
-    SetEvent (input_available_event);
-  ReleaseMutex (input_mutex);
 }
 
 DWORD
@@ -532,14 +259,6 @@ fhandler_pty_master::doecho (const void *str, DWORD len)
   release_output_mutex ();
 }
 
-int
-fhandler_pty_master::put_readahead (char value)
-{
-  if (to_be_read_from_pcon ())
-    return 1;
-  return fhandler_base::put_readahead (value);
-}
-
 int
 fhandler_pty_master::accept_input ()
 {
@@ -551,9 +270,11 @@ fhandler_pty_master::accept_input ()
   char *p = rabuf () + raixget ();
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
   if (to_be_read_from_pcon ())
-    ; /* Do nothing */
-  else if (!bytes_left)
+    write_to = to_slave;
+
+  if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
@@ -564,10 +285,10 @@ fhandler_pty_master::accept_input ()
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -725,52 +446,12 @@ out:
 
 fhandler_pty_slave::fhandler_pty_slave (int unit)
   : fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL),
-  io_handle_cyg (NULL), pid_restore (0), fd (-1)
+  io_handle_cyg (NULL)
 {
   if (unit >= 0)
     dev ().parse (DEV_PTYS_MAJOR, unit);
 }
 
-fhandler_pty_slave::~fhandler_pty_slave ()
-{
-  if (!get_ttyp ())
-    {
-      /* Why comes here? Who clears _tc? */
-      free_attached_console ();
-      return;
-    }
-  if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 0)
-	{
-	  pcon_attached_to = -1;
-	  last_ttyp = get_ttyp ();
-	}
-      if (used == 0)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
-}
-
 int
 fhandler_pty_slave::open (int flags, mode_t)
 {
@@ -833,8 +514,8 @@ fhandler_pty_slave::open (int flags, mode_t)
     release_output_mutex ();
   }
 
-  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg () ||
-      !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
+  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg ()
+      || !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
     {
       errmsg = "pty handles have been closed";
       set_errno (EACCES);
@@ -923,8 +604,8 @@ fhandler_pty_slave::open (int flags, mode_t)
       from_master_cyg_local = repl.from_master_cyg;
       to_master_local = repl.to_master;
       to_master_cyg_local = repl.to_master_cyg;
-      if (!from_master_local || !from_master_cyg_local ||
-	  !to_master_local || !to_master_cyg_local)
+      if (!from_master_local || !from_master_cyg_local
+	  || !to_master_local || !to_master_cyg_local)
 	{
 	  SetLastError (repl.error);
 	  errmsg = "error duplicating pipes, %E";
@@ -950,24 +631,7 @@ fhandler_pty_slave::open (int flags, mode_t)
   set_output_handle (to_master_local);
   set_output_handle_cyg (to_master_cyg_local);
 
-  if (!get_pseudo_console ())
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (!fhandler_console::get_console_process_id
-			       (GetCurrentProcessId (), true))
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (fhandler_console::get_console_process_id
-			       (get_helper_process_id (), true))
-    /* Attached to pcon of this pty */
-    {
-      pcon_attached_to = get_minor ();
-      init_console_handler (true);
-    }
+  fhandler_console::need_invisible ();
 
   set_open_status ();
   return 1;
@@ -1021,8 +685,7 @@ fhandler_pty_slave::close ()
   if (!ForceCloseHandle (get_handle_cyg ()))
     termios_printf ("CloseHandle (get_handle_cyg ()<%p>), %E",
 	get_handle_cyg ());
-  if (!get_pseudo_console () &&
-      (unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
+  if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
     fhandler_console::free_console ();	/* assumes that we are the last pty closer */
   fhandler_pty_common::close ();
   if (!ForceCloseHandle (output_mutex))
@@ -1070,423 +733,31 @@ fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
   return ret;
 }
 
-bool
-fhandler_pty_slave::try_reattach_pcon (void)
-{
-  pid_restore = 0;
-
-  /* Do not detach from the console because re-attaching will
-     fail if helper process is running as service account. */
-  if (get_ttyp()->attach_pcon_in_fork)
-    return false;
-  if (pcon_attached_to >= 0 &&
-      cygwin_shared->tty[pcon_attached_to]->attach_pcon_in_fork)
-    return false;
-
-  pid_restore =
-    fhandler_console::get_console_process_id (GetCurrentProcessId (),
-					      false);
-  /* If pid_restore is not set, give up. */
-  if (!pid_restore)
-    return false;
-
-  FreeConsole ();
-  if (!AttachConsole (get_helper_process_id ()))
-    {
-      system_printf ("pty%d: AttachConsole(helper=%d) failed. 0x%08lx",
-		     get_minor (), get_helper_process_id (), GetLastError ());
-      return false;
-    }
-  return true;
-}
-
 void
-fhandler_pty_slave::restore_reattach_pcon (void)
+fhandler_pty_slave::set_switch_to_pcon (void)
 {
-  if (pid_restore)
+  if (!get_ttyp ()->switch_to_pcon_in)
     {
-      FreeConsole ();
-      if (!AttachConsole (pid_restore))
-	{
-	  system_printf ("pty%d: AttachConsole(restore=%d) failed. 0x%08lx",
-			 get_minor (), pid_restore, GetLastError ());
-	  pcon_attached_to = -1;
-	}
-    }
-  pid_restore = 0;
-}
-
-/* This function requests transfering the input data from the input
-   pipe for cygwin apps to the other input pipe for native apps. */
-void
-fhandler_pty_slave::pull_pcon_input (void)
-{
-  get_ttyp ()->req_transfer_input_to_pcon = true;
-  while (get_ttyp ()->req_transfer_input_to_pcon)
-    Sleep (1);
-}
-
-void
-fhandler_pty_slave::update_pcon_input_state (bool need_lock)
-{
-  if (need_lock)
-    WaitForSingleObject (input_mutex, INFINITE);
-  /* Flush input buffer if it is requested by master.
-     This happens if ^C is pressed in pseudo console side. */
-  if (get_ttyp ()->req_flush_pcon_input)
-    {
-      FlushConsoleInputBuffer (get_handle ());
-      get_ttyp ()->req_flush_pcon_input = false;
-    }
-  /* Peek console input buffer and update state. */
-  INPUT_RECORD inp[INREC_SIZE];
-  DWORD n;
-  BOOL (WINAPI *PeekFunc)
-    (HANDLE, PINPUT_RECORD, DWORD, LPDWORD);
-  PeekFunc =
-    PeekConsoleInputA_Orig ? : PeekConsoleInput;
-  PeekFunc (get_handle (), inp, INREC_SIZE, &n);
-  bool saw_accept = false;
-  bool pipe_empty = true;
-  while (n-- > 0)
-    if (inp[n].EventType == KEY_EVENT && inp[n].Event.KeyEvent.bKeyDown &&
-	inp[n].Event.KeyEvent.uChar.AsciiChar)
-      {
-	pipe_empty = false;
-	char c = inp[n].Event.KeyEvent.uChar.AsciiChar;
-	const char sigs[] = {
-	  (char) get_ttyp ()->ti.c_cc[VINTR],
-	  (char) get_ttyp ()->ti.c_cc[VQUIT],
-	  (char) get_ttyp ()->ti.c_cc[VSUSP],
-	};
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n',
-	  '\r'
-	};
-	if (is_line_input () && c && memchr (eols, c, sizeof (eols)))
-	  saw_accept = true;
-	if ((get_ttyp ()->ti.c_lflag & ISIG)
-	    && c && memchr (sigs, c, sizeof (sigs)))
-	  saw_accept = true;
-      }
-  get_ttyp ()->pcon_in_empty = pipe_empty && !(ralen () > raixget ());
-  if (!get_readahead_valid () &&
-      (pipe_empty || (is_line_input () && !saw_accept)) &&
-      get_ttyp ()->read_retval == 1 && bytes_available (n) && n == 0)
-    ResetEvent (input_available_event);
-  if (need_lock)
-    ReleaseMutex (input_mutex);
-}
-
-int
-fhandler_pty_slave::eat_readahead (int n)
-{
-  int oralen = ralen ();
-  if (n < 0)
-    n = ralen () - raixget ();
-  if (n > 0 && ralen () > raixget ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      while (n > 0 && ralen () > raixget ())
-	{
-	  if (is_line_input () && rabuf ()[ralen ()-1]
-	      && memchr (eols, rabuf ()[ralen ()-1], sizeof (eols)))
-	    break;
-	  -- n;
-	  -- ralen ();
-	}
-
-      /* If IUTF8 is set, the terminal is in UTF-8 mode.  If so, we erase
-	 a complete UTF-8 multibyte sequence on VERASE/VWERASE.  Otherwise,
-	 if we only erase a single byte, invalid unicode chars are left in
-	 the input. */
-      if (get_ttyp ()->ti.c_iflag & IUTF8)
-	while (ralen () > raixget () &&
-	       ((unsigned char) rabuf ()[ralen ()] & 0xc0) == 0x80)
-	  --ralen ();
-    }
-  oralen = oralen - ralen ();
-  if (raixget () >= ralen ())
-    raixget () = raixput () = ralen () = 0;
-  else if (raixput () > ralen ())
-    raixput () = ralen ();
-
-  return oralen;
-}
-
-int
-fhandler_pty_slave::get_readahead_into_buffer (char *buf, size_t buflen)
-{
-  int ch;
-  int copied_chars = 0;
-
-  while (buflen)
-    if ((ch = get_readahead ()) < 0)
-      break;
-    else
-      {
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n'
-	};
-	buf[copied_chars++] = (unsigned char)(ch & 0xff);
-	buflen--;
-	if (is_line_input () && ch && memchr (eols, ch & 0xff, sizeof (eols)))
-	  break;
-      }
-
-  return copied_chars;
-}
-
-bool
-fhandler_pty_slave::get_readahead_valid (void)
-{
-  if (is_line_input ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      for (size_t i=raixget (); i<ralen (); i++)
-	if (rabuf ()[i] && memchr (eols, rabuf ()[i], sizeof (eols)))
-	  return true;
-      return false;
-    }
-  else
-    return ralen () > raixget ();
-}
-
-void
-fhandler_pty_slave::set_switch_to_pcon (int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  acquire_output_mutex (INFINITE);
-  if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
-    {
-      pull_pcon_input ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
+      isHybrid = true;
+      if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
 	get_ttyp ()->pcon_pid = myself->pid;
       get_ttyp ()->switch_to_pcon_in = true;
-      if (isHybrid && !get_ttyp ()->switch_to_pcon_out)
-	{
-	  get_ttyp ()->wait_pcon_fwd ();
-	  get_ttyp ()->switch_to_pcon_out = true;
-	}
     }
-  else if ((fd == 1 || fd == 2) && !get_ttyp ()->switch_to_pcon_out)
-    {
-      get_ttyp ()->wait_pcon_fwd ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
-	get_ttyp ()->pcon_pid = myself->pid;
-      get_ttyp ()->switch_to_pcon_out = true;
-      if (isHybrid)
-	get_ttyp ()->switch_to_pcon_in = true;
-    }
-  release_output_mutex ();
 }
 
 void
 fhandler_pty_slave::reset_switch_to_pcon (void)
 {
-  if (get_ttyp ()->pcon_pid &&
-      get_ttyp ()->pcon_pid != myself->pid &&
-      !!pinfo (get_ttyp ()->pcon_pid))
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
     /* There is a process which is grabbing pseudo console. */
     return;
   if (isHybrid)
     return;
-  if (do_not_reset_switch_to_pcon)
-    return;
-  acquire_output_mutex (INFINITE);
-  if (get_ttyp ()->switch_to_pcon_out)
-    /* Wait for pty_master_fwd_thread() */
-    get_ttyp ()->wait_pcon_fwd ();
   get_ttyp ()->pcon_pid = 0;
   get_ttyp ()->switch_to_pcon_in = false;
-  get_ttyp ()->switch_to_pcon_out = false;
-  release_output_mutex ();
-  init_console_handler (true);
-}
-
-void
-fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len,
-					       bool is_echo)
-{
-  bool attached =
-    !!fhandler_console::get_console_process_id (get_helper_process_id (), true);
-  if (!attached && pcon_attached_to == get_minor ())
-    {
-      for (DWORD t0 = GetTickCount (); GetTickCount () - t0 < 100; )
-	{
-	  Sleep (1);
-	  attached = fhandler_console::get_console_process_id
-				      (get_helper_process_id (), true);
-	  if (attached)
-	    break;
-	}
-      if (!attached)
-	{
-	  system_printf ("pty%d: pcon_attach_to mismatch??????", get_minor ());
-	  return;
-	}
-    }
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  if (pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      goto detach;
-
-  char *buf;
-  size_t nlen;
-  DWORD origCP;
-  origCP = GetConsoleOutputCP ();
-  SetConsoleOutputCP (get_ttyp ()->term_code_page);
-  /* Just copy */
-  buf = (char *) HeapAlloc (GetProcessHeap (), 0, len);
-  memcpy (buf, (char *)ptr, len);
-  nlen = len;
-  char *p0, *p1;
-  p0 = p1 = buf;
-  /* Remove alternate screen buffer drawing */
-  while (p0 && p1)
-    {
-      if (!get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to alternate screen buffer */
-	  p0 = (char *) memmem (p1, nlen - (p1-buf), "\033[?1049h", 8);
-	  if (p0)
-	    {
-	      //p0 += 8;
-	      get_ttyp ()->screen_alternated = true;
-	      if (get_ttyp ()->switch_to_pcon_out)
-		do_not_reset_switch_to_pcon = true;
-	    }
-	}
-      if (get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to main screen buffer */
-	  p1 = (char *) memmem (p0, nlen - (p0-buf), "\033[?1049l", 8);
-	  if (p1)
-	    {
-	      p1 += 8;
-	      get_ttyp ()->screen_alternated = false;
-	      do_not_reset_switch_to_pcon = false;
-	      memmove (p0, p1, buf+nlen - p1);
-	      nlen -= p1 - p0;
-	    }
-	  else
-	    nlen = p0 - buf;
-	}
-    }
-  if (!nlen) /* Nothing to be synchronized */
-    goto cleanup;
-  if (get_ttyp ()->switch_to_pcon_out && !is_echo)
-    goto cleanup;
-  /* Remove ESC sequence which returns results to console
-     input buffer. Without this, cursor position report
-     is put into the input buffer as a garbage. */
-  /* Remove ESC sequence to report cursor position. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[6n", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-  /* Remove ESC sequence to report terminal identity. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[0c", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-
-  /* If the ESC sequence ESC[?3h or ESC[?3l which clears console screen
-     buffer is pushed, set need_redraw_screen to trigger redraw screen. */
-  p0 = buf;
-  while ((p0 = (char *) memmem (p0, nlen - (p0 - buf), "\033[?", 3)))
-    {
-      p0 += 3;
-      bool exist_arg_3 = false;
-      while (p0 < buf + nlen && (isdigit (*p0) || *p0 == ';'))
-	{
-	  int arg = 0;
-	  while (p0 < buf + nlen && isdigit (*p0))
-	    arg = arg * 10 + (*p0 ++) - '0';
-	  if (arg == 3)
-	    exist_arg_3 = true;
-	  if (p0 < buf + nlen && *p0 == ';')
-	    p0 ++;
-	}
-      if (p0 < buf + nlen && exist_arg_3 && (*p0 == 'h' || *p0 == 'l'))
-	get_ttyp ()->need_redraw_screen = true;
-      p0 ++;
-      if (p0 >= buf + nlen)
-	break;
-    }
-
-  int retry_count;
-  retry_count = 0;
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  while (!GetConsoleMode (get_output_handle (), &dwMode))
-    {
-      termios_printf ("GetConsoleMode failed, %E");
-      int errno_save = errno;
-      /* Re-open handles */
-      this->open (0, 0);
-      /* Fix pseudo console window size */
-      this->ioctl (TIOCSWINSZ, &get_ttyp ()->winsize);
-      if (errno != errno_save)
-	set_errno (errno_save);
-      if (++retry_count > 3)
-	goto cleanup;
-    }
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-  char *p;
-  p = buf;
-  DWORD wLen, written;
-  written = 0;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
-  while (written <  nlen)
-    {
-      if (!WriteFunc (get_output_handle (), p, nlen - written, &wLen, NULL))
-	{
-	  termios_printf ("WriteFile failed, %E");
-	  break;
-	}
-      else
-	{
-	  written += wLen;
-	  p += wLen;
-	}
-    }
-  /* Detach from pseudo console and resume. */
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-cleanup:
-  SetConsoleOutputCP (origCP);
-  HeapFree (GetProcessHeap (), 0, buf);
-detach:
-  restore_reattach_pcon ();
+  get_ttyp ()->h_pseudo_console = NULL;
+  get_ttyp ()->pcon_start = false;
 }
 
 ssize_t __stdcall
@@ -1505,44 +776,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
   reset_switch_to_pcon ();
 
   acquire_output_mutex (INFINITE);
-  bool output_to_pcon = get_ttyp ()->switch_to_pcon_out;
-  release_output_mutex ();
-
-  UINT target_code_page = output_to_pcon ?
-    GetConsoleOutputCP () : get_ttyp ()->term_code_page;
-  ssize_t nlen;
-  char *buf = convert_mb_str (target_code_page, (size_t *) &nlen,
-		 get_ttyp ()->term_code_page, (const char *) ptr, len);
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  bool fallback = false;
-  if (output_to_pcon && pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      fallback = true;
-
-  if (output_to_pcon && !fallback &&
-      (memmem (buf, nlen, "\033[6n", 4) || memmem (buf, nlen, "\033[0c", 4)))
-    {
-      get_ttyp ()->pcon_in_empty = false;
-      if (!is_line_input ())
-	SetEvent (input_available_event);
-    }
-
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  if (output_to_pcon && !fallback)
-    {
-      GetConsoleMode (get_output_handle (), &dwMode);
-      SetConsoleMode (get_output_handle (), dwMode | flags);
-    }
-  HANDLE to = (output_to_pcon && !fallback) ?
-    get_output_handle () : get_output_handle_cyg ();
-  acquire_output_mutex (INFINITE);
-  if (!process_opost_output (to, buf, nlen, false))
+  if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false))
     {
       DWORD err = GetLastError ();
       termios_printf ("WriteFile failed, %E");
@@ -1557,20 +791,6 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
       towrite = -1;
     }
   release_output_mutex ();
-  mb_str_free (buf);
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (output_to_pcon && !fallback)
-    SetConsoleMode (get_output_handle (), dwMode | flags);
-
-  restore_reattach_pcon ();
-
-  /* Push slave output to pseudo console screen buffer */
-  if (get_pseudo_console ())
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer ((char *)ptr, len, false);
-      release_output_mutex ();
-    }
 
   return towrite;
 }
@@ -1582,16 +802,15 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 }
 
 bool
-fhandler_pty_common::to_be_read_from_pcon (void)
+fhandler_pty_master::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return get_ttyp ()->pcon_start
+    || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
 fhandler_pty_slave::read (void *ptr, size_t& len)
 {
-  char *ptr0 = (char *)ptr;
   ssize_t totalread = 0;
   int vmin = 0;
   int vtime = 0;	/* Initialized to prevent -Wuninitialized warning */
@@ -1616,8 +835,6 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
       mask_switch_to_pcon_in (true);
       reset_switch_to_pcon ();
     }
-  if (to_be_read_from_pcon ())
-    update_pcon_input_state (true);
 
   if (is_nonblocking () || !ptr) /* Indicating tcflush(). */
     time_to_wait = 0;
@@ -1703,98 +920,21 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 	      if (!totalread)
 		{
 		  set_sig_errno (EAGAIN);
-		  totalread = -1;
-		}
-	      goto out;
-	    }
-	  continue;
-	default:
-	  termios_printf ("wait for input mutex failed, %E");
-	  if (!totalread)
-	    {
-	      __seterrno ();
-	      totalread = -1;
-	    }
-	  goto out;
-	}
-      if (ptr && to_be_read_from_pcon ())
-	{
-	  if (get_readahead_valid ())
-	    {
-	      ReleaseMutex (input_mutex);
-	      totalread = get_readahead_into_buffer ((char *) ptr, len);
-	    }
-	  else
-	    {
-	      if (!try_reattach_pcon ())
-		{
-		  restore_reattach_pcon ();
-		  goto do_read_cyg;
-		}
-
-	      DWORD dwMode;
-	      GetConsoleMode (get_handle (), &dwMode);
-	      DWORD flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
-	      if (dwMode != flags)
-		SetConsoleMode (get_handle (), flags);
-	      /* Read get_handle() instad of get_handle_cyg() */
-	      BOOL (WINAPI *ReadFunc)
-		(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID);
-	      ReadFunc = ReadConsoleA_Orig ? ReadConsoleA_Orig : ReadConsoleA;
-	      DWORD rlen;
-	      readlen = MIN (len, sizeof (buf));
-	      if (!ReadFunc (get_handle (), buf, readlen, &rlen, NULL))
-		{
-		  termios_printf ("read failed, %E");
-		  SetConsoleMode (get_handle (), dwMode);
-		  restore_reattach_pcon ();
-		  ReleaseMutex (input_mutex);
-		  set_errno (EIO);
-		  totalread = -1;
-		  goto out;
-		}
-	      SetConsoleMode (get_handle (), dwMode);
-	      restore_reattach_pcon ();
-	      ReleaseMutex (input_mutex);
-
-	      ssize_t nlen;
-	      char *nbuf = convert_mb_str (get_ttyp ()->term_code_page,
-			     (size_t *) &nlen, GetConsoleCP (), buf, rlen);
-
-	      ssize_t ret;
-	      line_edit_status res =
-		line_edit (nbuf, nlen, get_ttyp ()->ti, &ret);
-
-	      mb_str_free (nbuf);
-
-	      if (res == line_edit_input_done || res == line_edit_ok)
-		totalread = get_readahead_into_buffer ((char *) ptr, len);
-	      else if (res > line_edit_signalled)
-		{
-		  set_sig_errno (EINTR);
-		  totalread = -1;
-		}
-	      else
-		{
-		  update_pcon_input_state (true);
-		  continue;
+		  totalread = -1;
 		}
+	      goto out;
+	    }
+	  continue;
+	default:
+	  termios_printf ("wait for input mutex failed, %E");
+	  if (!totalread)
+	    {
+	      __seterrno ();
+	      totalread = -1;
 	    }
-
-	  update_pcon_input_state (true);
-	  mask_switch_to_pcon_in (false);
 	  goto out;
 	}
-      if (!ptr && len == UINT_MAX && !get_ttyp ()->pcon_in_empty)
-	{
-	  FlushConsoleInputBuffer (get_handle ());
-	  get_ttyp ()->pcon_in_empty = true;
-	  DWORD n;
-	  if (bytes_available (n) && n == 0)
-	    ResetEvent (input_available_event);
-	}
 
-do_read_cyg:
       if (!bytes_available (bytes_in_pipe))
 	{
 	  ReleaseMutex (input_mutex);
@@ -1911,16 +1051,6 @@ do_read_cyg:
 out:
   termios_printf ("%d = read(%p, %lu)", totalread, ptr, len);
   len = (size_t) totalread;
-  /* Push slave read as echo to pseudo console screen buffer. */
-  if (get_pseudo_console () && ptr0 && totalread > 0 &&
-      (get_ttyp ()->ti.c_lflag & ECHO))
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer (ptr0, len, true);
-      if (get_ttyp ()->switch_to_pcon_out)
-	trigger_redraw_screen ();
-      release_output_mutex ();
-    }
   mask_switch_to_pcon_in (false);
 }
 
@@ -2061,38 +1191,11 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
       get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
       break;
     case TIOCSWINSZ:
-      if (get_pseudo_console ())
-	{
-	  /* If not attached to this pseudo console,
-	     try to attach temporarily. */
-	  pid_restore = 0;
-	  if (pcon_attached_to != get_minor ())
-	    if (!try_reattach_pcon ())
-	      goto cleanup;
-
-	  COORD size;
-	  size.X = ((struct winsize *) arg)->ws_col;
-	  size.Y = ((struct winsize *) arg)->ws_row;
-	  CONSOLE_SCREEN_BUFFER_INFO csbi;
-	  if (GetConsoleScreenBufferInfo (get_output_handle (), &csbi))
-	    if (size.X == csbi.srWindow.Right - csbi.srWindow.Left + 1 &&
-		size.Y == csbi.srWindow.Bottom - csbi.srWindow.Top + 1)
-	      goto cleanup;
-	  if (!SetConsoleScreenBufferSize (get_output_handle (), size))
-	    goto cleanup;
-	  SMALL_RECT rect;
-	  rect.Left = 0;
-	  rect.Top = 0;
-	  rect.Right = size.X-1;
-	  rect.Bottom = size.Y-1;
-	  SetConsoleWindowInfo (get_output_handle (), TRUE, &rect);
-cleanup:
-	  restore_reattach_pcon ();
-	}
-
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->arg.winsize = *(struct winsize *) arg;
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
@@ -2378,6 +1481,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2393,7 +1517,6 @@ fhandler_pty_master::close ()
 {
   OBJECT_BASIC_INFORMATION obi;
   NTSTATUS status;
-  pid_t master_pid_tmp = get_ttyp ()->master_pid;
 
   termios_printf ("closing from_master(%p)/from_master_cyg(%p)/to_master(%p)/to_master_cyg(%p) since we own them(%u)",
 		  from_master, from_master_cyg,
@@ -2438,30 +1561,6 @@ fhandler_pty_master::close ()
   else if (obi.HandleCount == 1)
     {
       termios_printf ("Closing last master of pty%d", get_minor ());
-      /* Close Pseudo Console */
-      if (get_pseudo_console ())
-	{
-	  /* Terminate helper process */
-	  SetEvent (get_ttyp ()->h_helper_goodbye);
-	  WaitForSingleObject (get_ttyp ()->h_helper_process, INFINITE);
-	  CloseHandle (get_ttyp ()->h_helper_goodbye);
-	  CloseHandle (get_ttyp ()->h_helper_process);
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (master_pid_tmp == myself->pid)
-	    {
-	      /* ClosePseudoConsole() seems to have a bug that one
-		 internal handle remains opened. This causes handle leak.
-		 This is a workaround for this problem. */
-	      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_pseudo_console ();
-	      HANDLE tmp = hp->hConHostProcess;
-	      /* Release pseudo console */
-	      ClosePseudoConsole (get_pseudo_console ());
-	      CloseHandle (tmp);
-	    }
-	  get_ttyp ()->switch_to_pcon_in = false;
-	  get_ttyp ()->switch_to_pcon_out = false;
-	}
       if (get_ttyp ()->getsid () > 0)
 	kill (get_ttyp ()->getsid (), SIGHUP);
       SetEvent (input_available_event);
@@ -2469,9 +1568,8 @@ fhandler_pty_master::close ()
 
   if (!ForceCloseHandle (from_master))
     termios_printf ("error closing from_master %p, %E", from_master);
-  if (from_master_cyg != from_master) /* Avoid double close. */
-    if (!ForceCloseHandle (from_master_cyg))
-      termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
+  if (!ForceCloseHandle (from_master_cyg))
+    termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
   if (!ForceCloseHandle (to_master))
     termios_printf ("error closing to_master %p, %E", to_master);
   from_master = to_master = NULL;
@@ -2513,7 +1611,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon () && get_ttyp ()->h_pseudo_console)
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2521,40 +1619,50 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
       WaitForSingleObject (input_mutex, INFINITE);
 
-      if (memchr (buf, '\003', nlen)) /* ^C intr key in pcon */
-	get_ttyp ()->req_flush_pcon_input = true;
-
       DWORD wLen;
-      WriteFile (to_slave, buf, nlen, &wLen, NULL);
-      get_ttyp ()->pcon_in_empty = false;
-
-      ReleaseMutex (input_mutex);
 
-      /* Use line_edit () in order to set input_available_event. */
-      bool is_echo = tc ()->ti.c_lflag & ECHO;
-      if (!get_ttyp ()->mask_switch_to_pcon_in)
+      if (get_ttyp ()->pcon_start)
 	{
-	  tc ()->ti.c_lflag &= ~ECHO;
-	  ti.c_lflag &= ~ECHO;
-	}
-      ti.c_lflag &= ~ISIG;
-      line_edit (buf, nlen, ti, &ret);
-      if (is_echo)
-	tc ()->ti.c_lflag |= ECHO;
-      get_ttyp ()->read_retval = 1;
-
-      const char sigs[] = {
-	(char) ti.c_cc[VINTR],
-	(char) ti.c_cc[VQUIT],
-	(char) ti.c_cc[VSUSP],
-      };
-      if (tc ()->ti.c_lflag & ISIG)
-	for (size_t i=0; i<sizeof (sigs); i++)
-	  if (sigs[i] && memchr (buf, sigs[i], nlen))
+	  /* Pseudo condole support uses "CSI6n" to get cursor position.
+	     If the reply for "CSI6n" is divided into multiple writes,
+	     pseudo console sometimes does not recognize it.  Therefore,
+	     put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon_start = false;
+	    }
+	  else
 	    {
-	      eat_readahead (-1);
-	      SetEvent (input_available_event);
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
 	    }
+	}
+
+      WriteFile (to_slave, buf, nlen, &wLen, NULL);
+
+      ReleaseMutex (input_mutex);
 
       mb_str_free (buf);
       return len;
@@ -2630,15 +1738,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (get_pseudo_console () && get_ttyp ()->master_pid == myself->pid)
-	    {
-	      COORD size;
-	      size.X = ((struct winsize *) arg)->ws_col;
-	      size.Y = ((struct winsize *) arg)->ws_row;
-	      ResizePseudoConsole (get_pseudo_console (), size);
-	    }
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
 	}
@@ -2763,7 +1864,7 @@ get_locale_from_env (char *locale)
   strcpy (locale, env);
 }
 
-static LCID
+static void
 get_langinfo (char *locale_out, char *charset_out)
 {
   /* Get locale from environment */
@@ -2776,11 +1877,6 @@ get_langinfo (char *locale_out, char *charset_out)
   if (!locale)
     locale = "C";
 
-  char tmp_locale[ENCODING_LEN + 1];
-  char *ret = __set_locale_from_locale_alias (locale, tmp_locale);
-  if (ret)
-    locale = tmp_locale;
-
   const char *charset;
   struct lc_ctype_T *lc_ctype = (struct lc_ctype_T *) loc.lc_cat[LC_CTYPE].ptr;
   if (!lc_ctype)
@@ -2830,23 +1926,9 @@ get_langinfo (char *locale_out, char *charset_out)
       charset = "CP932";
     }
 
-  wchar_t lc[ENCODING_LEN + 1];
-  wchar_t *p;
-  mbstowcs (lc, locale, ENCODING_LEN);
-  p = wcschr (lc, L'.');
-  if (p)
-    *p = L'\0';
-  p = wcschr (lc, L'_');
-  if (p)
-    *p = L'-';
-  LCID lcid = LocaleNameToLCID (lc, 0);
-  if (!lcid && !strcmp (charset, "ASCII"))
-    return 0;
-
   /* Set results */
   strcpy (locale_out, new_locale);
   strcpy (charset_out, charset);
-  return lcid;
 }
 
 void
@@ -2854,21 +1936,7 @@ fhandler_pty_slave::setup_locale (void)
 {
   char locale[ENCODING_LEN + 1] = "C";
   char charset[ENCODING_LEN + 1] = "ASCII";
-  LCID lcid = get_langinfo (locale, charset);
-
-  /* Set console code page form locale */
-  if (get_pseudo_console ())
-    {
-      UINT code_page;
-      if (lcid == 0 || lcid == (LCID) -1)
-	code_page = 20127; /* ASCII */
-      else if (!GetLocaleInfo (lcid,
-			       LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
-			       (char *) &code_page, sizeof (code_page)))
-	code_page = 20127; /* ASCII */
-      SetConsoleCP (code_page);
-      SetConsoleOutputCP (code_page);
-    }
+  get_langinfo (locale, charset);
 
   /* Set terminal code page from locale */
   /* This code is borrowed from mintty: charset.c */
@@ -2878,9 +1946,9 @@ fhandler_pty_slave::setup_locale (void)
     charset_u[i] = toupper (charset[i]);
   unsigned int iso;
   UINT cp = 20127; /* Default for fallback */
-  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859%u", &iso) == 1)
+  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859%u", &iso) == 1)
     {
       if (iso && iso <= 16 && iso !=12)
 	get_ttyp ()->term_code_page = 28590 + iso;
@@ -2896,90 +1964,9 @@ fhandler_pty_slave::setup_locale (void)
 	}
 }
 
-void
-fhandler_pty_slave::set_freeconsole_on_close (bool val)
-{
-  freeconsole_on_close = val;
-}
-
-void
-fhandler_pty_slave::trigger_redraw_screen (void)
-{
-  /* Forcibly redraw screen based on console screen buffer. */
-  /* The following code triggers redrawing the screen. */
-  CONSOLE_SCREEN_BUFFER_INFO sbi;
-  GetConsoleScreenBufferInfo (get_output_handle (), &sbi);
-  SMALL_RECT rect = {0, 0,
-    (SHORT) (sbi.dwSize.X -1), (SHORT) (sbi.dwSize.Y - 1)};
-  COORD dest = {0, 0};
-  CHAR_INFO fill = {' ', 0};
-  ScrollConsoleScreenBuffer (get_output_handle (), &rect, NULL, dest, &fill);
-  get_ttyp ()->need_redraw_screen = false;
-}
-
-void
-fhandler_pty_slave::fixup_after_attach (bool native_maybe, int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  if (get_pseudo_console ())
-    {
-      if (fhandler_console::get_console_process_id (get_helper_process_id (),
-						    true))
-	if (pcon_attached_to != get_minor ())
-	  {
-	    pcon_attached_to = get_minor ();
-	    init_console_handler (true);
-	  }
-
-#if 0 /* This is for debug only. */
-      isHybrid = true;
-      get_ttyp ()->switch_to_pcon_in = true;
-      get_ttyp ()->switch_to_pcon_out = true;
-#endif
-
-      if (pcon_attached_to == get_minor () && native_maybe)
-	{
-	  if (fd == 0)
-	    {
-	      pull_pcon_input ();
-	      DWORD mode =
-		ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	      SetConsoleMode (get_handle (), mode);
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_in = true;
-	    }
-	  else if (fd == 1 || fd == 2)
-	    {
-	      DWORD mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
-	      SetConsoleMode (get_output_handle (), mode);
-	      acquire_output_mutex (INFINITE);
-	      if (!get_ttyp ()->switch_to_pcon_out)
-		get_ttyp ()->wait_pcon_fwd ();
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_out = true;
-	      release_output_mutex ();
-
-	      if (get_ttyp ()->need_redraw_screen)
-		trigger_redraw_screen ();
-	    }
-	  init_console_handler (false);
-	}
-      else if (fd == 0 && native_maybe)
-	/* Read from unattached pseudo console cause freeze,
-	   therefore, fallback to legacy pty. */
-	set_handle (get_handle_cyg ());
-    }
-}
-
 void
 fhandler_pty_slave::fixup_after_fork (HANDLE parent)
 {
-  fixup_after_attach (false, -1);
   // fork_fixup (parent, inuse, "inuse");
   // fhandler_pty_common::fixup_after_fork (parent);
   report_tty_counts (this, "inherited", "");
@@ -2992,71 +1979,22 @@ fhandler_pty_slave::fixup_after_exec ()
 
   if (!close_on_exec ())
     fixup_after_fork (NULL);	/* No parent handle required. */
-  else if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 1 && get_minor () == pcon_attached_to)
-	pcon_attached_to = -1;
-      if (used == 1 /* About to close this tty */)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
 
   /* Set locale */
   if (get_ttyp ()->term_code_page == 0)
     setup_locale ();
 
   /* Hook Console API */
-  if (get_pseudo_console ())
-    {
 #define DO_HOOK(module, name) \
-      if (!name##_Orig) \
-	{ \
-	  void *api = hook_api (module, #name, (void *) name##_Hooked); \
-	  name##_Orig = (__typeof__ (name) *) api; \
-	  /*if (api) system_printf (#name " hooked.");*/ \
-	}
-      DO_HOOK (NULL, WriteFile);
-      DO_HOOK (NULL, WriteConsoleA);
-      DO_HOOK (NULL, WriteConsoleW);
-      DO_HOOK (NULL, ReadFile);
-      DO_HOOK (NULL, ReadConsoleA);
-      DO_HOOK (NULL, ReadConsoleW);
-      DO_HOOK (NULL, WriteConsoleOutputA);
-      DO_HOOK (NULL, WriteConsoleOutputW);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterA);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterW);
-      DO_HOOK (NULL, WriteConsoleOutputAttribute);
-      DO_HOOK (NULL, SetConsoleCursorPosition);
-      DO_HOOK (NULL, SetConsoleTextAttribute);
-      DO_HOOK (NULL, WriteConsoleInputA);
-      DO_HOOK (NULL, WriteConsoleInputW);
-      DO_HOOK (NULL, ReadConsoleInputA);
-      DO_HOOK (NULL, ReadConsoleInputW);
-      DO_HOOK (NULL, PeekConsoleInputA);
-      DO_HOOK (NULL, PeekConsoleInputW);
-      /* CreateProcess() is hooked for GDB etc. */
-      DO_HOOK (NULL, CreateProcessA);
-      DO_HOOK (NULL, CreateProcessW);
+  if (!name##_Orig) \
+    { \
+      void *api = hook_api (module, #name, (void *) name##_Hooked); \
+      name##_Orig = (__typeof__ (name) *) api; \
+      /*if (api) system_printf (#name " hooked.");*/ \
     }
+  /* CreateProcess() is hooked for GDB etc. */
+  DO_HOOK (NULL, CreateProcessA);
+  DO_HOOK (NULL, CreateProcessW);
 }
 
 /* This thread function handles the master control pipe.  It waits for a
@@ -3204,27 +2142,6 @@ reply:
   return 0;
 }
 
-void
-fhandler_pty_master::transfer_input_to_pcon (void)
-{
-  WaitForSingleObject (input_mutex, INFINITE);
-  DWORD n;
-  size_t transfered = 0;
-  while (::bytes_available (n, from_master_cyg) && n)
-    {
-      char buf[1024];
-      ReadFile (from_master_cyg, buf, sizeof (buf), &n, 0);
-      char *p = buf;
-      while ((p = (char *) memchr (p, '\n', n - (p - buf))))
-	*p = '\r';
-      if (WriteFile (to_slave, buf, n, &n, 0))
-	transfered += n;
-    }
-  if (transfered)
-    get_ttyp ()->pcon_in_empty = false;
-  ReleaseMutex (input_mutex);
-}
-
 static DWORD WINAPI
 pty_master_thread (VOID *arg)
 {
@@ -3240,23 +2157,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
   termios_printf ("Started.");
   for (;;)
     {
-      if (get_pseudo_console ())
-	{
-	  get_ttyp ()->pcon_last_time = GetTickCount ();
-	  while (::bytes_available (rlen, from_slave) && rlen == 0)
-	    {
-	      /* Forcibly transfer input if it is requested by slave.
-		 This happens when input data should be transfered
-		 from the input pipe for cygwin apps to the input pipe
-		 for native apps. */
-	      if (get_ttyp ()->req_transfer_input_to_pcon)
-		{
-		  transfer_input_to_pcon ();
-		  get_ttyp ()->req_transfer_input_to_pcon = false;
-		}
-	      Sleep (1);
-	    }
-	}
+      get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3264,14 +2165,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_ttyp ()->h_pseudo_console)
 	{
-	  /* Avoid duplicating slave output which is already sent to
-	     to_master_cyg */
-	  if (!get_ttyp ()->switch_to_pcon_out)
-	    continue;
-
-	  /* Avoid setting window title to "cygwin-console-helper.exe" */
+	  /* Remove CSI > Pm m */
 	  int state = 0;
 	  int start_at = 0;
 	  for (DWORD i=0; i<rlen; i++)
@@ -3281,43 +2177,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 		state = 1;
 		continue;
 	      }
-	    else if ((state == 1 && outbuf[i] == ']') ||
-		     (state == 2 && outbuf[i] == '0') ||
-		     (state == 3 && outbuf[i] == ';'))
-	      {
-		state ++;
-		continue;
-	      }
-	    else if (state == 4 && outbuf[i] == '\a')
-	      {
-		const char *helper_str = "\\bin\\cygwin-console-helper.exe";
-		if (memmem (&outbuf[start_at], i + 1 - start_at,
-			    helper_str, strlen (helper_str)))
-		  {
-		    memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
-		    rlen = wlen = start_at + rlen - i - 1;
-		  }
-		state = 0;
-		continue;
-	      }
-	    else if (outbuf[i] == '\a')
-	      {
-		state = 0;
-		continue;
-	      }
-
-	  /* Remove CSI > Pm m */
-	  state = 0;
-	  start_at = 0;
-	  for (DWORD i=0; i<rlen; i++)
-	    if (outbuf[i] == '\033')
-	      {
-		start_at = i;
-		state = 1;
-		continue;
-	      }
-	    else if ((state == 1 && outbuf[i] == '[') ||
-		     (state == 2 && outbuf[i] == '>'))
+	    else if ((state == 1 && outbuf[i] == '[')
+		     || (state == 2 && outbuf[i] == '>'))
 	      {
 		state ++;
 		continue;
@@ -3386,201 +2247,6 @@ pty_master_fwd_thread (VOID *arg)
   return ((fhandler_pty_master *) arg)->pty_master_fwd_thread ();
 }
 
-/* If master process is running as service, attaching to
-   pseudo console should be done in fork. If attaching
-   is done in spawn for inetd or sshd, it fails because
-   the helper process is running as privileged user while
-   slave process is not. This function is used to determine
-   if the process is running as a srvice or not. */
-inline static bool
-is_running_as_service (void)
-{
-  return check_token_membership (well_known_service_sid)
-    || cygheap->user.saved_sid () == well_known_system_sid;
-}
-
-bool
-fhandler_pty_master::setup_pseudoconsole ()
-{
-  if (disable_pcon)
-    return false;
-  /* If the legacy console mode is enabled, pseudo console seems
-     not to work as expected. To determine console mode, registry
-     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
-  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
-  if (reg.error ())
-    return false;
-  if (reg.get_dword (L"ForceV2", 1) == 0)
-    {
-      termios_printf ("Pseudo console is disabled "
-		      "because the legacy console mode is enabled.");
-      return false;
-    }
-
-  /* Pseudo console supprot is realized using a tricky technic.
-     PTY need the pseudo console handles, however, they cannot
-     be retrieved by normal procedure. Therefore, run a helper
-     process in a pseudo console and get them from the helper.
-     Slave process will attach to the pseudo console in the
-     helper process using AttachConsole(). */
-  COORD size = {
-    (SHORT) get_ttyp ()->winsize.ws_col,
-    (SHORT) get_ttyp ()->winsize.ws_row
-  };
-  CreatePipe (&from_master, &to_slave, &sec_none, 0);
-  SetLastError (ERROR_SUCCESS);
-  HRESULT res = CreatePseudoConsole (size, from_master, to_master,
-				     0, &get_ttyp ()->h_pseudo_console);
-  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
-    {
-      if (res != S_OK)
-	system_printf ("CreatePseudoConsole() failed. %08x\n",
-		       GetLastError ());
-      goto fallback;
-    }
-
-  /* If master process is running as service, attaching to
-     pseudo console should be done in fork. If attaching
-     is done in spawn for inetd or sshd, it fails because
-     the helper process is running as privileged user while
-     slave process is not. */
-  if (is_running_as_service ())
-    get_ttyp ()->attach_pcon_in_fork = true;
-
-  STARTUPINFOEXW si_helper;
-  HANDLE hello, goodbye;
-  HANDLE hr, hw;
-  PROCESS_INFORMATION pi_helper;
-  HANDLE hpConIn, hpConOut;
-  {
-    SIZE_T bytesRequired;
-    InitializeProcThreadAttributeList (NULL, 2, 0, &bytesRequired);
-    ZeroMemory (&si_helper, sizeof (si_helper));
-    si_helper.StartupInfo.cb = sizeof (STARTUPINFOEXW);
-    si_helper.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
-      HeapAlloc (GetProcessHeap (), 0, bytesRequired);
-    if (si_helper.lpAttributeList == NULL)
-      goto cleanup_pseudo_console;
-    if (!InitializeProcThreadAttributeList (si_helper.lpAttributeList,
-					    2, 0, &bytesRequired))
-      goto cleanup_heap;
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
-				    get_ttyp ()->h_pseudo_console,
-				    sizeof (get_ttyp ()->h_pseudo_console),
-				    NULL, NULL))
-      goto cleanup_heap;
-    /* Create events for start/stop helper process. */
-    hello = CreateEvent (&sec_none, true, false, NULL);
-    goodbye = CreateEvent (&sec_none, true, false, NULL);
-    /* Create a pipe for receiving pseudo console handles */
-    CreatePipe (&hr, &hw, &sec_none, 0);
-    /* Inherit only handles which are needed by helper. */
-    HANDLE handles_to_inherit[] = {hello, goodbye, hw};
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
-				    handles_to_inherit,
-				    sizeof (handles_to_inherit),
-				    NULL, NULL))
-      goto cleanup_event_and_pipes;
-    /* Create helper process */
-    WCHAR cmd[MAX_PATH];
-    path_conv helper ("/bin/cygwin-console-helper.exe");
-    size_t len = helper.get_wide_win32_path_len ();
-    helper.get_wide_win32_path (cmd);
-    __small_swprintf (cmd + len, L" %p %p %p", hello, goodbye, hw);
-    si_helper.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
-    si_helper.StartupInfo.hStdInput = NULL;
-    si_helper.StartupInfo.hStdOutput = NULL;
-    si_helper.StartupInfo.hStdError = NULL;
-    if (!CreateProcessW (NULL, cmd, &sec_none, &sec_none,
-			 TRUE, EXTENDED_STARTUPINFO_PRESENT,
-			 NULL, NULL, &si_helper.StartupInfo, &pi_helper))
-      goto cleanup_event_and_pipes;
-    for (;;)
-      {
-        DWORD wait_result = WaitForSingleObject (hello, 500);
-	if (wait_result == WAIT_OBJECT_0)
-	  break;
-	if (wait_result != WAIT_TIMEOUT)
-	  goto cleanup_helper_process;
-	DWORD exit_code;
-	if (!GetExitCodeProcess(pi_helper.hProcess, &exit_code))
-	  goto cleanup_helper_process;
-	if (exit_code == STILL_ACTIVE)
-	  continue;
-	if (exit_code != 0 ||
-	    WaitForSingleObject (hello, 500) != WAIT_OBJECT_0)
-	  goto cleanup_helper_process;
-	break;
-      }
-    CloseHandle (hello);
-    CloseHandle (pi_helper.hThread);
-    /* Retrieve pseudo console handles */
-    DWORD rLen;
-    char buf[64];
-    if (!ReadFile (hr, buf, sizeof (buf), &rLen, NULL))
-      goto cleanup_helper_process;
-    buf[rLen] = '\0';
-    sscanf (buf, "StdHandles=%p,%p", &hpConIn, &hpConOut);
-    if (!DuplicateHandle (pi_helper.hProcess, hpConIn,
-			  GetCurrentProcess (), &hpConIn, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_helper_process;
-    if (!DuplicateHandle (pi_helper.hProcess, hpConOut,
-			  GetCurrentProcess (), &hpConOut, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_pcon_in;
-    CloseHandle (hr);
-    CloseHandle (hw);
-    /* Clean up */
-    DeleteProcThreadAttributeList (si_helper.lpAttributeList);
-    HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-  }
-  /* Setting information of stuffs regarding pseudo console */
-  get_ttyp ()->h_helper_goodbye = goodbye;
-  get_ttyp ()->h_helper_process = pi_helper.hProcess;
-  get_ttyp ()->helper_process_id = pi_helper.dwProcessId;
-  CloseHandle (from_master);
-  CloseHandle (to_master);
-  from_master = hpConIn;
-  to_master = hpConOut;
-  ResizePseudoConsole (get_ttyp ()->h_pseudo_console, size);
-  return true;
-
-cleanup_pcon_in:
-  CloseHandle (hpConIn);
-cleanup_helper_process:
-  SetEvent (goodbye);
-  WaitForSingleObject (pi_helper.hProcess, INFINITE);
-  CloseHandle (pi_helper.hProcess);
-  goto skip_close_hello;
-cleanup_event_and_pipes:
-  CloseHandle (hello);
-skip_close_hello:
-  CloseHandle (goodbye);
-  CloseHandle (hr);
-  CloseHandle (hw);
-cleanup_heap:
-  HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-cleanup_pseudo_console:
-  {
-    HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
-    HANDLE tmp = hp->hConHostProcess;
-    ClosePseudoConsole (get_pseudo_console ());
-    CloseHandle (tmp);
-  }
-fallback:
-  CloseHandle (from_master);
-  CloseHandle (to_slave);
-  from_master = from_master_cyg;
-  to_slave = NULL;
-  get_ttyp ()->h_pseudo_console = NULL;
-  return false;
-}
-
 bool
 fhandler_pty_master::setup ()
 {
@@ -3593,11 +2259,6 @@ fhandler_pty_master::setup ()
   if (unit < 0)
     return false;
 
-  /* from_master should be used for pseudo console.
-     Just copy from_master_cyg here for the case that
-     pseudo console is not available. */
-  from_master = from_master_cyg;
-
   ProtectHandle1 (get_output_handle (), to_pty);
 
   tty& t = *cygwin_shared->tty[unit];
@@ -3696,15 +2357,21 @@ fhandler_pty_master::setup ()
       goto err;
     }
 
-  t.winsize.ws_col = 80;
-  t.winsize.ws_row = 25;
-
-  setup_pseudoconsole ();
+  __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;
+    }
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
   t.set_to_master (to_master);
   t.set_to_master_cyg (to_master_cyg);
+  t.winsize.ws_col = 80;
+  t.winsize.ws_row = 25;
   t.master_pid = myself->pid;
 
   dev ().parse (DEV_PTYM_MAJOR, unit);
@@ -3717,6 +2384,7 @@ fhandler_pty_master::setup ()
 err:
   __seterrno ();
   close_maybe (from_slave);
+  close_maybe (to_slave);
   close_maybe (get_handle ());
   close_maybe (get_output_handle ());
   close_maybe (input_available_event);
@@ -3776,9 +2444,6 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 {
   ssize_t towrite = len;
   BOOL res = TRUE;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
   while (towrite)
     {
       if (!is_echo)
@@ -3801,7 +2466,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
       if (!(get_ttyp ()->ti.c_oflag & OPOST))	// raw output mode
 	{
 	  DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
-	  res = WriteFunc (h, ptr, n, &n, NULL);
+	  res = WriteFile (h, ptr, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + n;
@@ -3851,7 +2516,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 		  break;
 		}
 	    }
-	  res = WriteFunc (h, outbuf, n, &n, NULL);
+	  res = WriteFile (h, outbuf, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + rc;
@@ -3861,3 +2526,134 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon)
+{
+
+  /* Setting switch_to_pcon_in is necessary even if
+     pseudo console will not be activated. */
+  fhandler_base *fh = ::cygheap->fdtab[0];
+  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+    {
+      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+      ptys->get_ttyp ()->switch_to_pcon_in = true;
+      if (ptys->get_ttyp ()->pcon_pid == 0
+	  || !pinfo (ptys->get_ttyp ()->pcon_pid))
+	ptys->get_ttyp ()->pcon_pid = myself->pid;
+    }
+
+  if (nopcon)
+    return false;
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  const DWORD inherit_cursor = 1;
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     inherit_cursor,
+				     &get_ttyp ()->h_pseudo_console);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console,
+				  sizeof (get_ttyp ()->h_pseudo_console),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_base *fh0 = ::cygheap->fdtab[0];
+    if (fh0 && fh0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = fh0->get_handle ();
+    fhandler_base *fh1 = ::cygheap->fdtab[1];
+    if (fh1 && fh1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = fh1->get_output_handle ();
+    fhandler_base *fh2 = ::cygheap->fdtab[2];
+    if (fh2 && fh2->get_device () != get_device ())
+      si->StartupInfo.hStdError = fh2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole (void)
+{
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      get_ttyp ()->wait_pcon_fwd ();
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+      get_ttyp ()->pcon_start = false;
+    }
+}
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 7c07b062e..38172ca1e 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -134,36 +134,6 @@ child_info::prefork (bool detached)
 int __stdcall
 frok::child (volatile char * volatile here)
 {
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR)
-      {
-	fhandler_base *fh = cfd;
-	fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
-	if (ptym->get_pseudo_console ())
-	  {
-	    debug_printf ("found a PTY master %d: helper_PID=%d",
-			  ptym->get_minor (), ptym->get_helper_process_id ());
-	    if (fhandler_console::get_console_process_id (
-				ptym->get_helper_process_id (), true))
-	      /* Already attached */
-	      break;
-	    else
-	      {
-		if (ptym->attach_pcon_in_fork ())
-		  {
-		    FreeConsole ();
-		    if (!AttachConsole (ptym->get_helper_process_id ()))
-		      /* Error */;
-		    else
-		      break;
-		  }
-	      }
-	  }
-      }
-  extern void clear_pcon_attached_to (void); /* fhandler_tty.cc */
-  clear_pcon_attached_to ();
-
   HANDLE& hParent = ch.parent;
 
   sync_with_parent ("after longjmp", true);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 3f3f33fb5..93acdd89a 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1213,8 +1213,7 @@ verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds,
 	   fd_set *exceptfds)
 {
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) me->fh;
-  if (me->read_selected && !ptys->to_be_read_from_pcon () &&
-      IsEventSignalled (ptys->input_available_event))
+  if (me->read_selected && IsEventSignalled (ptys->input_available_event))
     me->read_ready = true;
   return set_bits (me, readfds, writefds, exceptfds);
 }
@@ -1227,8 +1226,6 @@ peek_pty_slave (select_record *s, bool from_select)
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
 
   ptys->reset_switch_to_pcon ();
-  if (ptys->to_be_read_from_pcon ())
-    ptys->update_pcon_input_state (true);
 
   if (s->read_selected)
     {
diff --git a/winsup/cygwin/smallprint.cc b/winsup/cygwin/smallprint.cc
index 26d34d9e4..f208a057a 100644
--- a/winsup/cygwin/smallprint.cc
+++ b/winsup/cygwin/smallprint.cc
@@ -405,7 +405,6 @@ small_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
   WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, NULL);
   FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
 }
@@ -432,7 +431,6 @@ console_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (console_handle);
   WriteFile (console_handle, buf, count, &done, NULL);
   FlushFileBuffers (console_handle);
 }
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 840ec4a86..d12ce7b0a 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -194,6 +194,24 @@ handle (int fd, bool writing)
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -261,8 +279,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 {
   bool rc;
   int res = -1;
-  DWORD pid_restore = 0;
-  bool attach_to_console = false;
   pid_t ctty_pgid = 0;
 
   /* Search for CTTY and retrieve its PGID */
@@ -582,9 +598,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			 PROCESS_QUERY_LIMITED_INFORMATION))
 	sa = &sec_none_nih;
 
-      /* Attach to pseudo console if pty salve is used */
-      pid_restore = fhandler_console::get_console_process_id
-	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -593,29 +607,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	      if (ptys->get_pseudo_console ())
-		{
-		  DWORD helper_process_id = ptys->get_helper_process_id ();
-		  debug_printf ("found a PTY slave %d: helper_PID=%d",
-				    fh->get_minor (), helper_process_id);
-		  if (fhandler_console::get_console_process_id
-					      (helper_process_id, true))
-		    /* Already attached */
-		    attach_to_console = true;
-		  else if (!attach_to_console)
-		    {
-		      FreeConsole ();
-		      if (AttachConsole (helper_process_id))
-			attach_to_console = true;
-		    }
-		  ptys->fixup_after_attach (!iscygwin (), fd);
-		  if (mode == _P_OVERLAY)
-		    ptys->set_freeconsole_on_close (iscygwin ());
-		}
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	    }
 	  else if (fh && fh->get_major () == DEV_CONS_MAJOR)
 	    {
-	      attach_to_console = true;
 	      fhandler_console *cons = (fhandler_console *) fh;
 	      if (wincap.has_con_24bit_colors () && !iscygwin ())
 		if (fd == 1 || fd == 2)
@@ -634,6 +630,19 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool enable_pcon = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole (&si_pcon,
+			     mode != _P_OVERLAY && mode != _P_WAIT))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    enable_pcon = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -662,7 +671,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -716,7 +725,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -729,6 +738,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (enable_pcon)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -901,6 +915,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	    }
 	  if (sem)
 	    __posix_spawn_sem_release (sem, 0);
+	  if (enable_pcon)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->close_pseudoconsole ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
@@ -908,6 +927,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  system_call.arm ();
 	  if (waitpid (cygpid, &res, 0) != cygpid)
 	    res = -1;
+	  if (enable_pcon)
+	    ptys_primary->close_pseudoconsole ();
 	  break;
 	case _P_DETACH:
 	  res = 0;	/* Lost all memory of this child. */
@@ -934,21 +955,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
   if (envblock)
     free (envblock);
 
-  if (attach_to_console && pid_restore)
-    {
-      FreeConsole ();
-      AttachConsole (pid_restore);
-      cygheap_fdenum cfd (false);
-      int fd;
-      while ((fd = cfd.next ()) >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_pty_slave *ptys =
-	      (fhandler_pty_slave *) (fhandler_base *) cfd;
-	    ptys->fixup_after_attach (false, fd);
-	  }
-    }
-
   return (int) res;
 }
 
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index f0aef3a36..35f8a59ae 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -264,7 +264,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
   if (category & _STRACE_SYSTEM)
     {
       DWORD done;
-      set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
       WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
       FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
       /* Make sure that the message shows up on the screen, too, since this is
@@ -276,7 +275,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
 				 &sec_none, OPEN_EXISTING, 0, 0);
 	  if (h != INVALID_HANDLE_VALUE)
 	    {
-	      set_ishybrid_and_switch_to_pcon (h);
 	      WriteFile (h, buf, len, &done, 0);
 	      CloseHandle (h);
 	    }
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 4cb68f776..d60f27545 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -234,20 +234,14 @@ tty::init ()
   was_opened = false;
   master_pid = 0;
   is_console = false;
-  attach_pcon_in_fork = false;
-  h_pseudo_console = NULL;
   column = 0;
+  h_pseudo_console = NULL;
   switch_to_pcon_in = false;
-  switch_to_pcon_out = false;
-  screen_alternated = false;
   mask_switch_to_pcon_in = false;
   pcon_pid = 0;
   term_code_page = 0;
-  need_redraw_screen = true;
   pcon_last_time = 0;
-  pcon_in_empty = true;
-  req_transfer_input_to_pcon = false;
-  req_flush_pcon_input = false;
+  pcon_start = false;
 }
 
 HANDLE
@@ -293,16 +287,6 @@ tty_min::ttyname ()
   return d.name ();
 }
 
-void
-tty::set_switch_to_pcon_out (bool v)
-{
-  if (switch_to_pcon_out != v)
-    {
-      wait_pcon_fwd ();
-      switch_to_pcon_out = v;
-    }
-}
-
 void
 tty::wait_pcon_fwd (void)
 {
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 920e32b16..c491d3891 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -94,21 +94,13 @@ private:
   HANDLE _to_master;
   HANDLE _to_master_cyg;
   HPCON h_pseudo_console;
-  HANDLE h_helper_process;
-  DWORD helper_process_id;
-  HANDLE h_helper_goodbye;
-  bool attach_pcon_in_fork;
+  bool pcon_start;
   bool switch_to_pcon_in;
-  bool switch_to_pcon_out;
-  bool screen_alternated;
   bool mask_switch_to_pcon_in;
   pid_t pcon_pid;
   UINT term_code_page;
-  bool need_redraw_screen;
   DWORD pcon_last_time;
-  bool pcon_in_empty;
-  bool req_transfer_input_to_pcon;
-  bool req_flush_pcon_input;
+  HANDLE h_pcon_write_pipe;
 
 public:
   HANDLE from_master () const { return _from_master; }
@@ -138,7 +130,6 @@ public:
   void set_master_ctl_closed () {master_pid = -1;}
   static void __stdcall create_master (int);
   static void __stdcall init_session ();
-  void set_switch_to_pcon_out (bool v);
   void wait_pcon_fwd (void);
   friend class fhandler_pty_common;
   friend class fhandler_pty_master;
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index fff7d18f3..458fb2a23 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -222,9 +222,6 @@ void init_console_handler (bool);
 
 extern bool wsock_started;
 
-/* PTY related */
-void set_ishybrid_and_switch_to_pcon (HANDLE h);
-
 /* Printf type functions */
 extern "C" void vapi_fatal (const char *, va_list ap) __attribute__ ((noreturn));
 extern "C" void api_fatal (const char *, ...) __attribute__ ((noreturn));
-- 
2.27.0


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-03 12:23                                     ` Takashi Yano
@ 2020-08-11 11:12                                       ` Takashi Yano
  2020-08-13  9:58                                         ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-08-11 11:12 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 3700 bytes --]

On Mon, 3 Aug 2020 21:23:42 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Mon, 3 Aug 2020 11:11:03 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Fri, 24 Jul 2020 20:22:19 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Fri, 24 Jul 2020 14:38:42 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Thu, 23 Jul 2020 09:33:28 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > On Wed, 22 Jul 2020 17:45:41 +0900
> > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > On Wed, 22 Jul 2020 03:17:51 +0900
> > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > Hi Corinna,
> > > > > > > 
> > > > > > > On Mon, 20 Jul 2020 10:06:13 +0200
> > > > > > > Corinna Vinschen wrote:
> > > > > > > > On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
> > > > > > > > > Hi Corinna,
> > > > > > > > > 
> > > > > > > > > On Fri, 17 Jul 2020 13:19:12 +0200
> > > > > > > > > Corinna Vinschen wrote:
> > > > > > > > > > Hi Takashi,
> > > > > > > > > > 
> > > > > > > > > > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > > > > > > > > > > [...]
> > > > > > > > > > > Revise the patch to fit the current git head.
> > > > > > > > > > 
> > > > > > > > > > are you satisfied with the code?  If you want to merge it,
> > > > > > > > > > I'd bump Cygwin to 3.2.
> > > > > > > > > 
> > > > > > > > > Since this new implementation has both advantages and disadvantages,
> > > > > > > > > there might be some options.
> > > > > > > > > 
> > > > > > > > > 1) Default to new implementation and leave the current one as an
> > > > > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > > > > 2) Default to current implementation and add the new one as an
> > > > > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > > > > 3) Adopt only new implementation and throw the current one away.
> > > > > > > > > 
> > > > > > > > > What do you think?
> > > > > > > > 
> > > > > > > > Do you really want to maintain twice as much code doing the same stuff
> > > > > > > > and constantly having to ask users which version of the code they are
> > > > > > > > running?  The maintenance cost outweighs the advantages, IMHO.
> > > > > > > > Personally I'd go for option 3.
> > > > > > > 
> > > > > > > Personally, I feel a tinge of sadness to discard the current code,
> > > > > > > however, your opinion sounds reasonable.
> > > > > > > 
> > > > > > > I will submit a new patch in which all the codes specific to the
> > > > > > > current implementation are removed.
> > > > > > 
> > > > > > Attached is the patch in git format-patch format.
> > > > > > All the codes specific to the current implementation are removed.
> > > > > > 
> > > > > > Despite the utmost care, the changes are relatively large, so some
> > > > > > degradation may exist.
> > > > > > 
> > > > > > I will appreciate if you could test.
> > > > > 
> > > > > There were still unused code. Please try attached patch instead.
> > > > 
> > > > Changes:
> > > > * Do not activate pseudo console if it is already activated for
> > > >   another process on same pty.
> > > 
> > > Changes:
> > > * Fix a bug in the latest change.
> > 
> > Changes:
> > * Fix a handle leak caused when spawn is called with mode != _P_OVERLAY.
> 
> This patch cannot be applied cleanly against current git head.
> Please use attached patch instead.

Adapted to the current git head.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-Cygwin-pty-Implement-new-pseudo-console-support.patch --]
[-- Type: application/octet-stream, Size: 90717 bytes --]

From 9a70cb9d4e03e9ac4b939e309f51c2a4ff4196a9 Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Tue, 11 Aug 2020 19:42:12 +0900
Subject: [PATCH] Cygwin: pty: Implement new pseudo console support.

- In this implementation, pseudo console is created for each native
  console app. Advantages and disadvantages of this implementation
  over the previous implementation are as follows.

  Advantages:
  1) No performance degradation in pty output for cygwin process.
      https://cygwin.com/pipermail/cygwin/2020-February/243858.html
  2) Free from the problem caused by difference of behaviour of control
     sequences between real terminal and pseudo console.
      https://cygwin.com/pipermail/cygwin/2019-December/243281.html
      https://cygwin.com/pipermail/cygwin/2020-February/243855.html
  3) Free from the problem in cgdb and emacs gud.
      https://cygwin.com/pipermail/cygwin/2020-January/243601.html
      https://cygwin.com/pipermail/cygwin/2020-March/244146.html
  4) Redrawing screen on executing native console apps is not necessary.
  5) cygwin-console-helper is not necessary for the pseudo console
     support.
  6) The codes for pseudo console support are much simpler than that
     of the previous one.

  Disadvantages:
  1) The cygwin program which calls console API directly does not work.
  2) The apps which use console API cannot be debugged with gdb. This
     is because pseudo console is not activated since gdb uses
     CreateProcess() rather than exec(). Even with this limitation,
     attaching gdb to native apps, in which pseudo console is already
     activated, works.
  3) Typeahead key inputs are discarded while native console app is
     executed. Simirally, typeahead key inputs while cygwin app is
     executed are not inherited to native console app.
  4) Code page cannot be changed by chcp.com. Acctually, chcp works
     itself and changes code page of its own pseudo console.  However,
     since pseudo console is recreated for another process, it cannot
     inherit the code page.
  5) system_printf() does not work after stderr is closed. (Same with
     cygwin 3.0.7)
  6) Startup time of native console apps is about 3 times slower than
     previous implemenation.
  7) Pseudo console cannot be activated if it is already activated for
     another process on same pty.
---
 winsup/cygwin/dtable.cc           |   32 -
 winsup/cygwin/fhandler.h          |   53 +-
 winsup/cygwin/fhandler_console.cc |   43 -
 winsup/cygwin/fhandler_tty.cc     | 1770 +++++------------------------
 winsup/cygwin/fork.cc             |   30 -
 winsup/cygwin/select.cc           |    5 +-
 winsup/cygwin/smallprint.cc       |    2 -
 winsup/cygwin/spawn.cc            |  105 +-
 winsup/cygwin/strace.cc           |    2 -
 winsup/cygwin/tty.cc              |   20 +-
 winsup/cygwin/tty.h               |   13 +-
 winsup/cygwin/winsup.h            |    3 -
 12 files changed, 349 insertions(+), 1729 deletions(-)

diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index e9e005b08..6a91e33bc 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -147,38 +147,6 @@ dtable::get_debugger_info ()
 void
 dtable::stdio_init ()
 {
-  for (int i = 0; i < 3; i ++)
-    {
-      const int chk_order[] = {1, 0, 2};
-      int fd = chk_order[i];
-      fhandler_base *fh = cygheap->fdtab[fd];
-      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
-	{
-	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	  if (ptys->get_pseudo_console ())
-	    {
-	      bool attached = !!fhandler_console::get_console_process_id
-		(ptys->get_helper_process_id (), true);
-	      if (attached)
-		break;
-	      else
-		{
-		  /* Not attached to pseudo console in fork() or spawn()
-		     by some reason. This happens if the executable is
-		     a windows GUI binary, such as mintty. */
-		  FreeConsole ();
-		  if (AttachConsole (ptys->get_helper_process_id ()))
-		    {
-		      ptys->fixup_after_attach (false, fd);
-		      break;
-		    }
-		}
-	    }
-	}
-      else if (fh && fh->get_major () == DEV_CONS_MAJOR)
-	break;
-    }
-
   if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT))
     {
       tty_min *t = cygwin_shared->tty.get_cttyp ();
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index a577ca542..9fd95c098 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -326,16 +326,16 @@ class fhandler_base
   virtual size_t &raixput () { return ra.raixput; };
   virtual size_t &rabuflen () { return ra.rabuflen; };
 
-  virtual bool get_readahead_valid () { return raixget () < ralen (); }
+  bool get_readahead_valid () { return raixget () < ralen (); }
   int puts_readahead (const char *s, size_t len = (size_t) -1);
-  virtual int put_readahead (char value);
+  int put_readahead (char value);
 
   int get_readahead ();
   int peek_readahead (int queryput = 0);
 
   void set_readahead_valid (int val, int ch = -1);
 
-  virtual int get_readahead_into_buffer (char *buf, size_t buflen);
+  int get_readahead_into_buffer (char *buf, size_t buflen);
 
   bool has_acls () const { return pc.has_acls (); }
 
@@ -1905,7 +1905,7 @@ class fhandler_termios: public fhandler_base
   int ioctl (int, void *);
   tty_min *_tc;
   tty *get_ttyp () {return (tty *) tc ();}
-  virtual int eat_readahead (int n);
+  int eat_readahead (int n);
 
  public:
   tty_min*& tc () {return _tc;}
@@ -2184,7 +2184,6 @@ private:
   static bool need_invisible ();
   static void free_console ();
   static const char *get_nonascii_key (INPUT_RECORD& input_rec, char *);
-  static DWORD get_console_process_id (DWORD pid, bool match);
 
   fhandler_console (void *) {}
 
@@ -2264,19 +2263,7 @@ class fhandler_pty_common: public fhandler_termios
     return fh;
   }
 
-  bool attach_pcon_in_fork (void)
-  {
-    return get_ttyp ()->attach_pcon_in_fork;
-  }
-  DWORD get_helper_process_id (void)
-  {
-    return get_ttyp ()->helper_process_id;
-  }
-  HPCON get_pseudo_console (void)
-  {
-    return get_ttyp ()->h_pseudo_console;
-  }
-  bool to_be_read_from_pcon (void);
+  void resize_pseudo_console (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2287,23 +2274,15 @@ class fhandler_pty_slave: public fhandler_pty_common
 {
   HANDLE inuse;			// used to indicate that a tty is in use
   HANDLE output_handle_cyg, io_handle_cyg;
-  DWORD pid_restore;
-  int fd;
 
   /* Helper functions for fchmod and fchown. */
   bool fch_open_handles (bool chown);
   int fch_set_sd (security_descriptor &sd, bool chown);
   void fch_close_handles ();
 
-  bool try_reattach_pcon ();
-  void restore_reattach_pcon ();
-  inline void free_attached_console ();
-
  public:
   /* Constructor */
   fhandler_pty_slave (int);
-  /* Destructor */
-  ~fhandler_pty_slave ();
 
   void set_output_handle_cyg (HANDLE h) { output_handle_cyg = h; }
   HANDLE& get_output_handle_cyg () { return output_handle_cyg; }
@@ -2315,9 +2294,6 @@ class fhandler_pty_slave: public fhandler_pty_common
   ssize_t __stdcall write (const void *ptr, size_t len);
   void __reg3 read (void *ptr, size_t& len);
   int init (HANDLE, DWORD, mode_t);
-  int eat_readahead (int n);
-  int get_readahead_into_buffer (char *buf, size_t buflen);
-  bool get_readahead_valid (void);
 
   int tcsetattr (int a, const struct termios *t);
   int tcgetattr (struct termios *t);
@@ -2354,20 +2330,12 @@ class fhandler_pty_slave: public fhandler_pty_common
     copyto (fh);
     return fh;
   }
-  void set_switch_to_pcon (int fd);
+  bool setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon);
+  void close_pseudoconsole (void);
+  void set_switch_to_pcon (void);
   void reset_switch_to_pcon (void);
-  void push_to_pcon_screenbuffer (const char *ptr, size_t len, bool is_echo);
   void mask_switch_to_pcon_in (bool mask);
-  void fixup_after_attach (bool native_maybe, int fd);
-  bool is_line_input (void)
-  {
-    return get_ttyp ()->ti.c_lflag & ICANON;
-  }
   void setup_locale (void);
-  void set_freeconsole_on_close (bool val);
-  void trigger_redraw_screen (void);
-  void pull_pcon_input (void);
-  void update_pcon_input_state (bool need_lock);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
@@ -2392,7 +2360,6 @@ public:
   int process_slave_output (char *buf, size_t len, int pktmode_on);
   void doecho (const void *str, DWORD len);
   int accept_input ();
-  int put_readahead (char value);
   int open (int flags, mode_t mode = 0);
   void open_setup (int flags);
   ssize_t __stdcall write (const void *ptr, size_t len);
@@ -2431,9 +2398,7 @@ public:
     copyto (fh);
     return fh;
   }
-
-  bool setup_pseudoconsole (void);
-  void transfer_input_to_pcon (void);
+  bool to_be_read_from_pcon (void);
 };
 
 class fhandler_dev_null: public fhandler_base
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 52741ce8b..02a5996a1 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -1206,18 +1206,6 @@ fhandler_console::close ()
   if (con_ra.rabuf)
     free (con_ra.rabuf);
 
-  /* If already attached to pseudo console, don't call free_console () */
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR ||
-	cfd->get_major () == DEV_PTYS_MAJOR)
-      {
-	fhandler_pty_common *t =
-	  (fhandler_pty_common *) (fhandler_base *) cfd;
-	if (get_console_process_id (t->get_helper_process_id (), true))
-	  return 0;
-      }
-
   if (!have_execed)
     free_console ();
   return 0;
@@ -3611,37 +3599,6 @@ fhandler_console::need_invisible ()
   return b;
 }
 
-DWORD
-fhandler_console::get_console_process_id (DWORD pid, bool match)
-{
-  DWORD tmp;
-  DWORD num, num_req;
-  num = 1;
-  num_req = GetConsoleProcessList (&tmp, num);
-  DWORD *list;
-  while (true)
-    {
-      list = (DWORD *)
-	HeapAlloc (GetProcessHeap (), 0, num_req * sizeof (DWORD));
-      num = num_req;
-      num_req = GetConsoleProcessList (list, num);
-      if (num_req > num)
-	HeapFree (GetProcessHeap (), 0, list);
-      else
-	break;
-    }
-  num = num_req;
-
-  tmp = 0;
-  for (DWORD i=0; i<num; i++)
-    if ((match && list[i] == pid) || (!match && list[i] != pid))
-      /* Last one is the oldest. */
-      /* https://github.com/microsoft/terminal/issues/95 */
-      tmp = list[i];
-  HeapFree (GetProcessHeap (), 0, list);
-  return tmp;
-}
-
 DWORD
 fhandler_console::__acquire_input_mutex (const char *fn, int ln, DWORD ms)
 {
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 92449ad7e..8b1411310 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -25,7 +25,6 @@ details. */
 #include "child_info.h"
 #include <asm/socket.h>
 #include "cygwait.h"
-#include "tls_pbuf.h"
 #include "registry.h"
 
 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
@@ -33,7 +32,6 @@ details. */
 #endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
 
 extern "C" int sscanf (const char *, const char *, ...);
-extern "C" int ttyname_r (int, char*, size_t);
 
 extern "C" {
   HRESULT WINAPI CreatePseudoConsole (COORD, HANDLE, HANDLE, DWORD, HPCON *);
@@ -60,20 +58,10 @@ struct pipe_reply {
   DWORD error;
 };
 
-static int pcon_attached_to = -1;
 static bool isHybrid;
-static bool do_not_reset_switch_to_pcon;
-static bool freeconsole_on_close = true;
-static tty *last_ttyp = NULL;
-
-void
-clear_pcon_attached_to (void)
-{
-  pcon_attached_to = -1;
-}
 
 static void
-set_switch_to_pcon (void)
+set_switch_to_pcon (HANDLE h)
 {
   cygheap_fdenum cfd (false);
   int fd;
@@ -82,280 +70,17 @@ set_switch_to_pcon (void)
       {
 	fhandler_base *fh = cfd;
 	fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	if (ptys->get_pseudo_console ())
-	  {
-	    ptys->set_switch_to_pcon (fd);
-	    ptys->trigger_redraw_screen ();
-	    DWORD mode =
-	      ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	    SetConsoleMode (ptys->get_handle (), mode);
-	  }
+	if (h == ptys->get_handle ())
+	  ptys->set_switch_to_pcon ();
 	return;
       }
-  /* No pty slave opened */
-  if (last_ttyp) /* Make system_printf() work after closing pty slave */
-    last_ttyp->set_switch_to_pcon_out (true);
-}
-
-static void
-force_attach_to_pcon (HANDLE h)
-{
-  bool attach_done = false;
-  for (int n = 0; n < 2; n ++)
-    {
-      /* First time, attach to the pty whose handle value is match.
-	 Second time, try to attach to any pty. */
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	    if (!ptys->get_pseudo_console ())
-	      continue;
-	    if (n != 0
-		|| h == ptys->get_handle ()
-		|| h == ptys->get_output_handle ())
-	      {
-		if (fhandler_console::get_console_process_id
-				  (ptys->get_helper_process_id (), true))
-		  attach_done = true;
-		else
-		  {
-		    FreeConsole ();
-		    if (AttachConsole (ptys->get_helper_process_id ()))
-		      {
-			pcon_attached_to = ptys->get_minor ();
-			attach_done = true;
-		      }
-		    else
-		      pcon_attached_to = -1;
-		  }
-		break;
-	      }
-	  }
-	else if (cfd->get_major () == DEV_CONS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_console *cons = (fhandler_console *) fh;
-	    if (n != 0
-		|| h == cons->get_handle ()
-		|| h == cons->get_output_handle ())
-	      {
-		/* If the process is running on a console,
-		   the parent process should be attached
-		   to the same console. */
-		DWORD attach_wpid;
-		if (myself->ppid == 1)
-		  attach_wpid = ATTACH_PARENT_PROCESS;
-		else
-		  {
-		    pinfo p (myself->ppid);
-		    attach_wpid = p->dwProcessId;
-		  }
-		FreeConsole ();
-		if (AttachConsole (attach_wpid))
-		  {
-		    pcon_attached_to = -1;
-		    attach_done = true;
-		  }
-		else
-		  pcon_attached_to = -1;
-		break;
-	      }
-	  }
-      if (attach_done)
-	break;
-    }
-}
-
-void
-set_ishybrid_and_switch_to_pcon (HANDLE h)
-{
-  if (GetFileType (h) == FILE_TYPE_CHAR)
-    {
-      force_attach_to_pcon (h);
-      DWORD dummy;
-      if (!isHybrid && (GetConsoleMode (h, &dummy)
-			|| GetLastError () != ERROR_INVALID_HANDLE))
-	{
-	  isHybrid = true;
-	  set_switch_to_pcon ();
-	}
-    }
-}
-
-inline void
-fhandler_pty_slave::free_attached_console ()
-{
-  bool attached = get_ttyp () ?
-    fhandler_console::get_console_process_id (get_helper_process_id (), true)
-    : (get_minor () == pcon_attached_to);
-  if (freeconsole_on_close && attached)
-    {
-      FreeConsole ();
-      pcon_attached_to = -1;
-    }
 }
 
 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
-DEF_HOOK (WriteFile);
-DEF_HOOK (WriteConsoleA);
-DEF_HOOK (WriteConsoleW);
-DEF_HOOK (ReadFile);
-DEF_HOOK (ReadConsoleA);
-DEF_HOOK (ReadConsoleW);
-DEF_HOOK (WriteConsoleOutputA);
-DEF_HOOK (WriteConsoleOutputW);
-DEF_HOOK (WriteConsoleOutputCharacterA);
-DEF_HOOK (WriteConsoleOutputCharacterW);
-DEF_HOOK (WriteConsoleOutputAttribute);
-DEF_HOOK (SetConsoleCursorPosition);
-DEF_HOOK (SetConsoleTextAttribute);
-DEF_HOOK (WriteConsoleInputA);
-DEF_HOOK (WriteConsoleInputW);
-DEF_HOOK (ReadConsoleInputA);
-DEF_HOOK (ReadConsoleInputW);
-DEF_HOOK (PeekConsoleInputA);
-DEF_HOOK (PeekConsoleInputW);
 /* CreateProcess() is hooked for GDB etc. */
 DEF_HOOK (CreateProcessA);
 DEF_HOOK (CreateProcessW);
 
-static BOOL WINAPI
-WriteFile_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleA_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleW_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadFile_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleA_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleW_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleOutputA_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputA_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputW_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputW_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterA_Hooked
-     (HANDLE h, LPCSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterA_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterW_Hooked
-     (HANDLE h, LPCWSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterW_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputAttribute_Hooked
-     (HANDLE h, CONST WORD *a, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputAttribute_Orig (h, a, l, c, n);
-}
-static BOOL WINAPI
-SetConsoleCursorPosition_Hooked
-     (HANDLE h, COORD c)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleCursorPosition_Orig (h, c);
-}
-static BOOL WINAPI
-SetConsoleTextAttribute_Hooked
-     (HANDLE h, WORD a)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleTextAttribute_Orig (h, a);
-}
-static BOOL WINAPI
-WriteConsoleInputA_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-WriteConsoleInputW_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputW_Orig (h, r, l, n);
-}
-/* CreateProcess() is hooked for GDB etc. */
 static BOOL WINAPI
 CreateProcessA_Hooked
      (LPCSTR n, LPSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
@@ -363,11 +88,14 @@ CreateProcessA_Hooked
       LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 static BOOL WINAPI
@@ -377,11 +105,14 @@ CreateProcessW_Hooked
       LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 
@@ -464,10 +195,6 @@ fhandler_pty_master::flush_to_slave ()
 {
   if (get_readahead_valid () && !(get_ttyp ()->ti.c_lflag & ICANON))
     accept_input ();
-  WaitForSingleObject (input_mutex, INFINITE);
-  if (!get_ttyp ()->pcon_in_empty && !(get_ttyp ()->ti.c_lflag & ICANON))
-    SetEvent (input_available_event);
-  ReleaseMutex (input_mutex);
 }
 
 DWORD
@@ -532,14 +259,6 @@ fhandler_pty_master::doecho (const void *str, DWORD len)
   release_output_mutex ();
 }
 
-int
-fhandler_pty_master::put_readahead (char value)
-{
-  if (to_be_read_from_pcon ())
-    return 1;
-  return fhandler_base::put_readahead (value);
-}
-
 int
 fhandler_pty_master::accept_input ()
 {
@@ -551,9 +270,11 @@ fhandler_pty_master::accept_input ()
   char *p = rabuf () + raixget ();
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
   if (to_be_read_from_pcon ())
-    ; /* Do nothing */
-  else if (!bytes_left)
+    write_to = to_slave;
+
+  if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
@@ -564,10 +285,10 @@ fhandler_pty_master::accept_input ()
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -725,52 +446,12 @@ out:
 
 fhandler_pty_slave::fhandler_pty_slave (int unit)
   : fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL),
-  io_handle_cyg (NULL), pid_restore (0), fd (-1)
+  io_handle_cyg (NULL)
 {
   if (unit >= 0)
     dev ().parse (DEV_PTYS_MAJOR, unit);
 }
 
-fhandler_pty_slave::~fhandler_pty_slave ()
-{
-  if (!get_ttyp ())
-    {
-      /* Why comes here? Who clears _tc? */
-      free_attached_console ();
-      return;
-    }
-  if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 0)
-	{
-	  pcon_attached_to = -1;
-	  last_ttyp = get_ttyp ();
-	}
-      if (used == 0)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
-}
-
 int
 fhandler_pty_slave::open (int flags, mode_t)
 {
@@ -833,8 +514,8 @@ fhandler_pty_slave::open (int flags, mode_t)
     release_output_mutex ();
   }
 
-  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg () ||
-      !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
+  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg ()
+      || !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
     {
       errmsg = "pty handles have been closed";
       set_errno (EACCES);
@@ -923,8 +604,8 @@ fhandler_pty_slave::open (int flags, mode_t)
       from_master_cyg_local = repl.from_master_cyg;
       to_master_local = repl.to_master;
       to_master_cyg_local = repl.to_master_cyg;
-      if (!from_master_local || !from_master_cyg_local ||
-	  !to_master_local || !to_master_cyg_local)
+      if (!from_master_local || !from_master_cyg_local
+	  || !to_master_local || !to_master_cyg_local)
 	{
 	  SetLastError (repl.error);
 	  errmsg = "error duplicating pipes, %E";
@@ -950,24 +631,7 @@ fhandler_pty_slave::open (int flags, mode_t)
   set_output_handle (to_master_local);
   set_output_handle_cyg (to_master_cyg_local);
 
-  if (!get_pseudo_console ())
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (!fhandler_console::get_console_process_id
-			       (GetCurrentProcessId (), true))
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (fhandler_console::get_console_process_id
-			       (get_helper_process_id (), true))
-    /* Attached to pcon of this pty */
-    {
-      pcon_attached_to = get_minor ();
-      init_console_handler (true);
-    }
+  fhandler_console::need_invisible ();
 
   set_open_status ();
   return 1;
@@ -1021,8 +685,7 @@ fhandler_pty_slave::close ()
   if (!ForceCloseHandle (get_handle_cyg ()))
     termios_printf ("CloseHandle (get_handle_cyg ()<%p>), %E",
 	get_handle_cyg ());
-  if (!get_pseudo_console () &&
-      (unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
+  if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
     fhandler_console::free_console ();	/* assumes that we are the last pty closer */
   fhandler_pty_common::close ();
   if (!ForceCloseHandle (output_mutex))
@@ -1070,423 +733,31 @@ fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
   return ret;
 }
 
-bool
-fhandler_pty_slave::try_reattach_pcon (void)
-{
-  pid_restore = 0;
-
-  /* Do not detach from the console because re-attaching will
-     fail if helper process is running as service account. */
-  if (get_ttyp()->attach_pcon_in_fork)
-    return false;
-  if (pcon_attached_to >= 0 &&
-      cygwin_shared->tty[pcon_attached_to]->attach_pcon_in_fork)
-    return false;
-
-  pid_restore =
-    fhandler_console::get_console_process_id (GetCurrentProcessId (),
-					      false);
-  /* If pid_restore is not set, give up. */
-  if (!pid_restore)
-    return false;
-
-  FreeConsole ();
-  if (!AttachConsole (get_helper_process_id ()))
-    {
-      system_printf ("pty%d: AttachConsole(helper=%d) failed. 0x%08lx",
-		     get_minor (), get_helper_process_id (), GetLastError ());
-      return false;
-    }
-  return true;
-}
-
 void
-fhandler_pty_slave::restore_reattach_pcon (void)
+fhandler_pty_slave::set_switch_to_pcon (void)
 {
-  if (pid_restore)
+  if (!get_ttyp ()->switch_to_pcon_in)
     {
-      FreeConsole ();
-      if (!AttachConsole (pid_restore))
-	{
-	  system_printf ("pty%d: AttachConsole(restore=%d) failed. 0x%08lx",
-			 get_minor (), pid_restore, GetLastError ());
-	  pcon_attached_to = -1;
-	}
-    }
-  pid_restore = 0;
-}
-
-/* This function requests transfering the input data from the input
-   pipe for cygwin apps to the other input pipe for native apps. */
-void
-fhandler_pty_slave::pull_pcon_input (void)
-{
-  get_ttyp ()->req_transfer_input_to_pcon = true;
-  while (get_ttyp ()->req_transfer_input_to_pcon)
-    Sleep (1);
-}
-
-void
-fhandler_pty_slave::update_pcon_input_state (bool need_lock)
-{
-  if (need_lock)
-    WaitForSingleObject (input_mutex, INFINITE);
-  /* Flush input buffer if it is requested by master.
-     This happens if ^C is pressed in pseudo console side. */
-  if (get_ttyp ()->req_flush_pcon_input)
-    {
-      FlushConsoleInputBuffer (get_handle ());
-      get_ttyp ()->req_flush_pcon_input = false;
-    }
-  /* Peek console input buffer and update state. */
-  INPUT_RECORD inp[INREC_SIZE];
-  DWORD n;
-  BOOL (WINAPI *PeekFunc)
-    (HANDLE, PINPUT_RECORD, DWORD, LPDWORD);
-  PeekFunc =
-    PeekConsoleInputA_Orig ? : PeekConsoleInput;
-  PeekFunc (get_handle (), inp, INREC_SIZE, &n);
-  bool saw_accept = false;
-  bool pipe_empty = true;
-  while (n-- > 0)
-    if (inp[n].EventType == KEY_EVENT && inp[n].Event.KeyEvent.bKeyDown &&
-	inp[n].Event.KeyEvent.uChar.AsciiChar)
-      {
-	pipe_empty = false;
-	char c = inp[n].Event.KeyEvent.uChar.AsciiChar;
-	const char sigs[] = {
-	  (char) get_ttyp ()->ti.c_cc[VINTR],
-	  (char) get_ttyp ()->ti.c_cc[VQUIT],
-	  (char) get_ttyp ()->ti.c_cc[VSUSP],
-	};
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n',
-	  '\r'
-	};
-	if (is_line_input () && c && memchr (eols, c, sizeof (eols)))
-	  saw_accept = true;
-	if ((get_ttyp ()->ti.c_lflag & ISIG)
-	    && c && memchr (sigs, c, sizeof (sigs)))
-	  saw_accept = true;
-      }
-  get_ttyp ()->pcon_in_empty = pipe_empty && !(ralen () > raixget ());
-  if (!get_readahead_valid () &&
-      (pipe_empty || (is_line_input () && !saw_accept)) &&
-      get_ttyp ()->read_retval == 1 && bytes_available (n) && n == 0)
-    ResetEvent (input_available_event);
-  if (need_lock)
-    ReleaseMutex (input_mutex);
-}
-
-int
-fhandler_pty_slave::eat_readahead (int n)
-{
-  int oralen = ralen ();
-  if (n < 0)
-    n = ralen () - raixget ();
-  if (n > 0 && ralen () > raixget ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      while (n > 0 && ralen () > raixget ())
-	{
-	  if (is_line_input () && rabuf ()[ralen ()-1]
-	      && memchr (eols, rabuf ()[ralen ()-1], sizeof (eols)))
-	    break;
-	  -- n;
-	  -- ralen ();
-	}
-
-      /* If IUTF8 is set, the terminal is in UTF-8 mode.  If so, we erase
-	 a complete UTF-8 multibyte sequence on VERASE/VWERASE.  Otherwise,
-	 if we only erase a single byte, invalid unicode chars are left in
-	 the input. */
-      if (get_ttyp ()->ti.c_iflag & IUTF8)
-	while (ralen () > raixget () &&
-	       ((unsigned char) rabuf ()[ralen ()] & 0xc0) == 0x80)
-	  --ralen ();
-    }
-  oralen = oralen - ralen ();
-  if (raixget () >= ralen ())
-    raixget () = raixput () = ralen () = 0;
-  else if (raixput () > ralen ())
-    raixput () = ralen ();
-
-  return oralen;
-}
-
-int
-fhandler_pty_slave::get_readahead_into_buffer (char *buf, size_t buflen)
-{
-  int ch;
-  int copied_chars = 0;
-
-  while (buflen)
-    if ((ch = get_readahead ()) < 0)
-      break;
-    else
-      {
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n'
-	};
-	buf[copied_chars++] = (unsigned char)(ch & 0xff);
-	buflen--;
-	if (is_line_input () && ch && memchr (eols, ch & 0xff, sizeof (eols)))
-	  break;
-      }
-
-  return copied_chars;
-}
-
-bool
-fhandler_pty_slave::get_readahead_valid (void)
-{
-  if (is_line_input ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      for (size_t i=raixget (); i<ralen (); i++)
-	if (rabuf ()[i] && memchr (eols, rabuf ()[i], sizeof (eols)))
-	  return true;
-      return false;
-    }
-  else
-    return ralen () > raixget ();
-}
-
-void
-fhandler_pty_slave::set_switch_to_pcon (int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  acquire_output_mutex (INFINITE);
-  if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
-    {
-      pull_pcon_input ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
+      isHybrid = true;
+      if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
 	get_ttyp ()->pcon_pid = myself->pid;
       get_ttyp ()->switch_to_pcon_in = true;
-      if (isHybrid && !get_ttyp ()->switch_to_pcon_out)
-	{
-	  get_ttyp ()->wait_pcon_fwd ();
-	  get_ttyp ()->switch_to_pcon_out = true;
-	}
     }
-  else if ((fd == 1 || fd == 2) && !get_ttyp ()->switch_to_pcon_out)
-    {
-      get_ttyp ()->wait_pcon_fwd ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
-	get_ttyp ()->pcon_pid = myself->pid;
-      get_ttyp ()->switch_to_pcon_out = true;
-      if (isHybrid)
-	get_ttyp ()->switch_to_pcon_in = true;
-    }
-  release_output_mutex ();
 }
 
 void
 fhandler_pty_slave::reset_switch_to_pcon (void)
 {
-  if (get_ttyp ()->pcon_pid &&
-      get_ttyp ()->pcon_pid != myself->pid &&
-      !!pinfo (get_ttyp ()->pcon_pid))
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
     /* There is a process which is grabbing pseudo console. */
     return;
   if (isHybrid)
     return;
-  if (do_not_reset_switch_to_pcon)
-    return;
-  acquire_output_mutex (INFINITE);
-  if (get_ttyp ()->switch_to_pcon_out)
-    /* Wait for pty_master_fwd_thread() */
-    get_ttyp ()->wait_pcon_fwd ();
   get_ttyp ()->pcon_pid = 0;
   get_ttyp ()->switch_to_pcon_in = false;
-  get_ttyp ()->switch_to_pcon_out = false;
-  release_output_mutex ();
-  init_console_handler (true);
-}
-
-void
-fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len,
-					       bool is_echo)
-{
-  bool attached =
-    !!fhandler_console::get_console_process_id (get_helper_process_id (), true);
-  if (!attached && pcon_attached_to == get_minor ())
-    {
-      for (DWORD t0 = GetTickCount (); GetTickCount () - t0 < 100; )
-	{
-	  Sleep (1);
-	  attached = fhandler_console::get_console_process_id
-				      (get_helper_process_id (), true);
-	  if (attached)
-	    break;
-	}
-      if (!attached)
-	{
-	  system_printf ("pty%d: pcon_attach_to mismatch??????", get_minor ());
-	  return;
-	}
-    }
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  if (pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      goto detach;
-
-  char *buf;
-  size_t nlen;
-  DWORD origCP;
-  origCP = GetConsoleOutputCP ();
-  SetConsoleOutputCP (get_ttyp ()->term_code_page);
-  /* Just copy */
-  buf = (char *) HeapAlloc (GetProcessHeap (), 0, len);
-  memcpy (buf, (char *)ptr, len);
-  nlen = len;
-  char *p0, *p1;
-  p0 = p1 = buf;
-  /* Remove alternate screen buffer drawing */
-  while (p0 && p1)
-    {
-      if (!get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to alternate screen buffer */
-	  p0 = (char *) memmem (p1, nlen - (p1-buf), "\033[?1049h", 8);
-	  if (p0)
-	    {
-	      //p0 += 8;
-	      get_ttyp ()->screen_alternated = true;
-	      if (get_ttyp ()->switch_to_pcon_out)
-		do_not_reset_switch_to_pcon = true;
-	    }
-	}
-      if (get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to main screen buffer */
-	  p1 = (char *) memmem (p0, nlen - (p0-buf), "\033[?1049l", 8);
-	  if (p1)
-	    {
-	      p1 += 8;
-	      get_ttyp ()->screen_alternated = false;
-	      do_not_reset_switch_to_pcon = false;
-	      memmove (p0, p1, buf+nlen - p1);
-	      nlen -= p1 - p0;
-	    }
-	  else
-	    nlen = p0 - buf;
-	}
-    }
-  if (!nlen) /* Nothing to be synchronized */
-    goto cleanup;
-  if (get_ttyp ()->switch_to_pcon_out && !is_echo)
-    goto cleanup;
-  /* Remove ESC sequence which returns results to console
-     input buffer. Without this, cursor position report
-     is put into the input buffer as a garbage. */
-  /* Remove ESC sequence to report cursor position. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[6n", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-  /* Remove ESC sequence to report terminal identity. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[0c", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-
-  /* If the ESC sequence ESC[?3h or ESC[?3l which clears console screen
-     buffer is pushed, set need_redraw_screen to trigger redraw screen. */
-  p0 = buf;
-  while ((p0 = (char *) memmem (p0, nlen - (p0 - buf), "\033[?", 3)))
-    {
-      p0 += 3;
-      bool exist_arg_3 = false;
-      while (p0 < buf + nlen && (isdigit (*p0) || *p0 == ';'))
-	{
-	  int arg = 0;
-	  while (p0 < buf + nlen && isdigit (*p0))
-	    arg = arg * 10 + (*p0 ++) - '0';
-	  if (arg == 3)
-	    exist_arg_3 = true;
-	  if (p0 < buf + nlen && *p0 == ';')
-	    p0 ++;
-	}
-      if (p0 < buf + nlen && exist_arg_3 && (*p0 == 'h' || *p0 == 'l'))
-	get_ttyp ()->need_redraw_screen = true;
-      p0 ++;
-      if (p0 >= buf + nlen)
-	break;
-    }
-
-  int retry_count;
-  retry_count = 0;
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  while (!GetConsoleMode (get_output_handle (), &dwMode))
-    {
-      termios_printf ("GetConsoleMode failed, %E");
-      int errno_save = errno;
-      /* Re-open handles */
-      this->open (0, 0);
-      /* Fix pseudo console window size */
-      this->ioctl (TIOCSWINSZ, &get_ttyp ()->winsize);
-      if (errno != errno_save)
-	set_errno (errno_save);
-      if (++retry_count > 3)
-	goto cleanup;
-    }
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-  char *p;
-  p = buf;
-  DWORD wLen, written;
-  written = 0;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
-  while (written <  nlen)
-    {
-      if (!WriteFunc (get_output_handle (), p, nlen - written, &wLen, NULL))
-	{
-	  termios_printf ("WriteFile failed, %E");
-	  break;
-	}
-      else
-	{
-	  written += wLen;
-	  p += wLen;
-	}
-    }
-  /* Detach from pseudo console and resume. */
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-cleanup:
-  SetConsoleOutputCP (origCP);
-  HeapFree (GetProcessHeap (), 0, buf);
-detach:
-  restore_reattach_pcon ();
+  get_ttyp ()->h_pseudo_console = NULL;
+  get_ttyp ()->pcon_start = false;
 }
 
 ssize_t __stdcall
@@ -1505,44 +776,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
   reset_switch_to_pcon ();
 
   acquire_output_mutex (INFINITE);
-  bool output_to_pcon = get_ttyp ()->switch_to_pcon_out;
-  release_output_mutex ();
-
-  UINT target_code_page = output_to_pcon ?
-    GetConsoleOutputCP () : get_ttyp ()->term_code_page;
-  ssize_t nlen;
-  char *buf = convert_mb_str (target_code_page, (size_t *) &nlen,
-		 get_ttyp ()->term_code_page, (const char *) ptr, len);
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  bool fallback = false;
-  if (output_to_pcon && pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      fallback = true;
-
-  if (output_to_pcon && !fallback &&
-      (memmem (buf, nlen, "\033[6n", 4) || memmem (buf, nlen, "\033[0c", 4)))
-    {
-      get_ttyp ()->pcon_in_empty = false;
-      if (!is_line_input ())
-	SetEvent (input_available_event);
-    }
-
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  if (output_to_pcon && !fallback)
-    {
-      GetConsoleMode (get_output_handle (), &dwMode);
-      SetConsoleMode (get_output_handle (), dwMode | flags);
-    }
-  HANDLE to = (output_to_pcon && !fallback) ?
-    get_output_handle () : get_output_handle_cyg ();
-  acquire_output_mutex (INFINITE);
-  if (!process_opost_output (to, buf, nlen, false))
+  if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false))
     {
       DWORD err = GetLastError ();
       termios_printf ("WriteFile failed, %E");
@@ -1557,20 +791,6 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
       towrite = -1;
     }
   release_output_mutex ();
-  mb_str_free (buf);
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (output_to_pcon && !fallback)
-    SetConsoleMode (get_output_handle (), dwMode | flags);
-
-  restore_reattach_pcon ();
-
-  /* Push slave output to pseudo console screen buffer */
-  if (get_pseudo_console ())
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer ((char *)ptr, len, false);
-      release_output_mutex ();
-    }
 
   return towrite;
 }
@@ -1582,16 +802,15 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 }
 
 bool
-fhandler_pty_common::to_be_read_from_pcon (void)
+fhandler_pty_master::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return get_ttyp ()->pcon_start
+    || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
 fhandler_pty_slave::read (void *ptr, size_t& len)
 {
-  char *ptr0 = (char *)ptr;
   ssize_t totalread = 0;
   int vmin = 0;
   int vtime = 0;	/* Initialized to prevent -Wuninitialized warning */
@@ -1616,8 +835,6 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
       mask_switch_to_pcon_in (true);
       reset_switch_to_pcon ();
     }
-  if (to_be_read_from_pcon ())
-    update_pcon_input_state (true);
 
   if (is_nonblocking () || !ptr) /* Indicating tcflush(). */
     time_to_wait = 0;
@@ -1703,98 +920,21 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 	      if (!totalread)
 		{
 		  set_sig_errno (EAGAIN);
-		  totalread = -1;
-		}
-	      goto out;
-	    }
-	  continue;
-	default:
-	  termios_printf ("wait for input mutex failed, %E");
-	  if (!totalread)
-	    {
-	      __seterrno ();
-	      totalread = -1;
-	    }
-	  goto out;
-	}
-      if (ptr && to_be_read_from_pcon ())
-	{
-	  if (get_readahead_valid ())
-	    {
-	      ReleaseMutex (input_mutex);
-	      totalread = get_readahead_into_buffer ((char *) ptr, len);
-	    }
-	  else
-	    {
-	      if (!try_reattach_pcon ())
-		{
-		  restore_reattach_pcon ();
-		  goto do_read_cyg;
-		}
-
-	      DWORD dwMode;
-	      GetConsoleMode (get_handle (), &dwMode);
-	      DWORD flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
-	      if (dwMode != flags)
-		SetConsoleMode (get_handle (), flags);
-	      /* Read get_handle() instad of get_handle_cyg() */
-	      BOOL (WINAPI *ReadFunc)
-		(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID);
-	      ReadFunc = ReadConsoleA_Orig ? ReadConsoleA_Orig : ReadConsoleA;
-	      DWORD rlen;
-	      readlen = MIN (len, sizeof (buf));
-	      if (!ReadFunc (get_handle (), buf, readlen, &rlen, NULL))
-		{
-		  termios_printf ("read failed, %E");
-		  SetConsoleMode (get_handle (), dwMode);
-		  restore_reattach_pcon ();
-		  ReleaseMutex (input_mutex);
-		  set_errno (EIO);
-		  totalread = -1;
-		  goto out;
-		}
-	      SetConsoleMode (get_handle (), dwMode);
-	      restore_reattach_pcon ();
-	      ReleaseMutex (input_mutex);
-
-	      ssize_t nlen;
-	      char *nbuf = convert_mb_str (get_ttyp ()->term_code_page,
-			     (size_t *) &nlen, GetConsoleCP (), buf, rlen);
-
-	      ssize_t ret;
-	      line_edit_status res =
-		line_edit (nbuf, nlen, get_ttyp ()->ti, &ret);
-
-	      mb_str_free (nbuf);
-
-	      if (res == line_edit_input_done || res == line_edit_ok)
-		totalread = get_readahead_into_buffer ((char *) ptr, len);
-	      else if (res > line_edit_signalled)
-		{
-		  set_sig_errno (EINTR);
-		  totalread = -1;
-		}
-	      else
-		{
-		  update_pcon_input_state (true);
-		  continue;
+		  totalread = -1;
 		}
+	      goto out;
+	    }
+	  continue;
+	default:
+	  termios_printf ("wait for input mutex failed, %E");
+	  if (!totalread)
+	    {
+	      __seterrno ();
+	      totalread = -1;
 	    }
-
-	  update_pcon_input_state (true);
-	  mask_switch_to_pcon_in (false);
 	  goto out;
 	}
-      if (!ptr && len == UINT_MAX && !get_ttyp ()->pcon_in_empty)
-	{
-	  FlushConsoleInputBuffer (get_handle ());
-	  get_ttyp ()->pcon_in_empty = true;
-	  DWORD n;
-	  if (bytes_available (n) && n == 0)
-	    ResetEvent (input_available_event);
-	}
 
-do_read_cyg:
       if (!bytes_available (bytes_in_pipe))
 	{
 	  ReleaseMutex (input_mutex);
@@ -1911,16 +1051,6 @@ do_read_cyg:
 out:
   termios_printf ("%d = read(%p, %lu)", totalread, ptr, len);
   len = (size_t) totalread;
-  /* Push slave read as echo to pseudo console screen buffer. */
-  if (get_pseudo_console () && ptr0 && totalread > 0 &&
-      (get_ttyp ()->ti.c_lflag & ECHO))
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer (ptr0, len, true);
-      if (get_ttyp ()->switch_to_pcon_out)
-	trigger_redraw_screen ();
-      release_output_mutex ();
-    }
   mask_switch_to_pcon_in (false);
 }
 
@@ -2061,38 +1191,11 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
       get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
       break;
     case TIOCSWINSZ:
-      if (get_pseudo_console ())
-	{
-	  /* If not attached to this pseudo console,
-	     try to attach temporarily. */
-	  pid_restore = 0;
-	  if (pcon_attached_to != get_minor ())
-	    if (!try_reattach_pcon ())
-	      goto cleanup;
-
-	  COORD size;
-	  size.X = ((struct winsize *) arg)->ws_col;
-	  size.Y = ((struct winsize *) arg)->ws_row;
-	  CONSOLE_SCREEN_BUFFER_INFO csbi;
-	  if (GetConsoleScreenBufferInfo (get_output_handle (), &csbi))
-	    if (size.X == csbi.srWindow.Right - csbi.srWindow.Left + 1 &&
-		size.Y == csbi.srWindow.Bottom - csbi.srWindow.Top + 1)
-	      goto cleanup;
-	  if (!SetConsoleScreenBufferSize (get_output_handle (), size))
-	    goto cleanup;
-	  SMALL_RECT rect;
-	  rect.Left = 0;
-	  rect.Top = 0;
-	  rect.Right = size.X-1;
-	  rect.Bottom = size.Y-1;
-	  SetConsoleWindowInfo (get_output_handle (), TRUE, &rect);
-cleanup:
-	  restore_reattach_pcon ();
-	}
-
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->arg.winsize = *(struct winsize *) arg;
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
@@ -2378,6 +1481,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2393,7 +1517,6 @@ fhandler_pty_master::close ()
 {
   OBJECT_BASIC_INFORMATION obi;
   NTSTATUS status;
-  pid_t master_pid_tmp = get_ttyp ()->master_pid;
 
   termios_printf ("closing from_master(%p)/from_master_cyg(%p)/to_master(%p)/to_master_cyg(%p) since we own them(%u)",
 		  from_master, from_master_cyg,
@@ -2438,30 +1561,6 @@ fhandler_pty_master::close ()
   else if (obi.HandleCount == 1)
     {
       termios_printf ("Closing last master of pty%d", get_minor ());
-      /* Close Pseudo Console */
-      if (get_pseudo_console ())
-	{
-	  /* Terminate helper process */
-	  SetEvent (get_ttyp ()->h_helper_goodbye);
-	  WaitForSingleObject (get_ttyp ()->h_helper_process, INFINITE);
-	  CloseHandle (get_ttyp ()->h_helper_goodbye);
-	  CloseHandle (get_ttyp ()->h_helper_process);
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (master_pid_tmp == myself->pid)
-	    {
-	      /* ClosePseudoConsole() seems to have a bug that one
-		 internal handle remains opened. This causes handle leak.
-		 This is a workaround for this problem. */
-	      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_pseudo_console ();
-	      HANDLE tmp = hp->hConHostProcess;
-	      /* Release pseudo console */
-	      ClosePseudoConsole (get_pseudo_console ());
-	      CloseHandle (tmp);
-	    }
-	  get_ttyp ()->switch_to_pcon_in = false;
-	  get_ttyp ()->switch_to_pcon_out = false;
-	}
       if (get_ttyp ()->getsid () > 0)
 	kill (get_ttyp ()->getsid (), SIGHUP);
       SetEvent (input_available_event);
@@ -2469,9 +1568,8 @@ fhandler_pty_master::close ()
 
   if (!ForceCloseHandle (from_master))
     termios_printf ("error closing from_master %p, %E", from_master);
-  if (from_master_cyg != from_master) /* Avoid double close. */
-    if (!ForceCloseHandle (from_master_cyg))
-      termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
+  if (!ForceCloseHandle (from_master_cyg))
+    termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
   if (!ForceCloseHandle (to_master))
     termios_printf ("error closing to_master %p, %E", to_master);
   from_master = to_master = NULL;
@@ -2513,7 +1611,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon () && get_ttyp ()->h_pseudo_console)
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2521,40 +1619,50 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
       WaitForSingleObject (input_mutex, INFINITE);
 
-      if (memchr (buf, '\003', nlen)) /* ^C intr key in pcon */
-	get_ttyp ()->req_flush_pcon_input = true;
-
       DWORD wLen;
-      WriteFile (to_slave, buf, nlen, &wLen, NULL);
-      get_ttyp ()->pcon_in_empty = false;
-
-      ReleaseMutex (input_mutex);
 
-      /* Use line_edit () in order to set input_available_event. */
-      bool is_echo = tc ()->ti.c_lflag & ECHO;
-      if (!get_ttyp ()->mask_switch_to_pcon_in)
+      if (get_ttyp ()->pcon_start)
 	{
-	  tc ()->ti.c_lflag &= ~ECHO;
-	  ti.c_lflag &= ~ECHO;
-	}
-      ti.c_lflag &= ~ISIG;
-      line_edit (buf, nlen, ti, &ret);
-      if (is_echo)
-	tc ()->ti.c_lflag |= ECHO;
-      get_ttyp ()->read_retval = 1;
-
-      const char sigs[] = {
-	(char) ti.c_cc[VINTR],
-	(char) ti.c_cc[VQUIT],
-	(char) ti.c_cc[VSUSP],
-      };
-      if (tc ()->ti.c_lflag & ISIG)
-	for (size_t i=0; i<sizeof (sigs); i++)
-	  if (sigs[i] && memchr (buf, sigs[i], nlen))
+	  /* Pseudo condole support uses "CSI6n" to get cursor position.
+	     If the reply for "CSI6n" is divided into multiple writes,
+	     pseudo console sometimes does not recognize it.  Therefore,
+	     put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon_start = false;
+	    }
+	  else
 	    {
-	      eat_readahead (-1);
-	      SetEvent (input_available_event);
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
 	    }
+	}
+
+      WriteFile (to_slave, buf, nlen, &wLen, NULL);
+
+      ReleaseMutex (input_mutex);
 
       mb_str_free (buf);
       return len;
@@ -2630,15 +1738,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (get_pseudo_console () && get_ttyp ()->master_pid == myself->pid)
-	    {
-	      COORD size;
-	      size.X = ((struct winsize *) arg)->ws_col;
-	      size.Y = ((struct winsize *) arg)->ws_row;
-	      ResizePseudoConsole (get_pseudo_console (), size);
-	    }
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
 	}
@@ -2763,7 +1864,7 @@ get_locale_from_env (char *locale)
   strcpy (locale, env);
 }
 
-static LCID
+static void
 get_langinfo (char *locale_out, char *charset_out)
 {
   /* Get locale from environment */
@@ -2776,11 +1877,6 @@ get_langinfo (char *locale_out, char *charset_out)
   if (!locale)
     locale = "C";
 
-  char tmp_locale[ENCODING_LEN + 1];
-  char *ret = __set_locale_from_locale_alias (locale, tmp_locale);
-  if (ret)
-    locale = tmp_locale;
-
   const char *charset;
   struct lc_ctype_T *lc_ctype = (struct lc_ctype_T *) loc.lc_cat[LC_CTYPE].ptr;
   if (!lc_ctype)
@@ -2830,23 +1926,9 @@ get_langinfo (char *locale_out, char *charset_out)
       charset = "CP932";
     }
 
-  wchar_t lc[ENCODING_LEN + 1];
-  wchar_t *p;
-  mbstowcs (lc, locale, ENCODING_LEN);
-  p = wcschr (lc, L'.');
-  if (p)
-    *p = L'\0';
-  p = wcschr (lc, L'_');
-  if (p)
-    *p = L'-';
-  LCID lcid = LocaleNameToLCID (lc, 0);
-  if (!lcid && !strcmp (charset, "ASCII"))
-    return 0;
-
   /* Set results */
   strcpy (locale_out, new_locale);
   strcpy (charset_out, charset);
-  return lcid;
 }
 
 void
@@ -2854,21 +1936,7 @@ fhandler_pty_slave::setup_locale (void)
 {
   char locale[ENCODING_LEN + 1] = "C";
   char charset[ENCODING_LEN + 1] = "ASCII";
-  LCID lcid = get_langinfo (locale, charset);
-
-  /* Set console code page form locale */
-  if (get_pseudo_console ())
-    {
-      UINT code_page;
-      if (lcid == 0 || lcid == (LCID) -1)
-	code_page = 20127; /* ASCII */
-      else if (!GetLocaleInfo (lcid,
-			       LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
-			       (char *) &code_page, sizeof (code_page)))
-	code_page = 20127; /* ASCII */
-      SetConsoleCP (code_page);
-      SetConsoleOutputCP (code_page);
-    }
+  get_langinfo (locale, charset);
 
   /* Set terminal code page from locale */
   /* This code is borrowed from mintty: charset.c */
@@ -2878,9 +1946,9 @@ fhandler_pty_slave::setup_locale (void)
     charset_u[i] = toupper (charset[i]);
   unsigned int iso;
   UINT cp = 20127; /* Default for fallback */
-  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859%u", &iso) == 1)
+  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859%u", &iso) == 1)
     {
       if (iso && iso <= 16 && iso !=12)
 	get_ttyp ()->term_code_page = 28590 + iso;
@@ -2896,90 +1964,9 @@ fhandler_pty_slave::setup_locale (void)
 	}
 }
 
-void
-fhandler_pty_slave::set_freeconsole_on_close (bool val)
-{
-  freeconsole_on_close = val;
-}
-
-void
-fhandler_pty_slave::trigger_redraw_screen (void)
-{
-  /* Forcibly redraw screen based on console screen buffer. */
-  /* The following code triggers redrawing the screen. */
-  CONSOLE_SCREEN_BUFFER_INFO sbi;
-  GetConsoleScreenBufferInfo (get_output_handle (), &sbi);
-  SMALL_RECT rect = {0, 0,
-    (SHORT) (sbi.dwSize.X -1), (SHORT) (sbi.dwSize.Y - 1)};
-  COORD dest = {0, 0};
-  CHAR_INFO fill = {' ', 0};
-  ScrollConsoleScreenBuffer (get_output_handle (), &rect, NULL, dest, &fill);
-  get_ttyp ()->need_redraw_screen = false;
-}
-
-void
-fhandler_pty_slave::fixup_after_attach (bool native_maybe, int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  if (get_pseudo_console ())
-    {
-      if (fhandler_console::get_console_process_id (get_helper_process_id (),
-						    true))
-	if (pcon_attached_to != get_minor ())
-	  {
-	    pcon_attached_to = get_minor ();
-	    init_console_handler (true);
-	  }
-
-#if 0 /* This is for debug only. */
-      isHybrid = true;
-      get_ttyp ()->switch_to_pcon_in = true;
-      get_ttyp ()->switch_to_pcon_out = true;
-#endif
-
-      if (pcon_attached_to == get_minor () && native_maybe)
-	{
-	  if (fd == 0)
-	    {
-	      pull_pcon_input ();
-	      DWORD mode =
-		ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	      SetConsoleMode (get_handle (), mode);
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_in = true;
-	    }
-	  else if (fd == 1 || fd == 2)
-	    {
-	      DWORD mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
-	      SetConsoleMode (get_output_handle (), mode);
-	      acquire_output_mutex (INFINITE);
-	      if (!get_ttyp ()->switch_to_pcon_out)
-		get_ttyp ()->wait_pcon_fwd ();
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_out = true;
-	      release_output_mutex ();
-
-	      if (get_ttyp ()->need_redraw_screen)
-		trigger_redraw_screen ();
-	    }
-	  init_console_handler (false);
-	}
-      else if (fd == 0 && native_maybe)
-	/* Read from unattached pseudo console cause freeze,
-	   therefore, fallback to legacy pty. */
-	set_handle (get_handle_cyg ());
-    }
-}
-
 void
 fhandler_pty_slave::fixup_after_fork (HANDLE parent)
 {
-  fixup_after_attach (false, -1);
   // fork_fixup (parent, inuse, "inuse");
   // fhandler_pty_common::fixup_after_fork (parent);
   report_tty_counts (this, "inherited", "");
@@ -2992,71 +1979,22 @@ fhandler_pty_slave::fixup_after_exec ()
 
   if (!close_on_exec ())
     fixup_after_fork (NULL);	/* No parent handle required. */
-  else if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 1 && get_minor () == pcon_attached_to)
-	pcon_attached_to = -1;
-      if (used == 1 /* About to close this tty */)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
 
   /* Set locale */
   if (get_ttyp ()->term_code_page == 0)
     setup_locale ();
 
   /* Hook Console API */
-  if (get_pseudo_console ())
-    {
 #define DO_HOOK(module, name) \
-      if (!name##_Orig) \
-	{ \
-	  void *api = hook_api (module, #name, (void *) name##_Hooked); \
-	  name##_Orig = (__typeof__ (name) *) api; \
-	  /*if (api) system_printf (#name " hooked.");*/ \
-	}
-      DO_HOOK (NULL, WriteFile);
-      DO_HOOK (NULL, WriteConsoleA);
-      DO_HOOK (NULL, WriteConsoleW);
-      DO_HOOK (NULL, ReadFile);
-      DO_HOOK (NULL, ReadConsoleA);
-      DO_HOOK (NULL, ReadConsoleW);
-      DO_HOOK (NULL, WriteConsoleOutputA);
-      DO_HOOK (NULL, WriteConsoleOutputW);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterA);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterW);
-      DO_HOOK (NULL, WriteConsoleOutputAttribute);
-      DO_HOOK (NULL, SetConsoleCursorPosition);
-      DO_HOOK (NULL, SetConsoleTextAttribute);
-      DO_HOOK (NULL, WriteConsoleInputA);
-      DO_HOOK (NULL, WriteConsoleInputW);
-      DO_HOOK (NULL, ReadConsoleInputA);
-      DO_HOOK (NULL, ReadConsoleInputW);
-      DO_HOOK (NULL, PeekConsoleInputA);
-      DO_HOOK (NULL, PeekConsoleInputW);
-      /* CreateProcess() is hooked for GDB etc. */
-      DO_HOOK (NULL, CreateProcessA);
-      DO_HOOK (NULL, CreateProcessW);
+  if (!name##_Orig) \
+    { \
+      void *api = hook_api (module, #name, (void *) name##_Hooked); \
+      name##_Orig = (__typeof__ (name) *) api; \
+      /*if (api) system_printf (#name " hooked.");*/ \
     }
+  /* CreateProcess() is hooked for GDB etc. */
+  DO_HOOK (NULL, CreateProcessA);
+  DO_HOOK (NULL, CreateProcessW);
 }
 
 /* This thread function handles the master control pipe.  It waits for a
@@ -3204,27 +2142,6 @@ reply:
   return 0;
 }
 
-void
-fhandler_pty_master::transfer_input_to_pcon (void)
-{
-  WaitForSingleObject (input_mutex, INFINITE);
-  DWORD n;
-  size_t transfered = 0;
-  while (::bytes_available (n, from_master_cyg) && n)
-    {
-      char buf[1024];
-      ReadFile (from_master_cyg, buf, sizeof (buf), &n, 0);
-      char *p = buf;
-      while ((p = (char *) memchr (p, '\n', n - (p - buf))))
-	*p = '\r';
-      if (WriteFile (to_slave, buf, n, &n, 0))
-	transfered += n;
-    }
-  if (transfered)
-    get_ttyp ()->pcon_in_empty = false;
-  ReleaseMutex (input_mutex);
-}
-
 static DWORD WINAPI
 pty_master_thread (VOID *arg)
 {
@@ -3240,23 +2157,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
   termios_printf ("Started.");
   for (;;)
     {
-      if (get_pseudo_console ())
-	{
-	  get_ttyp ()->pcon_last_time = GetTickCount ();
-	  while (::bytes_available (rlen, from_slave) && rlen == 0)
-	    {
-	      /* Forcibly transfer input if it is requested by slave.
-		 This happens when input data should be transfered
-		 from the input pipe for cygwin apps to the input pipe
-		 for native apps. */
-	      if (get_ttyp ()->req_transfer_input_to_pcon)
-		{
-		  transfer_input_to_pcon ();
-		  get_ttyp ()->req_transfer_input_to_pcon = false;
-		}
-	      Sleep (1);
-	    }
-	}
+      get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3264,14 +2165,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_ttyp ()->h_pseudo_console)
 	{
-	  /* Avoid duplicating slave output which is already sent to
-	     to_master_cyg */
-	  if (!get_ttyp ()->switch_to_pcon_out)
-	    continue;
-
-	  /* Avoid setting window title to "cygwin-console-helper.exe" */
+	  /* Remove CSI > Pm m */
 	  int state = 0;
 	  int start_at = 0;
 	  for (DWORD i=0; i<rlen; i++)
@@ -3281,43 +2177,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 		state = 1;
 		continue;
 	      }
-	    else if ((state == 1 && outbuf[i] == ']') ||
-		     (state == 2 && outbuf[i] == '0') ||
-		     (state == 3 && outbuf[i] == ';'))
-	      {
-		state ++;
-		continue;
-	      }
-	    else if (state == 4 && outbuf[i] == '\a')
-	      {
-		const char *helper_str = "\\bin\\cygwin-console-helper.exe";
-		if (memmem (&outbuf[start_at], i + 1 - start_at,
-			    helper_str, strlen (helper_str)))
-		  {
-		    memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
-		    rlen = wlen = start_at + rlen - i - 1;
-		  }
-		state = 0;
-		continue;
-	      }
-	    else if (outbuf[i] == '\a')
-	      {
-		state = 0;
-		continue;
-	      }
-
-	  /* Remove CSI > Pm m */
-	  state = 0;
-	  start_at = 0;
-	  for (DWORD i=0; i<rlen; i++)
-	    if (outbuf[i] == '\033')
-	      {
-		start_at = i;
-		state = 1;
-		continue;
-	      }
-	    else if ((state == 1 && outbuf[i] == '[') ||
-		     (state == 2 && outbuf[i] == '>'))
+	    else if ((state == 1 && outbuf[i] == '[')
+		     || (state == 2 && outbuf[i] == '>'))
 	      {
 		state ++;
 		continue;
@@ -3386,201 +2247,6 @@ pty_master_fwd_thread (VOID *arg)
   return ((fhandler_pty_master *) arg)->pty_master_fwd_thread ();
 }
 
-/* If master process is running as service, attaching to
-   pseudo console should be done in fork. If attaching
-   is done in spawn for inetd or sshd, it fails because
-   the helper process is running as privileged user while
-   slave process is not. This function is used to determine
-   if the process is running as a srvice or not. */
-inline static bool
-is_running_as_service (void)
-{
-  return check_token_membership (well_known_service_sid)
-    || cygheap->user.saved_sid () == well_known_system_sid;
-}
-
-bool
-fhandler_pty_master::setup_pseudoconsole ()
-{
-  if (disable_pcon)
-    return false;
-  /* If the legacy console mode is enabled, pseudo console seems
-     not to work as expected. To determine console mode, registry
-     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
-  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
-  if (reg.error ())
-    return false;
-  if (reg.get_dword (L"ForceV2", 1) == 0)
-    {
-      termios_printf ("Pseudo console is disabled "
-		      "because the legacy console mode is enabled.");
-      return false;
-    }
-
-  /* Pseudo console supprot is realized using a tricky technic.
-     PTY need the pseudo console handles, however, they cannot
-     be retrieved by normal procedure. Therefore, run a helper
-     process in a pseudo console and get them from the helper.
-     Slave process will attach to the pseudo console in the
-     helper process using AttachConsole(). */
-  COORD size = {
-    (SHORT) get_ttyp ()->winsize.ws_col,
-    (SHORT) get_ttyp ()->winsize.ws_row
-  };
-  CreatePipe (&from_master, &to_slave, &sec_none, 0);
-  SetLastError (ERROR_SUCCESS);
-  HRESULT res = CreatePseudoConsole (size, from_master, to_master,
-				     0, &get_ttyp ()->h_pseudo_console);
-  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
-    {
-      if (res != S_OK)
-	system_printf ("CreatePseudoConsole() failed. %08x\n",
-		       GetLastError ());
-      goto fallback;
-    }
-
-  /* If master process is running as service, attaching to
-     pseudo console should be done in fork. If attaching
-     is done in spawn for inetd or sshd, it fails because
-     the helper process is running as privileged user while
-     slave process is not. */
-  if (is_running_as_service ())
-    get_ttyp ()->attach_pcon_in_fork = true;
-
-  STARTUPINFOEXW si_helper;
-  HANDLE hello, goodbye;
-  HANDLE hr, hw;
-  PROCESS_INFORMATION pi_helper;
-  HANDLE hpConIn, hpConOut;
-  {
-    SIZE_T bytesRequired;
-    InitializeProcThreadAttributeList (NULL, 2, 0, &bytesRequired);
-    ZeroMemory (&si_helper, sizeof (si_helper));
-    si_helper.StartupInfo.cb = sizeof (STARTUPINFOEXW);
-    si_helper.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
-      HeapAlloc (GetProcessHeap (), 0, bytesRequired);
-    if (si_helper.lpAttributeList == NULL)
-      goto cleanup_pseudo_console;
-    if (!InitializeProcThreadAttributeList (si_helper.lpAttributeList,
-					    2, 0, &bytesRequired))
-      goto cleanup_heap;
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
-				    get_ttyp ()->h_pseudo_console,
-				    sizeof (get_ttyp ()->h_pseudo_console),
-				    NULL, NULL))
-      goto cleanup_heap;
-    /* Create events for start/stop helper process. */
-    hello = CreateEvent (&sec_none, true, false, NULL);
-    goodbye = CreateEvent (&sec_none, true, false, NULL);
-    /* Create a pipe for receiving pseudo console handles */
-    CreatePipe (&hr, &hw, &sec_none, 0);
-    /* Inherit only handles which are needed by helper. */
-    HANDLE handles_to_inherit[] = {hello, goodbye, hw};
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
-				    handles_to_inherit,
-				    sizeof (handles_to_inherit),
-				    NULL, NULL))
-      goto cleanup_event_and_pipes;
-    /* Create helper process */
-    WCHAR cmd[MAX_PATH];
-    path_conv helper ("/bin/cygwin-console-helper.exe");
-    size_t len = helper.get_wide_win32_path_len ();
-    helper.get_wide_win32_path (cmd);
-    __small_swprintf (cmd + len, L" %p %p %p", hello, goodbye, hw);
-    si_helper.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
-    si_helper.StartupInfo.hStdInput = NULL;
-    si_helper.StartupInfo.hStdOutput = NULL;
-    si_helper.StartupInfo.hStdError = NULL;
-    if (!CreateProcessW (NULL, cmd, &sec_none, &sec_none,
-			 TRUE, EXTENDED_STARTUPINFO_PRESENT,
-			 NULL, NULL, &si_helper.StartupInfo, &pi_helper))
-      goto cleanup_event_and_pipes;
-    for (;;)
-      {
-        DWORD wait_result = WaitForSingleObject (hello, 500);
-	if (wait_result == WAIT_OBJECT_0)
-	  break;
-	if (wait_result != WAIT_TIMEOUT)
-	  goto cleanup_helper_process;
-	DWORD exit_code;
-	if (!GetExitCodeProcess(pi_helper.hProcess, &exit_code))
-	  goto cleanup_helper_process;
-	if (exit_code == STILL_ACTIVE)
-	  continue;
-	if (exit_code != 0 ||
-	    WaitForSingleObject (hello, 500) != WAIT_OBJECT_0)
-	  goto cleanup_helper_process;
-	break;
-      }
-    CloseHandle (hello);
-    CloseHandle (pi_helper.hThread);
-    /* Retrieve pseudo console handles */
-    DWORD rLen;
-    char buf[64];
-    if (!ReadFile (hr, buf, sizeof (buf), &rLen, NULL))
-      goto cleanup_helper_process;
-    buf[rLen] = '\0';
-    sscanf (buf, "StdHandles=%p,%p", &hpConIn, &hpConOut);
-    if (!DuplicateHandle (pi_helper.hProcess, hpConIn,
-			  GetCurrentProcess (), &hpConIn, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_helper_process;
-    if (!DuplicateHandle (pi_helper.hProcess, hpConOut,
-			  GetCurrentProcess (), &hpConOut, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_pcon_in;
-    CloseHandle (hr);
-    CloseHandle (hw);
-    /* Clean up */
-    DeleteProcThreadAttributeList (si_helper.lpAttributeList);
-    HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-  }
-  /* Setting information of stuffs regarding pseudo console */
-  get_ttyp ()->h_helper_goodbye = goodbye;
-  get_ttyp ()->h_helper_process = pi_helper.hProcess;
-  get_ttyp ()->helper_process_id = pi_helper.dwProcessId;
-  CloseHandle (from_master);
-  CloseHandle (to_master);
-  from_master = hpConIn;
-  to_master = hpConOut;
-  ResizePseudoConsole (get_ttyp ()->h_pseudo_console, size);
-  return true;
-
-cleanup_pcon_in:
-  CloseHandle (hpConIn);
-cleanup_helper_process:
-  SetEvent (goodbye);
-  WaitForSingleObject (pi_helper.hProcess, INFINITE);
-  CloseHandle (pi_helper.hProcess);
-  goto skip_close_hello;
-cleanup_event_and_pipes:
-  CloseHandle (hello);
-skip_close_hello:
-  CloseHandle (goodbye);
-  CloseHandle (hr);
-  CloseHandle (hw);
-cleanup_heap:
-  HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-cleanup_pseudo_console:
-  {
-    HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
-    HANDLE tmp = hp->hConHostProcess;
-    ClosePseudoConsole (get_pseudo_console ());
-    CloseHandle (tmp);
-  }
-fallback:
-  CloseHandle (from_master);
-  CloseHandle (to_slave);
-  from_master = from_master_cyg;
-  to_slave = NULL;
-  get_ttyp ()->h_pseudo_console = NULL;
-  return false;
-}
-
 bool
 fhandler_pty_master::setup ()
 {
@@ -3593,11 +2259,6 @@ fhandler_pty_master::setup ()
   if (unit < 0)
     return false;
 
-  /* from_master should be used for pseudo console.
-     Just copy from_master_cyg here for the case that
-     pseudo console is not available. */
-  from_master = from_master_cyg;
-
   ProtectHandle1 (get_output_handle (), to_pty);
 
   tty& t = *cygwin_shared->tty[unit];
@@ -3696,15 +2357,21 @@ fhandler_pty_master::setup ()
       goto err;
     }
 
-  t.winsize.ws_col = 80;
-  t.winsize.ws_row = 25;
-
-  setup_pseudoconsole ();
+  __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;
+    }
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
   t.set_to_master (to_master);
   t.set_to_master_cyg (to_master_cyg);
+  t.winsize.ws_col = 80;
+  t.winsize.ws_row = 25;
   t.master_pid = myself->pid;
 
   dev ().parse (DEV_PTYM_MAJOR, unit);
@@ -3717,6 +2384,7 @@ fhandler_pty_master::setup ()
 err:
   __seterrno ();
   close_maybe (from_slave);
+  close_maybe (to_slave);
   close_maybe (get_handle ());
   close_maybe (get_output_handle ());
   close_maybe (input_available_event);
@@ -3776,9 +2444,6 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 {
   ssize_t towrite = len;
   BOOL res = TRUE;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
   while (towrite)
     {
       if (!is_echo)
@@ -3801,7 +2466,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
       if (!(get_ttyp ()->ti.c_oflag & OPOST))	// raw output mode
 	{
 	  DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
-	  res = WriteFunc (h, ptr, n, &n, NULL);
+	  res = WriteFile (h, ptr, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + n;
@@ -3851,7 +2516,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 		  break;
 		}
 	    }
-	  res = WriteFunc (h, outbuf, n, &n, NULL);
+	  res = WriteFile (h, outbuf, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + rc;
@@ -3861,3 +2526,134 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon)
+{
+
+  /* Setting switch_to_pcon_in is necessary even if
+     pseudo console will not be activated. */
+  fhandler_base *fh = ::cygheap->fdtab[0];
+  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+    {
+      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+      ptys->get_ttyp ()->switch_to_pcon_in = true;
+      if (ptys->get_ttyp ()->pcon_pid == 0
+	  || !pinfo (ptys->get_ttyp ()->pcon_pid))
+	ptys->get_ttyp ()->pcon_pid = myself->pid;
+    }
+
+  if (nopcon)
+    return false;
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  const DWORD inherit_cursor = 1;
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     inherit_cursor,
+				     &get_ttyp ()->h_pseudo_console);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console,
+				  sizeof (get_ttyp ()->h_pseudo_console),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_base *fh0 = ::cygheap->fdtab[0];
+    if (fh0 && fh0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = fh0->get_handle ();
+    fhandler_base *fh1 = ::cygheap->fdtab[1];
+    if (fh1 && fh1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = fh1->get_output_handle ();
+    fhandler_base *fh2 = ::cygheap->fdtab[2];
+    if (fh2 && fh2->get_device () != get_device ())
+      si->StartupInfo.hStdError = fh2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole (void)
+{
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      get_ttyp ()->wait_pcon_fwd ();
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+      get_ttyp ()->pcon_start = false;
+    }
+}
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 7c07b062e..38172ca1e 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -134,36 +134,6 @@ child_info::prefork (bool detached)
 int __stdcall
 frok::child (volatile char * volatile here)
 {
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR)
-      {
-	fhandler_base *fh = cfd;
-	fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
-	if (ptym->get_pseudo_console ())
-	  {
-	    debug_printf ("found a PTY master %d: helper_PID=%d",
-			  ptym->get_minor (), ptym->get_helper_process_id ());
-	    if (fhandler_console::get_console_process_id (
-				ptym->get_helper_process_id (), true))
-	      /* Already attached */
-	      break;
-	    else
-	      {
-		if (ptym->attach_pcon_in_fork ())
-		  {
-		    FreeConsole ();
-		    if (!AttachConsole (ptym->get_helper_process_id ()))
-		      /* Error */;
-		    else
-		      break;
-		  }
-	      }
-	  }
-      }
-  extern void clear_pcon_attached_to (void); /* fhandler_tty.cc */
-  clear_pcon_attached_to ();
-
   HANDLE& hParent = ch.parent;
 
   sync_with_parent ("after longjmp", true);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 4a8f3b2ec..9f1a8a57a 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1215,8 +1215,7 @@ verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds,
 	   fd_set *exceptfds)
 {
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) me->fh;
-  if (me->read_selected && !ptys->to_be_read_from_pcon () &&
-      IsEventSignalled (ptys->input_available_event))
+  if (me->read_selected && IsEventSignalled (ptys->input_available_event))
     me->read_ready = true;
   return set_bits (me, readfds, writefds, exceptfds);
 }
@@ -1229,8 +1228,6 @@ peek_pty_slave (select_record *s, bool from_select)
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
 
   ptys->reset_switch_to_pcon ();
-  if (ptys->to_be_read_from_pcon ())
-    ptys->update_pcon_input_state (true);
 
   if (s->read_selected)
     {
diff --git a/winsup/cygwin/smallprint.cc b/winsup/cygwin/smallprint.cc
index 9cfb41987..4a14ee3cf 100644
--- a/winsup/cygwin/smallprint.cc
+++ b/winsup/cygwin/smallprint.cc
@@ -405,7 +405,6 @@ small_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
   WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, NULL);
   FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
 }
@@ -432,7 +431,6 @@ console_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (console_handle);
   WriteFile (console_handle, buf, count, &done, NULL);
   FlushFileBuffers (console_handle);
 }
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index e70ceb86d..d12ce7b0a 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -177,7 +177,7 @@ find_exec (const char *name, path_conv& buf, const char *search,
 /* Utility for child_info_spawn::worker.  */
 
 static HANDLE
-handle (int fd, bool writing, bool iscygwin)
+handle (int fd, bool writing)
 {
   HANDLE h;
   cygheap_fdget cfd (fd);
@@ -188,17 +188,30 @@ handle (int fd, bool writing, bool iscygwin)
     h = INVALID_HANDLE_VALUE;
   else if (!writing)
     h = cfd->get_handle ();
-  else if (cfd->get_major () == DEV_PTYS_MAJOR && iscygwin)
-    {
-      fhandler_pty_slave *ptys = (fhandler_pty_slave *)(fhandler_base *) cfd;
-      h = ptys->get_output_handle_cyg ();
-    }
   else
     h = cfd->get_output_handle ();
 
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -266,8 +279,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 {
   bool rc;
   int res = -1;
-  DWORD pid_restore = 0;
-  bool attach_to_console = false;
   pid_t ctty_pgid = 0;
 
   /* Search for CTTY and retrieve its PGID */
@@ -587,9 +598,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			 PROCESS_QUERY_LIMITED_INFORMATION))
 	sa = &sec_none_nih;
 
-      /* Attach to pseudo console if pty salve is used */
-      pid_restore = fhandler_console::get_console_process_id
-	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -598,29 +607,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	      if (ptys->get_pseudo_console ())
-		{
-		  DWORD helper_process_id = ptys->get_helper_process_id ();
-		  debug_printf ("found a PTY slave %d: helper_PID=%d",
-				    fh->get_minor (), helper_process_id);
-		  if (fhandler_console::get_console_process_id
-					      (helper_process_id, true))
-		    /* Already attached */
-		    attach_to_console = true;
-		  else if (!attach_to_console)
-		    {
-		      FreeConsole ();
-		      if (AttachConsole (helper_process_id))
-			attach_to_console = true;
-		    }
-		  ptys->fixup_after_attach (!iscygwin (), fd);
-		  if (mode == _P_OVERLAY)
-		    ptys->set_freeconsole_on_close (iscygwin ());
-		}
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	    }
 	  else if (fh && fh->get_major () == DEV_CONS_MAJOR)
 	    {
-	      attach_to_console = true;
 	      fhandler_console *cons = (fhandler_console *) fh;
 	      if (wincap.has_con_24bit_colors () && !iscygwin ())
 		if (fd == 1 || fd == 2)
@@ -630,17 +621,28 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 
       /* Set up needed handles for stdio */
       si.dwFlags = STARTF_USESTDHANDLES;
-      si.hStdInput = handle ((in__stdin < 0 ? 0 : in__stdin), false,
-			     iscygwin ());
-      si.hStdOutput = handle ((in__stdout < 0 ? 1 : in__stdout), true,
-			      iscygwin ());
-      si.hStdError = handle (2, true, iscygwin ());
+      si.hStdInput = handle ((in__stdin < 0 ? 0 : in__stdin), false);
+      si.hStdOutput = handle ((in__stdout < 0 ? 1 : in__stdout), true);
+      si.hStdError = handle (2, true);
 
       si.cb = sizeof (si);
 
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool enable_pcon = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole (&si_pcon,
+			     mode != _P_OVERLAY && mode != _P_WAIT))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    enable_pcon = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -669,7 +671,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -723,7 +725,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -736,6 +738,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (enable_pcon)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -908,6 +915,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	    }
 	  if (sem)
 	    __posix_spawn_sem_release (sem, 0);
+	  if (enable_pcon)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->close_pseudoconsole ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
@@ -915,6 +927,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  system_call.arm ();
 	  if (waitpid (cygpid, &res, 0) != cygpid)
 	    res = -1;
+	  if (enable_pcon)
+	    ptys_primary->close_pseudoconsole ();
 	  break;
 	case _P_DETACH:
 	  res = 0;	/* Lost all memory of this child. */
@@ -941,21 +955,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
   if (envblock)
     free (envblock);
 
-  if (attach_to_console && pid_restore)
-    {
-      FreeConsole ();
-      AttachConsole (pid_restore);
-      cygheap_fdenum cfd (false);
-      int fd;
-      while ((fd = cfd.next ()) >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_pty_slave *ptys =
-	      (fhandler_pty_slave *) (fhandler_base *) cfd;
-	    ptys->fixup_after_attach (false, fd);
-	  }
-    }
-
   return (int) res;
 }
 
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index f0aef3a36..35f8a59ae 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -264,7 +264,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
   if (category & _STRACE_SYSTEM)
     {
       DWORD done;
-      set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
       WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
       FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
       /* Make sure that the message shows up on the screen, too, since this is
@@ -276,7 +275,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
 				 &sec_none, OPEN_EXISTING, 0, 0);
 	  if (h != INVALID_HANDLE_VALUE)
 	    {
-	      set_ishybrid_and_switch_to_pcon (h);
 	      WriteFile (h, buf, len, &done, 0);
 	      CloseHandle (h);
 	    }
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 4cb68f776..d60f27545 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -234,20 +234,14 @@ tty::init ()
   was_opened = false;
   master_pid = 0;
   is_console = false;
-  attach_pcon_in_fork = false;
-  h_pseudo_console = NULL;
   column = 0;
+  h_pseudo_console = NULL;
   switch_to_pcon_in = false;
-  switch_to_pcon_out = false;
-  screen_alternated = false;
   mask_switch_to_pcon_in = false;
   pcon_pid = 0;
   term_code_page = 0;
-  need_redraw_screen = true;
   pcon_last_time = 0;
-  pcon_in_empty = true;
-  req_transfer_input_to_pcon = false;
-  req_flush_pcon_input = false;
+  pcon_start = false;
 }
 
 HANDLE
@@ -293,16 +287,6 @@ tty_min::ttyname ()
   return d.name ();
 }
 
-void
-tty::set_switch_to_pcon_out (bool v)
-{
-  if (switch_to_pcon_out != v)
-    {
-      wait_pcon_fwd ();
-      switch_to_pcon_out = v;
-    }
-}
-
 void
 tty::wait_pcon_fwd (void)
 {
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 920e32b16..c491d3891 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -94,21 +94,13 @@ private:
   HANDLE _to_master;
   HANDLE _to_master_cyg;
   HPCON h_pseudo_console;
-  HANDLE h_helper_process;
-  DWORD helper_process_id;
-  HANDLE h_helper_goodbye;
-  bool attach_pcon_in_fork;
+  bool pcon_start;
   bool switch_to_pcon_in;
-  bool switch_to_pcon_out;
-  bool screen_alternated;
   bool mask_switch_to_pcon_in;
   pid_t pcon_pid;
   UINT term_code_page;
-  bool need_redraw_screen;
   DWORD pcon_last_time;
-  bool pcon_in_empty;
-  bool req_transfer_input_to_pcon;
-  bool req_flush_pcon_input;
+  HANDLE h_pcon_write_pipe;
 
 public:
   HANDLE from_master () const { return _from_master; }
@@ -138,7 +130,6 @@ public:
   void set_master_ctl_closed () {master_pid = -1;}
   static void __stdcall create_master (int);
   static void __stdcall init_session ();
-  void set_switch_to_pcon_out (bool v);
   void wait_pcon_fwd (void);
   friend class fhandler_pty_common;
   friend class fhandler_pty_master;
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index 9bfa1a7a6..79844cb87 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -224,9 +224,6 @@ void init_console_handler (bool);
 
 extern bool wsock_started;
 
-/* PTY related */
-void set_ishybrid_and_switch_to_pcon (HANDLE h);
-
 /* Printf type functions */
 extern "C" void vapi_fatal (const char *, va_list ap) __attribute__ ((noreturn));
 extern "C" void api_fatal (const char *, ...) __attribute__ ((noreturn));
-- 
2.27.0


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-11 11:12                                       ` Takashi Yano
@ 2020-08-13  9:58                                         ` Takashi Yano
  2020-08-17 11:57                                           ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-08-13  9:58 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 4007 bytes --]

On Tue, 11 Aug 2020 20:12:58 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Mon, 3 Aug 2020 21:23:42 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Mon, 3 Aug 2020 11:11:03 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Fri, 24 Jul 2020 20:22:19 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Fri, 24 Jul 2020 14:38:42 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > On Thu, 23 Jul 2020 09:33:28 +0900
> > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > On Wed, 22 Jul 2020 17:45:41 +0900
> > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > On Wed, 22 Jul 2020 03:17:51 +0900
> > > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > > Hi Corinna,
> > > > > > > > 
> > > > > > > > On Mon, 20 Jul 2020 10:06:13 +0200
> > > > > > > > Corinna Vinschen wrote:
> > > > > > > > > On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
> > > > > > > > > > Hi Corinna,
> > > > > > > > > > 
> > > > > > > > > > On Fri, 17 Jul 2020 13:19:12 +0200
> > > > > > > > > > Corinna Vinschen wrote:
> > > > > > > > > > > Hi Takashi,
> > > > > > > > > > > 
> > > > > > > > > > > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > > > > > > > > > > > [...]
> > > > > > > > > > > > Revise the patch to fit the current git head.
> > > > > > > > > > > 
> > > > > > > > > > > are you satisfied with the code?  If you want to merge it,
> > > > > > > > > > > I'd bump Cygwin to 3.2.
> > > > > > > > > > 
> > > > > > > > > > Since this new implementation has both advantages and disadvantages,
> > > > > > > > > > there might be some options.
> > > > > > > > > > 
> > > > > > > > > > 1) Default to new implementation and leave the current one as an
> > > > > > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > > > > > 2) Default to current implementation and add the new one as an
> > > > > > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > > > > > 3) Adopt only new implementation and throw the current one away.
> > > > > > > > > > 
> > > > > > > > > > What do you think?
> > > > > > > > > 
> > > > > > > > > Do you really want to maintain twice as much code doing the same stuff
> > > > > > > > > and constantly having to ask users which version of the code they are
> > > > > > > > > running?  The maintenance cost outweighs the advantages, IMHO.
> > > > > > > > > Personally I'd go for option 3.
> > > > > > > > 
> > > > > > > > Personally, I feel a tinge of sadness to discard the current code,
> > > > > > > > however, your opinion sounds reasonable.
> > > > > > > > 
> > > > > > > > I will submit a new patch in which all the codes specific to the
> > > > > > > > current implementation are removed.
> > > > > > > 
> > > > > > > Attached is the patch in git format-patch format.
> > > > > > > All the codes specific to the current implementation are removed.
> > > > > > > 
> > > > > > > Despite the utmost care, the changes are relatively large, so some
> > > > > > > degradation may exist.
> > > > > > > 
> > > > > > > I will appreciate if you could test.
> > > > > > 
> > > > > > There were still unused code. Please try attached patch instead.
> > > > > 
> > > > > Changes:
> > > > > * Do not activate pseudo console if it is already activated for
> > > > >   another process on same pty.
> > > > 
> > > > Changes:
> > > > * Fix a bug in the latest change.
> > > 
> > > Changes:
> > > * Fix a handle leak caused when spawn is called with mode != _P_OVERLAY.
> > 
> > This patch cannot be applied cleanly against current git head.
> > Please use attached patch instead.
> 
> Adapted to the current git head.

Adapted to the current recent pty change.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-Cygwin-pty-Implement-new-pseudo-console-support.patch --]
[-- Type: application/octet-stream, Size: 90632 bytes --]

From 103fe2b8c7c6c972dbd0454fe9a5dd004a5b69c2 Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Tue, 11 Aug 2020 19:42:12 +0900
Subject: [PATCH] Cygwin: pty: Implement new pseudo console support.

- In this implementation, pseudo console is created for each native
  console app. Advantages and disadvantages of this implementation
  over the previous implementation are as follows.

  Advantages:
  1) No performance degradation in pty output for cygwin process.
      https://cygwin.com/pipermail/cygwin/2020-February/243858.html
  2) Free from the problem caused by difference of behaviour of control
     sequences between real terminal and pseudo console.
      https://cygwin.com/pipermail/cygwin/2019-December/243281.html
      https://cygwin.com/pipermail/cygwin/2020-February/243855.html
  3) Free from the problem in cgdb and emacs gud.
      https://cygwin.com/pipermail/cygwin/2020-January/243601.html
      https://cygwin.com/pipermail/cygwin/2020-March/244146.html
  4) Redrawing screen on executing native console apps is not necessary.
  5) cygwin-console-helper is not necessary for the pseudo console
     support.
  6) The codes for pseudo console support are much simpler than that
     of the previous one.

  Disadvantages:
  1) The cygwin program which calls console API directly does not work.
  2) The apps which use console API cannot be debugged with gdb. This
     is because pseudo console is not activated since gdb uses
     CreateProcess() rather than exec(). Even with this limitation,
     attaching gdb to native apps, in which pseudo console is already
     activated, works.
  3) Typeahead key inputs are discarded while native console app is
     executed. Simirally, typeahead key inputs while cygwin app is
     executed are not inherited to native console app.
  4) Code page cannot be changed by chcp.com. Acctually, chcp works
     itself and changes code page of its own pseudo console.  However,
     since pseudo console is recreated for another process, it cannot
     inherit the code page.
  5) system_printf() does not work after stderr is closed. (Same with
     cygwin 3.0.7)
  6) Startup time of native console apps is about 3 times slower than
     previous implemenation.
  7) Pseudo console cannot be activated if it is already activated for
     another process on same pty.
---
 winsup/cygwin/dtable.cc           |   32 -
 winsup/cygwin/fhandler.h          |   53 +-
 winsup/cygwin/fhandler_console.cc |   43 -
 winsup/cygwin/fhandler_tty.cc     | 1770 +++++------------------------
 winsup/cygwin/fork.cc             |   30 -
 winsup/cygwin/select.cc           |    5 +-
 winsup/cygwin/smallprint.cc       |    2 -
 winsup/cygwin/spawn.cc            |  105 +-
 winsup/cygwin/strace.cc           |    2 -
 winsup/cygwin/tty.cc              |   20 +-
 winsup/cygwin/tty.h               |   13 +-
 winsup/cygwin/winsup.h            |    3 -
 12 files changed, 349 insertions(+), 1729 deletions(-)

diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index e9e005b08..6a91e33bc 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -147,38 +147,6 @@ dtable::get_debugger_info ()
 void
 dtable::stdio_init ()
 {
-  for (int i = 0; i < 3; i ++)
-    {
-      const int chk_order[] = {1, 0, 2};
-      int fd = chk_order[i];
-      fhandler_base *fh = cygheap->fdtab[fd];
-      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
-	{
-	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	  if (ptys->get_pseudo_console ())
-	    {
-	      bool attached = !!fhandler_console::get_console_process_id
-		(ptys->get_helper_process_id (), true);
-	      if (attached)
-		break;
-	      else
-		{
-		  /* Not attached to pseudo console in fork() or spawn()
-		     by some reason. This happens if the executable is
-		     a windows GUI binary, such as mintty. */
-		  FreeConsole ();
-		  if (AttachConsole (ptys->get_helper_process_id ()))
-		    {
-		      ptys->fixup_after_attach (false, fd);
-		      break;
-		    }
-		}
-	    }
-	}
-      else if (fh && fh->get_major () == DEV_CONS_MAJOR)
-	break;
-    }
-
   if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT))
     {
       tty_min *t = cygwin_shared->tty.get_cttyp ();
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index a577ca542..9fd95c098 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -326,16 +326,16 @@ class fhandler_base
   virtual size_t &raixput () { return ra.raixput; };
   virtual size_t &rabuflen () { return ra.rabuflen; };
 
-  virtual bool get_readahead_valid () { return raixget () < ralen (); }
+  bool get_readahead_valid () { return raixget () < ralen (); }
   int puts_readahead (const char *s, size_t len = (size_t) -1);
-  virtual int put_readahead (char value);
+  int put_readahead (char value);
 
   int get_readahead ();
   int peek_readahead (int queryput = 0);
 
   void set_readahead_valid (int val, int ch = -1);
 
-  virtual int get_readahead_into_buffer (char *buf, size_t buflen);
+  int get_readahead_into_buffer (char *buf, size_t buflen);
 
   bool has_acls () const { return pc.has_acls (); }
 
@@ -1905,7 +1905,7 @@ class fhandler_termios: public fhandler_base
   int ioctl (int, void *);
   tty_min *_tc;
   tty *get_ttyp () {return (tty *) tc ();}
-  virtual int eat_readahead (int n);
+  int eat_readahead (int n);
 
  public:
   tty_min*& tc () {return _tc;}
@@ -2184,7 +2184,6 @@ private:
   static bool need_invisible ();
   static void free_console ();
   static const char *get_nonascii_key (INPUT_RECORD& input_rec, char *);
-  static DWORD get_console_process_id (DWORD pid, bool match);
 
   fhandler_console (void *) {}
 
@@ -2264,19 +2263,7 @@ class fhandler_pty_common: public fhandler_termios
     return fh;
   }
 
-  bool attach_pcon_in_fork (void)
-  {
-    return get_ttyp ()->attach_pcon_in_fork;
-  }
-  DWORD get_helper_process_id (void)
-  {
-    return get_ttyp ()->helper_process_id;
-  }
-  HPCON get_pseudo_console (void)
-  {
-    return get_ttyp ()->h_pseudo_console;
-  }
-  bool to_be_read_from_pcon (void);
+  void resize_pseudo_console (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2287,23 +2274,15 @@ class fhandler_pty_slave: public fhandler_pty_common
 {
   HANDLE inuse;			// used to indicate that a tty is in use
   HANDLE output_handle_cyg, io_handle_cyg;
-  DWORD pid_restore;
-  int fd;
 
   /* Helper functions for fchmod and fchown. */
   bool fch_open_handles (bool chown);
   int fch_set_sd (security_descriptor &sd, bool chown);
   void fch_close_handles ();
 
-  bool try_reattach_pcon ();
-  void restore_reattach_pcon ();
-  inline void free_attached_console ();
-
  public:
   /* Constructor */
   fhandler_pty_slave (int);
-  /* Destructor */
-  ~fhandler_pty_slave ();
 
   void set_output_handle_cyg (HANDLE h) { output_handle_cyg = h; }
   HANDLE& get_output_handle_cyg () { return output_handle_cyg; }
@@ -2315,9 +2294,6 @@ class fhandler_pty_slave: public fhandler_pty_common
   ssize_t __stdcall write (const void *ptr, size_t len);
   void __reg3 read (void *ptr, size_t& len);
   int init (HANDLE, DWORD, mode_t);
-  int eat_readahead (int n);
-  int get_readahead_into_buffer (char *buf, size_t buflen);
-  bool get_readahead_valid (void);
 
   int tcsetattr (int a, const struct termios *t);
   int tcgetattr (struct termios *t);
@@ -2354,20 +2330,12 @@ class fhandler_pty_slave: public fhandler_pty_common
     copyto (fh);
     return fh;
   }
-  void set_switch_to_pcon (int fd);
+  bool setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon);
+  void close_pseudoconsole (void);
+  void set_switch_to_pcon (void);
   void reset_switch_to_pcon (void);
-  void push_to_pcon_screenbuffer (const char *ptr, size_t len, bool is_echo);
   void mask_switch_to_pcon_in (bool mask);
-  void fixup_after_attach (bool native_maybe, int fd);
-  bool is_line_input (void)
-  {
-    return get_ttyp ()->ti.c_lflag & ICANON;
-  }
   void setup_locale (void);
-  void set_freeconsole_on_close (bool val);
-  void trigger_redraw_screen (void);
-  void pull_pcon_input (void);
-  void update_pcon_input_state (bool need_lock);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
@@ -2392,7 +2360,6 @@ public:
   int process_slave_output (char *buf, size_t len, int pktmode_on);
   void doecho (const void *str, DWORD len);
   int accept_input ();
-  int put_readahead (char value);
   int open (int flags, mode_t mode = 0);
   void open_setup (int flags);
   ssize_t __stdcall write (const void *ptr, size_t len);
@@ -2431,9 +2398,7 @@ public:
     copyto (fh);
     return fh;
   }
-
-  bool setup_pseudoconsole (void);
-  void transfer_input_to_pcon (void);
+  bool to_be_read_from_pcon (void);
 };
 
 class fhandler_dev_null: public fhandler_base
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 52741ce8b..02a5996a1 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -1206,18 +1206,6 @@ fhandler_console::close ()
   if (con_ra.rabuf)
     free (con_ra.rabuf);
 
-  /* If already attached to pseudo console, don't call free_console () */
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR ||
-	cfd->get_major () == DEV_PTYS_MAJOR)
-      {
-	fhandler_pty_common *t =
-	  (fhandler_pty_common *) (fhandler_base *) cfd;
-	if (get_console_process_id (t->get_helper_process_id (), true))
-	  return 0;
-      }
-
   if (!have_execed)
     free_console ();
   return 0;
@@ -3611,37 +3599,6 @@ fhandler_console::need_invisible ()
   return b;
 }
 
-DWORD
-fhandler_console::get_console_process_id (DWORD pid, bool match)
-{
-  DWORD tmp;
-  DWORD num, num_req;
-  num = 1;
-  num_req = GetConsoleProcessList (&tmp, num);
-  DWORD *list;
-  while (true)
-    {
-      list = (DWORD *)
-	HeapAlloc (GetProcessHeap (), 0, num_req * sizeof (DWORD));
-      num = num_req;
-      num_req = GetConsoleProcessList (list, num);
-      if (num_req > num)
-	HeapFree (GetProcessHeap (), 0, list);
-      else
-	break;
-    }
-  num = num_req;
-
-  tmp = 0;
-  for (DWORD i=0; i<num; i++)
-    if ((match && list[i] == pid) || (!match && list[i] != pid))
-      /* Last one is the oldest. */
-      /* https://github.com/microsoft/terminal/issues/95 */
-      tmp = list[i];
-  HeapFree (GetProcessHeap (), 0, list);
-  return tmp;
-}
-
 DWORD
 fhandler_console::__acquire_input_mutex (const char *fn, int ln, DWORD ms)
 {
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 40b79bfbb..7b5a57ba6 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -25,7 +25,6 @@ details. */
 #include "child_info.h"
 #include <asm/socket.h>
 #include "cygwait.h"
-#include "tls_pbuf.h"
 #include "registry.h"
 
 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
@@ -33,7 +32,6 @@ details. */
 #endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
 
 extern "C" int sscanf (const char *, const char *, ...);
-extern "C" int ttyname_r (int, char*, size_t);
 
 extern "C" {
   HRESULT WINAPI CreatePseudoConsole (COORD, HANDLE, HANDLE, DWORD, HPCON *);
@@ -60,20 +58,10 @@ struct pipe_reply {
   DWORD error;
 };
 
-static int pcon_attached_to = -1;
 static bool isHybrid;
-static bool do_not_reset_switch_to_pcon;
-static bool freeconsole_on_close = true;
-static tty *last_ttyp = NULL;
-
-void
-clear_pcon_attached_to (void)
-{
-  pcon_attached_to = -1;
-}
 
 static void
-set_switch_to_pcon (void)
+set_switch_to_pcon (HANDLE h)
 {
   cygheap_fdenum cfd (false);
   int fd;
@@ -82,280 +70,17 @@ set_switch_to_pcon (void)
       {
 	fhandler_base *fh = cfd;
 	fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	if (ptys->get_pseudo_console ())
-	  {
-	    ptys->set_switch_to_pcon (fd);
-	    ptys->trigger_redraw_screen ();
-	    DWORD mode =
-	      ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	    SetConsoleMode (ptys->get_handle (), mode);
-	  }
+	if (h == ptys->get_handle ())
+	  ptys->set_switch_to_pcon ();
 	return;
       }
-  /* No pty slave opened */
-  if (last_ttyp) /* Make system_printf() work after closing pty slave */
-    last_ttyp->set_switch_to_pcon_out (true);
-}
-
-static void
-force_attach_to_pcon (HANDLE h)
-{
-  bool attach_done = false;
-  for (int n = 0; n < 2; n ++)
-    {
-      /* First time, attach to the pty whose handle value is match.
-	 Second time, try to attach to any pty. */
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	    if (!ptys->get_pseudo_console ())
-	      continue;
-	    if (n != 0
-		|| h == ptys->get_handle ()
-		|| h == ptys->get_output_handle ())
-	      {
-		if (fhandler_console::get_console_process_id
-				  (ptys->get_helper_process_id (), true))
-		  attach_done = true;
-		else
-		  {
-		    FreeConsole ();
-		    if (AttachConsole (ptys->get_helper_process_id ()))
-		      {
-			pcon_attached_to = ptys->get_minor ();
-			attach_done = true;
-		      }
-		    else
-		      pcon_attached_to = -1;
-		  }
-		break;
-	      }
-	  }
-	else if (cfd->get_major () == DEV_CONS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_console *cons = (fhandler_console *) fh;
-	    if (n != 0
-		|| h == cons->get_handle ()
-		|| h == cons->get_output_handle ())
-	      {
-		/* If the process is running on a console,
-		   the parent process should be attached
-		   to the same console. */
-		DWORD attach_wpid;
-		if (myself->ppid == 1)
-		  attach_wpid = ATTACH_PARENT_PROCESS;
-		else
-		  {
-		    pinfo p (myself->ppid);
-		    attach_wpid = p->dwProcessId;
-		  }
-		FreeConsole ();
-		if (AttachConsole (attach_wpid))
-		  {
-		    pcon_attached_to = -1;
-		    attach_done = true;
-		  }
-		else
-		  pcon_attached_to = -1;
-		break;
-	      }
-	  }
-      if (attach_done)
-	break;
-    }
-}
-
-void
-set_ishybrid_and_switch_to_pcon (HANDLE h)
-{
-  if (GetFileType (h) == FILE_TYPE_CHAR)
-    {
-      force_attach_to_pcon (h);
-      DWORD dummy;
-      if (!isHybrid && (GetConsoleMode (h, &dummy)
-			|| GetLastError () != ERROR_INVALID_HANDLE))
-	{
-	  isHybrid = true;
-	  set_switch_to_pcon ();
-	}
-    }
-}
-
-inline void
-fhandler_pty_slave::free_attached_console ()
-{
-  bool attached = get_ttyp () ?
-    fhandler_console::get_console_process_id (get_helper_process_id (), true)
-    : (get_minor () == pcon_attached_to);
-  if (freeconsole_on_close && attached)
-    {
-      FreeConsole ();
-      pcon_attached_to = -1;
-    }
 }
 
 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
-DEF_HOOK (WriteFile);
-DEF_HOOK (WriteConsoleA);
-DEF_HOOK (WriteConsoleW);
-DEF_HOOK (ReadFile);
-DEF_HOOK (ReadConsoleA);
-DEF_HOOK (ReadConsoleW);
-DEF_HOOK (WriteConsoleOutputA);
-DEF_HOOK (WriteConsoleOutputW);
-DEF_HOOK (WriteConsoleOutputCharacterA);
-DEF_HOOK (WriteConsoleOutputCharacterW);
-DEF_HOOK (WriteConsoleOutputAttribute);
-DEF_HOOK (SetConsoleCursorPosition);
-DEF_HOOK (SetConsoleTextAttribute);
-DEF_HOOK (WriteConsoleInputA);
-DEF_HOOK (WriteConsoleInputW);
-DEF_HOOK (ReadConsoleInputA);
-DEF_HOOK (ReadConsoleInputW);
-DEF_HOOK (PeekConsoleInputA);
-DEF_HOOK (PeekConsoleInputW);
 /* CreateProcess() is hooked for GDB etc. */
 DEF_HOOK (CreateProcessA);
 DEF_HOOK (CreateProcessW);
 
-static BOOL WINAPI
-WriteFile_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleA_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleW_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadFile_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleA_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleW_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleOutputA_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputA_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputW_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputW_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterA_Hooked
-     (HANDLE h, LPCSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterA_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterW_Hooked
-     (HANDLE h, LPCWSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterW_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputAttribute_Hooked
-     (HANDLE h, CONST WORD *a, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputAttribute_Orig (h, a, l, c, n);
-}
-static BOOL WINAPI
-SetConsoleCursorPosition_Hooked
-     (HANDLE h, COORD c)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleCursorPosition_Orig (h, c);
-}
-static BOOL WINAPI
-SetConsoleTextAttribute_Hooked
-     (HANDLE h, WORD a)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleTextAttribute_Orig (h, a);
-}
-static BOOL WINAPI
-WriteConsoleInputA_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-WriteConsoleInputW_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputW_Orig (h, r, l, n);
-}
-/* CreateProcess() is hooked for GDB etc. */
 static BOOL WINAPI
 CreateProcessA_Hooked
      (LPCSTR n, LPSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
@@ -363,11 +88,14 @@ CreateProcessA_Hooked
       LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 static BOOL WINAPI
@@ -377,11 +105,14 @@ CreateProcessW_Hooked
       LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 
@@ -464,10 +195,6 @@ fhandler_pty_master::flush_to_slave ()
 {
   if (get_readahead_valid () && !(get_ttyp ()->ti.c_lflag & ICANON))
     accept_input ();
-  WaitForSingleObject (input_mutex, INFINITE);
-  if (!get_ttyp ()->pcon_in_empty && !(get_ttyp ()->ti.c_lflag & ICANON))
-    SetEvent (input_available_event);
-  ReleaseMutex (input_mutex);
 }
 
 DWORD
@@ -532,14 +259,6 @@ fhandler_pty_master::doecho (const void *str, DWORD len)
   release_output_mutex ();
 }
 
-int
-fhandler_pty_master::put_readahead (char value)
-{
-  if (to_be_read_from_pcon ())
-    return 1;
-  return fhandler_base::put_readahead (value);
-}
-
 int
 fhandler_pty_master::accept_input ()
 {
@@ -551,9 +270,11 @@ fhandler_pty_master::accept_input ()
   char *p = rabuf () + raixget ();
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
   if (to_be_read_from_pcon ())
-    ; /* Do nothing */
-  else if (!bytes_left)
+    write_to = to_slave;
+
+  if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
@@ -564,10 +285,10 @@ fhandler_pty_master::accept_input ()
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -725,52 +446,12 @@ out:
 
 fhandler_pty_slave::fhandler_pty_slave (int unit)
   : fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL),
-  io_handle_cyg (NULL), pid_restore (0), fd (-1)
+  io_handle_cyg (NULL)
 {
   if (unit >= 0)
     dev ().parse (DEV_PTYS_MAJOR, unit);
 }
 
-fhandler_pty_slave::~fhandler_pty_slave ()
-{
-  if (!get_ttyp ())
-    {
-      /* Why comes here? Who clears _tc? */
-      free_attached_console ();
-      return;
-    }
-  if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 0)
-	{
-	  pcon_attached_to = -1;
-	  last_ttyp = get_ttyp ();
-	}
-      if (used == 0)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
-}
-
 int
 fhandler_pty_slave::open (int flags, mode_t)
 {
@@ -833,8 +514,8 @@ fhandler_pty_slave::open (int flags, mode_t)
     release_output_mutex ();
   }
 
-  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg () ||
-      !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
+  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg ()
+      || !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
     {
       errmsg = "pty handles have been closed";
       set_errno (EACCES);
@@ -923,8 +604,8 @@ fhandler_pty_slave::open (int flags, mode_t)
       from_master_cyg_local = repl.from_master_cyg;
       to_master_local = repl.to_master;
       to_master_cyg_local = repl.to_master_cyg;
-      if (!from_master_local || !from_master_cyg_local ||
-	  !to_master_local || !to_master_cyg_local)
+      if (!from_master_local || !from_master_cyg_local
+	  || !to_master_local || !to_master_cyg_local)
 	{
 	  SetLastError (repl.error);
 	  errmsg = "error duplicating pipes, %E";
@@ -950,24 +631,7 @@ fhandler_pty_slave::open (int flags, mode_t)
   set_output_handle (to_master_local);
   set_output_handle_cyg (to_master_cyg_local);
 
-  if (!get_pseudo_console ())
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (!fhandler_console::get_console_process_id
-			       (GetCurrentProcessId (), true))
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (fhandler_console::get_console_process_id
-			       (get_helper_process_id (), true))
-    /* Attached to pcon of this pty */
-    {
-      pcon_attached_to = get_minor ();
-      init_console_handler (true);
-    }
+  fhandler_console::need_invisible ();
 
   set_open_status ();
   return 1;
@@ -1021,8 +685,7 @@ fhandler_pty_slave::close ()
   if (!ForceCloseHandle (get_handle_cyg ()))
     termios_printf ("CloseHandle (get_handle_cyg ()<%p>), %E",
 	get_handle_cyg ());
-  if (!get_pseudo_console () &&
-      (unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
+  if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
     fhandler_console::free_console ();	/* assumes that we are the last pty closer */
   fhandler_pty_common::close ();
   if (!ForceCloseHandle (output_mutex))
@@ -1070,423 +733,31 @@ fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
   return ret;
 }
 
-bool
-fhandler_pty_slave::try_reattach_pcon (void)
-{
-  pid_restore = 0;
-
-  /* Do not detach from the console because re-attaching will
-     fail if helper process is running as service account. */
-  if (get_ttyp()->attach_pcon_in_fork)
-    return false;
-  if (pcon_attached_to >= 0 &&
-      cygwin_shared->tty[pcon_attached_to]->attach_pcon_in_fork)
-    return false;
-
-  pid_restore =
-    fhandler_console::get_console_process_id (GetCurrentProcessId (),
-					      false);
-  /* If pid_restore is not set, give up. */
-  if (!pid_restore)
-    return false;
-
-  FreeConsole ();
-  if (!AttachConsole (get_helper_process_id ()))
-    {
-      system_printf ("pty%d: AttachConsole(helper=%d) failed. 0x%08lx",
-		     get_minor (), get_helper_process_id (), GetLastError ());
-      return false;
-    }
-  return true;
-}
-
 void
-fhandler_pty_slave::restore_reattach_pcon (void)
+fhandler_pty_slave::set_switch_to_pcon (void)
 {
-  if (pid_restore)
+  if (!get_ttyp ()->switch_to_pcon_in)
     {
-      FreeConsole ();
-      if (!AttachConsole (pid_restore))
-	{
-	  system_printf ("pty%d: AttachConsole(restore=%d) failed. 0x%08lx",
-			 get_minor (), pid_restore, GetLastError ());
-	  pcon_attached_to = -1;
-	}
-    }
-  pid_restore = 0;
-}
-
-/* This function requests transfering the input data from the input
-   pipe for cygwin apps to the other input pipe for native apps. */
-void
-fhandler_pty_slave::pull_pcon_input (void)
-{
-  get_ttyp ()->req_transfer_input_to_pcon = true;
-  while (get_ttyp ()->req_transfer_input_to_pcon)
-    Sleep (1);
-}
-
-void
-fhandler_pty_slave::update_pcon_input_state (bool need_lock)
-{
-  if (need_lock)
-    WaitForSingleObject (input_mutex, INFINITE);
-  /* Flush input buffer if it is requested by master.
-     This happens if ^C is pressed in pseudo console side. */
-  if (get_ttyp ()->req_flush_pcon_input)
-    {
-      FlushConsoleInputBuffer (get_handle ());
-      get_ttyp ()->req_flush_pcon_input = false;
-    }
-  /* Peek console input buffer and update state. */
-  INPUT_RECORD inp[INREC_SIZE];
-  DWORD n;
-  BOOL (WINAPI *PeekFunc)
-    (HANDLE, PINPUT_RECORD, DWORD, LPDWORD);
-  PeekFunc =
-    PeekConsoleInputA_Orig ? : PeekConsoleInput;
-  PeekFunc (get_handle (), inp, INREC_SIZE, &n);
-  bool saw_accept = false;
-  bool pipe_empty = true;
-  while (n-- > 0)
-    if (inp[n].EventType == KEY_EVENT && inp[n].Event.KeyEvent.bKeyDown &&
-	inp[n].Event.KeyEvent.uChar.AsciiChar)
-      {
-	pipe_empty = false;
-	char c = inp[n].Event.KeyEvent.uChar.AsciiChar;
-	const char sigs[] = {
-	  (char) get_ttyp ()->ti.c_cc[VINTR],
-	  (char) get_ttyp ()->ti.c_cc[VQUIT],
-	  (char) get_ttyp ()->ti.c_cc[VSUSP],
-	};
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n',
-	  '\r'
-	};
-	if (is_line_input () && c && memchr (eols, c, sizeof (eols)))
-	  saw_accept = true;
-	if ((get_ttyp ()->ti.c_lflag & ISIG)
-	    && c && memchr (sigs, c, sizeof (sigs)))
-	  saw_accept = true;
-      }
-  get_ttyp ()->pcon_in_empty = pipe_empty && !(ralen () > raixget ());
-  if (!get_readahead_valid () &&
-      (pipe_empty || (is_line_input () && !saw_accept)) &&
-      get_ttyp ()->read_retval == 1 && bytes_available (n) && n == 0)
-    ResetEvent (input_available_event);
-  if (need_lock)
-    ReleaseMutex (input_mutex);
-}
-
-int
-fhandler_pty_slave::eat_readahead (int n)
-{
-  int oralen = ralen ();
-  if (n < 0)
-    n = ralen () - raixget ();
-  if (n > 0 && ralen () > raixget ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      while (n > 0 && ralen () > raixget ())
-	{
-	  if (is_line_input () && rabuf ()[ralen ()-1]
-	      && memchr (eols, rabuf ()[ralen ()-1], sizeof (eols)))
-	    break;
-	  -- n;
-	  -- ralen ();
-	}
-
-      /* If IUTF8 is set, the terminal is in UTF-8 mode.  If so, we erase
-	 a complete UTF-8 multibyte sequence on VERASE/VWERASE.  Otherwise,
-	 if we only erase a single byte, invalid unicode chars are left in
-	 the input. */
-      if (get_ttyp ()->ti.c_iflag & IUTF8)
-	while (ralen () > raixget () &&
-	       ((unsigned char) rabuf ()[ralen ()] & 0xc0) == 0x80)
-	  --ralen ();
-    }
-  oralen = oralen - ralen ();
-  if (raixget () >= ralen ())
-    raixget () = raixput () = ralen () = 0;
-  else if (raixput () > ralen ())
-    raixput () = ralen ();
-
-  return oralen;
-}
-
-int
-fhandler_pty_slave::get_readahead_into_buffer (char *buf, size_t buflen)
-{
-  int ch;
-  int copied_chars = 0;
-
-  while (buflen)
-    if ((ch = get_readahead ()) < 0)
-      break;
-    else
-      {
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n'
-	};
-	buf[copied_chars++] = (unsigned char)(ch & 0xff);
-	buflen--;
-	if (is_line_input () && ch && memchr (eols, ch & 0xff, sizeof (eols)))
-	  break;
-      }
-
-  return copied_chars;
-}
-
-bool
-fhandler_pty_slave::get_readahead_valid (void)
-{
-  if (is_line_input ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      for (size_t i=raixget (); i<ralen (); i++)
-	if (rabuf ()[i] && memchr (eols, rabuf ()[i], sizeof (eols)))
-	  return true;
-      return false;
-    }
-  else
-    return ralen () > raixget ();
-}
-
-void
-fhandler_pty_slave::set_switch_to_pcon (int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  acquire_output_mutex (INFINITE);
-  if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
-    {
-      pull_pcon_input ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
+      isHybrid = true;
+      if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
 	get_ttyp ()->pcon_pid = myself->pid;
       get_ttyp ()->switch_to_pcon_in = true;
-      if (isHybrid && !get_ttyp ()->switch_to_pcon_out)
-	{
-	  get_ttyp ()->wait_pcon_fwd ();
-	  get_ttyp ()->switch_to_pcon_out = true;
-	}
     }
-  else if ((fd == 1 || fd == 2) && !get_ttyp ()->switch_to_pcon_out)
-    {
-      get_ttyp ()->wait_pcon_fwd ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
-	get_ttyp ()->pcon_pid = myself->pid;
-      get_ttyp ()->switch_to_pcon_out = true;
-      if (isHybrid)
-	get_ttyp ()->switch_to_pcon_in = true;
-    }
-  release_output_mutex ();
 }
 
 void
 fhandler_pty_slave::reset_switch_to_pcon (void)
 {
-  if (get_ttyp ()->pcon_pid &&
-      get_ttyp ()->pcon_pid != myself->pid &&
-      !!pinfo (get_ttyp ()->pcon_pid))
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
     /* There is a process which is grabbing pseudo console. */
     return;
   if (isHybrid)
     return;
-  if (do_not_reset_switch_to_pcon)
-    return;
-  acquire_output_mutex (INFINITE);
-  if (get_ttyp ()->switch_to_pcon_out)
-    /* Wait for pty_master_fwd_thread() */
-    get_ttyp ()->wait_pcon_fwd ();
   get_ttyp ()->pcon_pid = 0;
   get_ttyp ()->switch_to_pcon_in = false;
-  get_ttyp ()->switch_to_pcon_out = false;
-  release_output_mutex ();
-  init_console_handler (true);
-}
-
-void
-fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len,
-					       bool is_echo)
-{
-  bool attached =
-    !!fhandler_console::get_console_process_id (get_helper_process_id (), true);
-  if (!attached && pcon_attached_to == get_minor ())
-    {
-      for (DWORD t0 = GetTickCount (); GetTickCount () - t0 < 100; )
-	{
-	  Sleep (1);
-	  attached = fhandler_console::get_console_process_id
-				      (get_helper_process_id (), true);
-	  if (attached)
-	    break;
-	}
-      if (!attached)
-	{
-	  system_printf ("pty%d: pcon_attach_to mismatch??????", get_minor ());
-	  return;
-	}
-    }
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  if (pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      goto detach;
-
-  char *buf;
-  size_t nlen;
-  DWORD origCP;
-  origCP = GetConsoleOutputCP ();
-  SetConsoleOutputCP (get_ttyp ()->term_code_page);
-  /* Just copy */
-  buf = (char *) HeapAlloc (GetProcessHeap (), 0, len);
-  memcpy (buf, (char *)ptr, len);
-  nlen = len;
-  char *p0, *p1;
-  p0 = p1 = buf;
-  /* Remove alternate screen buffer drawing */
-  while (p0 && p1)
-    {
-      if (!get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to alternate screen buffer */
-	  p0 = (char *) memmem (p1, nlen - (p1-buf), "\033[?1049h", 8);
-	  if (p0)
-	    {
-	      //p0 += 8;
-	      get_ttyp ()->screen_alternated = true;
-	      if (get_ttyp ()->switch_to_pcon_out)
-		do_not_reset_switch_to_pcon = true;
-	    }
-	}
-      if (get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to main screen buffer */
-	  p1 = (char *) memmem (p0, nlen - (p0-buf), "\033[?1049l", 8);
-	  if (p1)
-	    {
-	      p1 += 8;
-	      get_ttyp ()->screen_alternated = false;
-	      do_not_reset_switch_to_pcon = false;
-	      memmove (p0, p1, buf+nlen - p1);
-	      nlen -= p1 - p0;
-	    }
-	  else
-	    nlen = p0 - buf;
-	}
-    }
-  if (!nlen) /* Nothing to be synchronized */
-    goto cleanup;
-  if (get_ttyp ()->switch_to_pcon_out && !is_echo)
-    goto cleanup;
-  /* Remove ESC sequence which returns results to console
-     input buffer. Without this, cursor position report
-     is put into the input buffer as a garbage. */
-  /* Remove ESC sequence to report cursor position. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[6n", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-  /* Remove ESC sequence to report terminal identity. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[0c", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-
-  /* If the ESC sequence ESC[?3h or ESC[?3l which clears console screen
-     buffer is pushed, set need_redraw_screen to trigger redraw screen. */
-  p0 = buf;
-  while ((p0 = (char *) memmem (p0, nlen - (p0 - buf), "\033[?", 3)))
-    {
-      p0 += 3;
-      bool exist_arg_3 = false;
-      while (p0 < buf + nlen && (isdigit (*p0) || *p0 == ';'))
-	{
-	  int arg = 0;
-	  while (p0 < buf + nlen && isdigit (*p0))
-	    arg = arg * 10 + (*p0 ++) - '0';
-	  if (arg == 3)
-	    exist_arg_3 = true;
-	  if (p0 < buf + nlen && *p0 == ';')
-	    p0 ++;
-	}
-      if (p0 < buf + nlen && exist_arg_3 && (*p0 == 'h' || *p0 == 'l'))
-	get_ttyp ()->need_redraw_screen = true;
-      p0 ++;
-      if (p0 >= buf + nlen)
-	break;
-    }
-
-  int retry_count;
-  retry_count = 0;
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  while (!GetConsoleMode (get_output_handle (), &dwMode))
-    {
-      termios_printf ("GetConsoleMode failed, %E");
-      int errno_save = errno;
-      /* Re-open handles */
-      this->open (0, 0);
-      /* Fix pseudo console window size */
-      this->ioctl (TIOCSWINSZ, &get_ttyp ()->winsize);
-      if (errno != errno_save)
-	set_errno (errno_save);
-      if (++retry_count > 3)
-	goto cleanup;
-    }
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-  char *p;
-  p = buf;
-  DWORD wLen, written;
-  written = 0;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
-  while (written <  nlen)
-    {
-      if (!WriteFunc (get_output_handle (), p, nlen - written, &wLen, NULL))
-	{
-	  termios_printf ("WriteFile failed, %E");
-	  break;
-	}
-      else
-	{
-	  written += wLen;
-	  p += wLen;
-	}
-    }
-  /* Detach from pseudo console and resume. */
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-cleanup:
-  SetConsoleOutputCP (origCP);
-  HeapFree (GetProcessHeap (), 0, buf);
-detach:
-  restore_reattach_pcon ();
+  get_ttyp ()->h_pseudo_console = NULL;
+  get_ttyp ()->pcon_start = false;
 }
 
 ssize_t __stdcall
@@ -1505,44 +776,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
   reset_switch_to_pcon ();
 
   acquire_output_mutex (INFINITE);
-  bool output_to_pcon = get_ttyp ()->switch_to_pcon_out;
-  release_output_mutex ();
-
-  UINT target_code_page = output_to_pcon ?
-    GetConsoleOutputCP () : get_ttyp ()->term_code_page;
-  ssize_t nlen;
-  char *buf = convert_mb_str (target_code_page, (size_t *) &nlen,
-		 get_ttyp ()->term_code_page, (const char *) ptr, len);
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  bool fallback = false;
-  if (output_to_pcon && pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      fallback = true;
-
-  if (output_to_pcon && !fallback &&
-      (memmem (buf, nlen, "\033[6n", 4) || memmem (buf, nlen, "\033[0c", 4)))
-    {
-      get_ttyp ()->pcon_in_empty = false;
-      if (!is_line_input ())
-	SetEvent (input_available_event);
-    }
-
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  if (output_to_pcon && !fallback)
-    {
-      GetConsoleMode (get_output_handle (), &dwMode);
-      SetConsoleMode (get_output_handle (), dwMode | flags);
-    }
-  HANDLE to = (output_to_pcon && !fallback) ?
-    get_output_handle () : get_output_handle_cyg ();
-  acquire_output_mutex (INFINITE);
-  if (!process_opost_output (to, buf, nlen, false))
+  if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false))
     {
       DWORD err = GetLastError ();
       termios_printf ("WriteFile failed, %E");
@@ -1557,20 +791,6 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
       towrite = -1;
     }
   release_output_mutex ();
-  mb_str_free (buf);
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (output_to_pcon && !fallback)
-    SetConsoleMode (get_output_handle (), dwMode | flags);
-
-  restore_reattach_pcon ();
-
-  /* Push slave output to pseudo console screen buffer */
-  if (get_pseudo_console ())
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer ((char *)ptr, len, false);
-      release_output_mutex ();
-    }
 
   return towrite;
 }
@@ -1582,16 +802,15 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 }
 
 bool
-fhandler_pty_common::to_be_read_from_pcon (void)
+fhandler_pty_master::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return get_ttyp ()->pcon_start
+    || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
 fhandler_pty_slave::read (void *ptr, size_t& len)
 {
-  char *ptr0 = (char *)ptr;
   ssize_t totalread = 0;
   int vmin = 0;
   int vtime = 0;	/* Initialized to prevent -Wuninitialized warning */
@@ -1616,8 +835,6 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
       mask_switch_to_pcon_in (true);
       reset_switch_to_pcon ();
     }
-  if (to_be_read_from_pcon ())
-    update_pcon_input_state (true);
 
   if (is_nonblocking () || !ptr) /* Indicating tcflush(). */
     time_to_wait = 0;
@@ -1703,98 +920,21 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 	      if (!totalread)
 		{
 		  set_sig_errno (EAGAIN);
-		  totalread = -1;
-		}
-	      goto out;
-	    }
-	  continue;
-	default:
-	  termios_printf ("wait for input mutex failed, %E");
-	  if (!totalread)
-	    {
-	      __seterrno ();
-	      totalread = -1;
-	    }
-	  goto out;
-	}
-      if (ptr && to_be_read_from_pcon ())
-	{
-	  if (get_readahead_valid ())
-	    {
-	      ReleaseMutex (input_mutex);
-	      totalread = get_readahead_into_buffer ((char *) ptr, len);
-	    }
-	  else
-	    {
-	      if (!try_reattach_pcon ())
-		{
-		  restore_reattach_pcon ();
-		  goto do_read_cyg;
-		}
-
-	      DWORD dwMode;
-	      GetConsoleMode (get_handle (), &dwMode);
-	      DWORD flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
-	      if (dwMode != flags)
-		SetConsoleMode (get_handle (), flags);
-	      /* Read get_handle() instad of get_handle_cyg() */
-	      BOOL (WINAPI *ReadFunc)
-		(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID);
-	      ReadFunc = ReadConsoleA_Orig ? ReadConsoleA_Orig : ReadConsoleA;
-	      DWORD rlen;
-	      readlen = MIN (len, sizeof (buf));
-	      if (!ReadFunc (get_handle (), buf, readlen, &rlen, NULL))
-		{
-		  termios_printf ("read failed, %E");
-		  SetConsoleMode (get_handle (), dwMode);
-		  restore_reattach_pcon ();
-		  ReleaseMutex (input_mutex);
-		  set_errno (EIO);
-		  totalread = -1;
-		  goto out;
-		}
-	      SetConsoleMode (get_handle (), dwMode);
-	      restore_reattach_pcon ();
-	      ReleaseMutex (input_mutex);
-
-	      ssize_t nlen;
-	      char *nbuf = convert_mb_str (get_ttyp ()->term_code_page,
-			     (size_t *) &nlen, GetConsoleCP (), buf, rlen);
-
-	      ssize_t ret;
-	      line_edit_status res =
-		line_edit (nbuf, nlen, get_ttyp ()->ti, &ret);
-
-	      mb_str_free (nbuf);
-
-	      if (res == line_edit_input_done || res == line_edit_ok)
-		totalread = get_readahead_into_buffer ((char *) ptr, len);
-	      else if (res > line_edit_signalled)
-		{
-		  set_sig_errno (EINTR);
-		  totalread = -1;
-		}
-	      else
-		{
-		  update_pcon_input_state (true);
-		  continue;
+		  totalread = -1;
 		}
+	      goto out;
+	    }
+	  continue;
+	default:
+	  termios_printf ("wait for input mutex failed, %E");
+	  if (!totalread)
+	    {
+	      __seterrno ();
+	      totalread = -1;
 	    }
-
-	  update_pcon_input_state (true);
-	  mask_switch_to_pcon_in (false);
 	  goto out;
 	}
-      if (!ptr && len == UINT_MAX && !get_ttyp ()->pcon_in_empty)
-	{
-	  FlushConsoleInputBuffer (get_handle ());
-	  get_ttyp ()->pcon_in_empty = true;
-	  DWORD n;
-	  if (bytes_available (n) && n == 0)
-	    ResetEvent (input_available_event);
-	}
 
-do_read_cyg:
       if (!bytes_available (bytes_in_pipe))
 	{
 	  ReleaseMutex (input_mutex);
@@ -1911,16 +1051,6 @@ do_read_cyg:
 out:
   termios_printf ("%d = read(%p, %lu)", totalread, ptr, len);
   len = (size_t) totalread;
-  /* Push slave read as echo to pseudo console screen buffer. */
-  if (get_pseudo_console () && ptr0 && totalread > 0 &&
-      (get_ttyp ()->ti.c_lflag & ECHO))
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer (ptr0, len, true);
-      if (get_ttyp ()->switch_to_pcon_out)
-	trigger_redraw_screen ();
-      release_output_mutex ();
-    }
   mask_switch_to_pcon_in (false);
 }
 
@@ -2061,38 +1191,11 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
       get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
       break;
     case TIOCSWINSZ:
-      if (get_pseudo_console ())
-	{
-	  /* If not attached to this pseudo console,
-	     try to attach temporarily. */
-	  pid_restore = 0;
-	  if (pcon_attached_to != get_minor ())
-	    if (!try_reattach_pcon ())
-	      goto cleanup;
-
-	  COORD size;
-	  size.X = ((struct winsize *) arg)->ws_col;
-	  size.Y = ((struct winsize *) arg)->ws_row;
-	  CONSOLE_SCREEN_BUFFER_INFO csbi;
-	  if (GetConsoleScreenBufferInfo (get_output_handle (), &csbi))
-	    if (size.X == csbi.srWindow.Right - csbi.srWindow.Left + 1 &&
-		size.Y == csbi.srWindow.Bottom - csbi.srWindow.Top + 1)
-	      goto cleanup;
-	  if (!SetConsoleScreenBufferSize (get_output_handle (), size))
-	    goto cleanup;
-	  SMALL_RECT rect;
-	  rect.Left = 0;
-	  rect.Top = 0;
-	  rect.Right = size.X-1;
-	  rect.Bottom = size.Y-1;
-	  SetConsoleWindowInfo (get_output_handle (), TRUE, &rect);
-cleanup:
-	  restore_reattach_pcon ();
-	}
-
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->arg.winsize = *(struct winsize *) arg;
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
@@ -2378,6 +1481,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2393,7 +1517,6 @@ fhandler_pty_master::close ()
 {
   OBJECT_BASIC_INFORMATION obi;
   NTSTATUS status;
-  pid_t master_pid_tmp = get_ttyp ()->master_pid;
 
   termios_printf ("closing from_master(%p)/from_master_cyg(%p)/to_master(%p)/to_master_cyg(%p) since we own them(%u)",
 		  from_master, from_master_cyg,
@@ -2438,30 +1561,6 @@ fhandler_pty_master::close ()
   else if (obi.HandleCount == 1)
     {
       termios_printf ("Closing last master of pty%d", get_minor ());
-      /* Close Pseudo Console */
-      if (get_pseudo_console ())
-	{
-	  /* Terminate helper process */
-	  SetEvent (get_ttyp ()->h_helper_goodbye);
-	  WaitForSingleObject (get_ttyp ()->h_helper_process, INFINITE);
-	  CloseHandle (get_ttyp ()->h_helper_goodbye);
-	  CloseHandle (get_ttyp ()->h_helper_process);
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (master_pid_tmp == myself->pid)
-	    {
-	      /* ClosePseudoConsole() seems to have a bug that one
-		 internal handle remains opened. This causes handle leak.
-		 This is a workaround for this problem. */
-	      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_pseudo_console ();
-	      HANDLE tmp = hp->hConHostProcess;
-	      /* Release pseudo console */
-	      ClosePseudoConsole (get_pseudo_console ());
-	      CloseHandle (tmp);
-	    }
-	  get_ttyp ()->switch_to_pcon_in = false;
-	  get_ttyp ()->switch_to_pcon_out = false;
-	}
       if (get_ttyp ()->getsid () > 0)
 	kill (get_ttyp ()->getsid (), SIGHUP);
       SetEvent (input_available_event);
@@ -2469,9 +1568,8 @@ fhandler_pty_master::close ()
 
   if (!ForceCloseHandle (from_master))
     termios_printf ("error closing from_master %p, %E", from_master);
-  if (from_master_cyg != from_master) /* Avoid double close. */
-    if (!ForceCloseHandle (from_master_cyg))
-      termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
+  if (!ForceCloseHandle (from_master_cyg))
+    termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
   if (!ForceCloseHandle (to_master))
     termios_printf ("error closing to_master %p, %E", to_master);
   from_master = to_master = NULL;
@@ -2513,7 +1611,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon () && get_ttyp ()->h_pseudo_console)
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2521,40 +1619,50 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
       WaitForSingleObject (input_mutex, INFINITE);
 
-      if (memchr (buf, '\003', nlen)) /* ^C intr key in pcon */
-	get_ttyp ()->req_flush_pcon_input = true;
-
       DWORD wLen;
-      WriteFile (to_slave, buf, nlen, &wLen, NULL);
-      get_ttyp ()->pcon_in_empty = false;
-
-      ReleaseMutex (input_mutex);
 
-      /* Use line_edit () in order to set input_available_event. */
-      bool is_echo = tc ()->ti.c_lflag & ECHO;
-      if (!get_ttyp ()->mask_switch_to_pcon_in)
+      if (get_ttyp ()->pcon_start)
 	{
-	  tc ()->ti.c_lflag &= ~ECHO;
-	  ti.c_lflag &= ~ECHO;
-	}
-      ti.c_lflag &= ~ISIG;
-      line_edit (buf, nlen, ti, &ret);
-      if (is_echo)
-	tc ()->ti.c_lflag |= ECHO;
-      get_ttyp ()->read_retval = 1;
-
-      const char sigs[] = {
-	(char) ti.c_cc[VINTR],
-	(char) ti.c_cc[VQUIT],
-	(char) ti.c_cc[VSUSP],
-      };
-      if (tc ()->ti.c_lflag & ISIG)
-	for (size_t i=0; i<sizeof (sigs); i++)
-	  if (sigs[i] && memchr (buf, sigs[i], nlen))
+	  /* Pseudo condole support uses "CSI6n" to get cursor position.
+	     If the reply for "CSI6n" is divided into multiple writes,
+	     pseudo console sometimes does not recognize it.  Therefore,
+	     put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon_start = false;
+	    }
+	  else
 	    {
-	      eat_readahead (-1);
-	      SetEvent (input_available_event);
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
 	    }
+	}
+
+      WriteFile (to_slave, buf, nlen, &wLen, NULL);
+
+      ReleaseMutex (input_mutex);
 
       mb_str_free (buf);
       return len;
@@ -2630,15 +1738,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (get_pseudo_console () && get_ttyp ()->master_pid == myself->pid)
-	    {
-	      COORD size;
-	      size.X = ((struct winsize *) arg)->ws_col;
-	      size.Y = ((struct winsize *) arg)->ws_row;
-	      ResizePseudoConsole (get_pseudo_console (), size);
-	    }
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
 	}
@@ -2763,7 +1864,7 @@ get_locale_from_env (char *locale)
   strcpy (locale, env);
 }
 
-static LCID
+static void
 get_langinfo (char *locale_out, char *charset_out)
 {
   /* Get locale from environment */
@@ -2776,11 +1877,6 @@ get_langinfo (char *locale_out, char *charset_out)
   if (!locale)
     locale = "C";
 
-  char tmp_locale[ENCODING_LEN + 1];
-  char *ret = __set_locale_from_locale_alias (locale, tmp_locale);
-  if (ret)
-    locale = tmp_locale;
-
   const char *charset;
   struct lc_ctype_T *lc_ctype = (struct lc_ctype_T *) loc.lc_cat[LC_CTYPE].ptr;
   if (!lc_ctype)
@@ -2830,23 +1926,9 @@ get_langinfo (char *locale_out, char *charset_out)
       charset = "CP932";
     }
 
-  wchar_t lc[ENCODING_LEN + 1];
-  wchar_t *p;
-  mbstowcs (lc, locale, ENCODING_LEN);
-  p = wcschr (lc, L'.');
-  if (p)
-    *p = L'\0';
-  p = wcschr (lc, L'_');
-  if (p)
-    *p = L'-';
-  LCID lcid = LocaleNameToLCID (lc, 0);
-  if (!lcid && !strcmp (charset, "ASCII"))
-    return 0;
-
   /* Set results */
   strcpy (locale_out, new_locale);
   strcpy (charset_out, charset);
-  return lcid;
 }
 
 void
@@ -2854,21 +1936,7 @@ fhandler_pty_slave::setup_locale (void)
 {
   char locale[ENCODING_LEN + 1] = "C";
   char charset[ENCODING_LEN + 1] = "ASCII";
-  LCID lcid = get_langinfo (locale, charset);
-
-  /* Set console code page form locale */
-  if (get_pseudo_console ())
-    {
-      UINT code_page;
-      if (lcid == 0 || lcid == (LCID) -1)
-	code_page = 20127; /* ASCII */
-      else if (!GetLocaleInfo (lcid,
-			       LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
-			       (char *) &code_page, sizeof (code_page)))
-	code_page = 20127; /* ASCII */
-      SetConsoleCP (code_page);
-      SetConsoleOutputCP (code_page);
-    }
+  get_langinfo (locale, charset);
 
   /* Set terminal code page from locale */
   /* This code is borrowed from mintty: charset.c */
@@ -2878,9 +1946,9 @@ fhandler_pty_slave::setup_locale (void)
     charset_u[i] = toupper (charset[i]);
   unsigned int iso;
   UINT cp = 20127; /* Default for fallback */
-  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859%u", &iso) == 1)
+  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859%u", &iso) == 1)
     {
       if (iso && iso <= 16 && iso !=12)
 	get_ttyp ()->term_code_page = 28590 + iso;
@@ -2896,90 +1964,9 @@ fhandler_pty_slave::setup_locale (void)
 	}
 }
 
-void
-fhandler_pty_slave::set_freeconsole_on_close (bool val)
-{
-  freeconsole_on_close = val;
-}
-
-void
-fhandler_pty_slave::trigger_redraw_screen (void)
-{
-  /* Forcibly redraw screen based on console screen buffer. */
-  /* The following code triggers redrawing the screen. */
-  CONSOLE_SCREEN_BUFFER_INFO sbi;
-  GetConsoleScreenBufferInfo (get_output_handle (), &sbi);
-  SMALL_RECT rect = {0, 0,
-    (SHORT) (sbi.dwSize.X -1), (SHORT) (sbi.dwSize.Y - 1)};
-  COORD dest = {0, 0};
-  CHAR_INFO fill = {' ', 0};
-  ScrollConsoleScreenBuffer (get_output_handle (), &rect, NULL, dest, &fill);
-  get_ttyp ()->need_redraw_screen = false;
-}
-
-void
-fhandler_pty_slave::fixup_after_attach (bool native_maybe, int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  if (get_pseudo_console ())
-    {
-      if (fhandler_console::get_console_process_id (get_helper_process_id (),
-						    true))
-	if (pcon_attached_to != get_minor ())
-	  {
-	    pcon_attached_to = get_minor ();
-	    init_console_handler (true);
-	  }
-
-#if 0 /* This is for debug only. */
-      isHybrid = true;
-      get_ttyp ()->switch_to_pcon_in = true;
-      get_ttyp ()->switch_to_pcon_out = true;
-#endif
-
-      if (pcon_attached_to == get_minor () && native_maybe)
-	{
-	  if (fd == 0)
-	    {
-	      pull_pcon_input ();
-	      DWORD mode =
-		ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	      SetConsoleMode (get_handle (), mode);
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_in = true;
-	    }
-	  else if (fd == 1 || fd == 2)
-	    {
-	      DWORD mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
-	      SetConsoleMode (get_output_handle (), mode);
-	      acquire_output_mutex (INFINITE);
-	      if (!get_ttyp ()->switch_to_pcon_out)
-		get_ttyp ()->wait_pcon_fwd ();
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_out = true;
-	      release_output_mutex ();
-
-	      if (get_ttyp ()->need_redraw_screen)
-		trigger_redraw_screen ();
-	    }
-	  init_console_handler (false);
-	}
-      else if (fd == 0 && native_maybe)
-	/* Read from unattached pseudo console cause freeze,
-	   therefore, fallback to legacy pty. */
-	set_handle (get_handle_cyg ());
-    }
-}
-
 void
 fhandler_pty_slave::fixup_after_fork (HANDLE parent)
 {
-  fixup_after_attach (false, -1);
   // fork_fixup (parent, inuse, "inuse");
   // fhandler_pty_common::fixup_after_fork (parent);
   report_tty_counts (this, "inherited", "");
@@ -2996,67 +1983,18 @@ fhandler_pty_slave::fixup_after_exec ()
 
   if (!close_on_exec ())
     fixup_after_fork (NULL);	/* No parent handle required. */
-  else if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 1 && get_minor () == pcon_attached_to)
-	pcon_attached_to = -1;
-      if (used == 1 /* About to close this tty */)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
 
   /* Hook Console API */
-  if (get_pseudo_console ())
-    {
 #define DO_HOOK(module, name) \
-      if (!name##_Orig) \
-	{ \
-	  void *api = hook_api (module, #name, (void *) name##_Hooked); \
-	  name##_Orig = (__typeof__ (name) *) api; \
-	  /*if (api) system_printf (#name " hooked.");*/ \
-	}
-      DO_HOOK (NULL, WriteFile);
-      DO_HOOK (NULL, WriteConsoleA);
-      DO_HOOK (NULL, WriteConsoleW);
-      DO_HOOK (NULL, ReadFile);
-      DO_HOOK (NULL, ReadConsoleA);
-      DO_HOOK (NULL, ReadConsoleW);
-      DO_HOOK (NULL, WriteConsoleOutputA);
-      DO_HOOK (NULL, WriteConsoleOutputW);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterA);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterW);
-      DO_HOOK (NULL, WriteConsoleOutputAttribute);
-      DO_HOOK (NULL, SetConsoleCursorPosition);
-      DO_HOOK (NULL, SetConsoleTextAttribute);
-      DO_HOOK (NULL, WriteConsoleInputA);
-      DO_HOOK (NULL, WriteConsoleInputW);
-      DO_HOOK (NULL, ReadConsoleInputA);
-      DO_HOOK (NULL, ReadConsoleInputW);
-      DO_HOOK (NULL, PeekConsoleInputA);
-      DO_HOOK (NULL, PeekConsoleInputW);
-      /* CreateProcess() is hooked for GDB etc. */
-      DO_HOOK (NULL, CreateProcessA);
-      DO_HOOK (NULL, CreateProcessW);
+  if (!name##_Orig) \
+    { \
+      void *api = hook_api (module, #name, (void *) name##_Hooked); \
+      name##_Orig = (__typeof__ (name) *) api; \
+      /*if (api) system_printf (#name " hooked.");*/ \
     }
+  /* CreateProcess() is hooked for GDB etc. */
+  DO_HOOK (NULL, CreateProcessA);
+  DO_HOOK (NULL, CreateProcessW);
 }
 
 /* This thread function handles the master control pipe.  It waits for a
@@ -3204,27 +2142,6 @@ reply:
   return 0;
 }
 
-void
-fhandler_pty_master::transfer_input_to_pcon (void)
-{
-  WaitForSingleObject (input_mutex, INFINITE);
-  DWORD n;
-  size_t transfered = 0;
-  while (::bytes_available (n, from_master_cyg) && n)
-    {
-      char buf[1024];
-      ReadFile (from_master_cyg, buf, sizeof (buf), &n, 0);
-      char *p = buf;
-      while ((p = (char *) memchr (p, '\n', n - (p - buf))))
-	*p = '\r';
-      if (WriteFile (to_slave, buf, n, &n, 0))
-	transfered += n;
-    }
-  if (transfered)
-    get_ttyp ()->pcon_in_empty = false;
-  ReleaseMutex (input_mutex);
-}
-
 static DWORD WINAPI
 pty_master_thread (VOID *arg)
 {
@@ -3240,23 +2157,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
   termios_printf ("Started.");
   for (;;)
     {
-      if (get_pseudo_console ())
-	{
-	  get_ttyp ()->pcon_last_time = GetTickCount ();
-	  while (::bytes_available (rlen, from_slave) && rlen == 0)
-	    {
-	      /* Forcibly transfer input if it is requested by slave.
-		 This happens when input data should be transfered
-		 from the input pipe for cygwin apps to the input pipe
-		 for native apps. */
-	      if (get_ttyp ()->req_transfer_input_to_pcon)
-		{
-		  transfer_input_to_pcon ();
-		  get_ttyp ()->req_transfer_input_to_pcon = false;
-		}
-	      Sleep (1);
-	    }
-	}
+      get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3264,14 +2165,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_ttyp ()->h_pseudo_console)
 	{
-	  /* Avoid duplicating slave output which is already sent to
-	     to_master_cyg */
-	  if (!get_ttyp ()->switch_to_pcon_out)
-	    continue;
-
-	  /* Avoid setting window title to "cygwin-console-helper.exe" */
+	  /* Remove CSI > Pm m */
 	  int state = 0;
 	  int start_at = 0;
 	  for (DWORD i=0; i<rlen; i++)
@@ -3281,43 +2177,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 		state = 1;
 		continue;
 	      }
-	    else if ((state == 1 && outbuf[i] == ']') ||
-		     (state == 2 && outbuf[i] == '0') ||
-		     (state == 3 && outbuf[i] == ';'))
-	      {
-		state ++;
-		continue;
-	      }
-	    else if (state == 4 && outbuf[i] == '\a')
-	      {
-		const char *helper_str = "\\bin\\cygwin-console-helper.exe";
-		if (memmem (&outbuf[start_at], i + 1 - start_at,
-			    helper_str, strlen (helper_str)))
-		  {
-		    memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
-		    rlen = wlen = start_at + rlen - i - 1;
-		  }
-		state = 0;
-		continue;
-	      }
-	    else if (outbuf[i] == '\a')
-	      {
-		state = 0;
-		continue;
-	      }
-
-	  /* Remove CSI > Pm m */
-	  state = 0;
-	  start_at = 0;
-	  for (DWORD i=0; i<rlen; i++)
-	    if (outbuf[i] == '\033')
-	      {
-		start_at = i;
-		state = 1;
-		continue;
-	      }
-	    else if ((state == 1 && outbuf[i] == '[') ||
-		     (state == 2 && outbuf[i] == '>'))
+	    else if ((state == 1 && outbuf[i] == '[')
+		     || (state == 2 && outbuf[i] == '>'))
 	      {
 		state ++;
 		continue;
@@ -3386,201 +2247,6 @@ pty_master_fwd_thread (VOID *arg)
   return ((fhandler_pty_master *) arg)->pty_master_fwd_thread ();
 }
 
-/* If master process is running as service, attaching to
-   pseudo console should be done in fork. If attaching
-   is done in spawn for inetd or sshd, it fails because
-   the helper process is running as privileged user while
-   slave process is not. This function is used to determine
-   if the process is running as a srvice or not. */
-inline static bool
-is_running_as_service (void)
-{
-  return check_token_membership (well_known_service_sid)
-    || cygheap->user.saved_sid () == well_known_system_sid;
-}
-
-bool
-fhandler_pty_master::setup_pseudoconsole ()
-{
-  if (disable_pcon)
-    return false;
-  /* If the legacy console mode is enabled, pseudo console seems
-     not to work as expected. To determine console mode, registry
-     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
-  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
-  if (reg.error ())
-    return false;
-  if (reg.get_dword (L"ForceV2", 1) == 0)
-    {
-      termios_printf ("Pseudo console is disabled "
-		      "because the legacy console mode is enabled.");
-      return false;
-    }
-
-  /* Pseudo console supprot is realized using a tricky technic.
-     PTY need the pseudo console handles, however, they cannot
-     be retrieved by normal procedure. Therefore, run a helper
-     process in a pseudo console and get them from the helper.
-     Slave process will attach to the pseudo console in the
-     helper process using AttachConsole(). */
-  COORD size = {
-    (SHORT) get_ttyp ()->winsize.ws_col,
-    (SHORT) get_ttyp ()->winsize.ws_row
-  };
-  CreatePipe (&from_master, &to_slave, &sec_none, 0);
-  SetLastError (ERROR_SUCCESS);
-  HRESULT res = CreatePseudoConsole (size, from_master, to_master,
-				     0, &get_ttyp ()->h_pseudo_console);
-  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
-    {
-      if (res != S_OK)
-	system_printf ("CreatePseudoConsole() failed. %08x\n",
-		       GetLastError ());
-      goto fallback;
-    }
-
-  /* If master process is running as service, attaching to
-     pseudo console should be done in fork. If attaching
-     is done in spawn for inetd or sshd, it fails because
-     the helper process is running as privileged user while
-     slave process is not. */
-  if (is_running_as_service ())
-    get_ttyp ()->attach_pcon_in_fork = true;
-
-  STARTUPINFOEXW si_helper;
-  HANDLE hello, goodbye;
-  HANDLE hr, hw;
-  PROCESS_INFORMATION pi_helper;
-  HANDLE hpConIn, hpConOut;
-  {
-    SIZE_T bytesRequired;
-    InitializeProcThreadAttributeList (NULL, 2, 0, &bytesRequired);
-    ZeroMemory (&si_helper, sizeof (si_helper));
-    si_helper.StartupInfo.cb = sizeof (STARTUPINFOEXW);
-    si_helper.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
-      HeapAlloc (GetProcessHeap (), 0, bytesRequired);
-    if (si_helper.lpAttributeList == NULL)
-      goto cleanup_pseudo_console;
-    if (!InitializeProcThreadAttributeList (si_helper.lpAttributeList,
-					    2, 0, &bytesRequired))
-      goto cleanup_heap;
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
-				    get_ttyp ()->h_pseudo_console,
-				    sizeof (get_ttyp ()->h_pseudo_console),
-				    NULL, NULL))
-      goto cleanup_heap;
-    /* Create events for start/stop helper process. */
-    hello = CreateEvent (&sec_none, true, false, NULL);
-    goodbye = CreateEvent (&sec_none, true, false, NULL);
-    /* Create a pipe for receiving pseudo console handles */
-    CreatePipe (&hr, &hw, &sec_none, 0);
-    /* Inherit only handles which are needed by helper. */
-    HANDLE handles_to_inherit[] = {hello, goodbye, hw};
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
-				    handles_to_inherit,
-				    sizeof (handles_to_inherit),
-				    NULL, NULL))
-      goto cleanup_event_and_pipes;
-    /* Create helper process */
-    WCHAR cmd[MAX_PATH];
-    path_conv helper ("/bin/cygwin-console-helper.exe");
-    size_t len = helper.get_wide_win32_path_len ();
-    helper.get_wide_win32_path (cmd);
-    __small_swprintf (cmd + len, L" %p %p %p", hello, goodbye, hw);
-    si_helper.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
-    si_helper.StartupInfo.hStdInput = NULL;
-    si_helper.StartupInfo.hStdOutput = NULL;
-    si_helper.StartupInfo.hStdError = NULL;
-    if (!CreateProcessW (NULL, cmd, &sec_none, &sec_none,
-			 TRUE, EXTENDED_STARTUPINFO_PRESENT,
-			 NULL, NULL, &si_helper.StartupInfo, &pi_helper))
-      goto cleanup_event_and_pipes;
-    for (;;)
-      {
-        DWORD wait_result = WaitForSingleObject (hello, 500);
-	if (wait_result == WAIT_OBJECT_0)
-	  break;
-	if (wait_result != WAIT_TIMEOUT)
-	  goto cleanup_helper_process;
-	DWORD exit_code;
-	if (!GetExitCodeProcess(pi_helper.hProcess, &exit_code))
-	  goto cleanup_helper_process;
-	if (exit_code == STILL_ACTIVE)
-	  continue;
-	if (exit_code != 0 ||
-	    WaitForSingleObject (hello, 500) != WAIT_OBJECT_0)
-	  goto cleanup_helper_process;
-	break;
-      }
-    CloseHandle (hello);
-    CloseHandle (pi_helper.hThread);
-    /* Retrieve pseudo console handles */
-    DWORD rLen;
-    char buf[64];
-    if (!ReadFile (hr, buf, sizeof (buf), &rLen, NULL))
-      goto cleanup_helper_process;
-    buf[rLen] = '\0';
-    sscanf (buf, "StdHandles=%p,%p", &hpConIn, &hpConOut);
-    if (!DuplicateHandle (pi_helper.hProcess, hpConIn,
-			  GetCurrentProcess (), &hpConIn, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_helper_process;
-    if (!DuplicateHandle (pi_helper.hProcess, hpConOut,
-			  GetCurrentProcess (), &hpConOut, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_pcon_in;
-    CloseHandle (hr);
-    CloseHandle (hw);
-    /* Clean up */
-    DeleteProcThreadAttributeList (si_helper.lpAttributeList);
-    HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-  }
-  /* Setting information of stuffs regarding pseudo console */
-  get_ttyp ()->h_helper_goodbye = goodbye;
-  get_ttyp ()->h_helper_process = pi_helper.hProcess;
-  get_ttyp ()->helper_process_id = pi_helper.dwProcessId;
-  CloseHandle (from_master);
-  CloseHandle (to_master);
-  from_master = hpConIn;
-  to_master = hpConOut;
-  ResizePseudoConsole (get_ttyp ()->h_pseudo_console, size);
-  return true;
-
-cleanup_pcon_in:
-  CloseHandle (hpConIn);
-cleanup_helper_process:
-  SetEvent (goodbye);
-  WaitForSingleObject (pi_helper.hProcess, INFINITE);
-  CloseHandle (pi_helper.hProcess);
-  goto skip_close_hello;
-cleanup_event_and_pipes:
-  CloseHandle (hello);
-skip_close_hello:
-  CloseHandle (goodbye);
-  CloseHandle (hr);
-  CloseHandle (hw);
-cleanup_heap:
-  HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-cleanup_pseudo_console:
-  {
-    HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
-    HANDLE tmp = hp->hConHostProcess;
-    ClosePseudoConsole (get_pseudo_console ());
-    CloseHandle (tmp);
-  }
-fallback:
-  CloseHandle (from_master);
-  CloseHandle (to_slave);
-  from_master = from_master_cyg;
-  to_slave = NULL;
-  get_ttyp ()->h_pseudo_console = NULL;
-  return false;
-}
-
 bool
 fhandler_pty_master::setup ()
 {
@@ -3593,11 +2259,6 @@ fhandler_pty_master::setup ()
   if (unit < 0)
     return false;
 
-  /* from_master should be used for pseudo console.
-     Just copy from_master_cyg here for the case that
-     pseudo console is not available. */
-  from_master = from_master_cyg;
-
   ProtectHandle1 (get_output_handle (), to_pty);
 
   tty& t = *cygwin_shared->tty[unit];
@@ -3696,15 +2357,21 @@ fhandler_pty_master::setup ()
       goto err;
     }
 
-  t.winsize.ws_col = 80;
-  t.winsize.ws_row = 25;
-
-  setup_pseudoconsole ();
+  __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;
+    }
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
   t.set_to_master (to_master);
   t.set_to_master_cyg (to_master_cyg);
+  t.winsize.ws_col = 80;
+  t.winsize.ws_row = 25;
   t.master_pid = myself->pid;
 
   dev ().parse (DEV_PTYM_MAJOR, unit);
@@ -3717,6 +2384,7 @@ fhandler_pty_master::setup ()
 err:
   __seterrno ();
   close_maybe (from_slave);
+  close_maybe (to_slave);
   close_maybe (get_handle ());
   close_maybe (get_output_handle ());
   close_maybe (input_available_event);
@@ -3776,9 +2444,6 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 {
   ssize_t towrite = len;
   BOOL res = TRUE;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
   while (towrite)
     {
       if (!is_echo)
@@ -3801,7 +2466,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
       if (!(get_ttyp ()->ti.c_oflag & OPOST))	// raw output mode
 	{
 	  DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
-	  res = WriteFunc (h, ptr, n, &n, NULL);
+	  res = WriteFile (h, ptr, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + n;
@@ -3851,7 +2516,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 		  break;
 		}
 	    }
-	  res = WriteFunc (h, outbuf, n, &n, NULL);
+	  res = WriteFile (h, outbuf, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + rc;
@@ -3861,3 +2526,134 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon)
+{
+
+  /* Setting switch_to_pcon_in is necessary even if
+     pseudo console will not be activated. */
+  fhandler_base *fh = ::cygheap->fdtab[0];
+  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+    {
+      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+      ptys->get_ttyp ()->switch_to_pcon_in = true;
+      if (ptys->get_ttyp ()->pcon_pid == 0
+	  || !pinfo (ptys->get_ttyp ()->pcon_pid))
+	ptys->get_ttyp ()->pcon_pid = myself->pid;
+    }
+
+  if (nopcon)
+    return false;
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  const DWORD inherit_cursor = 1;
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     inherit_cursor,
+				     &get_ttyp ()->h_pseudo_console);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console,
+				  sizeof (get_ttyp ()->h_pseudo_console),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_base *fh0 = ::cygheap->fdtab[0];
+    if (fh0 && fh0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = fh0->get_handle ();
+    fhandler_base *fh1 = ::cygheap->fdtab[1];
+    if (fh1 && fh1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = fh1->get_output_handle ();
+    fhandler_base *fh2 = ::cygheap->fdtab[2];
+    if (fh2 && fh2->get_device () != get_device ())
+      si->StartupInfo.hStdError = fh2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole (void)
+{
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      get_ttyp ()->wait_pcon_fwd ();
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+      get_ttyp ()->pcon_start = false;
+    }
+}
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 7c07b062e..38172ca1e 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -134,36 +134,6 @@ child_info::prefork (bool detached)
 int __stdcall
 frok::child (volatile char * volatile here)
 {
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR)
-      {
-	fhandler_base *fh = cfd;
-	fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
-	if (ptym->get_pseudo_console ())
-	  {
-	    debug_printf ("found a PTY master %d: helper_PID=%d",
-			  ptym->get_minor (), ptym->get_helper_process_id ());
-	    if (fhandler_console::get_console_process_id (
-				ptym->get_helper_process_id (), true))
-	      /* Already attached */
-	      break;
-	    else
-	      {
-		if (ptym->attach_pcon_in_fork ())
-		  {
-		    FreeConsole ();
-		    if (!AttachConsole (ptym->get_helper_process_id ()))
-		      /* Error */;
-		    else
-		      break;
-		  }
-	      }
-	  }
-      }
-  extern void clear_pcon_attached_to (void); /* fhandler_tty.cc */
-  clear_pcon_attached_to ();
-
   HANDLE& hParent = ch.parent;
 
   sync_with_parent ("after longjmp", true);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 4a8f3b2ec..9f1a8a57a 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1215,8 +1215,7 @@ verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds,
 	   fd_set *exceptfds)
 {
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) me->fh;
-  if (me->read_selected && !ptys->to_be_read_from_pcon () &&
-      IsEventSignalled (ptys->input_available_event))
+  if (me->read_selected && IsEventSignalled (ptys->input_available_event))
     me->read_ready = true;
   return set_bits (me, readfds, writefds, exceptfds);
 }
@@ -1229,8 +1228,6 @@ peek_pty_slave (select_record *s, bool from_select)
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
 
   ptys->reset_switch_to_pcon ();
-  if (ptys->to_be_read_from_pcon ())
-    ptys->update_pcon_input_state (true);
 
   if (s->read_selected)
     {
diff --git a/winsup/cygwin/smallprint.cc b/winsup/cygwin/smallprint.cc
index 9cfb41987..4a14ee3cf 100644
--- a/winsup/cygwin/smallprint.cc
+++ b/winsup/cygwin/smallprint.cc
@@ -405,7 +405,6 @@ small_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
   WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, NULL);
   FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
 }
@@ -432,7 +431,6 @@ console_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (console_handle);
   WriteFile (console_handle, buf, count, &done, NULL);
   FlushFileBuffers (console_handle);
 }
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index e70ceb86d..d12ce7b0a 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -177,7 +177,7 @@ find_exec (const char *name, path_conv& buf, const char *search,
 /* Utility for child_info_spawn::worker.  */
 
 static HANDLE
-handle (int fd, bool writing, bool iscygwin)
+handle (int fd, bool writing)
 {
   HANDLE h;
   cygheap_fdget cfd (fd);
@@ -188,17 +188,30 @@ handle (int fd, bool writing, bool iscygwin)
     h = INVALID_HANDLE_VALUE;
   else if (!writing)
     h = cfd->get_handle ();
-  else if (cfd->get_major () == DEV_PTYS_MAJOR && iscygwin)
-    {
-      fhandler_pty_slave *ptys = (fhandler_pty_slave *)(fhandler_base *) cfd;
-      h = ptys->get_output_handle_cyg ();
-    }
   else
     h = cfd->get_output_handle ();
 
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -266,8 +279,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 {
   bool rc;
   int res = -1;
-  DWORD pid_restore = 0;
-  bool attach_to_console = false;
   pid_t ctty_pgid = 0;
 
   /* Search for CTTY and retrieve its PGID */
@@ -587,9 +598,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			 PROCESS_QUERY_LIMITED_INFORMATION))
 	sa = &sec_none_nih;
 
-      /* Attach to pseudo console if pty salve is used */
-      pid_restore = fhandler_console::get_console_process_id
-	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -598,29 +607,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	      if (ptys->get_pseudo_console ())
-		{
-		  DWORD helper_process_id = ptys->get_helper_process_id ();
-		  debug_printf ("found a PTY slave %d: helper_PID=%d",
-				    fh->get_minor (), helper_process_id);
-		  if (fhandler_console::get_console_process_id
-					      (helper_process_id, true))
-		    /* Already attached */
-		    attach_to_console = true;
-		  else if (!attach_to_console)
-		    {
-		      FreeConsole ();
-		      if (AttachConsole (helper_process_id))
-			attach_to_console = true;
-		    }
-		  ptys->fixup_after_attach (!iscygwin (), fd);
-		  if (mode == _P_OVERLAY)
-		    ptys->set_freeconsole_on_close (iscygwin ());
-		}
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	    }
 	  else if (fh && fh->get_major () == DEV_CONS_MAJOR)
 	    {
-	      attach_to_console = true;
 	      fhandler_console *cons = (fhandler_console *) fh;
 	      if (wincap.has_con_24bit_colors () && !iscygwin ())
 		if (fd == 1 || fd == 2)
@@ -630,17 +621,28 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 
       /* Set up needed handles for stdio */
       si.dwFlags = STARTF_USESTDHANDLES;
-      si.hStdInput = handle ((in__stdin < 0 ? 0 : in__stdin), false,
-			     iscygwin ());
-      si.hStdOutput = handle ((in__stdout < 0 ? 1 : in__stdout), true,
-			      iscygwin ());
-      si.hStdError = handle (2, true, iscygwin ());
+      si.hStdInput = handle ((in__stdin < 0 ? 0 : in__stdin), false);
+      si.hStdOutput = handle ((in__stdout < 0 ? 1 : in__stdout), true);
+      si.hStdError = handle (2, true);
 
       si.cb = sizeof (si);
 
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool enable_pcon = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole (&si_pcon,
+			     mode != _P_OVERLAY && mode != _P_WAIT))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    enable_pcon = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -669,7 +671,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -723,7 +725,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -736,6 +738,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (enable_pcon)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -908,6 +915,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	    }
 	  if (sem)
 	    __posix_spawn_sem_release (sem, 0);
+	  if (enable_pcon)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->close_pseudoconsole ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
@@ -915,6 +927,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  system_call.arm ();
 	  if (waitpid (cygpid, &res, 0) != cygpid)
 	    res = -1;
+	  if (enable_pcon)
+	    ptys_primary->close_pseudoconsole ();
 	  break;
 	case _P_DETACH:
 	  res = 0;	/* Lost all memory of this child. */
@@ -941,21 +955,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
   if (envblock)
     free (envblock);
 
-  if (attach_to_console && pid_restore)
-    {
-      FreeConsole ();
-      AttachConsole (pid_restore);
-      cygheap_fdenum cfd (false);
-      int fd;
-      while ((fd = cfd.next ()) >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_pty_slave *ptys =
-	      (fhandler_pty_slave *) (fhandler_base *) cfd;
-	    ptys->fixup_after_attach (false, fd);
-	  }
-    }
-
   return (int) res;
 }
 
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index f0aef3a36..35f8a59ae 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -264,7 +264,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
   if (category & _STRACE_SYSTEM)
     {
       DWORD done;
-      set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
       WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
       FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
       /* Make sure that the message shows up on the screen, too, since this is
@@ -276,7 +275,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
 				 &sec_none, OPEN_EXISTING, 0, 0);
 	  if (h != INVALID_HANDLE_VALUE)
 	    {
-	      set_ishybrid_and_switch_to_pcon (h);
 	      WriteFile (h, buf, len, &done, 0);
 	      CloseHandle (h);
 	    }
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 4cb68f776..d60f27545 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -234,20 +234,14 @@ tty::init ()
   was_opened = false;
   master_pid = 0;
   is_console = false;
-  attach_pcon_in_fork = false;
-  h_pseudo_console = NULL;
   column = 0;
+  h_pseudo_console = NULL;
   switch_to_pcon_in = false;
-  switch_to_pcon_out = false;
-  screen_alternated = false;
   mask_switch_to_pcon_in = false;
   pcon_pid = 0;
   term_code_page = 0;
-  need_redraw_screen = true;
   pcon_last_time = 0;
-  pcon_in_empty = true;
-  req_transfer_input_to_pcon = false;
-  req_flush_pcon_input = false;
+  pcon_start = false;
 }
 
 HANDLE
@@ -293,16 +287,6 @@ tty_min::ttyname ()
   return d.name ();
 }
 
-void
-tty::set_switch_to_pcon_out (bool v)
-{
-  if (switch_to_pcon_out != v)
-    {
-      wait_pcon_fwd ();
-      switch_to_pcon_out = v;
-    }
-}
-
 void
 tty::wait_pcon_fwd (void)
 {
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 920e32b16..c491d3891 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -94,21 +94,13 @@ private:
   HANDLE _to_master;
   HANDLE _to_master_cyg;
   HPCON h_pseudo_console;
-  HANDLE h_helper_process;
-  DWORD helper_process_id;
-  HANDLE h_helper_goodbye;
-  bool attach_pcon_in_fork;
+  bool pcon_start;
   bool switch_to_pcon_in;
-  bool switch_to_pcon_out;
-  bool screen_alternated;
   bool mask_switch_to_pcon_in;
   pid_t pcon_pid;
   UINT term_code_page;
-  bool need_redraw_screen;
   DWORD pcon_last_time;
-  bool pcon_in_empty;
-  bool req_transfer_input_to_pcon;
-  bool req_flush_pcon_input;
+  HANDLE h_pcon_write_pipe;
 
 public:
   HANDLE from_master () const { return _from_master; }
@@ -138,7 +130,6 @@ public:
   void set_master_ctl_closed () {master_pid = -1;}
   static void __stdcall create_master (int);
   static void __stdcall init_session ();
-  void set_switch_to_pcon_out (bool v);
   void wait_pcon_fwd (void);
   friend class fhandler_pty_common;
   friend class fhandler_pty_master;
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index 9bfa1a7a6..79844cb87 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -224,9 +224,6 @@ void init_console_handler (bool);
 
 extern bool wsock_started;
 
-/* PTY related */
-void set_ishybrid_and_switch_to_pcon (HANDLE h);
-
 /* Printf type functions */
 extern "C" void vapi_fatal (const char *, va_list ap) __attribute__ ((noreturn));
 extern "C" void api_fatal (const char *, ...) __attribute__ ((noreturn));
-- 
2.27.0


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-13  9:58                                         ` Takashi Yano
@ 2020-08-17 11:57                                           ` Takashi Yano
  2020-08-19 11:39                                             ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-08-17 11:57 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 4313 bytes --]

On Thu, 13 Aug 2020 18:58:13 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Tue, 11 Aug 2020 20:12:58 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Mon, 3 Aug 2020 21:23:42 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Mon, 3 Aug 2020 11:11:03 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Fri, 24 Jul 2020 20:22:19 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > On Fri, 24 Jul 2020 14:38:42 +0900
> > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > On Thu, 23 Jul 2020 09:33:28 +0900
> > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > On Wed, 22 Jul 2020 17:45:41 +0900
> > > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > > On Wed, 22 Jul 2020 03:17:51 +0900
> > > > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > > > Hi Corinna,
> > > > > > > > > 
> > > > > > > > > On Mon, 20 Jul 2020 10:06:13 +0200
> > > > > > > > > Corinna Vinschen wrote:
> > > > > > > > > > On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
> > > > > > > > > > > Hi Corinna,
> > > > > > > > > > > 
> > > > > > > > > > > On Fri, 17 Jul 2020 13:19:12 +0200
> > > > > > > > > > > Corinna Vinschen wrote:
> > > > > > > > > > > > Hi Takashi,
> > > > > > > > > > > > 
> > > > > > > > > > > > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > > > > > > > > > > > > [...]
> > > > > > > > > > > > > Revise the patch to fit the current git head.
> > > > > > > > > > > > 
> > > > > > > > > > > > are you satisfied with the code?  If you want to merge it,
> > > > > > > > > > > > I'd bump Cygwin to 3.2.
> > > > > > > > > > > 
> > > > > > > > > > > Since this new implementation has both advantages and disadvantages,
> > > > > > > > > > > there might be some options.
> > > > > > > > > > > 
> > > > > > > > > > > 1) Default to new implementation and leave the current one as an
> > > > > > > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > > > > > > 2) Default to current implementation and add the new one as an
> > > > > > > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > > > > > > 3) Adopt only new implementation and throw the current one away.
> > > > > > > > > > > 
> > > > > > > > > > > What do you think?
> > > > > > > > > > 
> > > > > > > > > > Do you really want to maintain twice as much code doing the same stuff
> > > > > > > > > > and constantly having to ask users which version of the code they are
> > > > > > > > > > running?  The maintenance cost outweighs the advantages, IMHO.
> > > > > > > > > > Personally I'd go for option 3.
> > > > > > > > > 
> > > > > > > > > Personally, I feel a tinge of sadness to discard the current code,
> > > > > > > > > however, your opinion sounds reasonable.
> > > > > > > > > 
> > > > > > > > > I will submit a new patch in which all the codes specific to the
> > > > > > > > > current implementation are removed.
> > > > > > > > 
> > > > > > > > Attached is the patch in git format-patch format.
> > > > > > > > All the codes specific to the current implementation are removed.
> > > > > > > > 
> > > > > > > > Despite the utmost care, the changes are relatively large, so some
> > > > > > > > degradation may exist.
> > > > > > > > 
> > > > > > > > I will appreciate if you could test.
> > > > > > > 
> > > > > > > There were still unused code. Please try attached patch instead.
> > > > > > 
> > > > > > Changes:
> > > > > > * Do not activate pseudo console if it is already activated for
> > > > > >   another process on same pty.
> > > > > 
> > > > > Changes:
> > > > > * Fix a bug in the latest change.
> > > > 
> > > > Changes:
> > > > * Fix a handle leak caused when spawn is called with mode != _P_OVERLAY.
> > > 
> > > This patch cannot be applied cleanly against current git head.
> > > Please use attached patch instead.
> > 
> > Adapted to the current git head.
> 
> Adapted to the current recent pty change.

Adapted to the current git head.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-Cygwin-pty-Implement-new-pseudo-console-support.patch --]
[-- Type: application/octet-stream, Size: 91115 bytes --]

From 937eb31c388a772b11947d616188815621dc8e36 Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Sat, 15 Aug 2020 13:48:39 +0900
Subject: [PATCH] Cygwin: pty: Implement new pseudo console support.

- In this implementation, pseudo console is created for each native
  console app. Advantages and disadvantages of this implementation
  over the previous implementation are as follows.

  Advantages:
  1) No performance degradation in pty output for cygwin process.
      https://cygwin.com/pipermail/cygwin/2020-February/243858.html
  2) Free from the problem caused by difference of behaviour of control
     sequences between real terminal and pseudo console.
      https://cygwin.com/pipermail/cygwin/2019-December/243281.html
      https://cygwin.com/pipermail/cygwin/2020-February/243855.html
  3) Free from the problem in cgdb and emacs gud.
      https://cygwin.com/pipermail/cygwin/2020-January/243601.html
      https://cygwin.com/pipermail/cygwin/2020-March/244146.html
  4) Redrawing screen on executing native console apps is not necessary.
  5) cygwin-console-helper is not necessary for the pseudo console
     support.
  6) The codes for pseudo console support are much simpler than that
     of the previous one.

  Disadvantages:
  1) The cygwin program which calls console API directly does not work.
  2) The apps which use console API cannot be debugged with gdb. This
     is because pseudo console is not activated since gdb uses
     CreateProcess() rather than exec(). Even with this limitation,
     attaching gdb to native apps, in which pseudo console is already
     activated, works.
  3) Typeahead key inputs are discarded while native console app is
     executed. Simirally, typeahead key inputs while cygwin app is
     executed are not inherited to native console app.
  4) Code page cannot be changed by chcp.com. Acctually, chcp works
     itself and changes code page of its own pseudo console.  However,
     since pseudo console is recreated for another process, it cannot
     inherit the code page.
  5) system_printf() does not work after stderr is closed. (Same with
     cygwin 3.0.7)
  6) Startup time of native console apps is about 3 times slower than
     previous implemenation.
  7) Pseudo console cannot be activated if it is already activated for
     another process on same pty.
---
 winsup/cygwin/dtable.cc           |   32 -
 winsup/cygwin/fhandler.h          |   53 +-
 winsup/cygwin/fhandler_console.cc |   43 -
 winsup/cygwin/fhandler_tty.cc     | 1771 +++++------------------------
 winsup/cygwin/fork.cc             |   30 -
 winsup/cygwin/select.cc           |    5 +-
 winsup/cygwin/smallprint.cc       |    2 -
 winsup/cygwin/spawn.cc            |  124 +-
 winsup/cygwin/strace.cc           |    2 -
 winsup/cygwin/tty.cc              |   20 +-
 winsup/cygwin/tty.h               |   13 +-
 winsup/cygwin/winsup.h            |    3 -
 12 files changed, 356 insertions(+), 1742 deletions(-)

diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index e9e005b08..6a91e33bc 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -147,38 +147,6 @@ dtable::get_debugger_info ()
 void
 dtable::stdio_init ()
 {
-  for (int i = 0; i < 3; i ++)
-    {
-      const int chk_order[] = {1, 0, 2};
-      int fd = chk_order[i];
-      fhandler_base *fh = cygheap->fdtab[fd];
-      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
-	{
-	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	  if (ptys->get_pseudo_console ())
-	    {
-	      bool attached = !!fhandler_console::get_console_process_id
-		(ptys->get_helper_process_id (), true);
-	      if (attached)
-		break;
-	      else
-		{
-		  /* Not attached to pseudo console in fork() or spawn()
-		     by some reason. This happens if the executable is
-		     a windows GUI binary, such as mintty. */
-		  FreeConsole ();
-		  if (AttachConsole (ptys->get_helper_process_id ()))
-		    {
-		      ptys->fixup_after_attach (false, fd);
-		      break;
-		    }
-		}
-	    }
-	}
-      else if (fh && fh->get_major () == DEV_CONS_MAJOR)
-	break;
-    }
-
   if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT))
     {
       tty_min *t = cygwin_shared->tty.get_cttyp ();
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index a577ca542..9fd95c098 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -326,16 +326,16 @@ class fhandler_base
   virtual size_t &raixput () { return ra.raixput; };
   virtual size_t &rabuflen () { return ra.rabuflen; };
 
-  virtual bool get_readahead_valid () { return raixget () < ralen (); }
+  bool get_readahead_valid () { return raixget () < ralen (); }
   int puts_readahead (const char *s, size_t len = (size_t) -1);
-  virtual int put_readahead (char value);
+  int put_readahead (char value);
 
   int get_readahead ();
   int peek_readahead (int queryput = 0);
 
   void set_readahead_valid (int val, int ch = -1);
 
-  virtual int get_readahead_into_buffer (char *buf, size_t buflen);
+  int get_readahead_into_buffer (char *buf, size_t buflen);
 
   bool has_acls () const { return pc.has_acls (); }
 
@@ -1905,7 +1905,7 @@ class fhandler_termios: public fhandler_base
   int ioctl (int, void *);
   tty_min *_tc;
   tty *get_ttyp () {return (tty *) tc ();}
-  virtual int eat_readahead (int n);
+  int eat_readahead (int n);
 
  public:
   tty_min*& tc () {return _tc;}
@@ -2184,7 +2184,6 @@ private:
   static bool need_invisible ();
   static void free_console ();
   static const char *get_nonascii_key (INPUT_RECORD& input_rec, char *);
-  static DWORD get_console_process_id (DWORD pid, bool match);
 
   fhandler_console (void *) {}
 
@@ -2264,19 +2263,7 @@ class fhandler_pty_common: public fhandler_termios
     return fh;
   }
 
-  bool attach_pcon_in_fork (void)
-  {
-    return get_ttyp ()->attach_pcon_in_fork;
-  }
-  DWORD get_helper_process_id (void)
-  {
-    return get_ttyp ()->helper_process_id;
-  }
-  HPCON get_pseudo_console (void)
-  {
-    return get_ttyp ()->h_pseudo_console;
-  }
-  bool to_be_read_from_pcon (void);
+  void resize_pseudo_console (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2287,23 +2274,15 @@ class fhandler_pty_slave: public fhandler_pty_common
 {
   HANDLE inuse;			// used to indicate that a tty is in use
   HANDLE output_handle_cyg, io_handle_cyg;
-  DWORD pid_restore;
-  int fd;
 
   /* Helper functions for fchmod and fchown. */
   bool fch_open_handles (bool chown);
   int fch_set_sd (security_descriptor &sd, bool chown);
   void fch_close_handles ();
 
-  bool try_reattach_pcon ();
-  void restore_reattach_pcon ();
-  inline void free_attached_console ();
-
  public:
   /* Constructor */
   fhandler_pty_slave (int);
-  /* Destructor */
-  ~fhandler_pty_slave ();
 
   void set_output_handle_cyg (HANDLE h) { output_handle_cyg = h; }
   HANDLE& get_output_handle_cyg () { return output_handle_cyg; }
@@ -2315,9 +2294,6 @@ class fhandler_pty_slave: public fhandler_pty_common
   ssize_t __stdcall write (const void *ptr, size_t len);
   void __reg3 read (void *ptr, size_t& len);
   int init (HANDLE, DWORD, mode_t);
-  int eat_readahead (int n);
-  int get_readahead_into_buffer (char *buf, size_t buflen);
-  bool get_readahead_valid (void);
 
   int tcsetattr (int a, const struct termios *t);
   int tcgetattr (struct termios *t);
@@ -2354,20 +2330,12 @@ class fhandler_pty_slave: public fhandler_pty_common
     copyto (fh);
     return fh;
   }
-  void set_switch_to_pcon (int fd);
+  bool setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon);
+  void close_pseudoconsole (void);
+  void set_switch_to_pcon (void);
   void reset_switch_to_pcon (void);
-  void push_to_pcon_screenbuffer (const char *ptr, size_t len, bool is_echo);
   void mask_switch_to_pcon_in (bool mask);
-  void fixup_after_attach (bool native_maybe, int fd);
-  bool is_line_input (void)
-  {
-    return get_ttyp ()->ti.c_lflag & ICANON;
-  }
   void setup_locale (void);
-  void set_freeconsole_on_close (bool val);
-  void trigger_redraw_screen (void);
-  void pull_pcon_input (void);
-  void update_pcon_input_state (bool need_lock);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
@@ -2392,7 +2360,6 @@ public:
   int process_slave_output (char *buf, size_t len, int pktmode_on);
   void doecho (const void *str, DWORD len);
   int accept_input ();
-  int put_readahead (char value);
   int open (int flags, mode_t mode = 0);
   void open_setup (int flags);
   ssize_t __stdcall write (const void *ptr, size_t len);
@@ -2431,9 +2398,7 @@ public:
     copyto (fh);
     return fh;
   }
-
-  bool setup_pseudoconsole (void);
-  void transfer_input_to_pcon (void);
+  bool to_be_read_from_pcon (void);
 };
 
 class fhandler_dev_null: public fhandler_base
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 52741ce8b..02a5996a1 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -1206,18 +1206,6 @@ fhandler_console::close ()
   if (con_ra.rabuf)
     free (con_ra.rabuf);
 
-  /* If already attached to pseudo console, don't call free_console () */
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR ||
-	cfd->get_major () == DEV_PTYS_MAJOR)
-      {
-	fhandler_pty_common *t =
-	  (fhandler_pty_common *) (fhandler_base *) cfd;
-	if (get_console_process_id (t->get_helper_process_id (), true))
-	  return 0;
-      }
-
   if (!have_execed)
     free_console ();
   return 0;
@@ -3611,37 +3599,6 @@ fhandler_console::need_invisible ()
   return b;
 }
 
-DWORD
-fhandler_console::get_console_process_id (DWORD pid, bool match)
-{
-  DWORD tmp;
-  DWORD num, num_req;
-  num = 1;
-  num_req = GetConsoleProcessList (&tmp, num);
-  DWORD *list;
-  while (true)
-    {
-      list = (DWORD *)
-	HeapAlloc (GetProcessHeap (), 0, num_req * sizeof (DWORD));
-      num = num_req;
-      num_req = GetConsoleProcessList (list, num);
-      if (num_req > num)
-	HeapFree (GetProcessHeap (), 0, list);
-      else
-	break;
-    }
-  num = num_req;
-
-  tmp = 0;
-  for (DWORD i=0; i<num; i++)
-    if ((match && list[i] == pid) || (!match && list[i] != pid))
-      /* Last one is the oldest. */
-      /* https://github.com/microsoft/terminal/issues/95 */
-      tmp = list[i];
-  HeapFree (GetProcessHeap (), 0, list);
-  return tmp;
-}
-
 DWORD
 fhandler_console::__acquire_input_mutex (const char *fn, int ln, DWORD ms)
 {
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 6294e2c20..4bde03316 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -25,7 +25,6 @@ details. */
 #include "child_info.h"
 #include <asm/socket.h>
 #include "cygwait.h"
-#include "tls_pbuf.h"
 #include "registry.h"
 
 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
@@ -33,7 +32,6 @@ details. */
 #endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
 
 extern "C" int sscanf (const char *, const char *, ...);
-extern "C" int ttyname_r (int, char*, size_t);
 
 extern "C" {
   HRESULT WINAPI CreatePseudoConsole (COORD, HANDLE, HANDLE, DWORD, HPCON *);
@@ -60,20 +58,10 @@ struct pipe_reply {
   DWORD error;
 };
 
-static int pcon_attached_to = -1;
 static bool isHybrid;
-static bool do_not_reset_switch_to_pcon;
-static bool freeconsole_on_close = true;
-static tty *last_ttyp = NULL;
-
-void
-clear_pcon_attached_to (void)
-{
-  pcon_attached_to = -1;
-}
 
 static void
-set_switch_to_pcon (void)
+set_switch_to_pcon (HANDLE h)
 {
   cygheap_fdenum cfd (false);
   int fd;
@@ -82,280 +70,17 @@ set_switch_to_pcon (void)
       {
 	fhandler_base *fh = cfd;
 	fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	if (ptys->get_pseudo_console ())
-	  {
-	    ptys->set_switch_to_pcon (fd);
-	    ptys->trigger_redraw_screen ();
-	    DWORD mode =
-	      ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	    SetConsoleMode (ptys->get_handle (), mode);
-	  }
+	if (h == ptys->get_handle ())
+	  ptys->set_switch_to_pcon ();
 	return;
       }
-  /* No pty slave opened */
-  if (last_ttyp) /* Make system_printf() work after closing pty slave */
-    last_ttyp->set_switch_to_pcon_out (true);
-}
-
-static void
-force_attach_to_pcon (HANDLE h)
-{
-  bool attach_done = false;
-  for (int n = 0; n < 2; n ++)
-    {
-      /* First time, attach to the pty whose handle value is match.
-	 Second time, try to attach to any pty. */
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	    if (!ptys->get_pseudo_console ())
-	      continue;
-	    if (n != 0
-		|| h == ptys->get_handle ()
-		|| h == ptys->get_output_handle ())
-	      {
-		if (fhandler_console::get_console_process_id
-				  (ptys->get_helper_process_id (), true))
-		  attach_done = true;
-		else
-		  {
-		    FreeConsole ();
-		    if (AttachConsole (ptys->get_helper_process_id ()))
-		      {
-			pcon_attached_to = ptys->get_minor ();
-			attach_done = true;
-		      }
-		    else
-		      pcon_attached_to = -1;
-		  }
-		break;
-	      }
-	  }
-	else if (cfd->get_major () == DEV_CONS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_console *cons = (fhandler_console *) fh;
-	    if (n != 0
-		|| h == cons->get_handle ()
-		|| h == cons->get_output_handle ())
-	      {
-		/* If the process is running on a console,
-		   the parent process should be attached
-		   to the same console. */
-		DWORD attach_wpid;
-		if (myself->ppid == 1)
-		  attach_wpid = ATTACH_PARENT_PROCESS;
-		else
-		  {
-		    pinfo p (myself->ppid);
-		    attach_wpid = p->dwProcessId;
-		  }
-		FreeConsole ();
-		if (AttachConsole (attach_wpid))
-		  {
-		    pcon_attached_to = -1;
-		    attach_done = true;
-		  }
-		else
-		  pcon_attached_to = -1;
-		break;
-	      }
-	  }
-      if (attach_done)
-	break;
-    }
-}
-
-void
-set_ishybrid_and_switch_to_pcon (HANDLE h)
-{
-  if (GetFileType (h) == FILE_TYPE_CHAR)
-    {
-      force_attach_to_pcon (h);
-      DWORD dummy;
-      if (!isHybrid && (GetConsoleMode (h, &dummy)
-			|| GetLastError () != ERROR_INVALID_HANDLE))
-	{
-	  isHybrid = true;
-	  set_switch_to_pcon ();
-	}
-    }
-}
-
-inline void
-fhandler_pty_slave::free_attached_console ()
-{
-  bool attached = get_ttyp () ?
-    fhandler_console::get_console_process_id (get_helper_process_id (), true)
-    : (get_minor () == pcon_attached_to);
-  if (freeconsole_on_close && attached)
-    {
-      FreeConsole ();
-      pcon_attached_to = -1;
-    }
 }
 
 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
-DEF_HOOK (WriteFile);
-DEF_HOOK (WriteConsoleA);
-DEF_HOOK (WriteConsoleW);
-DEF_HOOK (ReadFile);
-DEF_HOOK (ReadConsoleA);
-DEF_HOOK (ReadConsoleW);
-DEF_HOOK (WriteConsoleOutputA);
-DEF_HOOK (WriteConsoleOutputW);
-DEF_HOOK (WriteConsoleOutputCharacterA);
-DEF_HOOK (WriteConsoleOutputCharacterW);
-DEF_HOOK (WriteConsoleOutputAttribute);
-DEF_HOOK (SetConsoleCursorPosition);
-DEF_HOOK (SetConsoleTextAttribute);
-DEF_HOOK (WriteConsoleInputA);
-DEF_HOOK (WriteConsoleInputW);
-DEF_HOOK (ReadConsoleInputA);
-DEF_HOOK (ReadConsoleInputW);
-DEF_HOOK (PeekConsoleInputA);
-DEF_HOOK (PeekConsoleInputW);
 /* CreateProcess() is hooked for GDB etc. */
 DEF_HOOK (CreateProcessA);
 DEF_HOOK (CreateProcessW);
 
-static BOOL WINAPI
-WriteFile_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleA_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleW_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadFile_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleA_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleW_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleOutputA_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputA_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputW_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputW_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterA_Hooked
-     (HANDLE h, LPCSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterA_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterW_Hooked
-     (HANDLE h, LPCWSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterW_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputAttribute_Hooked
-     (HANDLE h, CONST WORD *a, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputAttribute_Orig (h, a, l, c, n);
-}
-static BOOL WINAPI
-SetConsoleCursorPosition_Hooked
-     (HANDLE h, COORD c)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleCursorPosition_Orig (h, c);
-}
-static BOOL WINAPI
-SetConsoleTextAttribute_Hooked
-     (HANDLE h, WORD a)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleTextAttribute_Orig (h, a);
-}
-static BOOL WINAPI
-WriteConsoleInputA_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-WriteConsoleInputW_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputW_Orig (h, r, l, n);
-}
-/* CreateProcess() is hooked for GDB etc. */
 static BOOL WINAPI
 CreateProcessA_Hooked
      (LPCSTR n, LPSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
@@ -363,11 +88,14 @@ CreateProcessA_Hooked
       LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 static BOOL WINAPI
@@ -377,11 +105,14 @@ CreateProcessW_Hooked
       LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 
@@ -464,10 +195,6 @@ fhandler_pty_master::flush_to_slave ()
 {
   if (get_readahead_valid () && !(get_ttyp ()->ti.c_lflag & ICANON))
     accept_input ();
-  WaitForSingleObject (input_mutex, INFINITE);
-  if (!get_ttyp ()->pcon_in_empty && !(get_ttyp ()->ti.c_lflag & ICANON))
-    SetEvent (input_available_event);
-  ReleaseMutex (input_mutex);
 }
 
 DWORD
@@ -532,14 +259,6 @@ fhandler_pty_master::doecho (const void *str, DWORD len)
   release_output_mutex ();
 }
 
-int
-fhandler_pty_master::put_readahead (char value)
-{
-  if (to_be_read_from_pcon ())
-    return 1;
-  return fhandler_base::put_readahead (value);
-}
-
 int
 fhandler_pty_master::accept_input ()
 {
@@ -551,9 +270,11 @@ fhandler_pty_master::accept_input ()
   char *p = rabuf () + raixget ();
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
   if (to_be_read_from_pcon ())
-    ; /* Do nothing */
-  else if (!bytes_left)
+    write_to = to_slave;
+
+  if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
@@ -564,10 +285,10 @@ fhandler_pty_master::accept_input ()
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -725,52 +446,12 @@ out:
 
 fhandler_pty_slave::fhandler_pty_slave (int unit)
   : fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL),
-  io_handle_cyg (NULL), pid_restore (0), fd (-1)
+  io_handle_cyg (NULL)
 {
   if (unit >= 0)
     dev ().parse (DEV_PTYS_MAJOR, unit);
 }
 
-fhandler_pty_slave::~fhandler_pty_slave ()
-{
-  if (!get_ttyp ())
-    {
-      /* Why comes here? Who clears _tc? */
-      free_attached_console ();
-      return;
-    }
-  if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 0)
-	{
-	  pcon_attached_to = -1;
-	  last_ttyp = get_ttyp ();
-	}
-      if (used == 0)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
-}
-
 int
 fhandler_pty_slave::open (int flags, mode_t)
 {
@@ -833,8 +514,8 @@ fhandler_pty_slave::open (int flags, mode_t)
     release_output_mutex ();
   }
 
-  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg () ||
-      !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
+  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg ()
+      || !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
     {
       errmsg = "pty handles have been closed";
       set_errno (EACCES);
@@ -923,8 +604,8 @@ fhandler_pty_slave::open (int flags, mode_t)
       from_master_cyg_local = repl.from_master_cyg;
       to_master_local = repl.to_master;
       to_master_cyg_local = repl.to_master_cyg;
-      if (!from_master_local || !from_master_cyg_local ||
-	  !to_master_local || !to_master_cyg_local)
+      if (!from_master_local || !from_master_cyg_local
+	  || !to_master_local || !to_master_cyg_local)
 	{
 	  SetLastError (repl.error);
 	  errmsg = "error duplicating pipes, %E";
@@ -950,24 +631,7 @@ fhandler_pty_slave::open (int flags, mode_t)
   set_output_handle (to_master_local);
   set_output_handle_cyg (to_master_cyg_local);
 
-  if (!get_pseudo_console ())
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (!fhandler_console::get_console_process_id
-			       (GetCurrentProcessId (), true))
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (fhandler_console::get_console_process_id
-			       (get_helper_process_id (), true))
-    /* Attached to pcon of this pty */
-    {
-      pcon_attached_to = get_minor ();
-      init_console_handler (true);
-    }
+  fhandler_console::need_invisible ();
 
   set_open_status ();
   return 1;
@@ -1021,8 +685,7 @@ fhandler_pty_slave::close ()
   if (!ForceCloseHandle (get_handle_cyg ()))
     termios_printf ("CloseHandle (get_handle_cyg ()<%p>), %E",
 	get_handle_cyg ());
-  if (!get_pseudo_console () &&
-      (unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
+  if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
     fhandler_console::free_console ();	/* assumes that we are the last pty closer */
   fhandler_pty_common::close ();
   if (!ForceCloseHandle (output_mutex))
@@ -1070,423 +733,31 @@ fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
   return ret;
 }
 
-bool
-fhandler_pty_slave::try_reattach_pcon (void)
-{
-  pid_restore = 0;
-
-  /* Do not detach from the console because re-attaching will
-     fail if helper process is running as service account. */
-  if (get_ttyp()->attach_pcon_in_fork)
-    return false;
-  if (pcon_attached_to >= 0 &&
-      cygwin_shared->tty[pcon_attached_to]->attach_pcon_in_fork)
-    return false;
-
-  pid_restore =
-    fhandler_console::get_console_process_id (GetCurrentProcessId (),
-					      false);
-  /* If pid_restore is not set, give up. */
-  if (!pid_restore)
-    return false;
-
-  FreeConsole ();
-  if (!AttachConsole (get_helper_process_id ()))
-    {
-      system_printf ("pty%d: AttachConsole(helper=%d) failed. 0x%08lx",
-		     get_minor (), get_helper_process_id (), GetLastError ());
-      return false;
-    }
-  return true;
-}
-
-void
-fhandler_pty_slave::restore_reattach_pcon (void)
-{
-  if (pid_restore)
-    {
-      FreeConsole ();
-      if (!AttachConsole (pid_restore))
-	{
-	  system_printf ("pty%d: AttachConsole(restore=%d) failed. 0x%08lx",
-			 get_minor (), pid_restore, GetLastError ());
-	  pcon_attached_to = -1;
-	}
-    }
-  pid_restore = 0;
-}
-
-/* This function requests transfering the input data from the input
-   pipe for cygwin apps to the other input pipe for native apps. */
-void
-fhandler_pty_slave::pull_pcon_input (void)
-{
-  get_ttyp ()->req_transfer_input_to_pcon = true;
-  while (get_ttyp ()->req_transfer_input_to_pcon)
-    Sleep (1);
-}
-
-void
-fhandler_pty_slave::update_pcon_input_state (bool need_lock)
-{
-  if (need_lock)
-    WaitForSingleObject (input_mutex, INFINITE);
-  /* Flush input buffer if it is requested by master.
-     This happens if ^C is pressed in pseudo console side. */
-  if (get_ttyp ()->req_flush_pcon_input)
-    {
-      FlushConsoleInputBuffer (get_handle ());
-      get_ttyp ()->req_flush_pcon_input = false;
-    }
-  /* Peek console input buffer and update state. */
-  INPUT_RECORD inp[INREC_SIZE];
-  DWORD n;
-  BOOL (WINAPI *PeekFunc)
-    (HANDLE, PINPUT_RECORD, DWORD, LPDWORD);
-  PeekFunc =
-    PeekConsoleInputA_Orig ? : PeekConsoleInput;
-  PeekFunc (get_handle (), inp, INREC_SIZE, &n);
-  bool saw_accept = false;
-  bool pipe_empty = true;
-  while (n-- > 0)
-    if (inp[n].EventType == KEY_EVENT && inp[n].Event.KeyEvent.bKeyDown &&
-	inp[n].Event.KeyEvent.uChar.AsciiChar)
-      {
-	pipe_empty = false;
-	char c = inp[n].Event.KeyEvent.uChar.AsciiChar;
-	const char sigs[] = {
-	  (char) get_ttyp ()->ti.c_cc[VINTR],
-	  (char) get_ttyp ()->ti.c_cc[VQUIT],
-	  (char) get_ttyp ()->ti.c_cc[VSUSP],
-	};
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n',
-	  '\r'
-	};
-	if (is_line_input () && c && memchr (eols, c, sizeof (eols)))
-	  saw_accept = true;
-	if ((get_ttyp ()->ti.c_lflag & ISIG)
-	    && c && memchr (sigs, c, sizeof (sigs)))
-	  saw_accept = true;
-      }
-  get_ttyp ()->pcon_in_empty = pipe_empty && !(ralen () > raixget ());
-  if (!get_readahead_valid () &&
-      (pipe_empty || (is_line_input () && !saw_accept)) &&
-      get_ttyp ()->read_retval == 1 && bytes_available (n) && n == 0)
-    ResetEvent (input_available_event);
-  if (need_lock)
-    ReleaseMutex (input_mutex);
-}
-
-int
-fhandler_pty_slave::eat_readahead (int n)
-{
-  int oralen = ralen ();
-  if (n < 0)
-    n = ralen () - raixget ();
-  if (n > 0 && ralen () > raixget ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      while (n > 0 && ralen () > raixget ())
-	{
-	  if (is_line_input () && rabuf ()[ralen ()-1]
-	      && memchr (eols, rabuf ()[ralen ()-1], sizeof (eols)))
-	    break;
-	  -- n;
-	  -- ralen ();
-	}
-
-      /* If IUTF8 is set, the terminal is in UTF-8 mode.  If so, we erase
-	 a complete UTF-8 multibyte sequence on VERASE/VWERASE.  Otherwise,
-	 if we only erase a single byte, invalid unicode chars are left in
-	 the input. */
-      if (get_ttyp ()->ti.c_iflag & IUTF8)
-	while (ralen () > raixget () &&
-	       ((unsigned char) rabuf ()[ralen ()] & 0xc0) == 0x80)
-	  --ralen ();
-    }
-  oralen = oralen - ralen ();
-  if (raixget () >= ralen ())
-    raixget () = raixput () = ralen () = 0;
-  else if (raixput () > ralen ())
-    raixput () = ralen ();
-
-  return oralen;
-}
-
-int
-fhandler_pty_slave::get_readahead_into_buffer (char *buf, size_t buflen)
-{
-  int ch;
-  int copied_chars = 0;
-
-  while (buflen)
-    if ((ch = get_readahead ()) < 0)
-      break;
-    else
-      {
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n'
-	};
-	buf[copied_chars++] = (unsigned char)(ch & 0xff);
-	buflen--;
-	if (is_line_input () && ch && memchr (eols, ch & 0xff, sizeof (eols)))
-	  break;
-      }
-
-  return copied_chars;
-}
-
-bool
-fhandler_pty_slave::get_readahead_valid (void)
-{
-  if (is_line_input ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      for (size_t i=raixget (); i<ralen (); i++)
-	if (rabuf ()[i] && memchr (eols, rabuf ()[i], sizeof (eols)))
-	  return true;
-      return false;
-    }
-  else
-    return ralen () > raixget ();
-}
-
 void
-fhandler_pty_slave::set_switch_to_pcon (int fd_set)
+fhandler_pty_slave::set_switch_to_pcon (void)
 {
-  if (fd < 0)
-    fd = fd_set;
-  acquire_output_mutex (INFINITE);
-  if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
+  if (!get_ttyp ()->switch_to_pcon_in)
     {
-      pull_pcon_input ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
+      isHybrid = true;
+      if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
 	get_ttyp ()->pcon_pid = myself->pid;
       get_ttyp ()->switch_to_pcon_in = true;
-      if (isHybrid && !get_ttyp ()->switch_to_pcon_out)
-	{
-	  get_ttyp ()->wait_pcon_fwd ();
-	  get_ttyp ()->switch_to_pcon_out = true;
-	}
-    }
-  else if ((fd == 1 || fd == 2) && !get_ttyp ()->switch_to_pcon_out)
-    {
-      get_ttyp ()->wait_pcon_fwd ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
-	get_ttyp ()->pcon_pid = myself->pid;
-      get_ttyp ()->switch_to_pcon_out = true;
-      if (isHybrid)
-	get_ttyp ()->switch_to_pcon_in = true;
     }
-  release_output_mutex ();
 }
 
 void
 fhandler_pty_slave::reset_switch_to_pcon (void)
 {
-  if (get_ttyp ()->pcon_pid &&
-      get_ttyp ()->pcon_pid != myself->pid &&
-      !!pinfo (get_ttyp ()->pcon_pid))
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
     /* There is a process which is grabbing pseudo console. */
     return;
   if (isHybrid)
     return;
-  if (do_not_reset_switch_to_pcon)
-    return;
-  acquire_output_mutex (INFINITE);
-  if (get_ttyp ()->switch_to_pcon_out)
-    /* Wait for pty_master_fwd_thread() */
-    get_ttyp ()->wait_pcon_fwd ();
   get_ttyp ()->pcon_pid = 0;
   get_ttyp ()->switch_to_pcon_in = false;
-  get_ttyp ()->switch_to_pcon_out = false;
-  release_output_mutex ();
-  init_console_handler (true);
-}
-
-void
-fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len,
-					       bool is_echo)
-{
-  bool attached =
-    !!fhandler_console::get_console_process_id (get_helper_process_id (), true);
-  if (!attached && pcon_attached_to == get_minor ())
-    {
-      for (DWORD t0 = GetTickCount (); GetTickCount () - t0 < 100; )
-	{
-	  Sleep (1);
-	  attached = fhandler_console::get_console_process_id
-				      (get_helper_process_id (), true);
-	  if (attached)
-	    break;
-	}
-      if (!attached)
-	{
-	  system_printf ("pty%d: pcon_attach_to mismatch??????", get_minor ());
-	  return;
-	}
-    }
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  if (pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      goto detach;
-
-  char *buf;
-  size_t nlen;
-  DWORD origCP;
-  origCP = GetConsoleOutputCP ();
-  SetConsoleOutputCP (get_ttyp ()->term_code_page);
-  /* Just copy */
-  buf = (char *) HeapAlloc (GetProcessHeap (), 0, len);
-  memcpy (buf, (char *)ptr, len);
-  nlen = len;
-  char *p0, *p1;
-  p0 = p1 = buf;
-  /* Remove alternate screen buffer drawing */
-  while (p0 && p1)
-    {
-      if (!get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to alternate screen buffer */
-	  p0 = (char *) memmem (p1, nlen - (p1-buf), "\033[?1049h", 8);
-	  if (p0)
-	    {
-	      //p0 += 8;
-	      get_ttyp ()->screen_alternated = true;
-	      if (get_ttyp ()->switch_to_pcon_out)
-		do_not_reset_switch_to_pcon = true;
-	    }
-	}
-      if (get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to main screen buffer */
-	  p1 = (char *) memmem (p0, nlen - (p0-buf), "\033[?1049l", 8);
-	  if (p1)
-	    {
-	      p1 += 8;
-	      get_ttyp ()->screen_alternated = false;
-	      do_not_reset_switch_to_pcon = false;
-	      memmove (p0, p1, buf+nlen - p1);
-	      nlen -= p1 - p0;
-	    }
-	  else
-	    nlen = p0 - buf;
-	}
-    }
-  if (!nlen) /* Nothing to be synchronized */
-    goto cleanup;
-  if (get_ttyp ()->switch_to_pcon_out && !is_echo)
-    goto cleanup;
-  /* Remove ESC sequence which returns results to console
-     input buffer. Without this, cursor position report
-     is put into the input buffer as a garbage. */
-  /* Remove ESC sequence to report cursor position. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[6n", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-  /* Remove ESC sequence to report terminal identity. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[0c", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-
-  /* If the ESC sequence ESC[?3h or ESC[?3l which clears console screen
-     buffer is pushed, set need_redraw_screen to trigger redraw screen. */
-  p0 = buf;
-  while ((p0 = (char *) memmem (p0, nlen - (p0 - buf), "\033[?", 3)))
-    {
-      p0 += 3;
-      bool exist_arg_3 = false;
-      while (p0 < buf + nlen && (isdigit (*p0) || *p0 == ';'))
-	{
-	  int arg = 0;
-	  while (p0 < buf + nlen && isdigit (*p0))
-	    arg = arg * 10 + (*p0 ++) - '0';
-	  if (arg == 3)
-	    exist_arg_3 = true;
-	  if (p0 < buf + nlen && *p0 == ';')
-	    p0 ++;
-	}
-      if (p0 < buf + nlen && exist_arg_3 && (*p0 == 'h' || *p0 == 'l'))
-	get_ttyp ()->need_redraw_screen = true;
-      p0 ++;
-      if (p0 >= buf + nlen)
-	break;
-    }
-
-  int retry_count;
-  retry_count = 0;
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  while (!GetConsoleMode (get_output_handle (), &dwMode))
-    {
-      termios_printf ("GetConsoleMode failed, %E");
-      int errno_save = errno;
-      /* Re-open handles */
-      this->open (0, 0);
-      /* Fix pseudo console window size */
-      this->ioctl (TIOCSWINSZ, &get_ttyp ()->winsize);
-      if (errno != errno_save)
-	set_errno (errno_save);
-      if (++retry_count > 3)
-	goto cleanup;
-    }
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-  char *p;
-  p = buf;
-  DWORD wLen, written;
-  written = 0;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
-  while (written <  nlen)
-    {
-      if (!WriteFunc (get_output_handle (), p, nlen - written, &wLen, NULL))
-	{
-	  termios_printf ("WriteFile failed, %E");
-	  break;
-	}
-      else
-	{
-	  written += wLen;
-	  p += wLen;
-	}
-    }
-  /* Detach from pseudo console and resume. */
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-cleanup:
-  SetConsoleOutputCP (origCP);
-  HeapFree (GetProcessHeap (), 0, buf);
-detach:
-  restore_reattach_pcon ();
+  get_ttyp ()->h_pseudo_console = NULL;
+  get_ttyp ()->pcon_start = false;
 }
 
 ssize_t __stdcall
@@ -1505,44 +776,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
   reset_switch_to_pcon ();
 
   acquire_output_mutex (INFINITE);
-  bool output_to_pcon = get_ttyp ()->switch_to_pcon_out;
-  release_output_mutex ();
-
-  UINT target_code_page = output_to_pcon ?
-    GetConsoleOutputCP () : get_ttyp ()->term_code_page;
-  ssize_t nlen;
-  char *buf = convert_mb_str (target_code_page, (size_t *) &nlen,
-		 get_ttyp ()->term_code_page, (const char *) ptr, len);
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  bool fallback = false;
-  if (output_to_pcon && pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      fallback = true;
-
-  if (output_to_pcon && !fallback &&
-      (memmem (buf, nlen, "\033[6n", 4) || memmem (buf, nlen, "\033[0c", 4)))
-    {
-      get_ttyp ()->pcon_in_empty = false;
-      if (!is_line_input ())
-	SetEvent (input_available_event);
-    }
-
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  if (output_to_pcon && !fallback)
-    {
-      GetConsoleMode (get_output_handle (), &dwMode);
-      SetConsoleMode (get_output_handle (), dwMode | flags);
-    }
-  HANDLE to = (output_to_pcon && !fallback) ?
-    get_output_handle () : get_output_handle_cyg ();
-  acquire_output_mutex (INFINITE);
-  if (!process_opost_output (to, buf, nlen, false))
+  if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false))
     {
       DWORD err = GetLastError ();
       termios_printf ("WriteFile failed, %E");
@@ -1557,20 +791,6 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
       towrite = -1;
     }
   release_output_mutex ();
-  mb_str_free (buf);
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (output_to_pcon && !fallback)
-    SetConsoleMode (get_output_handle (), dwMode | flags);
-
-  restore_reattach_pcon ();
-
-  /* Push slave output to pseudo console screen buffer */
-  if (get_pseudo_console ())
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer ((char *)ptr, len, false);
-      release_output_mutex ();
-    }
 
   return towrite;
 }
@@ -1582,16 +802,15 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 }
 
 bool
-fhandler_pty_common::to_be_read_from_pcon (void)
+fhandler_pty_master::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return get_ttyp ()->pcon_start
+    || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
 fhandler_pty_slave::read (void *ptr, size_t& len)
 {
-  char *ptr0 = (char *)ptr;
   ssize_t totalread = 0;
   int vmin = 0;
   int vtime = 0;	/* Initialized to prevent -Wuninitialized warning */
@@ -1616,8 +835,6 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
       mask_switch_to_pcon_in (true);
       reset_switch_to_pcon ();
     }
-  if (to_be_read_from_pcon ())
-    update_pcon_input_state (true);
 
   if (is_nonblocking () || !ptr) /* Indicating tcflush(). */
     time_to_wait = 0;
@@ -1705,96 +922,19 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 		  set_sig_errno (EAGAIN);
 		  totalread = -1;
 		}
-	      goto out;
-	    }
-	  continue;
-	default:
-	  termios_printf ("wait for input mutex failed, %E");
-	  if (!totalread)
-	    {
-	      __seterrno ();
-	      totalread = -1;
-	    }
-	  goto out;
-	}
-      if (ptr && to_be_read_from_pcon ())
-	{
-	  if (get_readahead_valid ())
-	    {
-	      ReleaseMutex (input_mutex);
-	      totalread = get_readahead_into_buffer ((char *) ptr, len);
-	    }
-	  else
-	    {
-	      if (!try_reattach_pcon ())
-		{
-		  restore_reattach_pcon ();
-		  goto do_read_cyg;
-		}
-
-	      DWORD dwMode;
-	      GetConsoleMode (get_handle (), &dwMode);
-	      DWORD flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
-	      if (dwMode != flags)
-		SetConsoleMode (get_handle (), flags);
-	      /* Read get_handle() instad of get_handle_cyg() */
-	      BOOL (WINAPI *ReadFunc)
-		(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID);
-	      ReadFunc = ReadConsoleA_Orig ? ReadConsoleA_Orig : ReadConsoleA;
-	      DWORD rlen;
-	      readlen = MIN (len, sizeof (buf));
-	      if (!ReadFunc (get_handle (), buf, readlen, &rlen, NULL))
-		{
-		  termios_printf ("read failed, %E");
-		  SetConsoleMode (get_handle (), dwMode);
-		  restore_reattach_pcon ();
-		  ReleaseMutex (input_mutex);
-		  set_errno (EIO);
-		  totalread = -1;
-		  goto out;
-		}
-	      SetConsoleMode (get_handle (), dwMode);
-	      restore_reattach_pcon ();
-	      ReleaseMutex (input_mutex);
-
-	      ssize_t nlen;
-	      char *nbuf = convert_mb_str (get_ttyp ()->term_code_page,
-			     (size_t *) &nlen, GetConsoleCP (), buf, rlen);
-
-	      ssize_t ret;
-	      line_edit_status res =
-		line_edit (nbuf, nlen, get_ttyp ()->ti, &ret);
-
-	      mb_str_free (nbuf);
-
-	      if (res == line_edit_input_done || res == line_edit_ok)
-		totalread = get_readahead_into_buffer ((char *) ptr, len);
-	      else if (res > line_edit_signalled)
-		{
-		  set_sig_errno (EINTR);
-		  totalread = -1;
-		}
-	      else
-		{
-		  update_pcon_input_state (true);
-		  continue;
-		}
+	      goto out;
+	    }
+	  continue;
+	default:
+	  termios_printf ("wait for input mutex failed, %E");
+	  if (!totalread)
+	    {
+	      __seterrno ();
+	      totalread = -1;
 	    }
-
-	  update_pcon_input_state (true);
-	  mask_switch_to_pcon_in (false);
 	  goto out;
 	}
-      if (!ptr && len == UINT_MAX && !get_ttyp ()->pcon_in_empty)
-	{
-	  FlushConsoleInputBuffer (get_handle ());
-	  get_ttyp ()->pcon_in_empty = true;
-	  DWORD n;
-	  if (bytes_available (n) && n == 0)
-	    ResetEvent (input_available_event);
-	}
 
-do_read_cyg:
       if (!bytes_available (bytes_in_pipe))
 	{
 	  ReleaseMutex (input_mutex);
@@ -1911,16 +1051,6 @@ do_read_cyg:
 out:
   termios_printf ("%d = read(%p, %lu)", totalread, ptr, len);
   len = (size_t) totalread;
-  /* Push slave read as echo to pseudo console screen buffer. */
-  if (get_pseudo_console () && ptr0 && totalread > 0 &&
-      (get_ttyp ()->ti.c_lflag & ECHO))
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer (ptr0, len, true);
-      if (get_ttyp ()->switch_to_pcon_out)
-	trigger_redraw_screen ();
-      release_output_mutex ();
-    }
   mask_switch_to_pcon_in (false);
 }
 
@@ -2061,38 +1191,11 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
       get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
       break;
     case TIOCSWINSZ:
-      if (get_pseudo_console ())
-	{
-	  /* If not attached to this pseudo console,
-	     try to attach temporarily. */
-	  pid_restore = 0;
-	  if (pcon_attached_to != get_minor ())
-	    if (!try_reattach_pcon ())
-	      goto cleanup;
-
-	  COORD size;
-	  size.X = ((struct winsize *) arg)->ws_col;
-	  size.Y = ((struct winsize *) arg)->ws_row;
-	  CONSOLE_SCREEN_BUFFER_INFO csbi;
-	  if (GetConsoleScreenBufferInfo (get_output_handle (), &csbi))
-	    if (size.X == csbi.srWindow.Right - csbi.srWindow.Left + 1 &&
-		size.Y == csbi.srWindow.Bottom - csbi.srWindow.Top + 1)
-	      goto cleanup;
-	  if (!SetConsoleScreenBufferSize (get_output_handle (), size))
-	    goto cleanup;
-	  SMALL_RECT rect;
-	  rect.Left = 0;
-	  rect.Top = 0;
-	  rect.Right = size.X-1;
-	  rect.Bottom = size.Y-1;
-	  SetConsoleWindowInfo (get_output_handle (), TRUE, &rect);
-cleanup:
-	  restore_reattach_pcon ();
-	}
-
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->arg.winsize = *(struct winsize *) arg;
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
@@ -2378,6 +1481,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2393,7 +1517,6 @@ fhandler_pty_master::close ()
 {
   OBJECT_BASIC_INFORMATION obi;
   NTSTATUS status;
-  pid_t master_pid_tmp = get_ttyp ()->master_pid;
 
   termios_printf ("closing from_master(%p)/from_master_cyg(%p)/to_master(%p)/to_master_cyg(%p) since we own them(%u)",
 		  from_master, from_master_cyg,
@@ -2438,30 +1561,6 @@ fhandler_pty_master::close ()
   else if (obi.HandleCount == 1)
     {
       termios_printf ("Closing last master of pty%d", get_minor ());
-      /* Close Pseudo Console */
-      if (get_pseudo_console ())
-	{
-	  /* Terminate helper process */
-	  SetEvent (get_ttyp ()->h_helper_goodbye);
-	  WaitForSingleObject (get_ttyp ()->h_helper_process, INFINITE);
-	  CloseHandle (get_ttyp ()->h_helper_goodbye);
-	  CloseHandle (get_ttyp ()->h_helper_process);
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (master_pid_tmp == myself->pid)
-	    {
-	      /* ClosePseudoConsole() seems to have a bug that one
-		 internal handle remains opened. This causes handle leak.
-		 This is a workaround for this problem. */
-	      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_pseudo_console ();
-	      HANDLE tmp = hp->hConHostProcess;
-	      /* Release pseudo console */
-	      ClosePseudoConsole (get_pseudo_console ());
-	      CloseHandle (tmp);
-	    }
-	  get_ttyp ()->switch_to_pcon_in = false;
-	  get_ttyp ()->switch_to_pcon_out = false;
-	}
       if (get_ttyp ()->getsid () > 0)
 	kill (get_ttyp ()->getsid (), SIGHUP);
       SetEvent (input_available_event);
@@ -2469,9 +1568,8 @@ fhandler_pty_master::close ()
 
   if (!ForceCloseHandle (from_master))
     termios_printf ("error closing from_master %p, %E", from_master);
-  if (from_master_cyg != from_master) /* Avoid double close. */
-    if (!ForceCloseHandle (from_master_cyg))
-      termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
+  if (!ForceCloseHandle (from_master_cyg))
+    termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
   if (!ForceCloseHandle (to_master))
     termios_printf ("error closing to_master %p, %E", to_master);
   from_master = to_master = NULL;
@@ -2513,7 +1611,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon () && get_ttyp ()->h_pseudo_console)
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2521,40 +1619,50 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
       WaitForSingleObject (input_mutex, INFINITE);
 
-      if (memchr (buf, '\003', nlen)) /* ^C intr key in pcon */
-	get_ttyp ()->req_flush_pcon_input = true;
-
       DWORD wLen;
-      WriteFile (to_slave, buf, nlen, &wLen, NULL);
-      get_ttyp ()->pcon_in_empty = false;
-
-      ReleaseMutex (input_mutex);
 
-      /* Use line_edit () in order to set input_available_event. */
-      bool is_echo = tc ()->ti.c_lflag & ECHO;
-      if (!get_ttyp ()->mask_switch_to_pcon_in)
+      if (get_ttyp ()->pcon_start)
 	{
-	  tc ()->ti.c_lflag &= ~ECHO;
-	  ti.c_lflag &= ~ECHO;
-	}
-      ti.c_lflag &= ~ISIG;
-      line_edit (buf, nlen, ti, &ret);
-      if (is_echo)
-	tc ()->ti.c_lflag |= ECHO;
-      get_ttyp ()->read_retval = 1;
-
-      const char sigs[] = {
-	(char) ti.c_cc[VINTR],
-	(char) ti.c_cc[VQUIT],
-	(char) ti.c_cc[VSUSP],
-      };
-      if (tc ()->ti.c_lflag & ISIG)
-	for (size_t i=0; i<sizeof (sigs); i++)
-	  if (sigs[i] && memchr (buf, sigs[i], nlen))
+	  /* Pseudo condole support uses "CSI6n" to get cursor position.
+	     If the reply for "CSI6n" is divided into multiple writes,
+	     pseudo console sometimes does not recognize it.  Therefore,
+	     put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon_start = false;
+	    }
+	  else
 	    {
-	      eat_readahead (-1);
-	      SetEvent (input_available_event);
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
 	    }
+	}
+
+      WriteFile (to_slave, buf, nlen, &wLen, NULL);
+
+      ReleaseMutex (input_mutex);
 
       mb_str_free (buf);
       return len;
@@ -2630,15 +1738,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (get_pseudo_console () && get_ttyp ()->master_pid == myself->pid)
-	    {
-	      COORD size;
-	      size.X = ((struct winsize *) arg)->ws_col;
-	      size.Y = ((struct winsize *) arg)->ws_row;
-	      ResizePseudoConsole (get_pseudo_console (), size);
-	    }
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
 	}
@@ -2763,7 +1864,7 @@ get_locale_from_env (char *locale)
   strcpy (locale, env);
 }
 
-static LCID
+static void
 get_langinfo (char *locale_out, char *charset_out)
 {
   /* Get locale from environment */
@@ -2776,11 +1877,6 @@ get_langinfo (char *locale_out, char *charset_out)
   if (!locale)
     locale = "C";
 
-  char tmp_locale[ENCODING_LEN + 1];
-  char *ret = __set_locale_from_locale_alias (locale, tmp_locale);
-  if (ret)
-    locale = tmp_locale;
-
   const char *charset;
   struct lc_ctype_T *lc_ctype = (struct lc_ctype_T *) loc.lc_cat[LC_CTYPE].ptr;
   if (!lc_ctype)
@@ -2830,23 +1926,9 @@ get_langinfo (char *locale_out, char *charset_out)
       charset = "CP932";
     }
 
-  wchar_t lc[ENCODING_LEN + 1];
-  wchar_t *p;
-  mbstowcs (lc, locale, ENCODING_LEN);
-  p = wcschr (lc, L'.');
-  if (p)
-    *p = L'\0';
-  p = wcschr (lc, L'_');
-  if (p)
-    *p = L'-';
-  LCID lcid = LocaleNameToLCID (lc, 0);
-  if (!lcid && !strcmp (charset, "ASCII"))
-    return 0;
-
   /* Set results */
   strcpy (locale_out, new_locale);
   strcpy (charset_out, charset);
-  return lcid;
 }
 
 void
@@ -2857,21 +1939,7 @@ fhandler_pty_slave::setup_locale (void)
 
   char locale[ENCODING_LEN + 1] = "C";
   char charset[ENCODING_LEN + 1] = "ASCII";
-  LCID lcid = get_langinfo (locale, charset);
-
-  /* Set console code page form locale */
-  if (get_pseudo_console ())
-    {
-      UINT code_page;
-      if (lcid == 0 || lcid == (LCID) -1)
-	code_page = 20127; /* ASCII */
-      else if (!GetLocaleInfo (lcid,
-			       LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
-			       (char *) &code_page, sizeof (code_page)))
-	code_page = 20127; /* ASCII */
-      SetConsoleCP (code_page);
-      SetConsoleOutputCP (code_page);
-    }
+  get_langinfo (locale, charset);
 
   /* Set terminal code page from locale */
   /* This code is borrowed from mintty: charset.c */
@@ -2881,9 +1949,9 @@ fhandler_pty_slave::setup_locale (void)
     charset_u[i] = toupper (charset[i]);
   unsigned int iso;
   UINT cp = 20127; /* Default for fallback */
-  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859%u", &iso) == 1)
+  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859%u", &iso) == 1)
     {
       if (iso && iso <= 16 && iso !=12)
 	get_ttyp ()->term_code_page = 28590 + iso;
@@ -2899,90 +1967,9 @@ fhandler_pty_slave::setup_locale (void)
 	}
 }
 
-void
-fhandler_pty_slave::set_freeconsole_on_close (bool val)
-{
-  freeconsole_on_close = val;
-}
-
-void
-fhandler_pty_slave::trigger_redraw_screen (void)
-{
-  /* Forcibly redraw screen based on console screen buffer. */
-  /* The following code triggers redrawing the screen. */
-  CONSOLE_SCREEN_BUFFER_INFO sbi;
-  GetConsoleScreenBufferInfo (get_output_handle (), &sbi);
-  SMALL_RECT rect = {0, 0,
-    (SHORT) (sbi.dwSize.X -1), (SHORT) (sbi.dwSize.Y - 1)};
-  COORD dest = {0, 0};
-  CHAR_INFO fill = {' ', 0};
-  ScrollConsoleScreenBuffer (get_output_handle (), &rect, NULL, dest, &fill);
-  get_ttyp ()->need_redraw_screen = false;
-}
-
-void
-fhandler_pty_slave::fixup_after_attach (bool native_maybe, int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  if (get_pseudo_console ())
-    {
-      if (fhandler_console::get_console_process_id (get_helper_process_id (),
-						    true))
-	if (pcon_attached_to != get_minor ())
-	  {
-	    pcon_attached_to = get_minor ();
-	    init_console_handler (true);
-	  }
-
-#if 0 /* This is for debug only. */
-      isHybrid = true;
-      get_ttyp ()->switch_to_pcon_in = true;
-      get_ttyp ()->switch_to_pcon_out = true;
-#endif
-
-      if (pcon_attached_to == get_minor () && native_maybe)
-	{
-	  if (fd == 0)
-	    {
-	      pull_pcon_input ();
-	      DWORD mode =
-		ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	      SetConsoleMode (get_handle (), mode);
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_in = true;
-	    }
-	  else if (fd == 1 || fd == 2)
-	    {
-	      DWORD mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
-	      SetConsoleMode (get_output_handle (), mode);
-	      acquire_output_mutex (INFINITE);
-	      if (!get_ttyp ()->switch_to_pcon_out)
-		get_ttyp ()->wait_pcon_fwd ();
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_out = true;
-	      release_output_mutex ();
-
-	      if (get_ttyp ()->need_redraw_screen)
-		trigger_redraw_screen ();
-	    }
-	  init_console_handler (false);
-	}
-      else if (fd == 0 && native_maybe)
-	/* Read from unattached pseudo console cause freeze,
-	   therefore, fallback to legacy pty. */
-	set_handle (get_handle_cyg ());
-    }
-}
-
 void
 fhandler_pty_slave::fixup_after_fork (HANDLE parent)
 {
-  fixup_after_attach (false, -1);
   // fork_fixup (parent, inuse, "inuse");
   // fhandler_pty_common::fixup_after_fork (parent);
   report_tty_counts (this, "inherited", "");
@@ -2995,70 +1982,18 @@ fhandler_pty_slave::fixup_after_exec ()
 
   if (!close_on_exec ())
     fixup_after_fork (NULL);	/* No parent handle required. */
-  else if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 1 && get_minor () == pcon_attached_to)
-	pcon_attached_to = -1;
-      if (used == 1 /* About to close this tty */)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
-
-  /* Set locale */
-  setup_locale ();
 
   /* Hook Console API */
-  if (get_pseudo_console ())
-    {
 #define DO_HOOK(module, name) \
-      if (!name##_Orig) \
-	{ \
-	  void *api = hook_api (module, #name, (void *) name##_Hooked); \
-	  name##_Orig = (__typeof__ (name) *) api; \
-	  /*if (api) system_printf (#name " hooked.");*/ \
-	}
-      DO_HOOK (NULL, WriteFile);
-      DO_HOOK (NULL, WriteConsoleA);
-      DO_HOOK (NULL, WriteConsoleW);
-      DO_HOOK (NULL, ReadFile);
-      DO_HOOK (NULL, ReadConsoleA);
-      DO_HOOK (NULL, ReadConsoleW);
-      DO_HOOK (NULL, WriteConsoleOutputA);
-      DO_HOOK (NULL, WriteConsoleOutputW);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterA);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterW);
-      DO_HOOK (NULL, WriteConsoleOutputAttribute);
-      DO_HOOK (NULL, SetConsoleCursorPosition);
-      DO_HOOK (NULL, SetConsoleTextAttribute);
-      DO_HOOK (NULL, WriteConsoleInputA);
-      DO_HOOK (NULL, WriteConsoleInputW);
-      DO_HOOK (NULL, ReadConsoleInputA);
-      DO_HOOK (NULL, ReadConsoleInputW);
-      DO_HOOK (NULL, PeekConsoleInputA);
-      DO_HOOK (NULL, PeekConsoleInputW);
-      /* CreateProcess() is hooked for GDB etc. */
-      DO_HOOK (NULL, CreateProcessA);
-      DO_HOOK (NULL, CreateProcessW);
+  if (!name##_Orig) \
+    { \
+      void *api = hook_api (module, #name, (void *) name##_Hooked); \
+      name##_Orig = (__typeof__ (name) *) api; \
+      /*if (api) system_printf (#name " hooked.");*/ \
     }
+  /* CreateProcess() is hooked for GDB etc. */
+  DO_HOOK (NULL, CreateProcessA);
+  DO_HOOK (NULL, CreateProcessW);
 }
 
 /* This thread function handles the master control pipe.  It waits for a
@@ -3206,27 +2141,6 @@ reply:
   return 0;
 }
 
-void
-fhandler_pty_master::transfer_input_to_pcon (void)
-{
-  WaitForSingleObject (input_mutex, INFINITE);
-  DWORD n;
-  size_t transfered = 0;
-  while (::bytes_available (n, from_master_cyg) && n)
-    {
-      char buf[1024];
-      ReadFile (from_master_cyg, buf, sizeof (buf), &n, 0);
-      char *p = buf;
-      while ((p = (char *) memchr (p, '\n', n - (p - buf))))
-	*p = '\r';
-      if (WriteFile (to_slave, buf, n, &n, 0))
-	transfered += n;
-    }
-  if (transfered)
-    get_ttyp ()->pcon_in_empty = false;
-  ReleaseMutex (input_mutex);
-}
-
 static DWORD WINAPI
 pty_master_thread (VOID *arg)
 {
@@ -3242,23 +2156,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
   termios_printf ("Started.");
   for (;;)
     {
-      if (get_pseudo_console ())
-	{
-	  get_ttyp ()->pcon_last_time = GetTickCount ();
-	  while (::bytes_available (rlen, from_slave) && rlen == 0)
-	    {
-	      /* Forcibly transfer input if it is requested by slave.
-		 This happens when input data should be transfered
-		 from the input pipe for cygwin apps to the input pipe
-		 for native apps. */
-	      if (get_ttyp ()->req_transfer_input_to_pcon)
-		{
-		  transfer_input_to_pcon ();
-		  get_ttyp ()->req_transfer_input_to_pcon = false;
-		}
-	      Sleep (1);
-	    }
-	}
+      get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3266,14 +2164,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_ttyp ()->h_pseudo_console)
 	{
-	  /* Avoid duplicating slave output which is already sent to
-	     to_master_cyg */
-	  if (!get_ttyp ()->switch_to_pcon_out)
-	    continue;
-
-	  /* Avoid setting window title to "cygwin-console-helper.exe" */
+	  /* Remove CSI > Pm m */
 	  int state = 0;
 	  int start_at = 0;
 	  for (DWORD i=0; i<rlen; i++)
@@ -3283,43 +2176,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 		state = 1;
 		continue;
 	      }
-	    else if ((state == 1 && outbuf[i] == ']') ||
-		     (state == 2 && outbuf[i] == '0') ||
-		     (state == 3 && outbuf[i] == ';'))
-	      {
-		state ++;
-		continue;
-	      }
-	    else if (state == 4 && outbuf[i] == '\a')
-	      {
-		const char *helper_str = "\\bin\\cygwin-console-helper.exe";
-		if (memmem (&outbuf[start_at], i + 1 - start_at,
-			    helper_str, strlen (helper_str)))
-		  {
-		    memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
-		    rlen = wlen = start_at + rlen - i - 1;
-		  }
-		state = 0;
-		continue;
-	      }
-	    else if (outbuf[i] == '\a')
-	      {
-		state = 0;
-		continue;
-	      }
-
-	  /* Remove CSI > Pm m */
-	  state = 0;
-	  start_at = 0;
-	  for (DWORD i=0; i<rlen; i++)
-	    if (outbuf[i] == '\033')
-	      {
-		start_at = i;
-		state = 1;
-		continue;
-	      }
-	    else if ((state == 1 && outbuf[i] == '[') ||
-		     (state == 2 && outbuf[i] == '>'))
+	    else if ((state == 1 && outbuf[i] == '[')
+		     || (state == 2 && outbuf[i] == '>'))
 	      {
 		state ++;
 		continue;
@@ -3388,201 +2246,6 @@ pty_master_fwd_thread (VOID *arg)
   return ((fhandler_pty_master *) arg)->pty_master_fwd_thread ();
 }
 
-/* If master process is running as service, attaching to
-   pseudo console should be done in fork. If attaching
-   is done in spawn for inetd or sshd, it fails because
-   the helper process is running as privileged user while
-   slave process is not. This function is used to determine
-   if the process is running as a srvice or not. */
-inline static bool
-is_running_as_service (void)
-{
-  return check_token_membership (well_known_service_sid)
-    || cygheap->user.saved_sid () == well_known_system_sid;
-}
-
-bool
-fhandler_pty_master::setup_pseudoconsole ()
-{
-  if (disable_pcon)
-    return false;
-  /* If the legacy console mode is enabled, pseudo console seems
-     not to work as expected. To determine console mode, registry
-     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
-  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
-  if (reg.error ())
-    return false;
-  if (reg.get_dword (L"ForceV2", 1) == 0)
-    {
-      termios_printf ("Pseudo console is disabled "
-		      "because the legacy console mode is enabled.");
-      return false;
-    }
-
-  /* Pseudo console supprot is realized using a tricky technic.
-     PTY need the pseudo console handles, however, they cannot
-     be retrieved by normal procedure. Therefore, run a helper
-     process in a pseudo console and get them from the helper.
-     Slave process will attach to the pseudo console in the
-     helper process using AttachConsole(). */
-  COORD size = {
-    (SHORT) get_ttyp ()->winsize.ws_col,
-    (SHORT) get_ttyp ()->winsize.ws_row
-  };
-  CreatePipe (&from_master, &to_slave, &sec_none, 0);
-  SetLastError (ERROR_SUCCESS);
-  HRESULT res = CreatePseudoConsole (size, from_master, to_master,
-				     0, &get_ttyp ()->h_pseudo_console);
-  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
-    {
-      if (res != S_OK)
-	system_printf ("CreatePseudoConsole() failed. %08x\n",
-		       GetLastError ());
-      goto fallback;
-    }
-
-  /* If master process is running as service, attaching to
-     pseudo console should be done in fork. If attaching
-     is done in spawn for inetd or sshd, it fails because
-     the helper process is running as privileged user while
-     slave process is not. */
-  if (is_running_as_service ())
-    get_ttyp ()->attach_pcon_in_fork = true;
-
-  STARTUPINFOEXW si_helper;
-  HANDLE hello, goodbye;
-  HANDLE hr, hw;
-  PROCESS_INFORMATION pi_helper;
-  HANDLE hpConIn, hpConOut;
-  {
-    SIZE_T bytesRequired;
-    InitializeProcThreadAttributeList (NULL, 2, 0, &bytesRequired);
-    ZeroMemory (&si_helper, sizeof (si_helper));
-    si_helper.StartupInfo.cb = sizeof (STARTUPINFOEXW);
-    si_helper.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
-      HeapAlloc (GetProcessHeap (), 0, bytesRequired);
-    if (si_helper.lpAttributeList == NULL)
-      goto cleanup_pseudo_console;
-    if (!InitializeProcThreadAttributeList (si_helper.lpAttributeList,
-					    2, 0, &bytesRequired))
-      goto cleanup_heap;
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
-				    get_ttyp ()->h_pseudo_console,
-				    sizeof (get_ttyp ()->h_pseudo_console),
-				    NULL, NULL))
-      goto cleanup_heap;
-    /* Create events for start/stop helper process. */
-    hello = CreateEvent (&sec_none, true, false, NULL);
-    goodbye = CreateEvent (&sec_none, true, false, NULL);
-    /* Create a pipe for receiving pseudo console handles */
-    CreatePipe (&hr, &hw, &sec_none, 0);
-    /* Inherit only handles which are needed by helper. */
-    HANDLE handles_to_inherit[] = {hello, goodbye, hw};
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
-				    handles_to_inherit,
-				    sizeof (handles_to_inherit),
-				    NULL, NULL))
-      goto cleanup_event_and_pipes;
-    /* Create helper process */
-    WCHAR cmd[MAX_PATH];
-    path_conv helper ("/bin/cygwin-console-helper.exe");
-    size_t len = helper.get_wide_win32_path_len ();
-    helper.get_wide_win32_path (cmd);
-    __small_swprintf (cmd + len, L" %p %p %p", hello, goodbye, hw);
-    si_helper.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
-    si_helper.StartupInfo.hStdInput = NULL;
-    si_helper.StartupInfo.hStdOutput = NULL;
-    si_helper.StartupInfo.hStdError = NULL;
-    if (!CreateProcessW (NULL, cmd, &sec_none, &sec_none,
-			 TRUE, EXTENDED_STARTUPINFO_PRESENT,
-			 NULL, NULL, &si_helper.StartupInfo, &pi_helper))
-      goto cleanup_event_and_pipes;
-    for (;;)
-      {
-        DWORD wait_result = WaitForSingleObject (hello, 500);
-	if (wait_result == WAIT_OBJECT_0)
-	  break;
-	if (wait_result != WAIT_TIMEOUT)
-	  goto cleanup_helper_process;
-	DWORD exit_code;
-	if (!GetExitCodeProcess(pi_helper.hProcess, &exit_code))
-	  goto cleanup_helper_process;
-	if (exit_code == STILL_ACTIVE)
-	  continue;
-	if (exit_code != 0 ||
-	    WaitForSingleObject (hello, 500) != WAIT_OBJECT_0)
-	  goto cleanup_helper_process;
-	break;
-      }
-    CloseHandle (hello);
-    CloseHandle (pi_helper.hThread);
-    /* Retrieve pseudo console handles */
-    DWORD rLen;
-    char buf[64];
-    if (!ReadFile (hr, buf, sizeof (buf), &rLen, NULL))
-      goto cleanup_helper_process;
-    buf[rLen] = '\0';
-    sscanf (buf, "StdHandles=%p,%p", &hpConIn, &hpConOut);
-    if (!DuplicateHandle (pi_helper.hProcess, hpConIn,
-			  GetCurrentProcess (), &hpConIn, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_helper_process;
-    if (!DuplicateHandle (pi_helper.hProcess, hpConOut,
-			  GetCurrentProcess (), &hpConOut, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_pcon_in;
-    CloseHandle (hr);
-    CloseHandle (hw);
-    /* Clean up */
-    DeleteProcThreadAttributeList (si_helper.lpAttributeList);
-    HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-  }
-  /* Setting information of stuffs regarding pseudo console */
-  get_ttyp ()->h_helper_goodbye = goodbye;
-  get_ttyp ()->h_helper_process = pi_helper.hProcess;
-  get_ttyp ()->helper_process_id = pi_helper.dwProcessId;
-  CloseHandle (from_master);
-  CloseHandle (to_master);
-  from_master = hpConIn;
-  to_master = hpConOut;
-  ResizePseudoConsole (get_ttyp ()->h_pseudo_console, size);
-  return true;
-
-cleanup_pcon_in:
-  CloseHandle (hpConIn);
-cleanup_helper_process:
-  SetEvent (goodbye);
-  WaitForSingleObject (pi_helper.hProcess, INFINITE);
-  CloseHandle (pi_helper.hProcess);
-  goto skip_close_hello;
-cleanup_event_and_pipes:
-  CloseHandle (hello);
-skip_close_hello:
-  CloseHandle (goodbye);
-  CloseHandle (hr);
-  CloseHandle (hw);
-cleanup_heap:
-  HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-cleanup_pseudo_console:
-  {
-    HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
-    HANDLE tmp = hp->hConHostProcess;
-    ClosePseudoConsole (get_pseudo_console ());
-    CloseHandle (tmp);
-  }
-fallback:
-  CloseHandle (from_master);
-  CloseHandle (to_slave);
-  from_master = from_master_cyg;
-  to_slave = NULL;
-  get_ttyp ()->h_pseudo_console = NULL;
-  return false;
-}
-
 bool
 fhandler_pty_master::setup ()
 {
@@ -3595,11 +2258,6 @@ fhandler_pty_master::setup ()
   if (unit < 0)
     return false;
 
-  /* from_master should be used for pseudo console.
-     Just copy from_master_cyg here for the case that
-     pseudo console is not available. */
-  from_master = from_master_cyg;
-
   ProtectHandle1 (get_output_handle (), to_pty);
 
   tty& t = *cygwin_shared->tty[unit];
@@ -3698,15 +2356,21 @@ fhandler_pty_master::setup ()
       goto err;
     }
 
-  t.winsize.ws_col = 80;
-  t.winsize.ws_row = 25;
-
-  setup_pseudoconsole ();
+  __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;
+    }
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
   t.set_to_master (to_master);
   t.set_to_master_cyg (to_master_cyg);
+  t.winsize.ws_col = 80;
+  t.winsize.ws_row = 25;
   t.master_pid = myself->pid;
 
   dev ().parse (DEV_PTYM_MAJOR, unit);
@@ -3719,6 +2383,7 @@ fhandler_pty_master::setup ()
 err:
   __seterrno ();
   close_maybe (from_slave);
+  close_maybe (to_slave);
   close_maybe (get_handle ());
   close_maybe (get_output_handle ());
   close_maybe (input_available_event);
@@ -3778,9 +2443,6 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 {
   ssize_t towrite = len;
   BOOL res = TRUE;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
   while (towrite)
     {
       if (!is_echo)
@@ -3803,7 +2465,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
       if (!(get_ttyp ()->ti.c_oflag & OPOST))	// raw output mode
 	{
 	  DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
-	  res = WriteFunc (h, ptr, n, &n, NULL);
+	  res = WriteFile (h, ptr, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + n;
@@ -3853,7 +2515,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 		  break;
 		}
 	    }
-	  res = WriteFunc (h, outbuf, n, &n, NULL);
+	  res = WriteFile (h, outbuf, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + rc;
@@ -3863,3 +2525,134 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon)
+{
+
+  /* Setting switch_to_pcon_in is necessary even if
+     pseudo console will not be activated. */
+  fhandler_base *fh = ::cygheap->fdtab[0];
+  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+    {
+      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+      ptys->get_ttyp ()->switch_to_pcon_in = true;
+      if (ptys->get_ttyp ()->pcon_pid == 0
+	  || !pinfo (ptys->get_ttyp ()->pcon_pid))
+	ptys->get_ttyp ()->pcon_pid = myself->pid;
+    }
+
+  if (nopcon)
+    return false;
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  const DWORD inherit_cursor = 1;
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     inherit_cursor,
+				     &get_ttyp ()->h_pseudo_console);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console,
+				  sizeof (get_ttyp ()->h_pseudo_console),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_base *fh0 = ::cygheap->fdtab[0];
+    if (fh0 && fh0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = fh0->get_handle ();
+    fhandler_base *fh1 = ::cygheap->fdtab[1];
+    if (fh1 && fh1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = fh1->get_output_handle ();
+    fhandler_base *fh2 = ::cygheap->fdtab[2];
+    if (fh2 && fh2->get_device () != get_device ())
+      si->StartupInfo.hStdError = fh2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole (void)
+{
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      get_ttyp ()->wait_pcon_fwd ();
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+      get_ttyp ()->pcon_start = false;
+    }
+}
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 7c07b062e..38172ca1e 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -134,36 +134,6 @@ child_info::prefork (bool detached)
 int __stdcall
 frok::child (volatile char * volatile here)
 {
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR)
-      {
-	fhandler_base *fh = cfd;
-	fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
-	if (ptym->get_pseudo_console ())
-	  {
-	    debug_printf ("found a PTY master %d: helper_PID=%d",
-			  ptym->get_minor (), ptym->get_helper_process_id ());
-	    if (fhandler_console::get_console_process_id (
-				ptym->get_helper_process_id (), true))
-	      /* Already attached */
-	      break;
-	    else
-	      {
-		if (ptym->attach_pcon_in_fork ())
-		  {
-		    FreeConsole ();
-		    if (!AttachConsole (ptym->get_helper_process_id ()))
-		      /* Error */;
-		    else
-		      break;
-		  }
-	      }
-	  }
-      }
-  extern void clear_pcon_attached_to (void); /* fhandler_tty.cc */
-  clear_pcon_attached_to ();
-
   HANDLE& hParent = ch.parent;
 
   sync_with_parent ("after longjmp", true);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 4a8f3b2ec..9f1a8a57a 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1215,8 +1215,7 @@ verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds,
 	   fd_set *exceptfds)
 {
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) me->fh;
-  if (me->read_selected && !ptys->to_be_read_from_pcon () &&
-      IsEventSignalled (ptys->input_available_event))
+  if (me->read_selected && IsEventSignalled (ptys->input_available_event))
     me->read_ready = true;
   return set_bits (me, readfds, writefds, exceptfds);
 }
@@ -1229,8 +1228,6 @@ peek_pty_slave (select_record *s, bool from_select)
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
 
   ptys->reset_switch_to_pcon ();
-  if (ptys->to_be_read_from_pcon ())
-    ptys->update_pcon_input_state (true);
 
   if (s->read_selected)
     {
diff --git a/winsup/cygwin/smallprint.cc b/winsup/cygwin/smallprint.cc
index 9cfb41987..4a14ee3cf 100644
--- a/winsup/cygwin/smallprint.cc
+++ b/winsup/cygwin/smallprint.cc
@@ -405,7 +405,6 @@ small_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
   WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, NULL);
   FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
 }
@@ -432,7 +431,6 @@ console_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (console_handle);
   WriteFile (console_handle, buf, count, &done, NULL);
   FlushFileBuffers (console_handle);
 }
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index af177c0f1..dd685eef5 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -177,7 +177,7 @@ find_exec (const char *name, path_conv& buf, const char *search,
 /* Utility for child_info_spawn::worker.  */
 
 static HANDLE
-handle (int fd, bool writing, bool iscygwin)
+handle (int fd, bool writing)
 {
   HANDLE h;
   cygheap_fdget cfd (fd);
@@ -188,17 +188,30 @@ handle (int fd, bool writing, bool iscygwin)
     h = INVALID_HANDLE_VALUE;
   else if (!writing)
     h = cfd->get_handle ();
-  else if (cfd->get_major () == DEV_PTYS_MAJOR && iscygwin)
-    {
-      fhandler_pty_slave *ptys = (fhandler_pty_slave *)(fhandler_base *) cfd;
-      h = ptys->get_output_handle_cyg ();
-    }
   else
     h = cfd->get_output_handle ();
 
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -266,8 +279,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 {
   bool rc;
   int res = -1;
-  DWORD pid_restore = 0;
-  bool attach_to_console = false;
   pid_t ctty_pgid = 0;
 
   /* Search for CTTY and retrieve its PGID */
@@ -587,9 +598,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			 PROCESS_QUERY_LIMITED_INFORMATION))
 	sa = &sec_none_nih;
 
-      /* Attach to pseudo console if pty salve is used */
-      pid_restore = fhandler_console::get_console_process_id
-	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -598,29 +607,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	      if (ptys->get_pseudo_console ())
-		{
-		  DWORD helper_process_id = ptys->get_helper_process_id ();
-		  debug_printf ("found a PTY slave %d: helper_PID=%d",
-				    fh->get_minor (), helper_process_id);
-		  if (fhandler_console::get_console_process_id
-					      (helper_process_id, true))
-		    /* Already attached */
-		    attach_to_console = true;
-		  else if (!attach_to_console)
-		    {
-		      FreeConsole ();
-		      if (AttachConsole (helper_process_id))
-			attach_to_console = true;
-		    }
-		  ptys->fixup_after_attach (!iscygwin (), fd);
-		  if (mode == _P_OVERLAY)
-		    ptys->set_freeconsole_on_close (iscygwin ());
-		}
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	    }
 	  else if (fh && fh->get_major () == DEV_CONS_MAJOR)
 	    {
-	      attach_to_console = true;
 	      fhandler_console *cons = (fhandler_console *) fh;
 	      if (wincap.has_con_24bit_colors () && !iscygwin ())
 		if (fd == 1 || fd == 2)
@@ -628,31 +619,39 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	    }
 	}
 
-      if (!iscygwin ())
-	{
-	  cfd.rewind ();
-	  while (cfd.next () >= 0)
-	    if (cfd->get_major () == DEV_PTYS_MAJOR)
-	      {
-		fhandler_pty_slave *ptys =
-		  (fhandler_pty_slave *)(fhandler_base *) cfd;
-		ptys->setup_locale ();
-	      }
-	}
+      cfd.rewind ();
+      while (cfd.next () >= 0)
+	if (cfd->get_major () == DEV_PTYS_MAJOR)
+	  {
+	    fhandler_pty_slave *ptys =
+	      (fhandler_pty_slave *)(fhandler_base *) cfd;
+	    ptys->setup_locale ();
+	  }
 
       /* Set up needed handles for stdio */
       si.dwFlags = STARTF_USESTDHANDLES;
-      si.hStdInput = handle ((in__stdin < 0 ? 0 : in__stdin), false,
-			     iscygwin ());
-      si.hStdOutput = handle ((in__stdout < 0 ? 1 : in__stdout), true,
-			      iscygwin ());
-      si.hStdError = handle (2, true, iscygwin ());
+      si.hStdInput = handle ((in__stdin < 0 ? 0 : in__stdin), false);
+      si.hStdOutput = handle ((in__stdout < 0 ? 1 : in__stdout), true);
+      si.hStdError = handle (2, true);
 
       si.cb = sizeof (si);
 
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool enable_pcon = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole (&si_pcon,
+			     mode != _P_OVERLAY && mode != _P_WAIT))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    enable_pcon = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -681,7 +680,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -735,7 +734,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -748,6 +747,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (enable_pcon)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -920,6 +924,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	    }
 	  if (sem)
 	    __posix_spawn_sem_release (sem, 0);
+	  if (enable_pcon)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->close_pseudoconsole ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
@@ -927,6 +936,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  system_call.arm ();
 	  if (waitpid (cygpid, &res, 0) != cygpid)
 	    res = -1;
+	  if (enable_pcon)
+	    ptys_primary->close_pseudoconsole ();
 	  break;
 	case _P_DETACH:
 	  res = 0;	/* Lost all memory of this child. */
@@ -953,21 +964,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
   if (envblock)
     free (envblock);
 
-  if (attach_to_console && pid_restore)
-    {
-      FreeConsole ();
-      AttachConsole (pid_restore);
-      cygheap_fdenum cfd (false);
-      int fd;
-      while ((fd = cfd.next ()) >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_pty_slave *ptys =
-	      (fhandler_pty_slave *) (fhandler_base *) cfd;
-	    ptys->fixup_after_attach (false, fd);
-	  }
-    }
-
   return (int) res;
 }
 
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index f0aef3a36..35f8a59ae 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -264,7 +264,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
   if (category & _STRACE_SYSTEM)
     {
       DWORD done;
-      set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
       WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
       FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
       /* Make sure that the message shows up on the screen, too, since this is
@@ -276,7 +275,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
 				 &sec_none, OPEN_EXISTING, 0, 0);
 	  if (h != INVALID_HANDLE_VALUE)
 	    {
-	      set_ishybrid_and_switch_to_pcon (h);
 	      WriteFile (h, buf, len, &done, 0);
 	      CloseHandle (h);
 	    }
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 4cb68f776..d60f27545 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -234,20 +234,14 @@ tty::init ()
   was_opened = false;
   master_pid = 0;
   is_console = false;
-  attach_pcon_in_fork = false;
-  h_pseudo_console = NULL;
   column = 0;
+  h_pseudo_console = NULL;
   switch_to_pcon_in = false;
-  switch_to_pcon_out = false;
-  screen_alternated = false;
   mask_switch_to_pcon_in = false;
   pcon_pid = 0;
   term_code_page = 0;
-  need_redraw_screen = true;
   pcon_last_time = 0;
-  pcon_in_empty = true;
-  req_transfer_input_to_pcon = false;
-  req_flush_pcon_input = false;
+  pcon_start = false;
 }
 
 HANDLE
@@ -293,16 +287,6 @@ tty_min::ttyname ()
   return d.name ();
 }
 
-void
-tty::set_switch_to_pcon_out (bool v)
-{
-  if (switch_to_pcon_out != v)
-    {
-      wait_pcon_fwd ();
-      switch_to_pcon_out = v;
-    }
-}
-
 void
 tty::wait_pcon_fwd (void)
 {
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 920e32b16..c491d3891 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -94,21 +94,13 @@ private:
   HANDLE _to_master;
   HANDLE _to_master_cyg;
   HPCON h_pseudo_console;
-  HANDLE h_helper_process;
-  DWORD helper_process_id;
-  HANDLE h_helper_goodbye;
-  bool attach_pcon_in_fork;
+  bool pcon_start;
   bool switch_to_pcon_in;
-  bool switch_to_pcon_out;
-  bool screen_alternated;
   bool mask_switch_to_pcon_in;
   pid_t pcon_pid;
   UINT term_code_page;
-  bool need_redraw_screen;
   DWORD pcon_last_time;
-  bool pcon_in_empty;
-  bool req_transfer_input_to_pcon;
-  bool req_flush_pcon_input;
+  HANDLE h_pcon_write_pipe;
 
 public:
   HANDLE from_master () const { return _from_master; }
@@ -138,7 +130,6 @@ public:
   void set_master_ctl_closed () {master_pid = -1;}
   static void __stdcall create_master (int);
   static void __stdcall init_session ();
-  void set_switch_to_pcon_out (bool v);
   void wait_pcon_fwd (void);
   friend class fhandler_pty_common;
   friend class fhandler_pty_master;
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index 9bfa1a7a6..79844cb87 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -224,9 +224,6 @@ void init_console_handler (bool);
 
 extern bool wsock_started;
 
-/* PTY related */
-void set_ishybrid_and_switch_to_pcon (HANDLE h);
-
 /* Printf type functions */
 extern "C" void vapi_fatal (const char *, va_list ap) __attribute__ ((noreturn));
 extern "C" void api_fatal (const char *, ...) __attribute__ ((noreturn));
-- 
2.28.0


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-17 11:57                                           ` Takashi Yano
@ 2020-08-19 11:39                                             ` Takashi Yano
  2020-08-19 13:41                                               ` Corinna Vinschen
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-08-19 11:39 UTC (permalink / raw)
  To: cygwin-developers

[-- Attachment #1: Type: text/plain, Size: 4664 bytes --]

On Mon, 17 Aug 2020 20:57:18 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> On Thu, 13 Aug 2020 18:58:13 +0900
> Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > On Tue, 11 Aug 2020 20:12:58 +0900
> > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > On Mon, 3 Aug 2020 21:23:42 +0900
> > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > On Mon, 3 Aug 2020 11:11:03 +0900
> > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > On Fri, 24 Jul 2020 20:22:19 +0900
> > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > On Fri, 24 Jul 2020 14:38:42 +0900
> > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > On Thu, 23 Jul 2020 09:33:28 +0900
> > > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > > On Wed, 22 Jul 2020 17:45:41 +0900
> > > > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > > > On Wed, 22 Jul 2020 03:17:51 +0900
> > > > > > > > > Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:
> > > > > > > > > > Hi Corinna,
> > > > > > > > > > 
> > > > > > > > > > On Mon, 20 Jul 2020 10:06:13 +0200
> > > > > > > > > > Corinna Vinschen wrote:
> > > > > > > > > > > On Jul 18 14:30, Takashi Yano via Cygwin-developers wrote:
> > > > > > > > > > > > Hi Corinna,
> > > > > > > > > > > > 
> > > > > > > > > > > > On Fri, 17 Jul 2020 13:19:12 +0200
> > > > > > > > > > > > Corinna Vinschen wrote:
> > > > > > > > > > > > > Hi Takashi,
> > > > > > > > > > > > > 
> > > > > > > > > > > > > On Jul  1 20:47, Takashi Yano via Cygwin-developers wrote:
> > > > > > > > > > > > > > [...]
> > > > > > > > > > > > > > Revise the patch to fit the current git head.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > are you satisfied with the code?  If you want to merge it,
> > > > > > > > > > > > > I'd bump Cygwin to 3.2.
> > > > > > > > > > > > 
> > > > > > > > > > > > Since this new implementation has both advantages and disadvantages,
> > > > > > > > > > > > there might be some options.
> > > > > > > > > > > > 
> > > > > > > > > > > > 1) Default to new implementation and leave the current one as an
> > > > > > > > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > > > > > > > 2) Default to current implementation and add the new one as an
> > > > > > > > > > > >   alternative. Switch them using the environment CYGWIN.
> > > > > > > > > > > > 3) Adopt only new implementation and throw the current one away.
> > > > > > > > > > > > 
> > > > > > > > > > > > What do you think?
> > > > > > > > > > > 
> > > > > > > > > > > Do you really want to maintain twice as much code doing the same stuff
> > > > > > > > > > > and constantly having to ask users which version of the code they are
> > > > > > > > > > > running?  The maintenance cost outweighs the advantages, IMHO.
> > > > > > > > > > > Personally I'd go for option 3.
> > > > > > > > > > 
> > > > > > > > > > Personally, I feel a tinge of sadness to discard the current code,
> > > > > > > > > > however, your opinion sounds reasonable.
> > > > > > > > > > 
> > > > > > > > > > I will submit a new patch in which all the codes specific to the
> > > > > > > > > > current implementation are removed.
> > > > > > > > > 
> > > > > > > > > Attached is the patch in git format-patch format.
> > > > > > > > > All the codes specific to the current implementation are removed.
> > > > > > > > > 
> > > > > > > > > Despite the utmost care, the changes are relatively large, so some
> > > > > > > > > degradation may exist.
> > > > > > > > > 
> > > > > > > > > I will appreciate if you could test.
> > > > > > > > 
> > > > > > > > There were still unused code. Please try attached patch instead.
> > > > > > > 
> > > > > > > Changes:
> > > > > > > * Do not activate pseudo console if it is already activated for
> > > > > > >   another process on same pty.
> > > > > > 
> > > > > > Changes:
> > > > > > * Fix a bug in the latest change.
> > > > > 
> > > > > Changes:
> > > > > * Fix a handle leak caused when spawn is called with mode != _P_OVERLAY.
> > > > 
> > > > This patch cannot be applied cleanly against current git head.
> > > > Please use attached patch instead.
> > > 
> > > Adapted to the current git head.
> > 
> > Adapted to the current recent pty change.
> 
> Adapted to the current git head.

Aligned the timing of seup_locale () call with the recent pty change.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-Cygwin-pty-Implement-new-pseudo-console-support.patch --]
[-- Type: application/octet-stream, Size: 90673 bytes --]

From b2fba6b64d815fd17baf6f8b3f5b20de0b67fb04 Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Wed, 19 Aug 2020 20:25:21 +0900
Subject: [PATCH] Cygwin: pty: Implement new pseudo console support.

- In this implementation, pseudo console is created for each native
  console app. Advantages and disadvantages of this implementation
  over the previous implementation are as follows.

  Advantages:
  1) No performance degradation in pty output for cygwin process.
      https://cygwin.com/pipermail/cygwin/2020-February/243858.html
  2) Free from the problem caused by difference of behaviour of control
     sequences between real terminal and pseudo console.
      https://cygwin.com/pipermail/cygwin/2019-December/243281.html
      https://cygwin.com/pipermail/cygwin/2020-February/243855.html
  3) Free from the problem in cgdb and emacs gud.
      https://cygwin.com/pipermail/cygwin/2020-January/243601.html
      https://cygwin.com/pipermail/cygwin/2020-March/244146.html
  4) Redrawing screen on executing native console apps is not necessary.
  5) cygwin-console-helper is not necessary for the pseudo console
     support.
  6) The codes for pseudo console support are much simpler than that
     of the previous one.

  Disadvantages:
  1) The cygwin program which calls console API directly does not work.
  2) The apps which use console API cannot be debugged with gdb. This
     is because pseudo console is not activated since gdb uses
     CreateProcess() rather than exec(). Even with this limitation,
     attaching gdb to native apps, in which pseudo console is already
     activated, works.
  3) Typeahead key inputs are discarded while native console app is
     executed. Simirally, typeahead key inputs while cygwin app is
     executed are not inherited to native console app.
  4) Code page cannot be changed by chcp.com. Acctually, chcp works
     itself and changes code page of its own pseudo console.  However,
     since pseudo console is recreated for another process, it cannot
     inherit the code page.
  5) system_printf() does not work after stderr is closed. (Same with
     cygwin 3.0.7)
  6) Startup time of native console apps is about 3 times slower than
     previous implemenation.
  7) Pseudo console cannot be activated if it is already activated for
     another process on same pty.
---
 winsup/cygwin/dtable.cc           |   32 -
 winsup/cygwin/fhandler.h          |   53 +-
 winsup/cygwin/fhandler_console.cc |   43 -
 winsup/cygwin/fhandler_tty.cc     | 1770 +++++------------------------
 winsup/cygwin/fork.cc             |   30 -
 winsup/cygwin/select.cc           |    5 +-
 winsup/cygwin/smallprint.cc       |    2 -
 winsup/cygwin/spawn.cc            |  105 +-
 winsup/cygwin/strace.cc           |    2 -
 winsup/cygwin/tty.cc              |   20 +-
 winsup/cygwin/tty.h               |   13 +-
 winsup/cygwin/winsup.h            |    3 -
 12 files changed, 349 insertions(+), 1729 deletions(-)

diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index e9e005b08..6a91e33bc 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -147,38 +147,6 @@ dtable::get_debugger_info ()
 void
 dtable::stdio_init ()
 {
-  for (int i = 0; i < 3; i ++)
-    {
-      const int chk_order[] = {1, 0, 2};
-      int fd = chk_order[i];
-      fhandler_base *fh = cygheap->fdtab[fd];
-      if (fh && fh->get_major () == DEV_PTYS_MAJOR)
-	{
-	  fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	  if (ptys->get_pseudo_console ())
-	    {
-	      bool attached = !!fhandler_console::get_console_process_id
-		(ptys->get_helper_process_id (), true);
-	      if (attached)
-		break;
-	      else
-		{
-		  /* Not attached to pseudo console in fork() or spawn()
-		     by some reason. This happens if the executable is
-		     a windows GUI binary, such as mintty. */
-		  FreeConsole ();
-		  if (AttachConsole (ptys->get_helper_process_id ()))
-		    {
-		      ptys->fixup_after_attach (false, fd);
-		      break;
-		    }
-		}
-	    }
-	}
-      else if (fh && fh->get_major () == DEV_CONS_MAJOR)
-	break;
-    }
-
   if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT))
     {
       tty_min *t = cygwin_shared->tty.get_cttyp ();
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index a577ca542..9fd95c098 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -326,16 +326,16 @@ class fhandler_base
   virtual size_t &raixput () { return ra.raixput; };
   virtual size_t &rabuflen () { return ra.rabuflen; };
 
-  virtual bool get_readahead_valid () { return raixget () < ralen (); }
+  bool get_readahead_valid () { return raixget () < ralen (); }
   int puts_readahead (const char *s, size_t len = (size_t) -1);
-  virtual int put_readahead (char value);
+  int put_readahead (char value);
 
   int get_readahead ();
   int peek_readahead (int queryput = 0);
 
   void set_readahead_valid (int val, int ch = -1);
 
-  virtual int get_readahead_into_buffer (char *buf, size_t buflen);
+  int get_readahead_into_buffer (char *buf, size_t buflen);
 
   bool has_acls () const { return pc.has_acls (); }
 
@@ -1905,7 +1905,7 @@ class fhandler_termios: public fhandler_base
   int ioctl (int, void *);
   tty_min *_tc;
   tty *get_ttyp () {return (tty *) tc ();}
-  virtual int eat_readahead (int n);
+  int eat_readahead (int n);
 
  public:
   tty_min*& tc () {return _tc;}
@@ -2184,7 +2184,6 @@ private:
   static bool need_invisible ();
   static void free_console ();
   static const char *get_nonascii_key (INPUT_RECORD& input_rec, char *);
-  static DWORD get_console_process_id (DWORD pid, bool match);
 
   fhandler_console (void *) {}
 
@@ -2264,19 +2263,7 @@ class fhandler_pty_common: public fhandler_termios
     return fh;
   }
 
-  bool attach_pcon_in_fork (void)
-  {
-    return get_ttyp ()->attach_pcon_in_fork;
-  }
-  DWORD get_helper_process_id (void)
-  {
-    return get_ttyp ()->helper_process_id;
-  }
-  HPCON get_pseudo_console (void)
-  {
-    return get_ttyp ()->h_pseudo_console;
-  }
-  bool to_be_read_from_pcon (void);
+  void resize_pseudo_console (struct winsize *);
 
  protected:
   BOOL process_opost_output (HANDLE h,
@@ -2287,23 +2274,15 @@ class fhandler_pty_slave: public fhandler_pty_common
 {
   HANDLE inuse;			// used to indicate that a tty is in use
   HANDLE output_handle_cyg, io_handle_cyg;
-  DWORD pid_restore;
-  int fd;
 
   /* Helper functions for fchmod and fchown. */
   bool fch_open_handles (bool chown);
   int fch_set_sd (security_descriptor &sd, bool chown);
   void fch_close_handles ();
 
-  bool try_reattach_pcon ();
-  void restore_reattach_pcon ();
-  inline void free_attached_console ();
-
  public:
   /* Constructor */
   fhandler_pty_slave (int);
-  /* Destructor */
-  ~fhandler_pty_slave ();
 
   void set_output_handle_cyg (HANDLE h) { output_handle_cyg = h; }
   HANDLE& get_output_handle_cyg () { return output_handle_cyg; }
@@ -2315,9 +2294,6 @@ class fhandler_pty_slave: public fhandler_pty_common
   ssize_t __stdcall write (const void *ptr, size_t len);
   void __reg3 read (void *ptr, size_t& len);
   int init (HANDLE, DWORD, mode_t);
-  int eat_readahead (int n);
-  int get_readahead_into_buffer (char *buf, size_t buflen);
-  bool get_readahead_valid (void);
 
   int tcsetattr (int a, const struct termios *t);
   int tcgetattr (struct termios *t);
@@ -2354,20 +2330,12 @@ class fhandler_pty_slave: public fhandler_pty_common
     copyto (fh);
     return fh;
   }
-  void set_switch_to_pcon (int fd);
+  bool setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon);
+  void close_pseudoconsole (void);
+  void set_switch_to_pcon (void);
   void reset_switch_to_pcon (void);
-  void push_to_pcon_screenbuffer (const char *ptr, size_t len, bool is_echo);
   void mask_switch_to_pcon_in (bool mask);
-  void fixup_after_attach (bool native_maybe, int fd);
-  bool is_line_input (void)
-  {
-    return get_ttyp ()->ti.c_lflag & ICANON;
-  }
   void setup_locale (void);
-  void set_freeconsole_on_close (bool val);
-  void trigger_redraw_screen (void);
-  void pull_pcon_input (void);
-  void update_pcon_input_state (bool need_lock);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
@@ -2392,7 +2360,6 @@ public:
   int process_slave_output (char *buf, size_t len, int pktmode_on);
   void doecho (const void *str, DWORD len);
   int accept_input ();
-  int put_readahead (char value);
   int open (int flags, mode_t mode = 0);
   void open_setup (int flags);
   ssize_t __stdcall write (const void *ptr, size_t len);
@@ -2431,9 +2398,7 @@ public:
     copyto (fh);
     return fh;
   }
-
-  bool setup_pseudoconsole (void);
-  void transfer_input_to_pcon (void);
+  bool to_be_read_from_pcon (void);
 };
 
 class fhandler_dev_null: public fhandler_base
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 52741ce8b..02a5996a1 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -1206,18 +1206,6 @@ fhandler_console::close ()
   if (con_ra.rabuf)
     free (con_ra.rabuf);
 
-  /* If already attached to pseudo console, don't call free_console () */
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR ||
-	cfd->get_major () == DEV_PTYS_MAJOR)
-      {
-	fhandler_pty_common *t =
-	  (fhandler_pty_common *) (fhandler_base *) cfd;
-	if (get_console_process_id (t->get_helper_process_id (), true))
-	  return 0;
-      }
-
   if (!have_execed)
     free_console ();
   return 0;
@@ -3611,37 +3599,6 @@ fhandler_console::need_invisible ()
   return b;
 }
 
-DWORD
-fhandler_console::get_console_process_id (DWORD pid, bool match)
-{
-  DWORD tmp;
-  DWORD num, num_req;
-  num = 1;
-  num_req = GetConsoleProcessList (&tmp, num);
-  DWORD *list;
-  while (true)
-    {
-      list = (DWORD *)
-	HeapAlloc (GetProcessHeap (), 0, num_req * sizeof (DWORD));
-      num = num_req;
-      num_req = GetConsoleProcessList (list, num);
-      if (num_req > num)
-	HeapFree (GetProcessHeap (), 0, list);
-      else
-	break;
-    }
-  num = num_req;
-
-  tmp = 0;
-  for (DWORD i=0; i<num; i++)
-    if ((match && list[i] == pid) || (!match && list[i] != pid))
-      /* Last one is the oldest. */
-      /* https://github.com/microsoft/terminal/issues/95 */
-      tmp = list[i];
-  HeapFree (GetProcessHeap (), 0, list);
-  return tmp;
-}
-
 DWORD
 fhandler_console::__acquire_input_mutex (const char *fn, int ln, DWORD ms)
 {
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 6294e2c20..0865c1fac 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -25,7 +25,6 @@ details. */
 #include "child_info.h"
 #include <asm/socket.h>
 #include "cygwait.h"
-#include "tls_pbuf.h"
 #include "registry.h"
 
 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
@@ -33,7 +32,6 @@ details. */
 #endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
 
 extern "C" int sscanf (const char *, const char *, ...);
-extern "C" int ttyname_r (int, char*, size_t);
 
 extern "C" {
   HRESULT WINAPI CreatePseudoConsole (COORD, HANDLE, HANDLE, DWORD, HPCON *);
@@ -60,20 +58,10 @@ struct pipe_reply {
   DWORD error;
 };
 
-static int pcon_attached_to = -1;
 static bool isHybrid;
-static bool do_not_reset_switch_to_pcon;
-static bool freeconsole_on_close = true;
-static tty *last_ttyp = NULL;
-
-void
-clear_pcon_attached_to (void)
-{
-  pcon_attached_to = -1;
-}
 
 static void
-set_switch_to_pcon (void)
+set_switch_to_pcon (HANDLE h)
 {
   cygheap_fdenum cfd (false);
   int fd;
@@ -82,280 +70,17 @@ set_switch_to_pcon (void)
       {
 	fhandler_base *fh = cfd;
 	fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	if (ptys->get_pseudo_console ())
-	  {
-	    ptys->set_switch_to_pcon (fd);
-	    ptys->trigger_redraw_screen ();
-	    DWORD mode =
-	      ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	    SetConsoleMode (ptys->get_handle (), mode);
-	  }
+	if (h == ptys->get_handle ())
+	  ptys->set_switch_to_pcon ();
 	return;
       }
-  /* No pty slave opened */
-  if (last_ttyp) /* Make system_printf() work after closing pty slave */
-    last_ttyp->set_switch_to_pcon_out (true);
-}
-
-static void
-force_attach_to_pcon (HANDLE h)
-{
-  bool attach_done = false;
-  for (int n = 0; n < 2; n ++)
-    {
-      /* First time, attach to the pty whose handle value is match.
-	 Second time, try to attach to any pty. */
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	    if (!ptys->get_pseudo_console ())
-	      continue;
-	    if (n != 0
-		|| h == ptys->get_handle ()
-		|| h == ptys->get_output_handle ())
-	      {
-		if (fhandler_console::get_console_process_id
-				  (ptys->get_helper_process_id (), true))
-		  attach_done = true;
-		else
-		  {
-		    FreeConsole ();
-		    if (AttachConsole (ptys->get_helper_process_id ()))
-		      {
-			pcon_attached_to = ptys->get_minor ();
-			attach_done = true;
-		      }
-		    else
-		      pcon_attached_to = -1;
-		  }
-		break;
-	      }
-	  }
-	else if (cfd->get_major () == DEV_CONS_MAJOR)
-	  {
-	    fhandler_base *fh = cfd;
-	    fhandler_console *cons = (fhandler_console *) fh;
-	    if (n != 0
-		|| h == cons->get_handle ()
-		|| h == cons->get_output_handle ())
-	      {
-		/* If the process is running on a console,
-		   the parent process should be attached
-		   to the same console. */
-		DWORD attach_wpid;
-		if (myself->ppid == 1)
-		  attach_wpid = ATTACH_PARENT_PROCESS;
-		else
-		  {
-		    pinfo p (myself->ppid);
-		    attach_wpid = p->dwProcessId;
-		  }
-		FreeConsole ();
-		if (AttachConsole (attach_wpid))
-		  {
-		    pcon_attached_to = -1;
-		    attach_done = true;
-		  }
-		else
-		  pcon_attached_to = -1;
-		break;
-	      }
-	  }
-      if (attach_done)
-	break;
-    }
-}
-
-void
-set_ishybrid_and_switch_to_pcon (HANDLE h)
-{
-  if (GetFileType (h) == FILE_TYPE_CHAR)
-    {
-      force_attach_to_pcon (h);
-      DWORD dummy;
-      if (!isHybrid && (GetConsoleMode (h, &dummy)
-			|| GetLastError () != ERROR_INVALID_HANDLE))
-	{
-	  isHybrid = true;
-	  set_switch_to_pcon ();
-	}
-    }
-}
-
-inline void
-fhandler_pty_slave::free_attached_console ()
-{
-  bool attached = get_ttyp () ?
-    fhandler_console::get_console_process_id (get_helper_process_id (), true)
-    : (get_minor () == pcon_attached_to);
-  if (freeconsole_on_close && attached)
-    {
-      FreeConsole ();
-      pcon_attached_to = -1;
-    }
 }
 
 #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
-DEF_HOOK (WriteFile);
-DEF_HOOK (WriteConsoleA);
-DEF_HOOK (WriteConsoleW);
-DEF_HOOK (ReadFile);
-DEF_HOOK (ReadConsoleA);
-DEF_HOOK (ReadConsoleW);
-DEF_HOOK (WriteConsoleOutputA);
-DEF_HOOK (WriteConsoleOutputW);
-DEF_HOOK (WriteConsoleOutputCharacterA);
-DEF_HOOK (WriteConsoleOutputCharacterW);
-DEF_HOOK (WriteConsoleOutputAttribute);
-DEF_HOOK (SetConsoleCursorPosition);
-DEF_HOOK (SetConsoleTextAttribute);
-DEF_HOOK (WriteConsoleInputA);
-DEF_HOOK (WriteConsoleInputW);
-DEF_HOOK (ReadConsoleInputA);
-DEF_HOOK (ReadConsoleInputW);
-DEF_HOOK (PeekConsoleInputA);
-DEF_HOOK (PeekConsoleInputW);
 /* CreateProcess() is hooked for GDB etc. */
 DEF_HOOK (CreateProcessA);
 DEF_HOOK (CreateProcessW);
 
-static BOOL WINAPI
-WriteFile_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleA_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleW_Hooked
-     (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadFile_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadFile_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleA_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleA_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-ReadConsoleW_Hooked
-     (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleW_Orig (h, p, l, n, o);
-}
-static BOOL WINAPI
-WriteConsoleOutputA_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputA_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputW_Hooked
-     (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputW_Orig (h, p, s, c, r);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterA_Hooked
-     (HANDLE h, LPCSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterA_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputCharacterW_Hooked
-     (HANDLE h, LPCWSTR p, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputCharacterW_Orig (h, p, l, c, n);
-}
-static BOOL WINAPI
-WriteConsoleOutputAttribute_Hooked
-     (HANDLE h, CONST WORD *a, DWORD l, COORD c, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleOutputAttribute_Orig (h, a, l, c, n);
-}
-static BOOL WINAPI
-SetConsoleCursorPosition_Hooked
-     (HANDLE h, COORD c)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleCursorPosition_Orig (h, c);
-}
-static BOOL WINAPI
-SetConsoleTextAttribute_Hooked
-     (HANDLE h, WORD a)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return SetConsoleTextAttribute_Orig (h, a);
-}
-static BOOL WINAPI
-WriteConsoleInputA_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-WriteConsoleInputW_Hooked
-     (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return WriteConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-ReadConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return ReadConsoleInputW_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputA_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputA_Orig (h, r, l, n);
-}
-static BOOL WINAPI
-PeekConsoleInputW_Hooked
-     (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
-{
-  set_ishybrid_and_switch_to_pcon (h);
-  return PeekConsoleInputW_Orig (h, r, l, n);
-}
-/* CreateProcess() is hooked for GDB etc. */
 static BOOL WINAPI
 CreateProcessA_Hooked
      (LPCSTR n, LPSTR c, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta,
@@ -363,11 +88,14 @@ CreateProcessA_Hooked
       LPSTARTUPINFOA si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 static BOOL WINAPI
@@ -377,11 +105,14 @@ CreateProcessW_Hooked
       LPSTARTUPINFOW si, LPPROCESS_INFORMATION pi)
 {
   HANDLE h;
-  if (si->dwFlags & STARTF_USESTDHANDLES)
-    h = si->hStdOutput;
-  else
-    h = GetStdHandle (STD_OUTPUT_HANDLE);
-  set_ishybrid_and_switch_to_pcon (h);
+  if (!isHybrid)
+    {
+      if (si->dwFlags & STARTF_USESTDHANDLES)
+	h = si->hStdInput;
+      else
+	h = GetStdHandle (STD_INPUT_HANDLE);
+      set_switch_to_pcon (h);
+    }
   return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
 }
 
@@ -464,10 +195,6 @@ fhandler_pty_master::flush_to_slave ()
 {
   if (get_readahead_valid () && !(get_ttyp ()->ti.c_lflag & ICANON))
     accept_input ();
-  WaitForSingleObject (input_mutex, INFINITE);
-  if (!get_ttyp ()->pcon_in_empty && !(get_ttyp ()->ti.c_lflag & ICANON))
-    SetEvent (input_available_event);
-  ReleaseMutex (input_mutex);
 }
 
 DWORD
@@ -532,14 +259,6 @@ fhandler_pty_master::doecho (const void *str, DWORD len)
   release_output_mutex ();
 }
 
-int
-fhandler_pty_master::put_readahead (char value)
-{
-  if (to_be_read_from_pcon ())
-    return 1;
-  return fhandler_base::put_readahead (value);
-}
-
 int
 fhandler_pty_master::accept_input ()
 {
@@ -551,9 +270,11 @@ fhandler_pty_master::accept_input ()
   char *p = rabuf () + raixget ();
   bytes_left = eat_readahead (-1);
 
+  HANDLE write_to = get_output_handle ();
   if (to_be_read_from_pcon ())
-    ; /* Do nothing */
-  else if (!bytes_left)
+    write_to = to_slave;
+
+  if (!bytes_left)
     {
       termios_printf ("sending EOF to slave");
       get_ttyp ()->read_retval = 0;
@@ -564,10 +285,10 @@ fhandler_pty_master::accept_input ()
       DWORD written = 0;
 
       paranoid_printf ("about to write %u chars to slave", bytes_left);
-      rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
+      rc = WriteFile (write_to, p, bytes_left, &written, NULL);
       if (!rc)
 	{
-	  debug_printf ("error writing to pipe %p %E", get_output_handle ());
+	  debug_printf ("error writing to pipe %p %E", write_to);
 	  get_ttyp ()->read_retval = -1;
 	  ret = -1;
 	}
@@ -725,52 +446,12 @@ out:
 
 fhandler_pty_slave::fhandler_pty_slave (int unit)
   : fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL),
-  io_handle_cyg (NULL), pid_restore (0), fd (-1)
+  io_handle_cyg (NULL)
 {
   if (unit >= 0)
     dev ().parse (DEV_PTYS_MAJOR, unit);
 }
 
-fhandler_pty_slave::~fhandler_pty_slave ()
-{
-  if (!get_ttyp ())
-    {
-      /* Why comes here? Who clears _tc? */
-      free_attached_console ();
-      return;
-    }
-  if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 0)
-	{
-	  pcon_attached_to = -1;
-	  last_ttyp = get_ttyp ();
-	}
-      if (used == 0)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
-}
-
 int
 fhandler_pty_slave::open (int flags, mode_t)
 {
@@ -833,8 +514,8 @@ fhandler_pty_slave::open (int flags, mode_t)
     release_output_mutex ();
   }
 
-  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg () ||
-      !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
+  if (!get_ttyp ()->from_master () || !get_ttyp ()->from_master_cyg ()
+      || !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ())
     {
       errmsg = "pty handles have been closed";
       set_errno (EACCES);
@@ -923,8 +604,8 @@ fhandler_pty_slave::open (int flags, mode_t)
       from_master_cyg_local = repl.from_master_cyg;
       to_master_local = repl.to_master;
       to_master_cyg_local = repl.to_master_cyg;
-      if (!from_master_local || !from_master_cyg_local ||
-	  !to_master_local || !to_master_cyg_local)
+      if (!from_master_local || !from_master_cyg_local
+	  || !to_master_local || !to_master_cyg_local)
 	{
 	  SetLastError (repl.error);
 	  errmsg = "error duplicating pipes, %E";
@@ -950,24 +631,7 @@ fhandler_pty_slave::open (int flags, mode_t)
   set_output_handle (to_master_local);
   set_output_handle_cyg (to_master_cyg_local);
 
-  if (!get_pseudo_console ())
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (!fhandler_console::get_console_process_id
-			       (GetCurrentProcessId (), true))
-    {
-      fhandler_console::need_invisible ();
-      pcon_attached_to = -1;
-    }
-  else if (fhandler_console::get_console_process_id
-			       (get_helper_process_id (), true))
-    /* Attached to pcon of this pty */
-    {
-      pcon_attached_to = get_minor ();
-      init_console_handler (true);
-    }
+  fhandler_console::need_invisible ();
 
   set_open_status ();
   return 1;
@@ -1021,8 +685,7 @@ fhandler_pty_slave::close ()
   if (!ForceCloseHandle (get_handle_cyg ()))
     termios_printf ("CloseHandle (get_handle_cyg ()<%p>), %E",
 	get_handle_cyg ());
-  if (!get_pseudo_console () &&
-      (unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
+  if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
     fhandler_console::free_console ();	/* assumes that we are the last pty closer */
   fhandler_pty_common::close ();
   if (!ForceCloseHandle (output_mutex))
@@ -1070,423 +733,31 @@ fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
   return ret;
 }
 
-bool
-fhandler_pty_slave::try_reattach_pcon (void)
-{
-  pid_restore = 0;
-
-  /* Do not detach from the console because re-attaching will
-     fail if helper process is running as service account. */
-  if (get_ttyp()->attach_pcon_in_fork)
-    return false;
-  if (pcon_attached_to >= 0 &&
-      cygwin_shared->tty[pcon_attached_to]->attach_pcon_in_fork)
-    return false;
-
-  pid_restore =
-    fhandler_console::get_console_process_id (GetCurrentProcessId (),
-					      false);
-  /* If pid_restore is not set, give up. */
-  if (!pid_restore)
-    return false;
-
-  FreeConsole ();
-  if (!AttachConsole (get_helper_process_id ()))
-    {
-      system_printf ("pty%d: AttachConsole(helper=%d) failed. 0x%08lx",
-		     get_minor (), get_helper_process_id (), GetLastError ());
-      return false;
-    }
-  return true;
-}
-
 void
-fhandler_pty_slave::restore_reattach_pcon (void)
+fhandler_pty_slave::set_switch_to_pcon (void)
 {
-  if (pid_restore)
+  if (!get_ttyp ()->switch_to_pcon_in)
     {
-      FreeConsole ();
-      if (!AttachConsole (pid_restore))
-	{
-	  system_printf ("pty%d: AttachConsole(restore=%d) failed. 0x%08lx",
-			 get_minor (), pid_restore, GetLastError ());
-	  pcon_attached_to = -1;
-	}
-    }
-  pid_restore = 0;
-}
-
-/* This function requests transfering the input data from the input
-   pipe for cygwin apps to the other input pipe for native apps. */
-void
-fhandler_pty_slave::pull_pcon_input (void)
-{
-  get_ttyp ()->req_transfer_input_to_pcon = true;
-  while (get_ttyp ()->req_transfer_input_to_pcon)
-    Sleep (1);
-}
-
-void
-fhandler_pty_slave::update_pcon_input_state (bool need_lock)
-{
-  if (need_lock)
-    WaitForSingleObject (input_mutex, INFINITE);
-  /* Flush input buffer if it is requested by master.
-     This happens if ^C is pressed in pseudo console side. */
-  if (get_ttyp ()->req_flush_pcon_input)
-    {
-      FlushConsoleInputBuffer (get_handle ());
-      get_ttyp ()->req_flush_pcon_input = false;
-    }
-  /* Peek console input buffer and update state. */
-  INPUT_RECORD inp[INREC_SIZE];
-  DWORD n;
-  BOOL (WINAPI *PeekFunc)
-    (HANDLE, PINPUT_RECORD, DWORD, LPDWORD);
-  PeekFunc =
-    PeekConsoleInputA_Orig ? : PeekConsoleInput;
-  PeekFunc (get_handle (), inp, INREC_SIZE, &n);
-  bool saw_accept = false;
-  bool pipe_empty = true;
-  while (n-- > 0)
-    if (inp[n].EventType == KEY_EVENT && inp[n].Event.KeyEvent.bKeyDown &&
-	inp[n].Event.KeyEvent.uChar.AsciiChar)
-      {
-	pipe_empty = false;
-	char c = inp[n].Event.KeyEvent.uChar.AsciiChar;
-	const char sigs[] = {
-	  (char) get_ttyp ()->ti.c_cc[VINTR],
-	  (char) get_ttyp ()->ti.c_cc[VQUIT],
-	  (char) get_ttyp ()->ti.c_cc[VSUSP],
-	};
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n',
-	  '\r'
-	};
-	if (is_line_input () && c && memchr (eols, c, sizeof (eols)))
-	  saw_accept = true;
-	if ((get_ttyp ()->ti.c_lflag & ISIG)
-	    && c && memchr (sigs, c, sizeof (sigs)))
-	  saw_accept = true;
-      }
-  get_ttyp ()->pcon_in_empty = pipe_empty && !(ralen () > raixget ());
-  if (!get_readahead_valid () &&
-      (pipe_empty || (is_line_input () && !saw_accept)) &&
-      get_ttyp ()->read_retval == 1 && bytes_available (n) && n == 0)
-    ResetEvent (input_available_event);
-  if (need_lock)
-    ReleaseMutex (input_mutex);
-}
-
-int
-fhandler_pty_slave::eat_readahead (int n)
-{
-  int oralen = ralen ();
-  if (n < 0)
-    n = ralen () - raixget ();
-  if (n > 0 && ralen () > raixget ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      while (n > 0 && ralen () > raixget ())
-	{
-	  if (is_line_input () && rabuf ()[ralen ()-1]
-	      && memchr (eols, rabuf ()[ralen ()-1], sizeof (eols)))
-	    break;
-	  -- n;
-	  -- ralen ();
-	}
-
-      /* If IUTF8 is set, the terminal is in UTF-8 mode.  If so, we erase
-	 a complete UTF-8 multibyte sequence on VERASE/VWERASE.  Otherwise,
-	 if we only erase a single byte, invalid unicode chars are left in
-	 the input. */
-      if (get_ttyp ()->ti.c_iflag & IUTF8)
-	while (ralen () > raixget () &&
-	       ((unsigned char) rabuf ()[ralen ()] & 0xc0) == 0x80)
-	  --ralen ();
-    }
-  oralen = oralen - ralen ();
-  if (raixget () >= ralen ())
-    raixget () = raixput () = ralen () = 0;
-  else if (raixput () > ralen ())
-    raixput () = ralen ();
-
-  return oralen;
-}
-
-int
-fhandler_pty_slave::get_readahead_into_buffer (char *buf, size_t buflen)
-{
-  int ch;
-  int copied_chars = 0;
-
-  while (buflen)
-    if ((ch = get_readahead ()) < 0)
-      break;
-    else
-      {
-	const char eols[] = {
-	  (char) get_ttyp ()->ti.c_cc[VEOF],
-	  (char) get_ttyp ()->ti.c_cc[VEOL],
-	  (char) get_ttyp ()->ti.c_cc[VEOL2],
-	  '\n'
-	};
-	buf[copied_chars++] = (unsigned char)(ch & 0xff);
-	buflen--;
-	if (is_line_input () && ch && memchr (eols, ch & 0xff, sizeof (eols)))
-	  break;
-      }
-
-  return copied_chars;
-}
-
-bool
-fhandler_pty_slave::get_readahead_valid (void)
-{
-  if (is_line_input ())
-    {
-      const char eols[] = {
-	(char) get_ttyp ()->ti.c_cc[VEOF],
-	(char) get_ttyp ()->ti.c_cc[VEOL],
-	(char) get_ttyp ()->ti.c_cc[VEOL2],
-	'\n'
-      };
-      for (size_t i=raixget (); i<ralen (); i++)
-	if (rabuf ()[i] && memchr (eols, rabuf ()[i], sizeof (eols)))
-	  return true;
-      return false;
-    }
-  else
-    return ralen () > raixget ();
-}
-
-void
-fhandler_pty_slave::set_switch_to_pcon (int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  acquire_output_mutex (INFINITE);
-  if (fd == 0 && !get_ttyp ()->switch_to_pcon_in)
-    {
-      pull_pcon_input ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
+      isHybrid = true;
+      if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
 	get_ttyp ()->pcon_pid = myself->pid;
       get_ttyp ()->switch_to_pcon_in = true;
-      if (isHybrid && !get_ttyp ()->switch_to_pcon_out)
-	{
-	  get_ttyp ()->wait_pcon_fwd ();
-	  get_ttyp ()->switch_to_pcon_out = true;
-	}
     }
-  else if ((fd == 1 || fd == 2) && !get_ttyp ()->switch_to_pcon_out)
-    {
-      get_ttyp ()->wait_pcon_fwd ();
-      if (get_ttyp ()->pcon_pid == 0 ||
-	  !pinfo (get_ttyp ()->pcon_pid))
-	get_ttyp ()->pcon_pid = myself->pid;
-      get_ttyp ()->switch_to_pcon_out = true;
-      if (isHybrid)
-	get_ttyp ()->switch_to_pcon_in = true;
-    }
-  release_output_mutex ();
 }
 
 void
 fhandler_pty_slave::reset_switch_to_pcon (void)
 {
-  if (get_ttyp ()->pcon_pid &&
-      get_ttyp ()->pcon_pid != myself->pid &&
-      !!pinfo (get_ttyp ()->pcon_pid))
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
     /* There is a process which is grabbing pseudo console. */
     return;
   if (isHybrid)
     return;
-  if (do_not_reset_switch_to_pcon)
-    return;
-  acquire_output_mutex (INFINITE);
-  if (get_ttyp ()->switch_to_pcon_out)
-    /* Wait for pty_master_fwd_thread() */
-    get_ttyp ()->wait_pcon_fwd ();
   get_ttyp ()->pcon_pid = 0;
   get_ttyp ()->switch_to_pcon_in = false;
-  get_ttyp ()->switch_to_pcon_out = false;
-  release_output_mutex ();
-  init_console_handler (true);
-}
-
-void
-fhandler_pty_slave::push_to_pcon_screenbuffer (const char *ptr, size_t len,
-					       bool is_echo)
-{
-  bool attached =
-    !!fhandler_console::get_console_process_id (get_helper_process_id (), true);
-  if (!attached && pcon_attached_to == get_minor ())
-    {
-      for (DWORD t0 = GetTickCount (); GetTickCount () - t0 < 100; )
-	{
-	  Sleep (1);
-	  attached = fhandler_console::get_console_process_id
-				      (get_helper_process_id (), true);
-	  if (attached)
-	    break;
-	}
-      if (!attached)
-	{
-	  system_printf ("pty%d: pcon_attach_to mismatch??????", get_minor ());
-	  return;
-	}
-    }
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  if (pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      goto detach;
-
-  char *buf;
-  size_t nlen;
-  DWORD origCP;
-  origCP = GetConsoleOutputCP ();
-  SetConsoleOutputCP (get_ttyp ()->term_code_page);
-  /* Just copy */
-  buf = (char *) HeapAlloc (GetProcessHeap (), 0, len);
-  memcpy (buf, (char *)ptr, len);
-  nlen = len;
-  char *p0, *p1;
-  p0 = p1 = buf;
-  /* Remove alternate screen buffer drawing */
-  while (p0 && p1)
-    {
-      if (!get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to alternate screen buffer */
-	  p0 = (char *) memmem (p1, nlen - (p1-buf), "\033[?1049h", 8);
-	  if (p0)
-	    {
-	      //p0 += 8;
-	      get_ttyp ()->screen_alternated = true;
-	      if (get_ttyp ()->switch_to_pcon_out)
-		do_not_reset_switch_to_pcon = true;
-	    }
-	}
-      if (get_ttyp ()->screen_alternated)
-	{
-	  /* Check switching to main screen buffer */
-	  p1 = (char *) memmem (p0, nlen - (p0-buf), "\033[?1049l", 8);
-	  if (p1)
-	    {
-	      p1 += 8;
-	      get_ttyp ()->screen_alternated = false;
-	      do_not_reset_switch_to_pcon = false;
-	      memmove (p0, p1, buf+nlen - p1);
-	      nlen -= p1 - p0;
-	    }
-	  else
-	    nlen = p0 - buf;
-	}
-    }
-  if (!nlen) /* Nothing to be synchronized */
-    goto cleanup;
-  if (get_ttyp ()->switch_to_pcon_out && !is_echo)
-    goto cleanup;
-  /* Remove ESC sequence which returns results to console
-     input buffer. Without this, cursor position report
-     is put into the input buffer as a garbage. */
-  /* Remove ESC sequence to report cursor position. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[6n", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-  /* Remove ESC sequence to report terminal identity. */
-  while ((p0 = (char *) memmem (buf, nlen, "\033[0c", 4)))
-    {
-      memmove (p0, p0+4, nlen - (p0+4 - buf));
-      nlen -= 4;
-    }
-
-  /* If the ESC sequence ESC[?3h or ESC[?3l which clears console screen
-     buffer is pushed, set need_redraw_screen to trigger redraw screen. */
-  p0 = buf;
-  while ((p0 = (char *) memmem (p0, nlen - (p0 - buf), "\033[?", 3)))
-    {
-      p0 += 3;
-      bool exist_arg_3 = false;
-      while (p0 < buf + nlen && (isdigit (*p0) || *p0 == ';'))
-	{
-	  int arg = 0;
-	  while (p0 < buf + nlen && isdigit (*p0))
-	    arg = arg * 10 + (*p0 ++) - '0';
-	  if (arg == 3)
-	    exist_arg_3 = true;
-	  if (p0 < buf + nlen && *p0 == ';')
-	    p0 ++;
-	}
-      if (p0 < buf + nlen && exist_arg_3 && (*p0 == 'h' || *p0 == 'l'))
-	get_ttyp ()->need_redraw_screen = true;
-      p0 ++;
-      if (p0 >= buf + nlen)
-	break;
-    }
-
-  int retry_count;
-  retry_count = 0;
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  while (!GetConsoleMode (get_output_handle (), &dwMode))
-    {
-      termios_printf ("GetConsoleMode failed, %E");
-      int errno_save = errno;
-      /* Re-open handles */
-      this->open (0, 0);
-      /* Fix pseudo console window size */
-      this->ioctl (TIOCSWINSZ, &get_ttyp ()->winsize);
-      if (errno != errno_save)
-	set_errno (errno_save);
-      if (++retry_count > 3)
-	goto cleanup;
-    }
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-  char *p;
-  p = buf;
-  DWORD wLen, written;
-  written = 0;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
-  while (written <  nlen)
-    {
-      if (!WriteFunc (get_output_handle (), p, nlen - written, &wLen, NULL))
-	{
-	  termios_printf ("WriteFile failed, %E");
-	  break;
-	}
-      else
-	{
-	  written += wLen;
-	  p += wLen;
-	}
-    }
-  /* Detach from pseudo console and resume. */
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  SetConsoleMode (get_output_handle (), dwMode | flags);
-cleanup:
-  SetConsoleOutputCP (origCP);
-  HeapFree (GetProcessHeap (), 0, buf);
-detach:
-  restore_reattach_pcon ();
+  get_ttyp ()->h_pseudo_console = NULL;
+  get_ttyp ()->pcon_start = false;
 }
 
 ssize_t __stdcall
@@ -1505,44 +776,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
   reset_switch_to_pcon ();
 
   acquire_output_mutex (INFINITE);
-  bool output_to_pcon = get_ttyp ()->switch_to_pcon_out;
-  release_output_mutex ();
-
-  UINT target_code_page = output_to_pcon ?
-    GetConsoleOutputCP () : get_ttyp ()->term_code_page;
-  ssize_t nlen;
-  char *buf = convert_mb_str (target_code_page, (size_t *) &nlen,
-		 get_ttyp ()->term_code_page, (const char *) ptr, len);
-
-  /* If not attached to this pseudo console, try to attach temporarily. */
-  pid_restore = 0;
-  bool fallback = false;
-  if (output_to_pcon && pcon_attached_to != get_minor ())
-    if (!try_reattach_pcon ())
-      fallback = true;
-
-  if (output_to_pcon && !fallback &&
-      (memmem (buf, nlen, "\033[6n", 4) || memmem (buf, nlen, "\033[0c", 4)))
-    {
-      get_ttyp ()->pcon_in_empty = false;
-      if (!is_line_input ())
-	SetEvent (input_available_event);
-    }
-
-  DWORD dwMode, flags;
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
-      !(get_ttyp ()->ti.c_oflag & ONLCR))
-    flags |= DISABLE_NEWLINE_AUTO_RETURN;
-  if (output_to_pcon && !fallback)
-    {
-      GetConsoleMode (get_output_handle (), &dwMode);
-      SetConsoleMode (get_output_handle (), dwMode | flags);
-    }
-  HANDLE to = (output_to_pcon && !fallback) ?
-    get_output_handle () : get_output_handle_cyg ();
-  acquire_output_mutex (INFINITE);
-  if (!process_opost_output (to, buf, nlen, false))
+  if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false))
     {
       DWORD err = GetLastError ();
       termios_printf ("WriteFile failed, %E");
@@ -1557,20 +791,6 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
       towrite = -1;
     }
   release_output_mutex ();
-  mb_str_free (buf);
-  flags = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-  if (output_to_pcon && !fallback)
-    SetConsoleMode (get_output_handle (), dwMode | flags);
-
-  restore_reattach_pcon ();
-
-  /* Push slave output to pseudo console screen buffer */
-  if (get_pseudo_console ())
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer ((char *)ptr, len, false);
-      release_output_mutex ();
-    }
 
   return towrite;
 }
@@ -1582,16 +802,15 @@ fhandler_pty_slave::mask_switch_to_pcon_in (bool mask)
 }
 
 bool
-fhandler_pty_common::to_be_read_from_pcon (void)
+fhandler_pty_master::to_be_read_from_pcon (void)
 {
-  return !get_ttyp ()->pcon_in_empty ||
-    (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
+  return get_ttyp ()->pcon_start
+    || (get_ttyp ()->switch_to_pcon_in && !get_ttyp ()->mask_switch_to_pcon_in);
 }
 
 void __reg3
 fhandler_pty_slave::read (void *ptr, size_t& len)
 {
-  char *ptr0 = (char *)ptr;
   ssize_t totalread = 0;
   int vmin = 0;
   int vtime = 0;	/* Initialized to prevent -Wuninitialized warning */
@@ -1616,8 +835,6 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
       mask_switch_to_pcon_in (true);
       reset_switch_to_pcon ();
     }
-  if (to_be_read_from_pcon ())
-    update_pcon_input_state (true);
 
   if (is_nonblocking () || !ptr) /* Indicating tcflush(). */
     time_to_wait = 0;
@@ -1703,98 +920,21 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 	      if (!totalread)
 		{
 		  set_sig_errno (EAGAIN);
-		  totalread = -1;
-		}
-	      goto out;
-	    }
-	  continue;
-	default:
-	  termios_printf ("wait for input mutex failed, %E");
-	  if (!totalread)
-	    {
-	      __seterrno ();
-	      totalread = -1;
-	    }
-	  goto out;
-	}
-      if (ptr && to_be_read_from_pcon ())
-	{
-	  if (get_readahead_valid ())
-	    {
-	      ReleaseMutex (input_mutex);
-	      totalread = get_readahead_into_buffer ((char *) ptr, len);
-	    }
-	  else
-	    {
-	      if (!try_reattach_pcon ())
-		{
-		  restore_reattach_pcon ();
-		  goto do_read_cyg;
-		}
-
-	      DWORD dwMode;
-	      GetConsoleMode (get_handle (), &dwMode);
-	      DWORD flags = ENABLE_VIRTUAL_TERMINAL_INPUT;
-	      if (dwMode != flags)
-		SetConsoleMode (get_handle (), flags);
-	      /* Read get_handle() instad of get_handle_cyg() */
-	      BOOL (WINAPI *ReadFunc)
-		(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID);
-	      ReadFunc = ReadConsoleA_Orig ? ReadConsoleA_Orig : ReadConsoleA;
-	      DWORD rlen;
-	      readlen = MIN (len, sizeof (buf));
-	      if (!ReadFunc (get_handle (), buf, readlen, &rlen, NULL))
-		{
-		  termios_printf ("read failed, %E");
-		  SetConsoleMode (get_handle (), dwMode);
-		  restore_reattach_pcon ();
-		  ReleaseMutex (input_mutex);
-		  set_errno (EIO);
-		  totalread = -1;
-		  goto out;
-		}
-	      SetConsoleMode (get_handle (), dwMode);
-	      restore_reattach_pcon ();
-	      ReleaseMutex (input_mutex);
-
-	      ssize_t nlen;
-	      char *nbuf = convert_mb_str (get_ttyp ()->term_code_page,
-			     (size_t *) &nlen, GetConsoleCP (), buf, rlen);
-
-	      ssize_t ret;
-	      line_edit_status res =
-		line_edit (nbuf, nlen, get_ttyp ()->ti, &ret);
-
-	      mb_str_free (nbuf);
-
-	      if (res == line_edit_input_done || res == line_edit_ok)
-		totalread = get_readahead_into_buffer ((char *) ptr, len);
-	      else if (res > line_edit_signalled)
-		{
-		  set_sig_errno (EINTR);
-		  totalread = -1;
-		}
-	      else
-		{
-		  update_pcon_input_state (true);
-		  continue;
+		  totalread = -1;
 		}
+	      goto out;
+	    }
+	  continue;
+	default:
+	  termios_printf ("wait for input mutex failed, %E");
+	  if (!totalread)
+	    {
+	      __seterrno ();
+	      totalread = -1;
 	    }
-
-	  update_pcon_input_state (true);
-	  mask_switch_to_pcon_in (false);
 	  goto out;
 	}
-      if (!ptr && len == UINT_MAX && !get_ttyp ()->pcon_in_empty)
-	{
-	  FlushConsoleInputBuffer (get_handle ());
-	  get_ttyp ()->pcon_in_empty = true;
-	  DWORD n;
-	  if (bytes_available (n) && n == 0)
-	    ResetEvent (input_available_event);
-	}
 
-do_read_cyg:
       if (!bytes_available (bytes_in_pipe))
 	{
 	  ReleaseMutex (input_mutex);
@@ -1911,16 +1051,6 @@ do_read_cyg:
 out:
   termios_printf ("%d = read(%p, %lu)", totalread, ptr, len);
   len = (size_t) totalread;
-  /* Push slave read as echo to pseudo console screen buffer. */
-  if (get_pseudo_console () && ptr0 && totalread > 0 &&
-      (get_ttyp ()->ti.c_lflag & ECHO))
-    {
-      acquire_output_mutex (INFINITE);
-      push_to_pcon_screenbuffer (ptr0, len, true);
-      if (get_ttyp ()->switch_to_pcon_out)
-	trigger_redraw_screen ();
-      release_output_mutex ();
-    }
   mask_switch_to_pcon_in (false);
 }
 
@@ -2061,38 +1191,11 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg)
       get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
       break;
     case TIOCSWINSZ:
-      if (get_pseudo_console ())
-	{
-	  /* If not attached to this pseudo console,
-	     try to attach temporarily. */
-	  pid_restore = 0;
-	  if (pcon_attached_to != get_minor ())
-	    if (!try_reattach_pcon ())
-	      goto cleanup;
-
-	  COORD size;
-	  size.X = ((struct winsize *) arg)->ws_col;
-	  size.Y = ((struct winsize *) arg)->ws_row;
-	  CONSOLE_SCREEN_BUFFER_INFO csbi;
-	  if (GetConsoleScreenBufferInfo (get_output_handle (), &csbi))
-	    if (size.X == csbi.srWindow.Right - csbi.srWindow.Left + 1 &&
-		size.Y == csbi.srWindow.Bottom - csbi.srWindow.Top + 1)
-	      goto cleanup;
-	  if (!SetConsoleScreenBufferSize (get_output_handle (), size))
-	    goto cleanup;
-	  SMALL_RECT rect;
-	  rect.Left = 0;
-	  rect.Top = 0;
-	  rect.Right = size.X-1;
-	  rect.Bottom = size.Y-1;
-	  SetConsoleWindowInfo (get_output_handle (), TRUE, &rect);
-cleanup:
-	  restore_reattach_pcon ();
-	}
-
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->arg.winsize = *(struct winsize *) arg;
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
@@ -2378,6 +1481,27 @@ fhandler_pty_common::close ()
   return 0;
 }
 
+void
+fhandler_pty_common::resize_pseudo_console (struct winsize *ws)
+{
+  COORD size;
+  size.X = ws->ws_col;
+  size.Y = ws->ws_row;
+  pinfo p (get_ttyp ()->pcon_pid);
+  if (p)
+    {
+      HPCON_INTERNAL hpcon_local;
+      HANDLE pcon_owner =
+	OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->exec_dwProcessId);
+      DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_write_pipe,
+		       GetCurrentProcess (), &hpcon_local.hWritePipe,
+		       0, TRUE, DUPLICATE_SAME_ACCESS);
+      ResizePseudoConsole ((HPCON) &hpcon_local, size);
+      CloseHandle (pcon_owner);
+      CloseHandle (hpcon_local.hWritePipe);
+    }
+}
+
 void
 fhandler_pty_master::cleanup ()
 {
@@ -2393,7 +1517,6 @@ fhandler_pty_master::close ()
 {
   OBJECT_BASIC_INFORMATION obi;
   NTSTATUS status;
-  pid_t master_pid_tmp = get_ttyp ()->master_pid;
 
   termios_printf ("closing from_master(%p)/from_master_cyg(%p)/to_master(%p)/to_master_cyg(%p) since we own them(%u)",
 		  from_master, from_master_cyg,
@@ -2438,30 +1561,6 @@ fhandler_pty_master::close ()
   else if (obi.HandleCount == 1)
     {
       termios_printf ("Closing last master of pty%d", get_minor ());
-      /* Close Pseudo Console */
-      if (get_pseudo_console ())
-	{
-	  /* Terminate helper process */
-	  SetEvent (get_ttyp ()->h_helper_goodbye);
-	  WaitForSingleObject (get_ttyp ()->h_helper_process, INFINITE);
-	  CloseHandle (get_ttyp ()->h_helper_goodbye);
-	  CloseHandle (get_ttyp ()->h_helper_process);
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (master_pid_tmp == myself->pid)
-	    {
-	      /* ClosePseudoConsole() seems to have a bug that one
-		 internal handle remains opened. This causes handle leak.
-		 This is a workaround for this problem. */
-	      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_pseudo_console ();
-	      HANDLE tmp = hp->hConHostProcess;
-	      /* Release pseudo console */
-	      ClosePseudoConsole (get_pseudo_console ());
-	      CloseHandle (tmp);
-	    }
-	  get_ttyp ()->switch_to_pcon_in = false;
-	  get_ttyp ()->switch_to_pcon_out = false;
-	}
       if (get_ttyp ()->getsid () > 0)
 	kill (get_ttyp ()->getsid (), SIGHUP);
       SetEvent (input_available_event);
@@ -2469,9 +1568,8 @@ fhandler_pty_master::close ()
 
   if (!ForceCloseHandle (from_master))
     termios_printf ("error closing from_master %p, %E", from_master);
-  if (from_master_cyg != from_master) /* Avoid double close. */
-    if (!ForceCloseHandle (from_master_cyg))
-      termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
+  if (!ForceCloseHandle (from_master_cyg))
+    termios_printf ("error closing from_master_cyg %p, %E", from_master_cyg);
   if (!ForceCloseHandle (to_master))
     termios_printf ("error closing to_master %p, %E", to_master);
   from_master = to_master = NULL;
@@ -2513,7 +1611,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
   /* Write terminal input to to_slave pipe instead of output_handle
      if current application is native console application. */
-  if (to_be_read_from_pcon ())
+  if (to_be_read_from_pcon () && get_ttyp ()->h_pseudo_console)
     {
       size_t nlen;
       char *buf = convert_mb_str
@@ -2521,40 +1619,50 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 
       WaitForSingleObject (input_mutex, INFINITE);
 
-      if (memchr (buf, '\003', nlen)) /* ^C intr key in pcon */
-	get_ttyp ()->req_flush_pcon_input = true;
-
       DWORD wLen;
-      WriteFile (to_slave, buf, nlen, &wLen, NULL);
-      get_ttyp ()->pcon_in_empty = false;
-
-      ReleaseMutex (input_mutex);
 
-      /* Use line_edit () in order to set input_available_event. */
-      bool is_echo = tc ()->ti.c_lflag & ECHO;
-      if (!get_ttyp ()->mask_switch_to_pcon_in)
+      if (get_ttyp ()->pcon_start)
 	{
-	  tc ()->ti.c_lflag &= ~ECHO;
-	  ti.c_lflag &= ~ECHO;
-	}
-      ti.c_lflag &= ~ISIG;
-      line_edit (buf, nlen, ti, &ret);
-      if (is_echo)
-	tc ()->ti.c_lflag |= ECHO;
-      get_ttyp ()->read_retval = 1;
-
-      const char sigs[] = {
-	(char) ti.c_cc[VINTR],
-	(char) ti.c_cc[VQUIT],
-	(char) ti.c_cc[VSUSP],
-      };
-      if (tc ()->ti.c_lflag & ISIG)
-	for (size_t i=0; i<sizeof (sigs); i++)
-	  if (sigs[i] && memchr (buf, sigs[i], nlen))
+	  /* Pseudo condole support uses "CSI6n" to get cursor position.
+	     If the reply for "CSI6n" is divided into multiple writes,
+	     pseudo console sometimes does not recognize it.  Therefore,
+	     put them together into wpbuf and write all at once. */
+	  static const int wpbuf_len = 64;
+	  static char wpbuf[wpbuf_len];
+	  static int ixput = 0;
+
+	  if (ixput == 0 && buf[0] != '\033')
+	    { /* fail-safe */
+	      WriteFile (to_slave, "\033[1;1R", 6, &wLen, NULL); /* dummy */
+	      get_ttyp ()->pcon_start = false;
+	    }
+	  else
 	    {
-	      eat_readahead (-1);
-	      SetEvent (input_available_event);
+	      if (ixput + nlen < wpbuf_len)
+		for (size_t i=0; i<nlen; i++)
+		  wpbuf[ixput++] = buf[i];
+	      else
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		  WriteFile (to_slave, buf, nlen, &wLen, NULL);
+		}
+	      if (ixput && memchr (wpbuf, 'R', ixput))
+		{
+		  WriteFile (to_slave, wpbuf, ixput, &wLen, NULL);
+		  ixput = 0;
+		  get_ttyp ()->pcon_start = false;
+		}
+	      ReleaseMutex (input_mutex);
+	      mb_str_free (buf);
+	      return len;
 	    }
+	}
+
+      WriteFile (to_slave, buf, nlen, &wLen, NULL);
+
+      ReleaseMutex (input_mutex);
 
       mb_str_free (buf);
       return len;
@@ -2630,15 +1738,8 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
       if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
 	  || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
 	{
-	  /* FIXME: Pseudo console can be accessed via its handle
-	     only in the process which created it. What else can we do? */
-	  if (get_pseudo_console () && get_ttyp ()->master_pid == myself->pid)
-	    {
-	      COORD size;
-	      size.X = ((struct winsize *) arg)->ws_col;
-	      size.Y = ((struct winsize *) arg)->ws_row;
-	      ResizePseudoConsole (get_pseudo_console (), size);
-	    }
+	  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid)
+	    resize_pseudo_console ((struct winsize *) arg);
 	  get_ttyp ()->winsize = *(struct winsize *) arg;
 	  get_ttyp ()->kill_pgrp (SIGWINCH);
 	}
@@ -2763,7 +1864,7 @@ get_locale_from_env (char *locale)
   strcpy (locale, env);
 }
 
-static LCID
+static void
 get_langinfo (char *locale_out, char *charset_out)
 {
   /* Get locale from environment */
@@ -2776,11 +1877,6 @@ get_langinfo (char *locale_out, char *charset_out)
   if (!locale)
     locale = "C";
 
-  char tmp_locale[ENCODING_LEN + 1];
-  char *ret = __set_locale_from_locale_alias (locale, tmp_locale);
-  if (ret)
-    locale = tmp_locale;
-
   const char *charset;
   struct lc_ctype_T *lc_ctype = (struct lc_ctype_T *) loc.lc_cat[LC_CTYPE].ptr;
   if (!lc_ctype)
@@ -2830,23 +1926,9 @@ get_langinfo (char *locale_out, char *charset_out)
       charset = "CP932";
     }
 
-  wchar_t lc[ENCODING_LEN + 1];
-  wchar_t *p;
-  mbstowcs (lc, locale, ENCODING_LEN);
-  p = wcschr (lc, L'.');
-  if (p)
-    *p = L'\0';
-  p = wcschr (lc, L'_');
-  if (p)
-    *p = L'-';
-  LCID lcid = LocaleNameToLCID (lc, 0);
-  if (!lcid && !strcmp (charset, "ASCII"))
-    return 0;
-
   /* Set results */
   strcpy (locale_out, new_locale);
   strcpy (charset_out, charset);
-  return lcid;
 }
 
 void
@@ -2857,21 +1939,7 @@ fhandler_pty_slave::setup_locale (void)
 
   char locale[ENCODING_LEN + 1] = "C";
   char charset[ENCODING_LEN + 1] = "ASCII";
-  LCID lcid = get_langinfo (locale, charset);
-
-  /* Set console code page form locale */
-  if (get_pseudo_console ())
-    {
-      UINT code_page;
-      if (lcid == 0 || lcid == (LCID) -1)
-	code_page = 20127; /* ASCII */
-      else if (!GetLocaleInfo (lcid,
-			       LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
-			       (char *) &code_page, sizeof (code_page)))
-	code_page = 20127; /* ASCII */
-      SetConsoleCP (code_page);
-      SetConsoleOutputCP (code_page);
-    }
+  get_langinfo (locale, charset);
 
   /* Set terminal code page from locale */
   /* This code is borrowed from mintty: charset.c */
@@ -2881,9 +1949,9 @@ fhandler_pty_slave::setup_locale (void)
     charset_u[i] = toupper (charset[i]);
   unsigned int iso;
   UINT cp = 20127; /* Default for fallback */
-  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859-%u", &iso) == 1 ||
-      sscanf (charset_u, "ISO8859%u", &iso) == 1)
+  if (sscanf (charset_u, "ISO-8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859-%u", &iso) == 1
+      || sscanf (charset_u, "ISO8859%u", &iso) == 1)
     {
       if (iso && iso <= 16 && iso !=12)
 	get_ttyp ()->term_code_page = 28590 + iso;
@@ -2899,90 +1967,9 @@ fhandler_pty_slave::setup_locale (void)
 	}
 }
 
-void
-fhandler_pty_slave::set_freeconsole_on_close (bool val)
-{
-  freeconsole_on_close = val;
-}
-
-void
-fhandler_pty_slave::trigger_redraw_screen (void)
-{
-  /* Forcibly redraw screen based on console screen buffer. */
-  /* The following code triggers redrawing the screen. */
-  CONSOLE_SCREEN_BUFFER_INFO sbi;
-  GetConsoleScreenBufferInfo (get_output_handle (), &sbi);
-  SMALL_RECT rect = {0, 0,
-    (SHORT) (sbi.dwSize.X -1), (SHORT) (sbi.dwSize.Y - 1)};
-  COORD dest = {0, 0};
-  CHAR_INFO fill = {' ', 0};
-  ScrollConsoleScreenBuffer (get_output_handle (), &rect, NULL, dest, &fill);
-  get_ttyp ()->need_redraw_screen = false;
-}
-
-void
-fhandler_pty_slave::fixup_after_attach (bool native_maybe, int fd_set)
-{
-  if (fd < 0)
-    fd = fd_set;
-  if (get_pseudo_console ())
-    {
-      if (fhandler_console::get_console_process_id (get_helper_process_id (),
-						    true))
-	if (pcon_attached_to != get_minor ())
-	  {
-	    pcon_attached_to = get_minor ();
-	    init_console_handler (true);
-	  }
-
-#if 0 /* This is for debug only. */
-      isHybrid = true;
-      get_ttyp ()->switch_to_pcon_in = true;
-      get_ttyp ()->switch_to_pcon_out = true;
-#endif
-
-      if (pcon_attached_to == get_minor () && native_maybe)
-	{
-	  if (fd == 0)
-	    {
-	      pull_pcon_input ();
-	      DWORD mode =
-		ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
-	      SetConsoleMode (get_handle (), mode);
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_in = true;
-	    }
-	  else if (fd == 1 || fd == 2)
-	    {
-	      DWORD mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
-	      SetConsoleMode (get_output_handle (), mode);
-	      acquire_output_mutex (INFINITE);
-	      if (!get_ttyp ()->switch_to_pcon_out)
-		get_ttyp ()->wait_pcon_fwd ();
-	      if (get_ttyp ()->pcon_pid == 0 ||
-		  !pinfo (get_ttyp ()->pcon_pid))
-		get_ttyp ()->pcon_pid = myself->pid;
-	      get_ttyp ()->switch_to_pcon_out = true;
-	      release_output_mutex ();
-
-	      if (get_ttyp ()->need_redraw_screen)
-		trigger_redraw_screen ();
-	    }
-	  init_console_handler (false);
-	}
-      else if (fd == 0 && native_maybe)
-	/* Read from unattached pseudo console cause freeze,
-	   therefore, fallback to legacy pty. */
-	set_handle (get_handle_cyg ());
-    }
-}
-
 void
 fhandler_pty_slave::fixup_after_fork (HANDLE parent)
 {
-  fixup_after_attach (false, -1);
   // fork_fixup (parent, inuse, "inuse");
   // fhandler_pty_common::fixup_after_fork (parent);
   report_tty_counts (this, "inherited", "");
@@ -2995,70 +1982,21 @@ fhandler_pty_slave::fixup_after_exec ()
 
   if (!close_on_exec ())
     fixup_after_fork (NULL);	/* No parent handle required. */
-  else if (get_pseudo_console ())
-    {
-      int used = 0;
-      int attached = 0;
-      cygheap_fdenum cfd (false);
-      while (cfd.next () >= 0)
-	{
-	  if (cfd->get_major () == DEV_PTYS_MAJOR ||
-	      cfd->get_major () == DEV_CONS_MAJOR)
-	    used ++;
-	  if (cfd->get_major () == DEV_PTYS_MAJOR &&
-	      cfd->get_minor () == pcon_attached_to)
-	    attached ++;
-	}
-
-      /* Call FreeConsole() if no tty is opened and the process
-	 is attached to console corresponding to tty. This is
-	 needed to make GNU screen and tmux work in Windows 10
-	 1903. */
-      if (attached == 1 && get_minor () == pcon_attached_to)
-	pcon_attached_to = -1;
-      if (used == 1 /* About to close this tty */)
-	{
-	  init_console_handler (false);
-	  free_attached_console ();
-	}
-    }
 
   /* Set locale */
   setup_locale ();
 
   /* Hook Console API */
-  if (get_pseudo_console ())
-    {
 #define DO_HOOK(module, name) \
-      if (!name##_Orig) \
-	{ \
-	  void *api = hook_api (module, #name, (void *) name##_Hooked); \
-	  name##_Orig = (__typeof__ (name) *) api; \
-	  /*if (api) system_printf (#name " hooked.");*/ \
-	}
-      DO_HOOK (NULL, WriteFile);
-      DO_HOOK (NULL, WriteConsoleA);
-      DO_HOOK (NULL, WriteConsoleW);
-      DO_HOOK (NULL, ReadFile);
-      DO_HOOK (NULL, ReadConsoleA);
-      DO_HOOK (NULL, ReadConsoleW);
-      DO_HOOK (NULL, WriteConsoleOutputA);
-      DO_HOOK (NULL, WriteConsoleOutputW);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterA);
-      DO_HOOK (NULL, WriteConsoleOutputCharacterW);
-      DO_HOOK (NULL, WriteConsoleOutputAttribute);
-      DO_HOOK (NULL, SetConsoleCursorPosition);
-      DO_HOOK (NULL, SetConsoleTextAttribute);
-      DO_HOOK (NULL, WriteConsoleInputA);
-      DO_HOOK (NULL, WriteConsoleInputW);
-      DO_HOOK (NULL, ReadConsoleInputA);
-      DO_HOOK (NULL, ReadConsoleInputW);
-      DO_HOOK (NULL, PeekConsoleInputA);
-      DO_HOOK (NULL, PeekConsoleInputW);
-      /* CreateProcess() is hooked for GDB etc. */
-      DO_HOOK (NULL, CreateProcessA);
-      DO_HOOK (NULL, CreateProcessW);
+  if (!name##_Orig) \
+    { \
+      void *api = hook_api (module, #name, (void *) name##_Hooked); \
+      name##_Orig = (__typeof__ (name) *) api; \
+      /*if (api) system_printf (#name " hooked.");*/ \
     }
+  /* CreateProcess() is hooked for GDB etc. */
+  DO_HOOK (NULL, CreateProcessA);
+  DO_HOOK (NULL, CreateProcessW);
 }
 
 /* This thread function handles the master control pipe.  It waits for a
@@ -3206,27 +2144,6 @@ reply:
   return 0;
 }
 
-void
-fhandler_pty_master::transfer_input_to_pcon (void)
-{
-  WaitForSingleObject (input_mutex, INFINITE);
-  DWORD n;
-  size_t transfered = 0;
-  while (::bytes_available (n, from_master_cyg) && n)
-    {
-      char buf[1024];
-      ReadFile (from_master_cyg, buf, sizeof (buf), &n, 0);
-      char *p = buf;
-      while ((p = (char *) memchr (p, '\n', n - (p - buf))))
-	*p = '\r';
-      if (WriteFile (to_slave, buf, n, &n, 0))
-	transfered += n;
-    }
-  if (transfered)
-    get_ttyp ()->pcon_in_empty = false;
-  ReleaseMutex (input_mutex);
-}
-
 static DWORD WINAPI
 pty_master_thread (VOID *arg)
 {
@@ -3242,23 +2159,7 @@ fhandler_pty_master::pty_master_fwd_thread ()
   termios_printf ("Started.");
   for (;;)
     {
-      if (get_pseudo_console ())
-	{
-	  get_ttyp ()->pcon_last_time = GetTickCount ();
-	  while (::bytes_available (rlen, from_slave) && rlen == 0)
-	    {
-	      /* Forcibly transfer input if it is requested by slave.
-		 This happens when input data should be transfered
-		 from the input pipe for cygwin apps to the input pipe
-		 for native apps. */
-	      if (get_ttyp ()->req_transfer_input_to_pcon)
-		{
-		  transfer_input_to_pcon ();
-		  get_ttyp ()->req_transfer_input_to_pcon = false;
-		}
-	      Sleep (1);
-	    }
-	}
+      get_ttyp ()->pcon_last_time = GetTickCount ();
       if (!ReadFile (from_slave, outbuf, sizeof outbuf, &rlen, NULL))
 	{
 	  termios_printf ("ReadFile for forwarding failed, %E");
@@ -3266,14 +2167,9 @@ fhandler_pty_master::pty_master_fwd_thread ()
 	}
       ssize_t wlen = rlen;
       char *ptr = outbuf;
-      if (get_pseudo_console ())
+      if (get_ttyp ()->h_pseudo_console)
 	{
-	  /* Avoid duplicating slave output which is already sent to
-	     to_master_cyg */
-	  if (!get_ttyp ()->switch_to_pcon_out)
-	    continue;
-
-	  /* Avoid setting window title to "cygwin-console-helper.exe" */
+	  /* Remove CSI > Pm m */
 	  int state = 0;
 	  int start_at = 0;
 	  for (DWORD i=0; i<rlen; i++)
@@ -3283,43 +2179,8 @@ fhandler_pty_master::pty_master_fwd_thread ()
 		state = 1;
 		continue;
 	      }
-	    else if ((state == 1 && outbuf[i] == ']') ||
-		     (state == 2 && outbuf[i] == '0') ||
-		     (state == 3 && outbuf[i] == ';'))
-	      {
-		state ++;
-		continue;
-	      }
-	    else if (state == 4 && outbuf[i] == '\a')
-	      {
-		const char *helper_str = "\\bin\\cygwin-console-helper.exe";
-		if (memmem (&outbuf[start_at], i + 1 - start_at,
-			    helper_str, strlen (helper_str)))
-		  {
-		    memmove (&outbuf[start_at], &outbuf[i+1], rlen-i-1);
-		    rlen = wlen = start_at + rlen - i - 1;
-		  }
-		state = 0;
-		continue;
-	      }
-	    else if (outbuf[i] == '\a')
-	      {
-		state = 0;
-		continue;
-	      }
-
-	  /* Remove CSI > Pm m */
-	  state = 0;
-	  start_at = 0;
-	  for (DWORD i=0; i<rlen; i++)
-	    if (outbuf[i] == '\033')
-	      {
-		start_at = i;
-		state = 1;
-		continue;
-	      }
-	    else if ((state == 1 && outbuf[i] == '[') ||
-		     (state == 2 && outbuf[i] == '>'))
+	    else if ((state == 1 && outbuf[i] == '[')
+		     || (state == 2 && outbuf[i] == '>'))
 	      {
 		state ++;
 		continue;
@@ -3388,201 +2249,6 @@ pty_master_fwd_thread (VOID *arg)
   return ((fhandler_pty_master *) arg)->pty_master_fwd_thread ();
 }
 
-/* If master process is running as service, attaching to
-   pseudo console should be done in fork. If attaching
-   is done in spawn for inetd or sshd, it fails because
-   the helper process is running as privileged user while
-   slave process is not. This function is used to determine
-   if the process is running as a srvice or not. */
-inline static bool
-is_running_as_service (void)
-{
-  return check_token_membership (well_known_service_sid)
-    || cygheap->user.saved_sid () == well_known_system_sid;
-}
-
-bool
-fhandler_pty_master::setup_pseudoconsole ()
-{
-  if (disable_pcon)
-    return false;
-  /* If the legacy console mode is enabled, pseudo console seems
-     not to work as expected. To determine console mode, registry
-     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
-  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
-  if (reg.error ())
-    return false;
-  if (reg.get_dword (L"ForceV2", 1) == 0)
-    {
-      termios_printf ("Pseudo console is disabled "
-		      "because the legacy console mode is enabled.");
-      return false;
-    }
-
-  /* Pseudo console supprot is realized using a tricky technic.
-     PTY need the pseudo console handles, however, they cannot
-     be retrieved by normal procedure. Therefore, run a helper
-     process in a pseudo console and get them from the helper.
-     Slave process will attach to the pseudo console in the
-     helper process using AttachConsole(). */
-  COORD size = {
-    (SHORT) get_ttyp ()->winsize.ws_col,
-    (SHORT) get_ttyp ()->winsize.ws_row
-  };
-  CreatePipe (&from_master, &to_slave, &sec_none, 0);
-  SetLastError (ERROR_SUCCESS);
-  HRESULT res = CreatePseudoConsole (size, from_master, to_master,
-				     0, &get_ttyp ()->h_pseudo_console);
-  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
-    {
-      if (res != S_OK)
-	system_printf ("CreatePseudoConsole() failed. %08x\n",
-		       GetLastError ());
-      goto fallback;
-    }
-
-  /* If master process is running as service, attaching to
-     pseudo console should be done in fork. If attaching
-     is done in spawn for inetd or sshd, it fails because
-     the helper process is running as privileged user while
-     slave process is not. */
-  if (is_running_as_service ())
-    get_ttyp ()->attach_pcon_in_fork = true;
-
-  STARTUPINFOEXW si_helper;
-  HANDLE hello, goodbye;
-  HANDLE hr, hw;
-  PROCESS_INFORMATION pi_helper;
-  HANDLE hpConIn, hpConOut;
-  {
-    SIZE_T bytesRequired;
-    InitializeProcThreadAttributeList (NULL, 2, 0, &bytesRequired);
-    ZeroMemory (&si_helper, sizeof (si_helper));
-    si_helper.StartupInfo.cb = sizeof (STARTUPINFOEXW);
-    si_helper.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
-      HeapAlloc (GetProcessHeap (), 0, bytesRequired);
-    if (si_helper.lpAttributeList == NULL)
-      goto cleanup_pseudo_console;
-    if (!InitializeProcThreadAttributeList (si_helper.lpAttributeList,
-					    2, 0, &bytesRequired))
-      goto cleanup_heap;
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
-				    get_ttyp ()->h_pseudo_console,
-				    sizeof (get_ttyp ()->h_pseudo_console),
-				    NULL, NULL))
-      goto cleanup_heap;
-    /* Create events for start/stop helper process. */
-    hello = CreateEvent (&sec_none, true, false, NULL);
-    goodbye = CreateEvent (&sec_none, true, false, NULL);
-    /* Create a pipe for receiving pseudo console handles */
-    CreatePipe (&hr, &hw, &sec_none, 0);
-    /* Inherit only handles which are needed by helper. */
-    HANDLE handles_to_inherit[] = {hello, goodbye, hw};
-    if (!UpdateProcThreadAttribute (si_helper.lpAttributeList,
-				    0,
-				    PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
-				    handles_to_inherit,
-				    sizeof (handles_to_inherit),
-				    NULL, NULL))
-      goto cleanup_event_and_pipes;
-    /* Create helper process */
-    WCHAR cmd[MAX_PATH];
-    path_conv helper ("/bin/cygwin-console-helper.exe");
-    size_t len = helper.get_wide_win32_path_len ();
-    helper.get_wide_win32_path (cmd);
-    __small_swprintf (cmd + len, L" %p %p %p", hello, goodbye, hw);
-    si_helper.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
-    si_helper.StartupInfo.hStdInput = NULL;
-    si_helper.StartupInfo.hStdOutput = NULL;
-    si_helper.StartupInfo.hStdError = NULL;
-    if (!CreateProcessW (NULL, cmd, &sec_none, &sec_none,
-			 TRUE, EXTENDED_STARTUPINFO_PRESENT,
-			 NULL, NULL, &si_helper.StartupInfo, &pi_helper))
-      goto cleanup_event_and_pipes;
-    for (;;)
-      {
-        DWORD wait_result = WaitForSingleObject (hello, 500);
-	if (wait_result == WAIT_OBJECT_0)
-	  break;
-	if (wait_result != WAIT_TIMEOUT)
-	  goto cleanup_helper_process;
-	DWORD exit_code;
-	if (!GetExitCodeProcess(pi_helper.hProcess, &exit_code))
-	  goto cleanup_helper_process;
-	if (exit_code == STILL_ACTIVE)
-	  continue;
-	if (exit_code != 0 ||
-	    WaitForSingleObject (hello, 500) != WAIT_OBJECT_0)
-	  goto cleanup_helper_process;
-	break;
-      }
-    CloseHandle (hello);
-    CloseHandle (pi_helper.hThread);
-    /* Retrieve pseudo console handles */
-    DWORD rLen;
-    char buf[64];
-    if (!ReadFile (hr, buf, sizeof (buf), &rLen, NULL))
-      goto cleanup_helper_process;
-    buf[rLen] = '\0';
-    sscanf (buf, "StdHandles=%p,%p", &hpConIn, &hpConOut);
-    if (!DuplicateHandle (pi_helper.hProcess, hpConIn,
-			  GetCurrentProcess (), &hpConIn, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_helper_process;
-    if (!DuplicateHandle (pi_helper.hProcess, hpConOut,
-			  GetCurrentProcess (), &hpConOut, 0,
-			  TRUE, DUPLICATE_SAME_ACCESS))
-      goto cleanup_pcon_in;
-    CloseHandle (hr);
-    CloseHandle (hw);
-    /* Clean up */
-    DeleteProcThreadAttributeList (si_helper.lpAttributeList);
-    HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-  }
-  /* Setting information of stuffs regarding pseudo console */
-  get_ttyp ()->h_helper_goodbye = goodbye;
-  get_ttyp ()->h_helper_process = pi_helper.hProcess;
-  get_ttyp ()->helper_process_id = pi_helper.dwProcessId;
-  CloseHandle (from_master);
-  CloseHandle (to_master);
-  from_master = hpConIn;
-  to_master = hpConOut;
-  ResizePseudoConsole (get_ttyp ()->h_pseudo_console, size);
-  return true;
-
-cleanup_pcon_in:
-  CloseHandle (hpConIn);
-cleanup_helper_process:
-  SetEvent (goodbye);
-  WaitForSingleObject (pi_helper.hProcess, INFINITE);
-  CloseHandle (pi_helper.hProcess);
-  goto skip_close_hello;
-cleanup_event_and_pipes:
-  CloseHandle (hello);
-skip_close_hello:
-  CloseHandle (goodbye);
-  CloseHandle (hr);
-  CloseHandle (hw);
-cleanup_heap:
-  HeapFree (GetProcessHeap (), 0, si_helper.lpAttributeList);
-cleanup_pseudo_console:
-  {
-    HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
-    HANDLE tmp = hp->hConHostProcess;
-    ClosePseudoConsole (get_pseudo_console ());
-    CloseHandle (tmp);
-  }
-fallback:
-  CloseHandle (from_master);
-  CloseHandle (to_slave);
-  from_master = from_master_cyg;
-  to_slave = NULL;
-  get_ttyp ()->h_pseudo_console = NULL;
-  return false;
-}
-
 bool
 fhandler_pty_master::setup ()
 {
@@ -3595,11 +2261,6 @@ fhandler_pty_master::setup ()
   if (unit < 0)
     return false;
 
-  /* from_master should be used for pseudo console.
-     Just copy from_master_cyg here for the case that
-     pseudo console is not available. */
-  from_master = from_master_cyg;
-
   ProtectHandle1 (get_output_handle (), to_pty);
 
   tty& t = *cygwin_shared->tty[unit];
@@ -3698,15 +2359,21 @@ fhandler_pty_master::setup ()
       goto err;
     }
 
-  t.winsize.ws_col = 80;
-  t.winsize.ws_row = 25;
-
-  setup_pseudoconsole ();
+  __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;
+    }
 
   t.set_from_master (from_master);
   t.set_from_master_cyg (from_master_cyg);
   t.set_to_master (to_master);
   t.set_to_master_cyg (to_master_cyg);
+  t.winsize.ws_col = 80;
+  t.winsize.ws_row = 25;
   t.master_pid = myself->pid;
 
   dev ().parse (DEV_PTYM_MAJOR, unit);
@@ -3719,6 +2386,7 @@ fhandler_pty_master::setup ()
 err:
   __seterrno ();
   close_maybe (from_slave);
+  close_maybe (to_slave);
   close_maybe (get_handle ());
   close_maybe (get_output_handle ());
   close_maybe (input_available_event);
@@ -3778,9 +2446,6 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 {
   ssize_t towrite = len;
   BOOL res = TRUE;
-  BOOL (WINAPI *WriteFunc)
-    (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
-  WriteFunc = WriteFile_Orig ? WriteFile_Orig : WriteFile;
   while (towrite)
     {
       if (!is_echo)
@@ -3803,7 +2468,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
       if (!(get_ttyp ()->ti.c_oflag & OPOST))	// raw output mode
 	{
 	  DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
-	  res = WriteFunc (h, ptr, n, &n, NULL);
+	  res = WriteFile (h, ptr, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + n;
@@ -3853,7 +2518,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
 		  break;
 		}
 	    }
-	  res = WriteFunc (h, outbuf, n, &n, NULL);
+	  res = WriteFile (h, outbuf, n, &n, NULL);
 	  if (!res)
 	    break;
 	  ptr = (char *) ptr + rc;
@@ -3863,3 +2528,134 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& l
   len -= towrite;
   return res;
 }
+
+bool
+fhandler_pty_slave::setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon)
+{
+
+  /* Setting switch_to_pcon_in is necessary even if
+     pseudo console will not be activated. */
+  fhandler_base *fh = ::cygheap->fdtab[0];
+  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
+    {
+      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
+      ptys->get_ttyp ()->switch_to_pcon_in = true;
+      if (ptys->get_ttyp ()->pcon_pid == 0
+	  || !pinfo (ptys->get_ttyp ()->pcon_pid))
+	ptys->get_ttyp ()->pcon_pid = myself->pid;
+    }
+
+  if (nopcon)
+    return false;
+  if (get_ttyp ()->pcon_pid && get_ttyp ()->pcon_pid != myself->pid
+      && !!pinfo (get_ttyp ()->pcon_pid))
+    return false;
+  if (disable_pcon)
+    return false;
+  /* If the legacy console mode is enabled, pseudo console seems
+     not to work as expected. To determine console mode, registry
+     key ForceV2 in HKEY_CURRENT_USER\Console is checked. */
+  reg_key reg (HKEY_CURRENT_USER, KEY_READ, L"Console", NULL);
+  if (reg.error ())
+    return false;
+  if (reg.get_dword (L"ForceV2", 1) == 0)
+    {
+      termios_printf ("Pseudo console is disabled "
+		      "because the legacy console mode is enabled.");
+      return false;
+    }
+
+  COORD size = {
+    (SHORT) get_ttyp ()->winsize.ws_col,
+    (SHORT) get_ttyp ()->winsize.ws_row
+  };
+  const DWORD inherit_cursor = 1;
+  SetLastError (ERROR_SUCCESS);
+  HRESULT res = CreatePseudoConsole (size, get_handle (), get_output_handle (),
+				     inherit_cursor,
+				     &get_ttyp ()->h_pseudo_console);
+  if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      if (res != S_OK)
+	system_printf ("CreatePseudoConsole() failed. %08x %08x\n",
+		       GetLastError (), res);
+      goto fallback;
+    }
+
+  SIZE_T bytesRequired;
+  InitializeProcThreadAttributeList (NULL, 1, 0, &bytesRequired);
+  ZeroMemory (si, sizeof (*si));
+  si->StartupInfo.cb = sizeof (STARTUPINFOEXW);
+  si->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)
+    HeapAlloc (GetProcessHeap (), 0, bytesRequired);
+  if (si->lpAttributeList == NULL)
+    goto cleanup_pseudo_console;
+  if (!InitializeProcThreadAttributeList (si->lpAttributeList,
+					  1, 0, &bytesRequired))
+    goto cleanup_heap;
+  if (!UpdateProcThreadAttribute (si->lpAttributeList,
+				  0,
+				  PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+				  get_ttyp ()->h_pseudo_console,
+				  sizeof (get_ttyp ()->h_pseudo_console),
+				  NULL, NULL))
+    goto cleanup_heap;
+  si->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  si->StartupInfo.hStdInput = NULL;
+  si->StartupInfo.hStdOutput = NULL;
+  si->StartupInfo.hStdError = NULL;
+
+  {
+    fhandler_base *fh0 = ::cygheap->fdtab[0];
+    if (fh0 && fh0->get_device () != get_device ())
+      si->StartupInfo.hStdInput = fh0->get_handle ();
+    fhandler_base *fh1 = ::cygheap->fdtab[1];
+    if (fh1 && fh1->get_device () != get_device ())
+      si->StartupInfo.hStdOutput = fh1->get_output_handle ();
+    fhandler_base *fh2 = ::cygheap->fdtab[2];
+    if (fh2 && fh2->get_device () != get_device ())
+      si->StartupInfo.hStdError = fh2->get_output_handle ();
+  }
+
+  if (get_ttyp ()->pcon_pid == 0 || !pinfo (get_ttyp ()->pcon_pid))
+    get_ttyp ()->pcon_pid = myself->pid;
+
+  if (get_ttyp ()->h_pseudo_console && get_ttyp ()->pcon_pid == myself->pid)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      get_ttyp ()->h_pcon_write_pipe = hp->hWritePipe;
+    }
+  get_ttyp ()->pcon_start = true;
+  return true;
+
+cleanup_heap:
+  HeapFree (GetProcessHeap (), 0, si->lpAttributeList);
+cleanup_pseudo_console:
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+    }
+fallback:
+  get_ttyp ()->h_pseudo_console = NULL;
+  return false;
+}
+
+void
+fhandler_pty_slave::close_pseudoconsole (void)
+{
+  if (get_ttyp ()->h_pseudo_console)
+    {
+      get_ttyp ()->wait_pcon_fwd ();
+      HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+      HANDLE tmp = hp->hConHostProcess;
+      ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+      CloseHandle (tmp);
+      get_ttyp ()->h_pseudo_console = NULL;
+      get_ttyp ()->switch_to_pcon_in = false;
+      get_ttyp ()->pcon_pid = 0;
+      get_ttyp ()->pcon_start = false;
+    }
+}
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 7c07b062e..38172ca1e 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -134,36 +134,6 @@ child_info::prefork (bool detached)
 int __stdcall
 frok::child (volatile char * volatile here)
 {
-  cygheap_fdenum cfd (false);
-  while (cfd.next () >= 0)
-    if (cfd->get_major () == DEV_PTYM_MAJOR)
-      {
-	fhandler_base *fh = cfd;
-	fhandler_pty_master *ptym = (fhandler_pty_master *) fh;
-	if (ptym->get_pseudo_console ())
-	  {
-	    debug_printf ("found a PTY master %d: helper_PID=%d",
-			  ptym->get_minor (), ptym->get_helper_process_id ());
-	    if (fhandler_console::get_console_process_id (
-				ptym->get_helper_process_id (), true))
-	      /* Already attached */
-	      break;
-	    else
-	      {
-		if (ptym->attach_pcon_in_fork ())
-		  {
-		    FreeConsole ();
-		    if (!AttachConsole (ptym->get_helper_process_id ()))
-		      /* Error */;
-		    else
-		      break;
-		  }
-	      }
-	  }
-      }
-  extern void clear_pcon_attached_to (void); /* fhandler_tty.cc */
-  clear_pcon_attached_to ();
-
   HANDLE& hParent = ch.parent;
 
   sync_with_parent ("after longjmp", true);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 4a8f3b2ec..9f1a8a57a 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1215,8 +1215,7 @@ verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds,
 	   fd_set *exceptfds)
 {
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) me->fh;
-  if (me->read_selected && !ptys->to_be_read_from_pcon () &&
-      IsEventSignalled (ptys->input_available_event))
+  if (me->read_selected && IsEventSignalled (ptys->input_available_event))
     me->read_ready = true;
   return set_bits (me, readfds, writefds, exceptfds);
 }
@@ -1229,8 +1228,6 @@ peek_pty_slave (select_record *s, bool from_select)
   fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
 
   ptys->reset_switch_to_pcon ();
-  if (ptys->to_be_read_from_pcon ())
-    ptys->update_pcon_input_state (true);
 
   if (s->read_selected)
     {
diff --git a/winsup/cygwin/smallprint.cc b/winsup/cygwin/smallprint.cc
index 9cfb41987..4a14ee3cf 100644
--- a/winsup/cygwin/smallprint.cc
+++ b/winsup/cygwin/smallprint.cc
@@ -405,7 +405,6 @@ small_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
   WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, NULL);
   FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
 }
@@ -432,7 +431,6 @@ console_printf (const char *fmt, ...)
   count = __small_vsprintf (buf, fmt, ap);
   va_end (ap);
 
-  set_ishybrid_and_switch_to_pcon (console_handle);
   WriteFile (console_handle, buf, count, &done, NULL);
   FlushFileBuffers (console_handle);
 }
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index af177c0f1..8308bccf3 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -177,7 +177,7 @@ find_exec (const char *name, path_conv& buf, const char *search,
 /* Utility for child_info_spawn::worker.  */
 
 static HANDLE
-handle (int fd, bool writing, bool iscygwin)
+handle (int fd, bool writing)
 {
   HANDLE h;
   cygheap_fdget cfd (fd);
@@ -188,17 +188,30 @@ handle (int fd, bool writing, bool iscygwin)
     h = INVALID_HANDLE_VALUE;
   else if (!writing)
     h = cfd->get_handle ();
-  else if (cfd->get_major () == DEV_PTYS_MAJOR && iscygwin)
-    {
-      fhandler_pty_slave *ptys = (fhandler_pty_slave *)(fhandler_base *) cfd;
-      h = ptys->get_output_handle_cyg ();
-    }
   else
     h = cfd->get_output_handle ();
 
   return h;
 }
 
+static bool
+is_console_app (WCHAR *filename)
+{
+  HANDLE h;
+  const int id_offset = 92;
+  h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
+		  NULL, OPEN_EXISTING, 0, NULL);
+  char buf[1024];
+  DWORD n;
+  ReadFile (h, buf, sizeof (buf), &n, 0);
+  CloseHandle (h);
+  char *p = (char *) memmem (buf, n, "PE\0\0", 4);
+  if (p && p + id_offset <= buf + n)
+    return p[id_offset] == '\003'; /* 02: GUI, 03: console */
+  else
+    return false;
+}
+
 int
 iscmd (const char *argv0, const char *what)
 {
@@ -266,8 +279,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 {
   bool rc;
   int res = -1;
-  DWORD pid_restore = 0;
-  bool attach_to_console = false;
   pid_t ctty_pgid = 0;
 
   /* Search for CTTY and retrieve its PGID */
@@ -587,9 +598,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			 PROCESS_QUERY_LIMITED_INFORMATION))
 	sa = &sec_none_nih;
 
-      /* Attach to pseudo console if pty salve is used */
-      pid_restore = fhandler_console::get_console_process_id
-	(GetCurrentProcessId (), false);
+      fhandler_pty_slave *ptys_primary = NULL;
       for (int i = 0; i < 3; i ++)
 	{
 	  const int chk_order[] = {1, 0, 2};
@@ -598,29 +607,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  if (fh && fh->get_major () == DEV_PTYS_MAJOR)
 	    {
 	      fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
-	      if (ptys->get_pseudo_console ())
-		{
-		  DWORD helper_process_id = ptys->get_helper_process_id ();
-		  debug_printf ("found a PTY slave %d: helper_PID=%d",
-				    fh->get_minor (), helper_process_id);
-		  if (fhandler_console::get_console_process_id
-					      (helper_process_id, true))
-		    /* Already attached */
-		    attach_to_console = true;
-		  else if (!attach_to_console)
-		    {
-		      FreeConsole ();
-		      if (AttachConsole (helper_process_id))
-			attach_to_console = true;
-		    }
-		  ptys->fixup_after_attach (!iscygwin (), fd);
-		  if (mode == _P_OVERLAY)
-		    ptys->set_freeconsole_on_close (iscygwin ());
-		}
+	      if (ptys_primary == NULL)
+		ptys_primary = ptys;
 	    }
 	  else if (fh && fh->get_major () == DEV_CONS_MAJOR)
 	    {
-	      attach_to_console = true;
 	      fhandler_console *cons = (fhandler_console *) fh;
 	      if (wincap.has_con_24bit_colors () && !iscygwin ())
 		if (fd == 1 || fd == 2)
@@ -642,17 +633,28 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 
       /* Set up needed handles for stdio */
       si.dwFlags = STARTF_USESTDHANDLES;
-      si.hStdInput = handle ((in__stdin < 0 ? 0 : in__stdin), false,
-			     iscygwin ());
-      si.hStdOutput = handle ((in__stdout < 0 ? 1 : in__stdout), true,
-			      iscygwin ());
-      si.hStdError = handle (2, true, iscygwin ());
+      si.hStdInput = handle ((in__stdin < 0 ? 0 : in__stdin), false);
+      si.hStdOutput = handle ((in__stdout < 0 ? 1 : in__stdout), true);
+      si.hStdError = handle (2, true);
 
       si.cb = sizeof (si);
 
       if (!iscygwin ())
 	init_console_handler (myself->ctty > 0);
 
+      bool enable_pcon = false;
+      STARTUPINFOEXW si_pcon;
+      ZeroMemory (&si_pcon, sizeof (si_pcon));
+      STARTUPINFOW *si_tmp = &si;
+      if (!iscygwin () && ptys_primary && is_console_app (runpath))
+	if (ptys_primary->setup_pseudoconsole (&si_pcon,
+			     mode != _P_OVERLAY && mode != _P_WAIT))
+	  {
+	    c_flags |= EXTENDED_STARTUPINFO_PRESENT;
+	    si_tmp = &si_pcon.StartupInfo;
+	    enable_pcon = true;
+	  }
+
     loop:
       /* When ruid != euid we create the new process under the current original
 	 account and impersonate in child, this way maintaining the different
@@ -681,7 +683,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	}
       else
@@ -735,7 +737,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 			       c_flags,
 			       envblock,	/* environment */
 			       NULL,
-			       &si,
+			       si_tmp,
 			       &pi);
 	  if (hwst)
 	    {
@@ -748,6 +750,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	      CloseDesktop (hdsk);
 	    }
 	}
+      if (enable_pcon)
+	{
+	  DeleteProcThreadAttributeList (si_pcon.lpAttributeList);
+	  HeapFree (GetProcessHeap (), 0, si_pcon.lpAttributeList);
+	}
 
       if (mode != _P_OVERLAY)
 	SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
@@ -920,6 +927,11 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	    }
 	  if (sem)
 	    __posix_spawn_sem_release (sem, 0);
+	  if (enable_pcon)
+	    {
+	      WaitForSingleObject (pi.hProcess, INFINITE);
+	      ptys_primary->close_pseudoconsole ();
+	    }
 	  myself.exit (EXITCODE_NOSET);
 	  break;
 	case _P_WAIT:
@@ -927,6 +939,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	  system_call.arm ();
 	  if (waitpid (cygpid, &res, 0) != cygpid)
 	    res = -1;
+	  if (enable_pcon)
+	    ptys_primary->close_pseudoconsole ();
 	  break;
 	case _P_DETACH:
 	  res = 0;	/* Lost all memory of this child. */
@@ -953,21 +967,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
   if (envblock)
     free (envblock);
 
-  if (attach_to_console && pid_restore)
-    {
-      FreeConsole ();
-      AttachConsole (pid_restore);
-      cygheap_fdenum cfd (false);
-      int fd;
-      while ((fd = cfd.next ()) >= 0)
-	if (cfd->get_major () == DEV_PTYS_MAJOR)
-	  {
-	    fhandler_pty_slave *ptys =
-	      (fhandler_pty_slave *) (fhandler_base *) cfd;
-	    ptys->fixup_after_attach (false, fd);
-	  }
-    }
-
   return (int) res;
 }
 
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index f0aef3a36..35f8a59ae 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -264,7 +264,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
   if (category & _STRACE_SYSTEM)
     {
       DWORD done;
-      set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
       WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
       FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
       /* Make sure that the message shows up on the screen, too, since this is
@@ -276,7 +275,6 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
 				 &sec_none, OPEN_EXISTING, 0, 0);
 	  if (h != INVALID_HANDLE_VALUE)
 	    {
-	      set_ishybrid_and_switch_to_pcon (h);
 	      WriteFile (h, buf, len, &done, 0);
 	      CloseHandle (h);
 	    }
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 4cb68f776..d60f27545 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -234,20 +234,14 @@ tty::init ()
   was_opened = false;
   master_pid = 0;
   is_console = false;
-  attach_pcon_in_fork = false;
-  h_pseudo_console = NULL;
   column = 0;
+  h_pseudo_console = NULL;
   switch_to_pcon_in = false;
-  switch_to_pcon_out = false;
-  screen_alternated = false;
   mask_switch_to_pcon_in = false;
   pcon_pid = 0;
   term_code_page = 0;
-  need_redraw_screen = true;
   pcon_last_time = 0;
-  pcon_in_empty = true;
-  req_transfer_input_to_pcon = false;
-  req_flush_pcon_input = false;
+  pcon_start = false;
 }
 
 HANDLE
@@ -293,16 +287,6 @@ tty_min::ttyname ()
   return d.name ();
 }
 
-void
-tty::set_switch_to_pcon_out (bool v)
-{
-  if (switch_to_pcon_out != v)
-    {
-      wait_pcon_fwd ();
-      switch_to_pcon_out = v;
-    }
-}
-
 void
 tty::wait_pcon_fwd (void)
 {
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 920e32b16..c491d3891 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -94,21 +94,13 @@ private:
   HANDLE _to_master;
   HANDLE _to_master_cyg;
   HPCON h_pseudo_console;
-  HANDLE h_helper_process;
-  DWORD helper_process_id;
-  HANDLE h_helper_goodbye;
-  bool attach_pcon_in_fork;
+  bool pcon_start;
   bool switch_to_pcon_in;
-  bool switch_to_pcon_out;
-  bool screen_alternated;
   bool mask_switch_to_pcon_in;
   pid_t pcon_pid;
   UINT term_code_page;
-  bool need_redraw_screen;
   DWORD pcon_last_time;
-  bool pcon_in_empty;
-  bool req_transfer_input_to_pcon;
-  bool req_flush_pcon_input;
+  HANDLE h_pcon_write_pipe;
 
 public:
   HANDLE from_master () const { return _from_master; }
@@ -138,7 +130,6 @@ public:
   void set_master_ctl_closed () {master_pid = -1;}
   static void __stdcall create_master (int);
   static void __stdcall init_session ();
-  void set_switch_to_pcon_out (bool v);
   void wait_pcon_fwd (void);
   friend class fhandler_pty_common;
   friend class fhandler_pty_master;
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index 9bfa1a7a6..79844cb87 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -224,9 +224,6 @@ void init_console_handler (bool);
 
 extern bool wsock_started;
 
-/* PTY related */
-void set_ishybrid_and_switch_to_pcon (HANDLE h);
-
 /* Printf type functions */
 extern "C" void vapi_fatal (const char *, va_list ap) __attribute__ ((noreturn));
 extern "C" void api_fatal (const char *, ...) __attribute__ ((noreturn));
-- 
2.28.0


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-19 11:39                                             ` Takashi Yano
@ 2020-08-19 13:41                                               ` Corinna Vinschen
  2020-08-19 15:43                                                 ` Thomas Wolff
                                                                   ` (2 more replies)
  0 siblings, 3 replies; 73+ messages in thread
From: Corinna Vinschen @ 2020-08-19 13:41 UTC (permalink / raw)
  To: cygwin-developers

Guys,

On Aug 19 20:39, Takashi Yano via Cygwin-developers wrote:
> On Mon, 17 Aug 2020 20:57:18 +0900
> > Adapted to the current git head.
> 
> Aligned the timing of seup_locale () call with the recent pty change.

Shall we release 3.1.7 as bugfix release and then merge this patch
and bump to 3.2.0?


Thanks,
Corinna

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-19 13:41                                               ` Corinna Vinschen
@ 2020-08-19 15:43                                                 ` Thomas Wolff
  2020-08-19 20:47                                                 ` Mark Geisert
  2020-08-20  8:02                                                 ` Takashi Yano
  2 siblings, 0 replies; 73+ messages in thread
From: Thomas Wolff @ 2020-08-19 15:43 UTC (permalink / raw)
  To: cygwin-developers

Am 19.08.2020 um 15:41 schrieb Corinna Vinschen:
> Guys,
>
> On Aug 19 20:39, Takashi Yano via Cygwin-developers wrote:
>> On Mon, 17 Aug 2020 20:57:18 +0900
>>> Adapted to the current git head.
>> Aligned the timing of seup_locale () call with the recent pty change.
> Shall we release 3.1.7 as bugfix release and then merge this patch
> and bump to 3.2.0?
I'd welcome it.
Thomas
>
> Thanks,
> Corinna


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-19 13:41                                               ` Corinna Vinschen
  2020-08-19 15:43                                                 ` Thomas Wolff
@ 2020-08-19 20:47                                                 ` Mark Geisert
  2020-08-20  8:02                                                 ` Takashi Yano
  2 siblings, 0 replies; 73+ messages in thread
From: Mark Geisert @ 2020-08-19 20:47 UTC (permalink / raw)
  To: cygwin-developers

Corinna Vinschen wrote:
> Guys,
[...]
> Shall we release 3.1.7 as bugfix release and then merge this patch
> and bump to 3.2.0?

SGTM & Cheers,

..mark

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-19 13:41                                               ` Corinna Vinschen
  2020-08-19 15:43                                                 ` Thomas Wolff
  2020-08-19 20:47                                                 ` Mark Geisert
@ 2020-08-20  8:02                                                 ` Takashi Yano
  2020-08-31 12:49                                                   ` Johannes Schindelin
  2 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-08-20  8:02 UTC (permalink / raw)
  To: cygwin-developers

On Wed, 19 Aug 2020 15:41:56 +0200
Corinna Vinschen wrote:
> Guys,
> 
> On Aug 19 20:39, Takashi Yano via Cygwin-developers wrote:
> > On Mon, 17 Aug 2020 20:57:18 +0900
> > > Adapted to the current git head.
> > 
> > Aligned the timing of seup_locale () call with the recent pty change.
> 
> Shall we release 3.1.7 as bugfix release and then merge this patch
> and bump to 3.2.0?

It might be time to do so. Thanks.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-20  8:02                                                 ` Takashi Yano
@ 2020-08-31 12:49                                                   ` Johannes Schindelin
  2020-08-31 14:14                                                     ` Takashi Yano
       [not found]                                                     ` <20200831231253.332c66fdddb33ceed5f61db6@nifty.ne.jp>
  0 siblings, 2 replies; 73+ messages in thread
From: Johannes Schindelin @ 2020-08-31 12:49 UTC (permalink / raw)
  To: Takashi Yano; +Cc: cygwin-developers

Hi Takashi,

On Thu, 20 Aug 2020, Takashi Yano via Cygwin-developers wrote:

> On Wed, 19 Aug 2020 15:41:56 +0200
> Corinna Vinschen wrote:
> > Guys,
> >
> > On Aug 19 20:39, Takashi Yano via Cygwin-developers wrote:
> > > On Mon, 17 Aug 2020 20:57:18 +0900
> > > > Adapted to the current git head.
> > >
> > > Aligned the timing of seup_locale () call with the recent pty change.
> >
> > Shall we release 3.1.7 as bugfix release and then merge this patch
> > and bump to 3.2.0?
>
> It might be time to do so. Thanks.

Sorry to latch onto this thread with something slightly different, but we
do see pretty serious encoding problems (both with and without
`CYGWIN=disable_pcon`) in the Git for Windows and the MSYS2 projects. For
example, in https://github.com/msys2/MSYS2-packages/issues/1974 the
following issue was reported. If you compile a _MINGW_ program from this
source code:

-- snip --
#include <stdio.h>

int main(){
  puts("Привет мир! Hello world!");
  return 0;
}
-- snap --

and then execute it, you will see this output:

-- snip --
Привет мир! Hello world!
-- snap --

Piping the output through `cat.exe` "fixes" the issue. I tried both with
v3.1.7 and with the tip of the main branch. Could I ask you to have a look
at this?

Ciao,
Johannes

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-31 12:49                                                   ` Johannes Schindelin
@ 2020-08-31 14:14                                                     ` Takashi Yano
       [not found]                                                     ` <20200831231253.332c66fdddb33ceed5f61db6@nifty.ne.jp>
  1 sibling, 0 replies; 73+ messages in thread
From: Takashi Yano @ 2020-08-31 14:14 UTC (permalink / raw)
  To: cygwin-developers

On Mon, 31 Aug 2020 14:49:04 +0200 (CEST)
Johannes Schindelin wrote:
> Hi Takashi,
> 
> On Thu, 20 Aug 2020, Takashi Yano via Cygwin-developers wrote:
> 
> > On Wed, 19 Aug 2020 15:41:56 +0200
> > Corinna Vinschen wrote:
> > > Guys,
> > >
> > > On Aug 19 20:39, Takashi Yano via Cygwin-developers wrote:
> > > > On Mon, 17 Aug 2020 20:57:18 +0900
> > > > > Adapted to the current git head.
> > > >
> > > > Aligned the timing of seup_locale () call with the recent pty change.
> > >
> > > Shall we release 3.1.7 as bugfix release and then merge this patch
> > > and bump to 3.2.0?
> >
> > It might be time to do so. Thanks.
> 
> Sorry to latch onto this thread with something slightly different, but we
> do see pretty serious encoding problems (both with and without
> `CYGWIN=disable_pcon`) in the Git for Windows and the MSYS2 projects. For
> example, in https://github.com/msys2/MSYS2-packages/issues/1974 the
> following issue was reported. If you compile a _MINGW_ program from this
> source code:
> 
> -- snip --
> #include <stdio.h>
> 
> int main(){
>   puts("Привет мир! Hello world!");
>   return 0;
> }
> -- snap --
> 
> and then execute it, you will see this output:
> 
> -- snip --
> Привет мир! Hello world!
> -- snap --

I guess your program (binary exe) does not work as you expect
in command prompt as well. If you want to use UTF-8 coding in
output, you should add SetConsoleOutputCP(CP_UTF8) call befere
puts().

> Piping the output through `cat.exe` "fixes" the issue. I tried both with
> v3.1.7 and with the tip of the main branch. Could I ask you to have a look
> at this?
> 
> Ciao,
> Johannes


-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
       [not found]                                                     ` <20200831231253.332c66fdddb33ceed5f61db6@nifty.ne.jp>
@ 2020-08-31 14:22                                                       ` Johannes Schindelin
  2020-08-31 14:53                                                         ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Johannes Schindelin @ 2020-08-31 14:22 UTC (permalink / raw)
  To: Takashi Yano; +Cc: cygwin-developers

Hi Takashi,

On Mon, 31 Aug 2020, Takashi Yano wrote:

> On Mon, 31 Aug 2020 14:49:04 +0200 (CEST)
> Johannes Schindelin wrote:
>
> > On Thu, 20 Aug 2020, Takashi Yano via Cygwin-developers wrote:
> >
> > > On Wed, 19 Aug 2020 15:41:56 +0200
> > > Corinna Vinschen wrote:
> > > > Guys,
> > > >
> > > > On Aug 19 20:39, Takashi Yano via Cygwin-developers wrote:
> > > > > On Mon, 17 Aug 2020 20:57:18 +0900
> > > > > > Adapted to the current git head.
> > > > >
> > > > > Aligned the timing of seup_locale () call with the recent pty change.
> > > >
> > > > Shall we release 3.1.7 as bugfix release and then merge this patch
> > > > and bump to 3.2.0?
> > >
> > > It might be time to do so. Thanks.
> >
> > Sorry to latch onto this thread with something slightly different, but we
> > do see pretty serious encoding problems (both with and without
> > `CYGWIN=disable_pcon`) in the Git for Windows and the MSYS2 projects. For
> > example, in https://github.com/msys2/MSYS2-packages/issues/1974 the
> > following issue was reported. If you compile a _MINGW_ program from this
> > source code:
> >
> > -- snip --
> > #include <stdio.h>
> >
> > int main(){
> >   puts("Привет мир! Hello world!");
> >   return 0;
> > }
> > -- snap --
> >
> > and then execute it, you will see this output:
> >
> > -- snip --
> > Привет мир! Hello world!
> > -- snap --
>
> I guess your program (binary exe) does not work as you expect
> in command prompt as well. If you want to use UTF-8 coding in
> output, you should add SetConsoleOutputCP(CP_UTF8) call befere
> puts().

That may be, but I would like to point out that the very same executable
worked quite well in a MinTTY using v3.0.7... Meaning: the default
changed, and that broke a lot of users' expectations.

Is there really _no_ easy way to get the old behavior back?

Ciao,
Johannes

>
> > Piping the output through `cat.exe` "fixes" the issue. I tried both with
> > v3.1.7 and with the tip of the main branch. Could I ask you to have a look
> > at this?
> >
> > Ciao,
> > Johannes
>
>
> --
> Takashi Yano <takashi.yano@nifty.ne.jp>
>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-31 14:22                                                       ` Johannes Schindelin
@ 2020-08-31 14:53                                                         ` Takashi Yano
  2020-08-31 15:56                                                           ` Johannes Schindelin
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-08-31 14:53 UTC (permalink / raw)
  To: cygwin-developers

On Mon, 31 Aug 2020 16:22:20 +0200 (CEST)
Johannes Schindelin wrote:
> Hi Takashi,
> 
> On Mon, 31 Aug 2020, Takashi Yano wrote:
> 
> > On Mon, 31 Aug 2020 14:49:04 +0200 (CEST)
> > Johannes Schindelin wrote:
> >
> > > On Thu, 20 Aug 2020, Takashi Yano via Cygwin-developers wrote:
> > >
> > > > On Wed, 19 Aug 2020 15:41:56 +0200
> > > > Corinna Vinschen wrote:
> > > > > Guys,
> > > > >
> > > > > On Aug 19 20:39, Takashi Yano via Cygwin-developers wrote:
> > > > > > On Mon, 17 Aug 2020 20:57:18 +0900
> > > > > > > Adapted to the current git head.
> > > > > >
> > > > > > Aligned the timing of seup_locale () call with the recent pty change.
> > > > >
> > > > > Shall we release 3.1.7 as bugfix release and then merge this patch
> > > > > and bump to 3.2.0?
> > > >
> > > > It might be time to do so. Thanks.
> > >
> > > Sorry to latch onto this thread with something slightly different, but we
> > > do see pretty serious encoding problems (both with and without
> > > `CYGWIN=disable_pcon`) in the Git for Windows and the MSYS2 projects. For
> > > example, in https://github.com/msys2/MSYS2-packages/issues/1974 the
> > > following issue was reported. If you compile a _MINGW_ program from this
> > > source code:
> > >
> > > -- snip --
> > > #include <stdio.h>
> > >
> > > int main(){
> > >   puts("Привет мир! Hello world!");
> > >   return 0;
> > > }
> > > -- snap --
> > >
> > > and then execute it, you will see this output:
> > >
> > > -- snip --
> > > Привет мир! Hello world!
> > > -- snap --
> >
> > I guess your program (binary exe) does not work as you expect
> > in command prompt as well. If you want to use UTF-8 coding in
> > output, you should add SetConsoleOutputCP(CP_UTF8) call befere
> > puts().
> 
> That may be, but I would like to point out that the very same executable
> worked quite well in a MinTTY using v3.0.7...

at the expense of garbled output for apps which use native
code page of the system in the correct maner.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-31 14:53                                                         ` Takashi Yano
@ 2020-08-31 15:56                                                           ` Johannes Schindelin
  2020-08-31 16:12                                                             ` Thomas Wolff
  0 siblings, 1 reply; 73+ messages in thread
From: Johannes Schindelin @ 2020-08-31 15:56 UTC (permalink / raw)
  To: Takashi Yano; +Cc: cygwin-developers

Hi Takashi,

On Mon, 31 Aug 2020, Takashi Yano wrote:

> On Mon, 31 Aug 2020 16:22:20 +0200 (CEST)
> Johannes Schindelin wrote:
> >
> > On Mon, 31 Aug 2020, Takashi Yano wrote:
> >
> > > On Mon, 31 Aug 2020 14:49:04 +0200 (CEST)
> > > Johannes Schindelin wrote:
> > >
> > > > Sorry to latch onto this thread with something slightly different, but we
> > > > do see pretty serious encoding problems (both with and without
> > > > `CYGWIN=disable_pcon`) in the Git for Windows and the MSYS2 projects. For
> > > > example, in https://github.com/msys2/MSYS2-packages/issues/1974 the
> > > > following issue was reported. If you compile a _MINGW_ program from this
> > > > source code:
> > > >
> > > > -- snip --
> > > > #include <stdio.h>
> > > >
> > > > int main(){
> > > >   puts("Привет мир! Hello world!");
> > > >   return 0;
> > > > }
> > > > -- snap --
> > > >
> > > > and then execute it, you will see this output:
> > > >
> > > > -- snip --
> > > > Привет мир! Hello world!
> > > > -- snap --
> > >
> > > I guess your program (binary exe) does not work as you expect
> > > in command prompt as well. If you want to use UTF-8 coding in
> > > output, you should add SetConsoleOutputCP(CP_UTF8) call befere
> > > puts().
> >
> > That may be, but I would like to point out that the very same executable
> > worked quite well in a MinTTY using v3.0.7...
>
> at the expense of garbled output for apps which use native
> code page of the system in the correct maner.

Are you referring to apps that call the SetConsoleOutputCP() function? If
so, I am asking myself what would be broken. Because apps that do _not_
call that function (expecting UTF-8 to be active) would be fixed, while
apps that _do_ call that function would not care if the Cygwin runtime
changed it.

Ciao,
Johannes

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-31 15:56                                                           ` Johannes Schindelin
@ 2020-08-31 16:12                                                             ` Thomas Wolff
  2020-08-31 17:39                                                               ` Thomas Wolff
  0 siblings, 1 reply; 73+ messages in thread
From: Thomas Wolff @ 2020-08-31 16:12 UTC (permalink / raw)
  To: cygwin-developers



Am 31.08.2020 um 17:56 schrieb Johannes Schindelin:
> Hi Takashi,
>
> On Mon, 31 Aug 2020, Takashi Yano wrote:
>
>> On Mon, 31 Aug 2020 16:22:20 +0200 (CEST)
>> Johannes Schindelin wrote:
>>> On Mon, 31 Aug 2020, Takashi Yano wrote:
>>>
>>>> On Mon, 31 Aug 2020 14:49:04 +0200 (CEST)
>>>> Johannes Schindelin wrote:
>>>>
>>>>> Sorry to latch onto this thread with something slightly different, but we
>>>>> do see pretty serious encoding problems (both with and without
>>>>> `CYGWIN=disable_pcon`) in the Git for Windows and the MSYS2 projects. For
>>>>> example, in https://github.com/msys2/MSYS2-packages/issues/1974 the
>>>>> following issue was reported. If you compile a _MINGW_ program from this
>>>>> source code:
>>>>>
>>>>> -- snip --
>>>>> #include <stdio.h>
>>>>>
>>>>> int main(){
>>>>>    puts("Привет мир! Hello world!");
>>>>>    return 0;
>>>>> }
>>>>> -- snap --
>>>>>
>>>>> and then execute it, you will see this output:
>>>>>
>>>>> -- snip --
>>>>> Привет мир! Hello world!
>>>>> -- snap --
>>>> I guess your program (binary exe) does not work as you expect
>>>> in command prompt as well. If you want to use UTF-8 coding in
>>>> output, you should add SetConsoleOutputCP(CP_UTF8) call befere
>>>> puts().
>>> That may be, but I would like to point out that the very same executable
>>> worked quite well in a MinTTY using v3.0.7...
Assuming the test program source file is encoded in UTF-8 when compiling 
with x86_64-w64-mingw32-gcc, the string would be output byte by byte, 
which happend to be interpreted in UTF-8 when run in a terminal on 
cygwin 3.0.7, although the program was not set up to use UTF-8.
The "correct" output was actually buggy behaviour, so current cygwin has 
"fixed" it, to your disadvantage in this case.
With ConPTY support, matching encoding on Windows and terminal side need 
to be taken care of.
Thomas

>> at the expense of garbled output for apps which use native
>> code page of the system in the correct maner.
> Are you referring to apps that call the SetConsoleOutputCP() function? If
> so, I am asking myself what would be broken. Because apps that do _not_
> call that function (expecting UTF-8 to be active) would be fixed, while
> apps that _do_ call that function would not care if the Cygwin runtime
> changed it.
>
> Ciao,
> Johannes


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-31 16:12                                                             ` Thomas Wolff
@ 2020-08-31 17:39                                                               ` Thomas Wolff
  2020-08-31 19:17                                                                 ` Johannes Schindelin
  0 siblings, 1 reply; 73+ messages in thread
From: Thomas Wolff @ 2020-08-31 17:39 UTC (permalink / raw)
  To: cygwin-developers



Am 31.08.2020 um 18:12 schrieb Thomas Wolff:
>
>
> Am 31.08.2020 um 17:56 schrieb Johannes Schindelin:
>> Hi Takashi,
>>
>> On Mon, 31 Aug 2020, Takashi Yano wrote:
>>
>>> On Mon, 31 Aug 2020 16:22:20 +0200 (CEST)
>>> Johannes Schindelin wrote:
>>>> On Mon, 31 Aug 2020, Takashi Yano wrote:
>>>>
>>>>> On Mon, 31 Aug 2020 14:49:04 +0200 (CEST)
>>>>> Johannes Schindelin wrote:
>>>>>
>>>>>> Sorry to latch onto this thread with something slightly 
>>>>>> different, but we
>>>>>> do see pretty serious encoding problems (both with and without
>>>>>> `CYGWIN=disable_pcon`) in the Git for Windows and the MSYS2 
>>>>>> projects. For
>>>>>> example, in https://github.com/msys2/MSYS2-packages/issues/1974 the
>>>>>> following issue was reported. If you compile a _MINGW_ program 
>>>>>> from this
>>>>>> source code:
>>>>>>
>>>>>> -- snip --
>>>>>> #include <stdio.h>
>>>>>>
>>>>>> int main(){
>>>>>>    puts("Привет мир! Hello world!");
>>>>>>    return 0;
>>>>>> }
>>>>>> -- snap --
>>>>>>
>>>>>> and then execute it, you will see this output:
>>>>>>
>>>>>> -- snip --
>>>>>> Привет мир! Hello world!
>>>>>> -- snap --
>>>>> I guess your program (binary exe) does not work as you expect
>>>>> in command prompt as well. If you want to use UTF-8 coding in
>>>>> output, you should add SetConsoleOutputCP(CP_UTF8) call befere
>>>>> puts().
>>>> That may be, but I would like to point out that the very same 
>>>> executable
>>>> worked quite well in a MinTTY using v3.0.7...
> Assuming the test program source file is encoded in UTF-8 when 
> compiling with x86_64-w64-mingw32-gcc, the string would be output byte 
> by byte, which happend to be interpreted in UTF-8 when run in a 
> terminal on cygwin 3.0.7, although the program was not set up to use 
> UTF-8.
> The "correct" output was actually buggy behaviour, so current cygwin 
> has "fixed" it, to your disadvantage in this case.
> With ConPTY support, matching encoding on Windows and terminal side 
> need to be taken care of.
My wording was misleading. Maybe it's proper to say it this way:
Matching encoding on each side between application and respective system 
is needed, as ConPTY transforms encoding properly on system level.
> Thomas
>
>>> at the expense of garbled output for apps which use native
>>> code page of the system in the correct maner.
>> Are you referring to apps that call the SetConsoleOutputCP() 
>> function? If
>> so, I am asking myself what would be broken. Because apps that do _not_
>> call that function (expecting UTF-8 to be active) would be fixed, while
>> apps that _do_ call that function would not care if the Cygwin runtime
>> changed it.
>>
>> Ciao,
>> Johannes
>


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-31 17:39                                                               ` Thomas Wolff
@ 2020-08-31 19:17                                                                 ` Johannes Schindelin
  2020-08-31 19:37                                                                   ` Corinna Vinschen
  2020-08-31 21:07                                                                   ` Thomas Wolff
  0 siblings, 2 replies; 73+ messages in thread
From: Johannes Schindelin @ 2020-08-31 19:17 UTC (permalink / raw)
  To: Thomas Wolff; +Cc: cygwin-developers

Hi Thomas,

On Mon, 31 Aug 2020, Thomas Wolff wrote:

> Am 31.08.2020 um 18:12 schrieb Thomas Wolff:
> >
> > Am 31.08.2020 um 17:56 schrieb Johannes Schindelin:
> >
> > > On Mon, 31 Aug 2020, Takashi Yano wrote:
> > >
> > > > On Mon, 31 Aug 2020 16:22:20 +0200 (CEST)
> > > > Johannes Schindelin wrote:
> > > > > On Mon, 31 Aug 2020, Takashi Yano wrote:
> > > > >
> > > > > > On Mon, 31 Aug 2020 14:49:04 +0200 (CEST)
> > > > > > Johannes Schindelin wrote:
> > > > > >
> > > > > > > Sorry to latch onto this thread with something slightly
> > > > > > > different, but we do see pretty serious encoding problems
> > > > > > > (both with and without `CYGWIN=disable_pcon`) in the Git for
> > > > > > > Windows and the MSYS2 projects. For example, in
> > > > > > > https://github.com/msys2/MSYS2-packages/issues/1974 the
> > > > > > > following issue was reported. If you compile a _MINGW_
> > > > > > > program from this source code:
> > > > > > >
> > > > > > > -- snip --
> > > > > > > #include <stdio.h>
> > > > > > >
> > > > > > > int main(){
> > > > > > >    puts("Привет мир! Hello world!");
> > > > > > >    return 0;
> > > > > > > }
> > > > > > > -- snap --
> > > > > > >
> > > > > > > and then execute it, you will see this output:
> > > > > > >
> > > > > > > -- snip --
> > > > > > > Привет мир! Hello world!
> > > > > > > -- snap --
> > > > > >
> > > > > > I guess your program (binary exe) does not work as you expect
> > > > > > in command prompt as well. If you want to use UTF-8 coding in
> > > > > > output, you should add SetConsoleOutputCP(CP_UTF8) call befere
> > > > > > puts().
> > > > >
> > > > > That may be, but I would like to point out that the very same
> > > > > executable worked quite well in a MinTTY using v3.0.7...
> >
> > Assuming the test program source file is encoded in UTF-8 when
> > compiling with x86_64-w64-mingw32-gcc, the string would be output byte
> > by byte, which happend to be interpreted in UTF-8 when run in a
> > terminal on cygwin 3.0.7, although the program was not set up to use
> > UTF-8. The "correct" output was actually buggy behaviour, so current
> > cygwin has "fixed" it, to your disadvantage in this case. With ConPTY
> > support, matching encoding on Windows and terminal side need to be
> > taken care of.
>
> My wording was misleading. Maybe it's proper to say it this way:
> Matching encoding on each side between application and respective system
> is needed, as ConPTY transforms encoding properly on system level.

Well, I just wonder how your wording (misleading or not) relates to the
issue at hand: there are programs out there that simply do not take care
of calling `SetConsoleOutputCP()`.

What you are telling me is that those programs are wrong, which I can kind
of get behind.

However, what I do not understand is what you argue should happen with the
output of such programs (if you address that concern at all, which I am
not really sure of).

Previously, we assumed the output to be in UTF-8 (although I frankly have
no idea how that worked). Starting with v3.1.0 (or at least v3.1.4, I have
not _really_ verified with earlier versions), the output is assumed to use
code page 437.

With seemingly everybody and their sister switching to UTF-8, I wonder
whether that even makes sense.

So I had a look at the code, and it seems that
`fhandler_pty_slave::setup_locale()` forces the output encoding to
C.ASCII if Pseudo Console support is enabled:

  char locale[ENCODING_LEN + 1] = "C";
  char charset[ENCODING_LEN + 1] = "ASCII";
  LCID lcid = get_langinfo (locale, charset);

  /* Set console code page from locale */
  if (get_pseudo_console ())
    {
      UINT code_page;
      if (lcid == 0 || lcid == (LCID) -1)
        code_page = 20127; /* ASCII */
      else if (!GetLocaleInfo (lcid,
                               LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
                               (char *) &code_page, sizeof (code_page)))
        code_page = 20127; /* ASCII */
      SetConsoleCP (code_page);
      SetConsoleOutputCP (code_page);
    }

Please note that this essentially forces the console output code page to
ASCII (in my case, the fall-back to 20127 seems not to kick in, but 437 is
used instead, as LCID x0409 is used).

However, there is no overriding call to `SetConsoleOutputCP()` later in
that method, not even when the `charset` is correctly identified as
`UTF-8` (because my `LANG=en_US.UTF-8`).

Now, what I _really_ do not understand is why Cygwin insists on using the
console output code page when running in `CYGWIN=disable_pcon` mode...

Otherwise, this patch would be enough to fix it for me:

-- snip --
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 43eebc174..2ce8dae9a 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -2867,11 +2867,13 @@ fhandler_pty_slave::setup_locale (void)
   char charset[ENCODING_LEN + 1] = "ASCII";
   LCID lcid = get_langinfo (locale, charset);

-  /* Set console code page form locale */
+  /* Set console code page from locale */
   if (get_pseudo_console ())
     {
       UINT code_page;
-      if (lcid == 0 || lcid == (LCID) -1)
+      if (!strcasecmp (charset, "utf-8"))
+	code_page = CP_UTF8;
+      else if (lcid == 0 || lcid == (LCID) -1)
 	code_page = 20127; /* ASCII */
       else if (!GetLocaleInfo (lcid,
 			       LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
-- snap --

But that does _not_ reinstate the previous behavior when Pseudo Console
support is disabled.

Now, I would call that a regression (the entire idea of `disable_pcon` was
to fall back to the previous behavior, no?). And I do not really
understand where it comes from, that regression. Where does the code path
differ from the previous one when Pseudo Console support is disabled, and
how does that relate to the current console output code page?

Ciao,
Johannes

> > Thomas
> >
> > > > at the expense of garbled output for apps which use native
> > > > code page of the system in the correct maner.
> > > Are you referring to apps that call the SetConsoleOutputCP() function? If
> > > so, I am asking myself what would be broken. Because apps that do _not_
> > > call that function (expecting UTF-8 to be active) would be fixed, while
> > > apps that _do_ call that function would not care if the Cygwin runtime
> > > changed it.
> > >
> > > Ciao,
> > > Johannes
> >
>
>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-31 19:17                                                                 ` Johannes Schindelin
@ 2020-08-31 19:37                                                                   ` Corinna Vinschen
  2020-09-01  4:46                                                                     ` Johannes Schindelin
  2020-08-31 21:07                                                                   ` Thomas Wolff
  1 sibling, 1 reply; 73+ messages in thread
From: Corinna Vinschen @ 2020-08-31 19:37 UTC (permalink / raw)
  To: cygwin-developers

On Aug 31 21:17, Johannes Schindelin wrote:
> [...]
> So I had a look at the code, and it seems that
> `fhandler_pty_slave::setup_locale()` forces the output encoding to
> C.ASCII if Pseudo Console support is enabled:
> 
>   char locale[ENCODING_LEN + 1] = "C";
>   char charset[ENCODING_LEN + 1] = "ASCII";
>   LCID lcid = get_langinfo (locale, charset);
> 
>   /* Set console code page from locale */
>   if (get_pseudo_console ())
>     {
>       UINT code_page;
>       if (lcid == 0 || lcid == (LCID) -1)
>         code_page = 20127; /* ASCII */

This looks wrong, actually.  The default behaviour of Cygwin since
Cygwin 1.7 was to assume UTF-8, even if the application doesn't call
setlocale.  This means the locale is "C", so ASCII is expected.
However, even in this case, the internal conversions use UTF-8.
See function internal_setlocale() in nlsfuncs.cc, lines 1553/1554.

We never switched the console codepage, though, because the codepage
doesn't make much sense when using wide character functions only,
i. e. WriteConsoleW.  Only the alternate charset is 437/ASCII.  So,
if the pseudo console actually *requires* to set the charset...


>       else if (!GetLocaleInfo (lcid,
>                                LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
>                                (char *) &code_page, sizeof (code_page)))
>         code_page = 20127; /* ASCII */
>       SetConsoleCP (code_page);
>       SetConsoleOutputCP (code_page);

can we please default to UTF-8 here even if the code page is ASCII?


Corinna

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-31 19:17                                                                 ` Johannes Schindelin
  2020-08-31 19:37                                                                   ` Corinna Vinschen
@ 2020-08-31 21:07                                                                   ` Thomas Wolff
  2020-08-31 23:23                                                                     ` Takashi Yano
  2020-09-01  5:00                                                                     ` Johannes Schindelin
  1 sibling, 2 replies; 73+ messages in thread
From: Thomas Wolff @ 2020-08-31 21:07 UTC (permalink / raw)
  To: Johannes Schindelin, cygwin-developers

Am 31.08.2020 um 21:17 schrieb Johannes Schindelin:
> Hi Thomas,
>
> On Mon, 31 Aug 2020, Thomas Wolff wrote:
>
>> Am 31.08.2020 um 18:12 schrieb Thomas Wolff:
>>> Am 31.08.2020 um 17:56 schrieb Johannes Schindelin:
>>>
>>>> On Mon, 31 Aug 2020, Takashi Yano wrote:
>>>>
>>>>> On Mon, 31 Aug 2020 16:22:20 +0200 (CEST)
>>>>> Johannes Schindelin wrote:
>>>>>> On Mon, 31 Aug 2020, Takashi Yano wrote:
>>>>>>
>>>>>>> On Mon, 31 Aug 2020 14:49:04 +0200 (CEST)
>>>>>>> Johannes Schindelin wrote:
>>>>>>>
>>>>>>>> Sorry to latch onto this thread with something slightly
>>>>>>>> different, but we do see pretty serious encoding problems
>>>>>>>> (both with and without `CYGWIN=disable_pcon`) in the Git for
>>>>>>>> Windows and the MSYS2 projects. For example, in
>>>>>>>> https://github.com/msys2/MSYS2-packages/issues/1974 the
>>>>>>>> following issue was reported. If you compile a _MINGW_
>>>>>>>> program from this source code:
>>>>>>>>
>>>>>>>> -- snip --
>>>>>>>> #include <stdio.h>
>>>>>>>>
>>>>>>>> int main(){
>>>>>>>>     puts("Привет мир! Hello world!");
>>>>>>>>     return 0;
>>>>>>>> }
>>>>>>>> -- snap --
>>>>>>>>
>>>>>>>> and then execute it, you will see this output:
>>>>>>>>
>>>>>>>> -- snip --
>>>>>>>> Привет мир! Hello world!
>>>>>>>> -- snap --
>>>>>>> I guess your program (binary exe) does not work as you expect
>>>>>>> in command prompt as well. If you want to use UTF-8 coding in
>>>>>>> output, you should add SetConsoleOutputCP(CP_UTF8) call befere
>>>>>>> puts().
>>>>>> That may be, but I would like to point out that the very same
>>>>>> executable worked quite well in a MinTTY using v3.0.7...
>>> Assuming the test program source file is encoded in UTF-8 when
>>> compiling with x86_64-w64-mingw32-gcc, the string would be output byte
>>> by byte, which happend to be interpreted in UTF-8 when run in a
>>> terminal on cygwin 3.0.7, although the program was not set up to use
>>> UTF-8. The "correct" output was actually buggy behaviour, so current
>>> cygwin has "fixed" it, to your disadvantage in this case. With ConPTY
>>> support, matching encoding on Windows and terminal side need to be
>>> taken care of.
>> My wording was misleading. Maybe it's proper to say it this way:
>> Matching encoding on each side between application and respective system
>> is needed, as ConPTY transforms encoding properly on system level.
> Well, I just wonder how your wording (misleading or not) relates to the
> issue at hand: there are programs out there that simply do not take care
> of calling `SetConsoleOutputCP()`.
Those would use the pre-set system codepage. Unless POSIX functions, 
which need an initial dummy call to setlocale to work, in the Windows 
API, always a codepage is set, typically 850 in European Windows 
installations.
>
> What you are telling me is that those programs are wrong, which I can kind
> of get behind.
No, but ConsoleOutput functions would involve the current codepage, 
which is usually *not* 65001 (the UTF-8 codepage). So if those programs 
output UTF-8 strings, they would actually be byte strings in the 
respective codepage (e.g. 850) by definition of the Windows API. 
Ignoring that in previous cygwin versions and just sending the bytes to 
a UTF-8 terminal would have given you the expected result, but it's 
unfortunately not really correct.
> However, what I do not understand is what you argue should happen with the
> output of such programs (if you address that concern at all, which I am
> not really sure of).
I'm afraid I think the proper way is to show the respective CP850 (or 
whichever) interpretation that you saw;
I'm puzzled though that the output is changed by piping through cat.
Note that you can set previous/expected behaviour consistently with chcp 
as follows:
 > chcp.com
Aktive Codepage: 850.
 > ./conming
ðƒÐÇð©ð▓ðÁÐé ð╝ð©ÐÇ! Hello world!
 > ./conming | cat
?????? ???! Hello world!
 > chcp.com 65001
Aktive Codepage: 65001.
 > ./conming
Привет мир! Hello world!
 > ./conming | cat
Привет мир! Hello world!
 >

>
> Previously, we assumed the output to be in UTF-8 (although I frankly have
> no idea how that worked).
Just by chance, as I described above.
> Starting with v3.1.0 (or at least v3.1.4, I have
> not _really_ verified with earlier versions), the output is assumed to use
> code page 437.
Or whatever the system / you have set.
> With seemingly everybody and their sister switching to UTF-8, I wonder
> whether that even makes sense.
When using the Windows API, the modern way would be to use UTF-16, i.e. 
all functions ending with "W", like WriteConsoleW. If you prefer 8-bit 
functions and want to support Unicode, set the codepage to 65001.
You may still use 8-bit codepages if desired, like CP1252 for Windows 
European ANSI.
A "DOS mode" program using 8 bit output and not setting a codepage is 
really doing something undefined and cannot expect specific output 
beyond ASCII.
>
> So I had a look at the code, and it seems that
> `fhandler_pty_slave::setup_locale()` forces the output encoding to
> C.ASCII if Pseudo Console support is enabled:
>
>    char locale[ENCODING_LEN + 1] = "C";
>    char charset[ENCODING_LEN + 1] = "ASCII";
>    LCID lcid = get_langinfo (locale, charset);
>
>    /* Set console code page from locale */
>    if (get_pseudo_console ())
>      {
>        UINT code_page;
>        if (lcid == 0 || lcid == (LCID) -1)
>          code_page = 20127; /* ASCII */
>        else if (!GetLocaleInfo (lcid,
>                                 LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
>                                 (char *) &code_page, sizeof (code_page)))
>          code_page = 20127; /* ASCII */
>        SetConsoleCP (code_page);
>        SetConsoleOutputCP (code_page);
>      }
>
> Please note that this essentially forces the console output code page to
> ASCII (in my case, the fall-back to 20127 seems not to kick in, but 437 is
> used instead, as LCID x0409 is used).
As seen, the output "ðƒÐÇð©ð▓ðÁÐé ð╝ð©ÐÇ" is not confined to ASCII. I 
doubt the branch with 20127 is taken in the test case, as lcid is likely 
to be something other than 0 or -1.
> However, there is no overriding call to `SetConsoleOutputCP()` later in
> that method, not even when the `charset` is correctly identified as
> `UTF-8` (because my `LANG=en_US.UTF-8`).
I don't know how the ConPTY support code works, but I'd say 
SetConsoleOutputCP is rather to be called on the client side of the pty, 
in the Windows program, if it wants. It might have been an alternative 
way to support Windows codepages from cygwin, before the age of ConPTY, 
as I had once considered.
> Now, what I _really_ do not understand is why Cygwin insists on using the
> console output code page when running in `CYGWIN=disable_pcon` mode...
Because it is proper to interpret output in the way it would be intended 
by the original program if that was correct.
Writing Windows programs so that they could nicely output to UTF-8 
terminals was a neat trick but unfortunately not correct.
>
> Otherwise, this patch would be enough to fix it for me:
>
> -- snip --
> diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
> index 43eebc174..2ce8dae9a 100644
> --- a/winsup/cygwin/fhandler_tty.cc
> +++ b/winsup/cygwin/fhandler_tty.cc
> @@ -2867,11 +2867,13 @@ fhandler_pty_slave::setup_locale (void)
>     char charset[ENCODING_LEN + 1] = "ASCII";
>     LCID lcid = get_langinfo (locale, charset);
>
> -  /* Set console code page form locale */
> +  /* Set console code page from locale */
>     if (get_pseudo_console ())
>       {
>         UINT code_page;
> -      if (lcid == 0 || lcid == (LCID) -1)
> +      if (!strcasecmp (charset, "utf-8"))
> +	code_page = CP_UTF8;
> +      else if (lcid == 0 || lcid == (LCID) -1)
>   	code_page = 20127; /* ASCII */
>         else if (!GetLocaleInfo (lcid,
>   			       LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
> -- snap --
>
> But that does _not_ reinstate the previous behavior when Pseudo Console
> support is disabled.
>
> Now, I would call that a regression (the entire idea of `disable_pcon` was
> to fall back to the previous behavior, no?). And I do not really
> understand where it comes from, that regression.
I wouldn't quite call it a regression as it disables buggy behaviour 
which was used as a workaround for a buggy system environment. But 
arguably you could expect such an option to fall back to previous buggy 
behaviour.

Thomas

>   Where does the code path
> differ from the previous one when Pseudo Console support is disabled, and
> how does that relate to the current console output code page?
>
> Ciao,
> Johannes
>
>>> Thomas
>>>
>>>>> at the expense of garbled output for apps which use native
>>>>> code page of the system in the correct maner.
>>>> Are you referring to apps that call the SetConsoleOutputCP() function? If
>>>> so, I am asking myself what would be broken. Because apps that do _not_
>>>> call that function (expecting UTF-8 to be active) would be fixed, while
>>>> apps that _do_ call that function would not care if the Cygwin runtime
>>>> changed it.
>>>>
>>>> Ciao,
>>>> Johannes
>>


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-31 21:07                                                                   ` Thomas Wolff
@ 2020-08-31 23:23                                                                     ` Takashi Yano
  2020-09-01  5:00                                                                     ` Johannes Schindelin
  1 sibling, 0 replies; 73+ messages in thread
From: Takashi Yano @ 2020-08-31 23:23 UTC (permalink / raw)
  To: cygwin-developers

On Mon, 31 Aug 2020 23:07:03 +0200
Thomas Wolff wrote:
> I'm puzzled though that the output is changed by piping through cat.

If the output is piped, the output device is not a pty
but a pipe. Therefore, pty cannot touch it. Pipe and
cat are transparent, so there is no chance to convert
charset.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-31 19:37                                                                   ` Corinna Vinschen
@ 2020-09-01  4:46                                                                     ` Johannes Schindelin
  2020-09-01  9:23                                                                       ` Takashi Yano
  0 siblings, 1 reply; 73+ messages in thread
From: Johannes Schindelin @ 2020-09-01  4:46 UTC (permalink / raw)
  To: cygwin-developers; +Cc: Corinna Vinschen

Hi Corinna,

On Mon, 31 Aug 2020, Corinna Vinschen wrote:

> On Aug 31 21:17, Johannes Schindelin wrote:
> > [...]
> > So I had a look at the code, and it seems that
> > `fhandler_pty_slave::setup_locale()` forces the output encoding to
> > C.ASCII if Pseudo Console support is enabled:
> >
> >   char locale[ENCODING_LEN + 1] = "C";
> >   char charset[ENCODING_LEN + 1] = "ASCII";
> >   LCID lcid = get_langinfo (locale, charset);
> >
> >   /* Set console code page from locale */
> >   if (get_pseudo_console ())
> >     {
> >       UINT code_page;
> >       if (lcid == 0 || lcid == (LCID) -1)
> >         code_page = 20127; /* ASCII */
>
> This looks wrong, actually.  The default behaviour of Cygwin since
> Cygwin 1.7 was to assume UTF-8, even if the application doesn't call
> setlocale.  This means the locale is "C", so ASCII is expected.
> However, even in this case, the internal conversions use UTF-8.
> See function internal_setlocale() in nlsfuncs.cc, lines 1553/1554.
>
> We never switched the console codepage, though, because the codepage
> doesn't make much sense when using wide character functions only,
> i. e. WriteConsoleW.  Only the alternate charset is 437/ASCII.  So,
> if the pseudo console actually *requires* to set the charset...

Well, it is worse, as I have reported elsewhere in this thread. For some
reason (which was not answered yet, and which I am still very much
interested in knowing), the Console output code page is _still_ used
in `disable_pcon`.

That smells completely wrong. Why would the actual Console output encoding
be involved when Pseudo Console support is disabled, when it was not at
all used in v3.0.7 (which is supposedly using the same code paths that
`disable_pcon` is still expected to use)?

>
>
> >       else if (!GetLocaleInfo (lcid,
> >                                LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
> >                                (char *) &code_page, sizeof (code_page)))
> >         code_page = 20127; /* ASCII */
> >       SetConsoleCP (code_page);
> >       SetConsoleOutputCP (code_page);
>
> can we please default to UTF-8 here even if the code page is ASCII?

Yes, please. In fact, I am tempted to do this:

-- snip --
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 43eebc174..65b4d45fa 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -2867,7 +2867,16 @@ fhandler_pty_slave::setup_locale (void)
   char charset[ENCODING_LEN + 1] = "ASCII";
   LCID lcid = get_langinfo (locale, charset);

-  /* Set console code page form locale */
+  /* Special-case the UTF-8 character set */
+  if (strcasecmp (charset, "UTF-8") == 0)
+    {
+      get_ttyp ()->term_code_page = CP_UTF8;
+      SetConsoleCP (CP_UTF8);
+      SetConsoleOutputCP (CP_UTF8);
+      return;
+    }
+
+  /* Set console code page from locale */
   if (get_pseudo_console ())
     {
       UINT code_page;
-- snap --

The main reason why I am hesitating is that I smell a bigger problem here:
the mere fact that a code path that is supposed not to use Console
functions at all (`disable_pcon`) _does_ respect the output code page
indicates to me that that code path was changed in a totally unintended
way.

Ciao,
Johannes

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-08-31 21:07                                                                   ` Thomas Wolff
  2020-08-31 23:23                                                                     ` Takashi Yano
@ 2020-09-01  5:00                                                                     ` Johannes Schindelin
  2020-09-01  8:56                                                                       ` Thomas Wolff
  1 sibling, 1 reply; 73+ messages in thread
From: Johannes Schindelin @ 2020-09-01  5:00 UTC (permalink / raw)
  To: Thomas Wolff; +Cc: cygwin-developers

Hi Thomas,

On Mon, 31 Aug 2020, Thomas Wolff wrote:

> Am 31.08.2020 um 21:17 schrieb Johannes Schindelin:
> >
> > [...]
> >
> > But that does _not_ reinstate the previous behavior when Pseudo
> > Console support is disabled.
> >
> > Now, I would call that a regression (the entire idea of `disable_pcon`
> > was to fall back to the previous behavior, no?). And I do not really
> > understand where it comes from, that regression.
>
> I wouldn't quite call it a regression as it disables buggy behaviour
> which was used as a workaround for a buggy system environment. But
> arguably you could expect such an option to fall back to previous buggy
> behaviour.

I think I got it. After you called this kind of application buggy for a
dozen times, I think I finally understood. You think they are buggy!

And while you sink into your comfy chair, thinking that you settled the
issue, in reality it is not settled at all. Arguing whether it is correct
for an application not to call `SetConsoleOutputCP()` does not help
anyone. Just because the behavior is considered undefined does not mean
that we should make the situation _intentionally_ worse.

That is, if we can get back to a spot where the (yes, buggy, buggy,
BUGGY!) applications behave in at least roughly the same way as before,
users will be much better off.

The work-around could be e.g. what I suggested in my reply to Corinna (and
which is the equivalent of what you suggested -- "just run chcp once" --
just without putting the burden on the users' shoulders, by calling
`SetConsoleOutputCP()` in the runtime, once).

In any case, my question why `disable_pcon` still uses the console output
code page was directed more at Takashi than you (or anybody else familiar
with that code path).

Ciao,
Johannes

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-09-01  9:23                                                                       ` Takashi Yano
@ 2020-09-01  6:32                                                                         ` Johannes Schindelin
  2020-09-01 22:33                                                                           ` Takashi Yano
  2020-09-01  9:42                                                                         ` Takashi Yano
  1 sibling, 1 reply; 73+ messages in thread
From: Johannes Schindelin @ 2020-09-01  6:32 UTC (permalink / raw)
  To: Takashi Yano; +Cc: cygwin-developers

Hi Takashi,

On Tue, 1 Sep 2020, Takashi Yano via Cygwin-developers wrote:

> On Tue, 1 Sep 2020 06:46:53 +0200 (CEST)
> Johannes Schindelin wrote:
>
> > -- snip --
> > diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
> > index 43eebc174..65b4d45fa 100644
> > --- a/winsup/cygwin/fhandler_tty.cc
> > +++ b/winsup/cygwin/fhandler_tty.cc
> > @@ -2867,7 +2867,16 @@ fhandler_pty_slave::setup_locale (void)
> >    char charset[ENCODING_LEN + 1] = "ASCII";
> >    LCID lcid = get_langinfo (locale, charset);
> >
> > -  /* Set console code page form locale */
> > +  /* Special-case the UTF-8 character set */
> > +  if (strcasecmp (charset, "UTF-8") == 0)
> > +    {
> > +      get_ttyp ()->term_code_page = CP_UTF8;
> > +      SetConsoleCP (CP_UTF8);
> > +      SetConsoleOutputCP (CP_UTF8);
> > +      return;
> > +    }
> > +
> > +  /* Set console code page from locale */
> >    if (get_pseudo_console ())
> >      {
> >        UINT code_page;
> > -- snap --
>
> I don't think you do right thing. Your first test case makes
> garbled output in command prompt, therefore output in cygwin
> should be the same.
>
> I believe the correct maner as Windows programs are such as:
>
> [Code A]
> #include <windows.h>
> #include <stdio.h>
>
> int main(){
>   int origcp = GetConsoleOutputCP();
>   SetConsoleOutputCP(CP_UTF8);
>   puts("Привет мир! Hello world!");
>   SetConsoleOutputCP(origcp);
>   return 0;
> }
>
> [Code B]
> #include <locale.h>
> #include <stdio.h>
>
> int main(){
>   setlocale (LC_ALL, "");
>   _putws(L"Привет мир! Hello world!");
>   return 0;
> }
>
> if the source code is in UTF-8 coding. Or compiled
> with -fexec-charset=utf-8.
>
> Both work as expected in command prompt as well as
> in current cygwin.

Sorry for being unclear.

The test program was only provided in order to provide a working
reproducer for an issue we see in _many_ instances.

In many cases, I am _not_ at liberty (nor do I have the time) to recompile
the programs.

And even if what you say is true, the fact is that there are many existing
executables out there that do not call `SetConsoleOutputCP()`.

All of them would be helped with my patch (provided that `LANG` or friends
define the charset to be `UTF-8`).

Are they buggy? Yes. Does the patch help the users? Also yes.

But what I am really a lot more interested in is your answer to the
question why the code path behind `disable_pcon` does anything different
from what v3.0.7 did.

I think that really is important to understand. Without that information,
I am not sure whether my patch is hiding an even bigger problem.

So please, please, please, can I have an answer to that? Why did the
non-Pseudo Console code path change? And in what way?

Ciao,
Johannes

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-09-01  5:00                                                                     ` Johannes Schindelin
@ 2020-09-01  8:56                                                                       ` Thomas Wolff
  0 siblings, 0 replies; 73+ messages in thread
From: Thomas Wolff @ 2020-09-01  8:56 UTC (permalink / raw)
  To: Johannes Schindelin, cygwin-developers

Am 01.09.2020 um 07:00 schrieb Johannes Schindelin:
> Hi Thomas,
>
> On Mon, 31 Aug 2020, Thomas Wolff wrote:
>
>> Am 31.08.2020 um 21:17 schrieb Johannes Schindelin:
>>> [...]
>>>
>>> But that does _not_ reinstate the previous behavior when Pseudo
>>> Console support is disabled.
>>>
>>> Now, I would call that a regression (the entire idea of `disable_pcon`
>>> was to fall back to the previous behavior, no?). And I do not really
>>> understand where it comes from, that regression.
>> I wouldn't quite call it a regression as it disables buggy behaviour
>> which was used as a workaround for a buggy system environment. But
>> arguably you could expect such an option to fall back to previous buggy
>> behaviour.
> I think I got it. After you called this kind of application buggy for a
> dozen times, I think I finally understood. You think they are buggy!
>
> And while you sink into your comfy chair, thinking that you settled the
> issue, in reality it is not settled at all. Arguing whether it is correct
> for an application not to call `SetConsoleOutputCP()` does not help
> anyone. Just because the behavior is considered undefined does not mean
> that we should make the situation _intentionally_ worse.
>
> That is, if we can get back to a spot where the (yes, buggy, buggy,
> BUGGY!) applications behave in at least roughly the same way as before,
> users will be much better off.
I'm fine with that, I was just trying to sort out the situation and 
explain how I understand it.
In fact, your patch could be taken as an alternative complement to the 
ConPTY support;
for completeness, it could handle other charsets as well.
And I'm curious whether that'll work seamlessly. My previous proposal 
"winpty injection" (2018) was rejected because it failed in some special 
case reported by you... Would be nice to get this working, though.
Thomas

> The work-around could be e.g. what I suggested in my reply to Corinna (and
> which is the equivalent of what you suggested -- "just run chcp once" --
> just without putting the burden on the users' shoulders, by calling
> `SetConsoleOutputCP()` in the runtime, once).
>
> In any case, my question why `disable_pcon` still uses the console output
> code page was directed more at Takashi than you (or anybody else familiar
> with that code path).
>
> Ciao,
> Johannes


^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-09-01  4:46                                                                     ` Johannes Schindelin
@ 2020-09-01  9:23                                                                       ` Takashi Yano
  2020-09-01  6:32                                                                         ` Johannes Schindelin
  2020-09-01  9:42                                                                         ` Takashi Yano
  0 siblings, 2 replies; 73+ messages in thread
From: Takashi Yano @ 2020-09-01  9:23 UTC (permalink / raw)
  To: cygwin-developers

On Tue, 1 Sep 2020 06:46:53 +0200 (CEST)
Johannes Schindelin wrote:

> -- snip --
> diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
> index 43eebc174..65b4d45fa 100644
> --- a/winsup/cygwin/fhandler_tty.cc
> +++ b/winsup/cygwin/fhandler_tty.cc
> @@ -2867,7 +2867,16 @@ fhandler_pty_slave::setup_locale (void)
>    char charset[ENCODING_LEN + 1] = "ASCII";
>    LCID lcid = get_langinfo (locale, charset);
> 
> -  /* Set console code page form locale */
> +  /* Special-case the UTF-8 character set */
> +  if (strcasecmp (charset, "UTF-8") == 0)
> +    {
> +      get_ttyp ()->term_code_page = CP_UTF8;
> +      SetConsoleCP (CP_UTF8);
> +      SetConsoleOutputCP (CP_UTF8);
> +      return;
> +    }
> +
> +  /* Set console code page from locale */
>    if (get_pseudo_console ())
>      {
>        UINT code_page;
> -- snap --

I don't think you do right thing. Your first test case makes
garbled output in command prompt, therefore output in cygwin
should be the same.

I believe the correct maner as Windows programs are such as:

[Code A]
#include <windows.h>
#include <stdio.h>

int main(){
  int origcp = GetConsoleOutputCP();
  SetConsoleOutputCP(CP_UTF8);
  puts("Привет мир! Hello world!");
  SetConsoleOutputCP(origcp);
  return 0;
}

[Code B]
#include <locale.h>
#include <stdio.h>

int main(){
  setlocale (LC_ALL, "");
  _putws(L"Привет мир! Hello world!");
  return 0;
}

if the source code is in UTF-8 coding. Or compiled
with -fexec-charset=utf-8.

Both work as expected in command prompt as well as
in current cygwin.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-09-01  9:23                                                                       ` Takashi Yano
  2020-09-01  6:32                                                                         ` Johannes Schindelin
@ 2020-09-01  9:42                                                                         ` Takashi Yano
  1 sibling, 0 replies; 73+ messages in thread
From: Takashi Yano @ 2020-09-01  9:42 UTC (permalink / raw)
  To: cygwin-developers

Hi Johannes,

On Tue, 1 Sep 2020 18:23:03 +0900
Takashi Yano via Cygwin-developers <cygwin-developers@cygwin.com> wrote:

> On Tue, 1 Sep 2020 06:46:53 +0200 (CEST)
> Johannes Schindelin wrote:
> 
> > -- snip --
> > diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
> > index 43eebc174..65b4d45fa 100644
> > --- a/winsup/cygwin/fhandler_tty.cc
> > +++ b/winsup/cygwin/fhandler_tty.cc
> > @@ -2867,7 +2867,16 @@ fhandler_pty_slave::setup_locale (void)
> >    char charset[ENCODING_LEN + 1] = "ASCII";
> >    LCID lcid = get_langinfo (locale, charset);
> > 
> > -  /* Set console code page form locale */
> > +  /* Special-case the UTF-8 character set */
> > +  if (strcasecmp (charset, "UTF-8") == 0)
> > +    {
> > +      get_ttyp ()->term_code_page = CP_UTF8;
> > +      SetConsoleCP (CP_UTF8);
> > +      SetConsoleOutputCP (CP_UTF8);
> > +      return;
> > +    }
> > +
> > +  /* Set console code page from locale */
> >    if (get_pseudo_console ())
> >      {
> >        UINT code_page;
> > -- snap --
> 
> I don't think you do right thing. Your first test case makes
> garbled output in command prompt, therefore output in cygwin
> should be the same.
> 
> I believe the correct maner as Windows programs are such as:
> 
> [Code A]
> #include <windows.h>
> #include <stdio.h>
> 
> int main(){
>   int origcp = GetConsoleOutputCP();
>   SetConsoleOutputCP(CP_UTF8);
>   puts("Привет мир! Hello world!");
>   SetConsoleOutputCP(origcp);
>   return 0;
> }
> 
> [Code B]
> #include <locale.h>
> #include <stdio.h>
> 
> int main(){
>   setlocale (LC_ALL, "");
>   _putws(L"Привет мир! Hello world!");
>   return 0;
> }
> 
> if the source code is in UTF-8 coding. Or compiled
> with -fexec-charset=utf-8.
> 
> Both work as expected in command prompt as well as
> in current cygwin.

What is your expectation if your test case is compiled
with -fexec-charset=cp1251?

This will cause garbled output if your default code page
is not 1251.
In this case, SetConsoleOutputCP(1251) is necessary.

Why do you think only the UTF-8 output should work without
SetConsoleOutputCP(CP_UTF8)?

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-09-01  6:32                                                                         ` Johannes Schindelin
@ 2020-09-01 22:33                                                                           ` Takashi Yano
  2020-09-02  6:13                                                                             ` Johannes Schindelin
  0 siblings, 1 reply; 73+ messages in thread
From: Takashi Yano @ 2020-09-01 22:33 UTC (permalink / raw)
  To: cygwin-developers

Hi Johannes,

On Tue, 1 Sep 2020 08:32:30 +0200 (CEST)
Johannes Schindelin wrote:
> why the code path behind `disable_pcon` does anything different
> from what v3.0.7 did.

Thomas answered already for this question.

On Mon, 31 Aug 2020 18:12:19 +0200
Thomas Wolff wrote:
> The "correct" output was actually buggy behaviour, so current cygwin has 
> "fixed" it, to your disadvantage in this case.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: New implementation of pseudo console support (experimental)
  2020-09-01 22:33                                                                           ` Takashi Yano
@ 2020-09-02  6:13                                                                             ` Johannes Schindelin
  0 siblings, 0 replies; 73+ messages in thread
From: Johannes Schindelin @ 2020-09-02  6:13 UTC (permalink / raw)
  To: Takashi Yano; +Cc: cygwin-developers

Hi,

On Wed, 2 Sep 2020, Takashi Yano wrote:

> On Tue, 1 Sep 2020 08:32:30 +0200 (CEST)
> Johannes Schindelin wrote:
> > why the code path behind `disable_pcon` does anything different
> > from what v3.0.7 did.
>
> Thomas answered already for this question.
>
> On Mon, 31 Aug 2020 18:12:19 +0200
> Thomas Wolff wrote:
> > The "correct" output was actually buggy behaviour, so current cygwin has
> > "fixed" it, to your disadvantage in this case.

I was under the impression that Thomas was unfamiliar with your
implementation, so I kind of waited for your authoritative answer.

Now, seeing how many users face real-world problems using console
applications they are not necessarily equipped (or even allowed) to patch,
I do see the need for a sensible default code page.

Hopefully you agree that in light of this, it does not matter whether it
was "actually buggy behavior". Nobody cares whether it was buggy or not,
when it breaks *quite* a few existing workflows.

In our case, the default code page should quite clearly be UTF-8 because
that's what `/etc/profile.d/lang.sh` configures when it passes the `-U`
flag to `locale` to determine the value of the `LANG` variable.

I would really appreciate your help to get there.

Ciao,
Johannes

P.S.: what you suggest implicitly to be the solution ("just call
`SetConsoleOutputCP()` in your console application!") seems to be fraught
with a bit of peril, see e.g.
https://entropymine.wordpress.com/2020/05/06/win32-i-o-character-encoding-supplement-1-a-cygwin-issue/

^ permalink raw reply	[flat|nested] 73+ messages in thread

end of thread, other threads:[~2020-09-02 11:03 UTC | newest]

Thread overview: 73+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-13 12:16 New implementation of pseudo console support (experimental) Takashi Yano
2020-05-13 12:35 ` Thomas Wolff
2020-05-14  9:28 ` Takashi Yano
2020-05-14  9:34   ` Takashi Yano
2020-05-16  0:29     ` Takashi Yano
2020-05-16  7:47       ` Takashi Yano
2020-05-19 13:40         ` Takashi Yano
2020-05-25 10:53           ` Takashi Yano
2020-05-25 15:22             ` Corinna Vinschen
2020-05-25 19:16               ` Thomas Wolff
2020-05-26  1:00               ` Takashi Yano
2020-05-26  7:14                 ` Thomas Wolff
2020-05-26  9:21                   ` Takashi Yano
2020-05-26  9:32                     ` Thomas Wolff
2020-05-26  8:33                 ` Corinna Vinschen
2020-05-26  1:09             ` Takashi Yano
2020-05-28 15:40               ` Takashi Yano
2020-05-29 15:30                 ` Corinna Vinschen
2020-05-30  7:36                   ` Takashi Yano
2020-05-30 13:14                     ` Takashi Yano
2020-05-30 17:43                       ` Corinna Vinschen
2020-05-31  5:52                         ` Takashi Yano
2020-07-01 11:47                 ` Takashi Yano
2020-07-17 11:19                   ` Corinna Vinschen
2020-07-17 12:47                     ` Thomas Wolff
2020-07-17 14:59                       ` Thomas Wolff
2020-07-18  5:05                         ` Takashi Yano
2020-07-18 20:57                           ` Thomas Wolff
2020-07-23 17:17                             ` Takashi Yano
2020-07-27 17:10                               ` Thomas Wolff
2020-07-17 12:52                     ` Ken Brown
2020-07-18  5:07                       ` Takashi Yano
2020-07-18  5:30                     ` Takashi Yano
2020-07-20  8:06                       ` Corinna Vinschen
2020-07-21 18:17                         ` Takashi Yano
2020-07-22  8:45                           ` Takashi Yano
2020-07-22 11:49                             ` Corinna Vinschen
2020-07-22 12:13                               ` Ken Brown
2020-07-23  0:33                             ` Takashi Yano
2020-07-24  5:38                               ` Takashi Yano
2020-07-24 11:22                                 ` Takashi Yano
2020-08-02 12:01                                   ` Corinna Vinschen
2020-08-03  2:05                                     ` Takashi Yano
2020-08-03 10:50                                       ` Corinna Vinschen
2020-08-03  2:11                                   ` Takashi Yano
2020-08-03 12:23                                     ` Takashi Yano
2020-08-11 11:12                                       ` Takashi Yano
2020-08-13  9:58                                         ` Takashi Yano
2020-08-17 11:57                                           ` Takashi Yano
2020-08-19 11:39                                             ` Takashi Yano
2020-08-19 13:41                                               ` Corinna Vinschen
2020-08-19 15:43                                                 ` Thomas Wolff
2020-08-19 20:47                                                 ` Mark Geisert
2020-08-20  8:02                                                 ` Takashi Yano
2020-08-31 12:49                                                   ` Johannes Schindelin
2020-08-31 14:14                                                     ` Takashi Yano
     [not found]                                                     ` <20200831231253.332c66fdddb33ceed5f61db6@nifty.ne.jp>
2020-08-31 14:22                                                       ` Johannes Schindelin
2020-08-31 14:53                                                         ` Takashi Yano
2020-08-31 15:56                                                           ` Johannes Schindelin
2020-08-31 16:12                                                             ` Thomas Wolff
2020-08-31 17:39                                                               ` Thomas Wolff
2020-08-31 19:17                                                                 ` Johannes Schindelin
2020-08-31 19:37                                                                   ` Corinna Vinschen
2020-09-01  4:46                                                                     ` Johannes Schindelin
2020-09-01  9:23                                                                       ` Takashi Yano
2020-09-01  6:32                                                                         ` Johannes Schindelin
2020-09-01 22:33                                                                           ` Takashi Yano
2020-09-02  6:13                                                                             ` Johannes Schindelin
2020-09-01  9:42                                                                         ` Takashi Yano
2020-08-31 21:07                                                                   ` Thomas Wolff
2020-08-31 23:23                                                                     ` Takashi Yano
2020-09-01  5:00                                                                     ` Johannes Schindelin
2020-09-01  8:56                                                                       ` Thomas Wolff

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).