4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-01-19 04:49:25 +08:00
Takashi Yano via Cygwin-patches 10d083c745 Cygwin: pty: Inherit typeahead data between two input pipes.
- PTY has a problem that the key input, which is typed during windows
  native app is running, disappears when it returns to shell. This is
  beacuse pty has two input pipes, one is for cygwin apps and the other
  one is for native windows apps. The key input during windows native
  program is running is sent to the second input pipe while cygwin
  shell reads input from the first input pipe. This issue had been
  fixed once by commit 29431fcb, however, the new implementation of
  pseudo console support by commit bb428520 could not inherit this
  feature. This patch realize transfering input data between these
  two pipes bidirectionally by utilizing cygwin-console-helper process.
  The helper process is launched prior to starting the non-cygwin app,
  however, exits immediately unlike previous implementation.
2021-01-28 11:21:12 +01:00

312 lines
6.1 KiB
C++

/* tty.cc
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
#include "miscfuncs.h"
#include <unistd.h>
#include <utmp.h>
#include <sys/cygwin.h>
#include "cygerrno.h"
#include "security.h"
#include "path.h"
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "pinfo.h"
#include "shared_info.h"
HANDLE NO_COPY tty_list::mutex = NULL;
extern "C" int
getpt (void)
{
return open ("/dev/ptmx", O_RDWR | O_NOCTTY);
}
extern "C" int
posix_openpt (int oflags)
{
return open ("/dev/ptmx", oflags);
}
extern "C" int
grantpt (int fd)
{
cygheap_fdget cfd (fd);
return cfd < 0 ? -1 : 0;
}
extern "C" int
unlockpt (int fd)
{
cygheap_fdget cfd (fd);
return cfd < 0 ? -1 : 0;
}
extern "C" int
revoke (char *ttyname)
{
set_errno (ENOSYS);
return -1;
}
extern "C" int
ttyslot (void)
{
if (myself->ctty <= 0 || iscons_dev (myself->ctty))
return -1;
return device::minor (myself->ctty);
}
void __stdcall
tty_list::init_session ()
{
char mutex_name[MAX_PATH];
char *name = shared_name (mutex_name, "tty_list::mutex", 0);
/* tty_list::mutex is used while searching for a tty slot */
if (!(mutex = CreateMutex (&sec_all_nih, FALSE, name)))
api_fatal ("can't create tty_list::mutex '%s', %E", name);
ProtectHandle (mutex);
}
void __stdcall
tty::init_session ()
{
if (!myself->cygstarted && NOTSTATE (myself, PID_CYGPARENT))
cygheap->fdtab.get_debugger_info ();
}
int __reg2
tty_list::attach (int n)
{
int res;
if (iscons_dev (n))
res = -1;
else if (n != -1)
res = connect (device::minor (n));
else
res = -1;
return res;
}
int
tty_list::connect (int ttynum)
{
if (ttynum < 0 || ttynum >= NTTYS)
{
termios_printf ("ttynum (%d) out of range", ttynum);
return -1;
}
if (!ttys[ttynum].exists ())
{
termios_printf ("pty %d was not allocated", ttynum);
set_errno (ENXIO);
return -1;
}
return ttynum;
}
void
tty_list::init ()
{
for (int i = 0; i < NTTYS; i++)
{
ttys[i].init ();
ttys[i].setntty (DEV_PTYS_MAJOR, i);
}
}
/* Search for a free tty and allocate it.
Return tty number or -1 if error.
*/
int
tty_list::allocate (HANDLE& r, HANDLE& w)
{
lock_ttys here;
int freetty = -1;
tty *t = NULL;
for (int i = 0; i < NTTYS; i++)
if (ttys[i].not_allocated (r, w))
{
t = ttys + i;
t->init ();
t->setsid (0);
freetty = i;
break;
}
if (freetty >= 0)
termios_printf ("pty%d allocated", freetty);
else
{
system_printf ("No pty allocated");
r = w = NULL;
}
return freetty;
}
bool
tty::not_allocated (HANDLE& r, HANDLE& w)
{
/* Attempt to open the from-master side of the tty. If it is accessible
then it exists although we may not have privileges to actually use it. */
char pipename[sizeof("ptyNNNN-from-master")];
__small_sprintf (pipename, "pty%d-from-master", get_minor ());
/* fhandler_pipe::create returns 0 when creation succeeds */
return fhandler_pipe::create (&sec_none, &r, &w,
fhandler_pty_common::pipesize, pipename,
0) == 0;
}
bool
tty::exists ()
{
HANDLE r, w;
bool res;
if (!not_allocated (r, w))
res = true;
else
{
/* Handles are left open when not_allocated finds a non-open "tty" */
CloseHandle (r);
CloseHandle (w);
res = false;
}
debug_printf ("exists %d", res);
return res;
}
bool
tty::slave_alive ()
{
HANDLE ev;
if ((ev = open_inuse (READ_CONTROL)))
CloseHandle (ev);
return ev != NULL;
}
HANDLE
tty::open_mutex (const char *mutex, ACCESS_MASK access)
{
char buf[MAX_PATH];
shared_name (buf, mutex, get_minor ());
return OpenMutex (access, TRUE, buf);
}
HANDLE
tty::open_inuse (ACCESS_MASK access)
{
char buf[MAX_PATH];
shared_name (buf, TTY_SLAVE_ALIVE, get_minor ());
return OpenEvent (access, FALSE, buf);
}
HANDLE
tty::create_inuse (PSECURITY_ATTRIBUTES sa)
{
HANDLE h;
char buf[MAX_PATH];
shared_name (buf, TTY_SLAVE_ALIVE, get_minor ());
h = CreateEvent (sa, TRUE, FALSE, buf);
termios_printf ("%s %p", buf, h);
if (!h)
termios_printf ("couldn't open inuse event %s, %E", buf);
return h;
}
void
tty::init ()
{
output_stopped = 0;
setsid (0);
pgid = 0;
was_opened = false;
master_pid = 0;
is_console = false;
column = 0;
h_pseudo_console = NULL;
switch_to_pcon_in = false;
mask_switch_to_pcon_in = false;
pcon_pid = 0;
term_code_page = 0;
pcon_last_time = 0;
pcon_start = false;
pcon_cap_checked = false;
has_csi6n = false;
need_invisible_console = false;
invisible_console_pid = 0;
}
HANDLE
tty::get_event (const char *fmt, PSECURITY_ATTRIBUTES sa, BOOL manual_reset)
{
HANDLE hev;
char buf[MAX_PATH];
shared_name (buf, fmt, get_minor ());
if (!sa)
sa = &sec_all;
if (!(hev = CreateEvent (sa, manual_reset, FALSE, buf)))
{
termios_printf ("couldn't create %s", buf);
set_errno (ENOENT); /* FIXME this can't be the right errno */
return NULL;
}
termios_printf ("created event %s", buf);
return hev;
}
lock_ttys::lock_ttys (DWORD howlong): release_me (true)
{
if (WaitForSingleObject (tty_list::mutex, howlong) == WAIT_FAILED)
{
termios_printf ("WFSO for mutex %p failed, %E", tty_list::mutex);
release_me = false;
}
}
void
lock_ttys::release ()
{
ReleaseMutex (tty_list::mutex);
}
const char *
tty_min::ttyname ()
{
device d;
d.parse (ntty);
return d.name ();
}
void
tty::wait_pcon_fwd (void)
{
/* The forwarding in pseudo console sometimes stops for
16-32 msec even if it already has data to transfer.
If the time without transfer exceeds 32 msec, the
forwarding is supposed to be finished. pcon_last_time
is reset to GetTickCount() in pty master forwarding
thread when the last data is transfered. */
const int sleep_in_pcon = 16;
const int time_to_wait = sleep_in_pcon * 2 + 1/* margine */;
pcon_last_time = GetTickCount ();
while (GetTickCount () - pcon_last_time < time_to_wait)
{
int tw = time_to_wait - (GetTickCount () - pcon_last_time);
cygwait (tw);
}
}