Cygwin: pty, console: Encapsulate spawn.cc code related to pty/console.

- The codes related to pty and console in spawn.cc have been moved
  into the new class fhandler_termios::spawn_worker, and make spawn.cc
  call them. The functionality has not been changed at all.
This commit is contained in:
Takashi Yano 2022-11-19 17:28:15 +09:00
parent c03f0c3062
commit 32d6a6cb5f
4 changed files with 149 additions and 121 deletions

View File

@ -692,6 +692,29 @@ fhandler_termios::tcgetsid ()
return -1;
}
static bool
is_console_app (const 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
{
wchar_t *e = wcsrchr (filename, L'.');
if (e && (wcscasecmp (e, L".bat") == 0 || wcscasecmp (e, L".cmd") == 0))
return true;
}
return false;
}
int
fhandler_termios::ioctl (int cmd, void *varg)
{
@ -718,3 +741,79 @@ fhandler_termios::ioctl (int cmd, void *varg)
myself->set_ctty (this, 0);
return 0;
}
void
fhandler_termios::spawn_worker::setup (bool iscygwin, HANDLE h_stdin,
const WCHAR *runpath, bool nopcon,
bool reset_sendsig,
const WCHAR *envblock)
{
fhandler_pty_slave *ptys_primary = NULL;
fhandler_console *cons_native = NULL;
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 && ptys_primary == NULL)
ptys_primary = (fhandler_pty_slave *) fh;
else if (fh && fh->get_major () == DEV_CONS_MAJOR
&& !iscygwin && cons_native == NULL)
cons_native = (fhandler_console *) fh;
}
if (cons_native)
{
cons_native->setup_for_non_cygwin_app ();
/* Console handles will be already closed by close_all_files()
when cleaning up, therefore, duplicate them here. */
cons_native->get_duplicated_handle_set (&cons_handle_set);
cons_need_cleanup = true;
}
if (!iscygwin)
{
int fd;
cygheap_fdenum cfd (false);
while ((fd = cfd.next ()) >= 0)
if (cfd->get_major () == DEV_PTYS_MAJOR)
{
fhandler_pty_slave *ptys
= (fhandler_pty_slave *)(fhandler_base *) cfd;
ptys->create_invisible_console ();
ptys->setup_locale ();
}
}
if (!iscygwin && ptys_primary && is_console_app (runpath))
{
if (h_stdin == ptys_primary->get_handle_nat ())
stdin_is_ptys = true;
if (reset_sendsig)
myself->sendsig = myself->exec_sendsig;
ptys_primary->setup_for_non_cygwin_app (nopcon, envblock, stdin_is_ptys);
if (reset_sendsig)
myself->sendsig = NULL;
ptys_primary->get_duplicated_handle_set (&ptys_handle_set);
ptys_ttyp = (tty *) ptys_primary->tc ();
ptys_need_cleanup = true;
}
}
void
fhandler_termios::spawn_worker::cleanup ()
{
if (ptys_need_cleanup)
fhandler_pty_slave::cleanup_for_non_cygwin_app (&ptys_handle_set,
ptys_ttyp, stdin_is_ptys);
if (cons_need_cleanup)
fhandler_console::cleanup_for_non_cygwin_app (&cons_handle_set);
close_handle_set ();
}
void
fhandler_termios::spawn_worker::close_handle_set ()
{
if (ptys_need_cleanup)
fhandler_pty_slave::close_handle_set (&ptys_handle_set);
if (cons_need_cleanup)
fhandler_console::close_handle_set (&cons_handle_set);
}

View File

