diff --git a/src/fdlib.c b/src/fdlib.c
index ff2f0bb7e22afbc33536aaf38b05d5efbb053332..41367bc6a793b492cdccaab1e86be94cf07e0a37 100644
--- a/src/fdlib.c
+++ b/src/fdlib.c
@@ -268,12 +268,22 @@ PMOD_EXPORT void set_errno_from_win32_error (unsigned long err)
 
 #include "ntlibfuncs.h"
 
+void free_pty(struct my_pty *pty)
+{
+  if (sub_ref(pty)) return;
+  free(pty);
+}
+
 /* NB: fd_mutex MUST be held at entry. */
 static void close_pty(struct my_pty *pty)
 {
   struct my_pty *other;
+  struct pid_status *pid;
 
-  if (sub_ref(pty)) return;
+  if (--pty->fd_refs) {
+    sub_ref(pty);
+    return;
+  }
 
   CloseHandle(pty->write_pipe);
   CloseHandle(pty->read_pipe);
@@ -289,6 +299,11 @@ static void close_pty(struct my_pty *pty)
     pty->other = NULL;
   }
 
+  while ((pid = pty->clients)) {
+    pid->clients = pid_status_unlink_pty(pid);
+  }
+
+  free_pty(pty);
 }
 
 #define ISSEPARATOR(a) ((a) == '\\' || (a) == '/')
@@ -2152,6 +2167,15 @@ PMOD_EXPORT ptrdiff_t debug_fd_read(FD fd, void *to, ptrdiff_t len)
       {
 	struct my_pty *pty = (struct my_pty *)handle;
 	handle = pty->read_pipe;
+
+	if (pty->conpty && !pty->other && !check_pty_clients(pty)) {
+	  /* Master side, no local slave and all known clients are dead.
+	   *
+	   * Terminate the ConPTY so that we can get an EOF.
+	   */
+	  Pike_NT_ClosePseudoConsole(pty->conpty);
+	  pty->conpty = 0;
+	}
       }
       /* FALLTHRU */
 
@@ -2626,6 +2650,8 @@ PMOD_EXPORT FD debug_fd_dup(FD from)
     if (fd < 0) return -1;
 
     add_ref(pty);
+    pty->fd_refs++;
+
     release_fd(fd);
     return fd;
   }
@@ -2677,6 +2703,7 @@ PMOD_EXPORT FD debug_fd_dup2(FD from, FD to)
      * or freed by close_pty().
      */
     add_ref(pty);