@ -247,7 +247,7 @@ atexit_func (void)
tty *ttyp = (tty *) ptys->tc ();
bool stdin_is_ptys =
GetStdHandle (STD_INPUT_HANDLE) == ptys->get_handle ();
struct fhandler_pty_slave::handle_set_t handles =
fhandler_pty_slave::handle_set_t handles =
{
ptys->get_handle_nat (),
ptys->get_input_available_event (),
@ -4096,7 +4096,8 @@ fhandler_pty_slave::close_handle_set (handle_set_t *p)
}
void
fhandler_pty_slave::setup_for_non_cygwin_app (bool nopcon, PWCHAR envblock,
fhandler_pty_slave::setup_for_non_cygwin_app (bool nopcon,
const WCHAR *envblock,
bool stdin_is_ptys)
{
if (disable_pcon || !term_has_pcon_cap (envblock))

View File

@ -1989,6 +1989,40 @@ class fhandler_termios: public fhandler_base
virtual bool need_console_handler () { return false; }
virtual bool need_send_ctrl_c_event () { return true; }
virtual DWORD get_helper_pid () { return 0; }
struct ptys_handle_set_t
{
HANDLE from_master_nat;
HANDLE input_available_event;
HANDLE input_mutex;
HANDLE pipe_sw_mutex;
};
struct cons_handle_set_t
{
HANDLE input_handle;
HANDLE output_handle;
HANDLE input_mutex;
HANDLE output_mutex;
};
class spawn_worker
{
private:
ptys_handle_set_t ptys_handle_set;
cons_handle_set_t cons_handle_set;
bool ptys_need_cleanup;
bool cons_need_cleanup;
bool stdin_is_ptys;
tty *ptys_ttyp;
public:
spawn_worker () :
ptys_need_cleanup (false), cons_need_cleanup (false),
stdin_is_ptys (false), ptys_ttyp (NULL) {}
void setup (bool iscygwin, HANDLE h_stdin, const WCHAR *runpath,
bool nopcon, bool reset_sendsig, const WCHAR *envblock);
bool need_cleanup () { return ptys_need_cleanup || cons_need_cleanup; }
void cleanup ();
void close_handle_set ();
};
};
enum ansi_intensity
@ -2133,13 +2167,7 @@ public:
input_signalled = 2,
input_winch = 3
};
struct handle_set_t
{
HANDLE input_handle;
HANDLE output_handle;
HANDLE input_mutex;
HANDLE output_mutex;
};
typedef cons_handle_set_t handle_set_t;
HANDLE thread_sync_event;
private:
static const unsigned MAX_WRITE_CHARS;
@ -2375,13 +2403,7 @@ class fhandler_pty_slave: public fhandler_pty_common
public:
pid_t tc_getpgid () { return _tc ? _tc->pgid : 0; }
struct handle_set_t
{
HANDLE from_master_nat;
HANDLE input_available_event;
HANDLE input_mutex;
HANDLE pipe_sw_mutex;
};
typedef ptys_handle_set_t handle_set_t;
/* Constructor */
fhandler_pty_slave (int);
@ -2450,7 +2472,7 @@ class fhandler_pty_slave: public fhandler_pty_common
void cleanup_before_exit ();
void get_duplicated_handle_set (handle_set_t *p);
static void close_handle_set (handle_set_t *p);
void setup_for_non_cygwin_app (bool nopcon, PWCHAR envblock,
void setup_for_non_cygwin_app (bool nopcon, const WCHAR *envblock,
bool stdin_is_ptys);
static void cleanup_for_non_cygwin_app (handle_set_t *p, tty *ttyp,
bool stdin_is_ptys,

View File

@ -211,29 +211,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
{
wchar_t *e = wcsrchr (filename, L'.');
if (e && (wcscasecmp (e, L".bat") == 0 || wcscasecmp (e, L".cmd") == 0))
return true;
}
return false;
}
int
iscmd (const char *argv0, const char *what)
{
@ -345,10 +322,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
STARTUPINFOW si = {};
int looped = 0;
struct fhandler_pty_slave::handle_set_t ptys_handle_set = { 0, };
bool ptys_need_cleanup = false;
struct fhandler_console::handle_set_t cons_handle_set = { 0, };
bool cons_need_cleanup = false;
fhandler_termios::spawn_worker term_spawn_worker;
system_call_handle system_call (mode == _P_SYSTEM);
@ -598,29 +572,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
PROCESS_QUERY_LIMITED_INFORMATION))
sa = &sec_none_nih;
fhandler_pty_slave *ptys_primary = NULL;
fhandler_console *cons_native = NULL;
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 && ptys_primary == NULL)
ptys_primary = (fhandler_pty_slave *) fh;
else if (fh && fh->get_major () == DEV_CONS_MAJOR
&& !iscygwin () && cons_native == NULL)
cons_native = (fhandler_console *) fh;
}
if (cons_native)
{
cons_native->setup_for_non_cygwin_app ();
/* Console handles will be already closed by close_all_files()
when cleaning up, therefore, duplicate them here. */
cons_native->get_duplicated_handle_set (&cons_handle_set);
cons_need_cleanup = true;
}
int fileno_stdin = in__stdin < 0 ? 0 : in__stdin;
int fileno_stdout = in__stdout < 0 ? 1 : in__stdout;
int fileno_stderr = 2;
@ -631,14 +582,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
int fd;
cygheap_fdenum cfd (false);
while ((fd = cfd.next ()) >= 0)
if (cfd->get_major () == DEV_PTYS_MAJOR)
{
fhandler_pty_slave *ptys =
(fhandler_pty_slave *)(fhandler_base *) cfd;
ptys->create_invisible_console ();
ptys->setup_locale ();
}
else if (cfd->get_dev () == FH_PIPEW
if (cfd->get_dev () == FH_PIPEW
&& (fd == fileno_stdout || fd == fileno_stderr))
{
fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd;
@ -666,24 +610,9 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
}
}
bool stdin_is_ptys = false;
tty *ptys_ttyp = NULL;
if (!iscygwin () && ptys_primary && is_console_app (runpath))
{
bool nopcon = mode != _P_OVERLAY && mode != _P_WAIT;
HANDLE h_stdin = handle (fileno_stdin, false);
if (h_stdin == ptys_primary->get_handle_nat ())
stdin_is_ptys = true;
if (reset_sendsig)
myself->sendsig = myself->exec_sendsig;
ptys_primary->setup_for_non_cygwin_app (nopcon, envblock,
stdin_is_ptys);
if (reset_sendsig)
myself->sendsig = NULL;
ptys_primary->get_duplicated_handle_set (&ptys_handle_set);
ptys_ttyp = (tty *) ptys_primary->tc ();
ptys_need_cleanup = true;
}
bool no_pcon = mode != _P_OVERLAY && mode != _P_WAIT;
term_spawn_worker.setup (iscygwin (), handle (fileno_stdin, false),
runpath, no_pcon, reset_sendsig, envblock);
/* Set up needed handles for stdio */
si.dwFlags = STARTF_USESTDHANDLES;
@ -844,11 +773,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
/* Name the handle similarly to proc_subproc. */
ProtectHandle1 (pi.hProcess, childhProc);
/* Do not touch these terminal instances after here.
They may be destroyed by close_all_files(). */
ptys_primary = NULL;
cons_native = NULL;
if (mode == _P_OVERLAY)
{
myself->dwProcessId = pi.dwProcessId;
@ -966,7 +890,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
}
if (sem)
__posix_spawn_sem_release (sem, 0);
if (ptys_need_cleanup || cons_need_cleanup)
if (term_spawn_worker.need_cleanup ())
{
LONG prev_sigExeced = sigExeced;
while (WaitForSingleObject (pi.hProcess, 100) == WAIT_TIMEOUT)
@ -975,18 +899,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
the signal sigExeced. Therefore, clear sigExeced here. */
prev_sigExeced =
InterlockedCompareExchange (&sigExeced, 0, prev_sigExeced);
}
if (ptys_need_cleanup)
{
fhandler_pty_slave::cleanup_for_non_cygwin_app (&ptys_handle_set,
ptys_ttyp,
stdin_is_ptys);
fhandler_pty_slave::close_handle_set (&ptys_handle_set);
}
if (cons_need_cleanup)
{
fhandler_console::cleanup_for_non_cygwin_app (&cons_handle_set);
fhandler_console::close_handle_set (&cons_handle_set);
term_spawn_worker.cleanup ();
term_spawn_worker.close_handle_set ();
}
/* Make sure that ctrl_c_handler() is not on going. Calling
init_console_handler(false) locks until returning from
@ -1000,12 +914,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
system_call.arm ();
if (waitpid (cygpid, &res, 0) != cygpid)
res = -1;
if (ptys_need_cleanup)
fhandler_pty_slave::cleanup_for_non_cygwin_app (&ptys_handle_set,
ptys_ttyp,
stdin_is_ptys);
if (cons_need_cleanup)
fhandler_console::cleanup_for_non_cygwin_app (&cons_handle_set);
term_spawn_worker.cleanup ();
break;
case _P_DETACH:
res = 0; /* Lost all memory of this child. */
@ -1028,10 +937,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
res = -1;
}
__endtry
if (ptys_need_cleanup)
fhandler_pty_slave::close_handle_set (&ptys_handle_set);
if (cons_need_cleanup)
fhandler_console::close_handle_set (&cons_handle_set);
term_spawn_worker.close_handle_set ();
this->cleanup ();
if (envblock)
free (envblock);