+    pty->fd_refs++;
     x = h;
   } else if(!DuplicateHandle(p, h, p, &x, 0, 0, DUPLICATE_SAME_ACCESS)) {
     release_fd(from);
@@ -2799,10 +2826,12 @@ PMOD_EXPORT int debug_fd_openpty(int *master, int *slave,
   }
 
   add_ref(master_pty);
+  master_pty->fd_refs++;
   master_pty->read_pipe = INVALID_HANDLE_VALUE;
   master_pty->write_pipe = INVALID_HANDLE_VALUE;
   master_pty->other = slave_pty;
   add_ref(slave_pty);
+  slave_pty->fd_refs++;
   slave_pty->read_pipe = INVALID_HANDLE_VALUE;
   slave_pty->write_pipe = INVALID_HANDLE_VALUE;
   slave_pty->other = master_pty;
diff --git a/src/fdlib.h b/src/fdlib.h
index 74bfdf3ce0d7b609859032ca8fb639ee9d1b2170..b632ff734f1f757e776474f7874941eac2b54bd1 100644
--- a/src/fdlib.h
+++ b/src/fdlib.h
@@ -171,6 +171,7 @@ struct winsize {
 
 /* Prototypes begin here */
 PMOD_EXPORT void set_errno_from_win32_error (unsigned long err);
+void free_pty(struct my_pty *pty);
 int fd_to_handle(int fd, int *type, HANDLE *handle, int exclusive);
 void release_fd(int fd);
 PMOD_EXPORT char *debug_fd_info(int fd);
@@ -277,9 +278,11 @@ struct my_fd_set_s
 
 struct my_pty
 {
-  INT32 refs;		/* Number of references from da_handle[]. */
+  INT32 refs;		/* Total number of references. */
+  INT32 fd_refs;	/* Number of references from da_handle[]. */
   HPCON conpty;		/* Only valid for master side. */
   struct my_pty *other;	/* Other end (if any), NULL otherwise. */
+  struct pid_status *clients; /* List of client processes. */
   HANDLE read_pipe;	/* Pipe that supports read(). */
   HANDLE write_pipe;	/* Pipe that supports write(). */
 };
diff --git a/src/signal_handler.c b/src/signal_handler.c
index 243feb493ce5f3dc9e6860a93456b4be1d8321ee..0400aa5ee74cc71e33d3a394723693a769deacdb 100644
--- a/src/signal_handler.c
+++ b/src/signal_handler.c
@@ -1254,6 +1254,8 @@ struct pid_status
   INT_TYPE pid;
 #ifdef __NT__
   HANDLE handle;
+  struct pid_status *next_pty_client;	/* PTY client chain. */
+  struct my_pty *pty;			/* PTY master, refcounted. */
 #else
   INT_TYPE sig;
   INT_TYPE flags;
@@ -1279,6 +1281,48 @@ static void init_pid_status(struct object *UNUSED(o))
 #endif
 }
 
+#ifdef __NT__
+struct pid_status *pid_status_unlink_pty(struct pid_status *pid)
+{
+  struct pid_status *ret;
+  if (!pid) return NULL;
+  ret = pid->next_pty_client;
+  pid->next_pty_client = NULL;
+  if (pid->pty) {
+    free_pty(pid->pty);
+    pid->pty = NULL;
+  }
+  return ret;
+}
+
+static void pid_status_link_pty(struct pid_status *pid, struct my_pty *pty)
+{
+  add_ref(pty);
+  pid->pty = pty;
+  pid->next_pty_client = pty->clients;
+  pty->clients = pid;
+}
+
+int check_pty_clients(struct my_pty *pty)
+{
+  struct pid_status *pid;
+  while ((pid = pty->clients)) {
+    DWORD status;
+    /* FIXME: RACE: pid->handle my be INVALID_HANDLE_VALUE if
+     *              the process is about to be started.
+     */
+    if ((pid->pid == -1) && (pid->handle == INVALID_HANDLE_VALUE)) return 1;
+    if (GetExitCodeProcess(pid->handle, &status) &&
+	(status == STILL_ACTIVE)) {
+      return 1;
+    }
+    /* Process has terminated. Unlink and check the next. */
+    pty->clients = pid_status_unlink_pty(pid);
+  }
+  return 0;
+}
+#endif /* __NT__ */
+
 static void exit_pid_status(struct object *UNUSED(o))
 {
 #ifdef USE_PID_MAPPING
@@ -1291,6 +1335,16 @@ static void exit_pid_status(struct object *UNUSED(o))
 #endif
 
 #ifdef __NT__
+  if (THIS->pty) {
+    struct my_pty *pty = THIS->pty;
+    struct pid_status *pidptr = &pty->clients;
+    while (*pidptr && (*pidptr != THIS)) {
+      pidptr = &(*pidptr)->next_pty_client;
+    }
+    if (*pidptr) {
+      *pidptr = pid_status_unlink_pty(THIS);
+    }
+  }
   CloseHandle(THIS->handle);
 #endif
 }
@@ -2187,6 +2241,7 @@ static HANDLE get_inheritable_handle(struct mapping *optional,
 	   *       pty for stdin, stdout and stderr wins
 	   *       (see above).
 	   */
+	  pid_status_link_pty(pty->other);
 	  *conpty = pty->other->conpty;
 	  release_fd(fd);
 	  return ret;
diff --git a/src/signal_handler.h b/src/signal_handler.h
index ce1a37aa7f80ab87b707bd094a03afdbbd2cd7eb..8a2c0d12451d5b4af2e4fd7a1fa0e62538c5a91c 100644
--- a/src/signal_handler.h
+++ b/src/signal_handler.h
@@ -14,6 +14,10 @@ struct sigdesc;
 void my_signal(int sig, sigfunctype fun);
 PMOD_EXPORT void check_signals(struct callback *foo, void *bar, void *gazonk);
 void set_default_signal_handler(int signum, void (*func)(INT32));
+#ifdef __NT__
+struct pid_status *pid_status_unlink_pty(struct pid_status *pid);
+int check_pty_clients(struct my_pty *pty);
+#endif
 void process_started(pid_t pid);
 void process_done(pid_t pid, const char *from);
 struct wait_data;