📄 fhandler_tty.cc
字号:
raise (SIGHUP); /* FIXME: Should this be SIGTTOU? */ towrite = (DWORD) -1; break; } if (output_done_event != NULL) { DWORD rc; DWORD x = n * 1000; rc = WaitForSingleObject (output_done_event, x); termios_printf ("waited %d ms for output_done_event, WFSO %d", x, rc); } } release_output_mutex (); return towrite;}int __stdcallfhandler_tty_slave::read (void *ptr, size_t len){ int totalread = 0; int vmin = 0; int vtime = 0; /* Initialized to prevent -Wuninitialized warning */ size_t readlen; DWORD bytes_in_pipe; char buf[INP_BUFFER_SIZE]; char peek_buf[INP_BUFFER_SIZE]; DWORD time_to_wait; DWORD rc; HANDLE w4[2]; termios_printf ("read(%x, %d) handle %p", ptr, len, get_handle ()); if ((get_ttyp ()->ti.c_lflag & ICANON)) time_to_wait = INFINITE; else { vmin = get_ttyp ()->ti.c_cc[VMIN]; if (vmin > INP_BUFFER_SIZE) vmin = INP_BUFFER_SIZE; vtime = get_ttyp ()->ti.c_cc[VTIME]; if (vmin < 0) vmin = 0; if (vtime < 0) vtime = 0; if (!vmin && !vtime) time_to_wait = 0; else time_to_wait = !vtime ? INFINITE : 100 * vtime; } w4[0] = signal_arrived; w4[1] = input_available_event; DWORD waiter = INFINITE; while (len) { rc = WaitForMultipleObjects (2, w4, FALSE, waiter); if (rc == WAIT_TIMEOUT) break; if (rc == WAIT_FAILED) { termios_printf ("wait for input event failed, %E"); break; } if (rc == WAIT_OBJECT_0) { /* if we've received signal after successfully reading some data, just return all data successfully read */ if (totalread > 0) break; set_sig_errno (EINTR); return -1; } rc = WaitForSingleObject (input_mutex, 1000); if (rc == WAIT_FAILED) { termios_printf ("wait for input mutex failed, %E"); break; } else if (rc == WAIT_TIMEOUT) { termios_printf ("failed to acquire input mutex after input event arrived"); break; } if (!PeekNamedPipe (get_handle (), peek_buf, sizeof (peek_buf), &bytes_in_pipe, NULL, NULL)) { termios_printf ("PeekNamedPipe failed, %E"); raise (SIGHUP); bytes_in_pipe = 0; } if (!vmin && !time_to_wait) { ReleaseMutex (input_mutex); return bytes_in_pipe; } readlen = min (bytes_in_pipe, min (len, sizeof (buf))); if (vmin && readlen > (unsigned) vmin) readlen = vmin; DWORD n = 0; if (readlen) { termios_printf ("reading %d bytes (vtime %d)", readlen, vtime); if (ReadFile (get_handle (), buf, readlen, &n, NULL) == FALSE) { termios_printf ("read failed, %E"); raise (SIGHUP); } /* MSDN states that 5th prameter can be used to determine total number of bytes in pipe, but for some reason this number doesn't change after successful read. So we have to peek into the pipe again to see if input is still available */ if (!PeekNamedPipe (get_handle (), peek_buf, 1, &bytes_in_pipe, NULL, NULL)) { termios_printf ("PeekNamedPipe failed, %E"); raise (SIGHUP); bytes_in_pipe = 0; } if (n) { len -= n; totalread += n; memcpy (ptr, buf, n); ptr = (char *) ptr + n; } } if (!bytes_in_pipe) ResetEvent (input_available_event); ReleaseMutex (input_mutex); if (get_ttyp ()->read_retval < 0) // read error { set_errno (-get_ttyp ()->read_retval); totalread = -1; break; } if (get_ttyp ()->read_retval == 0) //EOF { termios_printf ("saw EOF"); break; } if (get_ttyp ()->ti.c_lflag & ICANON || is_nonblocking ()) break; if (vmin && totalread >= vmin) break; /* vmin == 0 && vtime == 0: * we've already read all input, if any, so return immediately * vmin == 0 && vtime > 0: * we've waited for input 10*vtime ms in WFSO(input_available_event), * no matter whether any input arrived, we shouldn't wait any longer, * so return immediately * vmin > 0 && vtime == 0: * here, totalread < vmin, so continue waiting until more data * arrive * vmin > 0 && vtime > 0: * similar to the previous here, totalread < vmin, and timer * hadn't expired -- WFSO(input_available_event) != WAIT_TIMEOUT, * so "restart timer" and wait until more data arrive */ if (vmin == 0) break; if (n) waiter = time_to_wait; } termios_printf ("%d=read(%x, %d)", totalread, ptr, len); return totalread;}intfhandler_tty_common::dup (fhandler_base *child){ fhandler_tty_slave *fts = (fhandler_tty_slave *) child; int errind; fts->ttynum = ttynum; fts->tcinit (get_ttyp ()); attach_tty (ttynum); tc->set_ctty (ttynum, openflags); HANDLE nh; if (output_done_event == NULL) fts->output_done_event = NULL; else if (!DuplicateHandle (hMainProc, output_done_event, hMainProc, &fts->output_done_event, 0, 1, DUPLICATE_SAME_ACCESS)) { errind = 1; goto err; } if (ioctl_request_event == NULL) fts->ioctl_request_event = NULL; else if (!DuplicateHandle (hMainProc, ioctl_request_event, hMainProc, &fts->ioctl_request_event, 0, 1, DUPLICATE_SAME_ACCESS)) { errind = 2; goto err; } if (ioctl_done_event == NULL) fts->ioctl_done_event = NULL; else if (!DuplicateHandle (hMainProc, ioctl_done_event, hMainProc, &fts->ioctl_done_event, 0, 1, DUPLICATE_SAME_ACCESS)) { errind = 3; goto err; } if (!DuplicateHandle (hMainProc, input_available_event, hMainProc, &fts->input_available_event, 0, 1, DUPLICATE_SAME_ACCESS)) { errind = 4; goto err; } if (!DuplicateHandle (hMainProc, output_mutex, hMainProc, &fts->output_mutex, 0, 1, DUPLICATE_SAME_ACCESS)) { errind = 5; goto err; } if (!DuplicateHandle (hMainProc, input_mutex, hMainProc, &fts->input_mutex, 0, 1, DUPLICATE_SAME_ACCESS)) { errind = 6; goto err; } if (!DuplicateHandle (hMainProc, get_handle (), hMainProc, &nh, 0, 1, DUPLICATE_SAME_ACCESS)) { errind = 7; goto err; } fts->set_io_handle (nh); if (!DuplicateHandle (hMainProc, get_output_handle (), hMainProc, &nh, 0, 1, DUPLICATE_SAME_ACCESS)) { errind = 8; goto err; } fts->set_output_handle (nh); if (inuse == NULL) fts->inuse = NULL; else if (!DuplicateHandle (hMainProc, inuse, hMainProc, &fts->inuse, 0, 1, DUPLICATE_SAME_ACCESS)) { errind = 9; goto err; } return 0;err: __seterrno (); termios_printf ("dup %d failed in DuplicateHandle, %E", errind); return -1;}intfhandler_tty_slave::tcgetattr (struct termios *t){ *t = get_ttyp ()->ti; return 0;}intfhandler_tty_slave::tcsetattr (int, const struct termios *t){ acquire_output_mutex (INFINITE); get_ttyp ()->ti = *t; release_output_mutex (); return 0;}intfhandler_tty_slave::tcflush (int){ return 0;}intfhandler_tty_slave::ioctl (unsigned int cmd, void *arg){ termios_printf ("ioctl (%x)", cmd); if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid && myself->ctty == ttynum && (get_ttyp ()->ti.c_lflag & TOSTOP)) { /* background process */ termios_printf ("bg ioctl pgid %d, tpgid %d, ctty %d", myself->pgid, get_ttyp ()->getpgid (), myself->ctty); raise (SIGTTOU); } switch (cmd) { case TIOCGWINSZ: case TIOCSWINSZ: break; case FIONBIO: set_nonblocking (*(int *) arg); goto out; default: set_errno (EINVAL); return -1; } acquire_output_mutex (INFINITE); get_ttyp ()->cmd = cmd; get_ttyp ()->ioctl_retval = 0; switch (cmd) { case TIOCGWINSZ: get_ttyp ()->arg.winsize = get_ttyp ()->winsize; if (ioctl_request_event) SetEvent (ioctl_request_event); *(struct winsize *) arg = get_ttyp ()->arg.winsize; if (ioctl_done_event) WaitForSingleObject (ioctl_done_event, INFINITE); get_ttyp ()->winsize = get_ttyp ()->arg.winsize; break; case TIOCSWINSZ: if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col) { get_ttyp ()->arg.winsize = *(struct winsize *) arg; if (ioctl_request_event) { get_ttyp ()->ioctl_retval = -1; SetEvent (ioctl_request_event); } else { get_ttyp ()->winsize = *(struct winsize *) arg; kill (-get_ttyp ()->getpgid (), SIGWINCH); } if (ioctl_done_event) WaitForSingleObject (ioctl_done_event, INFINITE); } break; } release_output_mutex ();out: termios_printf ("%d = ioctl (%x)", get_ttyp ()->ioctl_retval, cmd); return get_ttyp ()->ioctl_retval;}/******************************************************* fhandler_pty_master*/fhandler_pty_master::fhandler_pty_master (DWORD devtype, int unit) : fhandler_tty_common (devtype, unit){}intfhandler_pty_master::open (path_conv *, int flags, mode_t){ ttynum = cygwin_shared->tty.allocate_tty (0); if (ttynum < 0) return 0; cygwin_shared->tty[ttynum]->common_init (this); inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE); set_flags ((flags & ~O_TEXT) | O_BINARY); set_open_status (); termios_printf ("opened pty master tty%d<%p>", ttynum, this); return 1;}intfhandler_tty_common::close (){ if (output_done_event && !CloseHandle (output_done_event)) termios_printf ("CloseHandle (output_done_event), %E"); if (ioctl_done_event && !CloseHandle (ioctl_done_event)) termios_printf ("CloseHandle (ioctl_done_event), %E"); if (ioctl_request_event && !CloseHandle (ioctl_request_event)) termios_printf ("CloseHandle (ioctl_request_event), %E"); if (inuse && !CloseHandle (inuse)) termios_printf ("CloseHandle (inuse), %E"); if (!ForceCloseHandle (input_mutex)) termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex); if (!ForceCloseHandle (output_mutex)) termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex); /* Send EOF to slaves if master side is closed */ if (!get_ttyp ()->master_alive ()) { termios_printf ("no more masters left. sending EOF" ); SetEvent (input_available_event); } if (!ForceCloseHandle (input_available_event)) termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event); if (!ForceCloseHandle1 (get_handle (), from_pty)) termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ()); if (!ForceCloseHandle1 (get_output_handle (), to_pty)) termios_printf ("CloseHandle (get_output_handle ()<%p>), %E", get_output_handle ()); inuse = NULL; termios_printf ("tty%d <%p,%p> closed", ttynum, get_handle (), get_output_handle ()); return 0;}intfhandler_pty_master::close (){#if 0 while (accept_input () > 0) continue;#endif this->fhandler_tty_common::close (); if (!get_ttyp ()->master_alive ()) { termios_printf ("freeing tty%d (%d)", ttynum, get_ttyp ()->ntty);#if 0 if (get_ttyp ()->to_slave) ForceCloseHandle1 (get_ttyp ()->to_slave, to_slave); if (get_ttyp ()->from_slave) ForceCloseHandle1 (get_ttyp ()->from_slave, from_slave);#endif if (get_ttyp ()->from_master) CloseHandle (get_ttyp ()->from_master); if (get_ttyp ()->to_master) CloseHandle (get_ttyp ()->to_master); get_ttyp ()->init (); } return 0;}intfhandler_pty_master::write (const void *ptr, size_t len){ (void) line_edit ((char *) ptr, len); return len;}int __stdcallfhandler_pty_master::read (void *ptr, size_t len){ return process_slave_output ((char *) ptr, len, pktmode);}intfhandler_pty_master::tcgetattr (struct termios *t){ *t = cygwin_shared->tty[ttynum]->ti; return 0;}intfhandler_pty_master::tcsetattr (int, const struct termios *t){ cygwin_shared->tty[ttynum]->ti = *t; return 0;}intfhandler_pty_master::tcflush (int){ return 0;}intfhandler_pty_master::ioctl (unsigned int cmd, void *arg){ switch (cmd) { case TIOCPKT: pktmode = * (int *) arg; break; case TIOCGWINSZ: * (struct winsize *) arg = get_ttyp ()->winsize; break; case TIOCSWINSZ: if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col) { get_ttyp ()->winsize = * (struct winsize *) arg; kill (-get_ttyp ()->getpgid (), SIGWINCH); } break; case FIONBIO: set_nonblocking (*(int *) arg); break; default: set_errno (EINVAL); return -1; } return 0;}char *fhandler_pty_master::ptsname (void){ static char buf[32]; __small_sprintf (buf, "/dev/tty%d", ttynum); return buf;}voidfhandler_tty_common::set_close_on_exec (int val){#ifndef DEBUGGING this->fhandler_base::set_close_on_exec (val);#else /* FIXME: This is a duplication from fhandler_base::set_close_on_exec. It is here because we need to specify the "from_pty" stuff here or we'll get warnings from ForceCloseHandle when debugging. */ set_inheritance (get_io_handle (), val); set_close_on_exec_flag (val);#endif if (output_done_event) set_inheritance (output_done_event, val); if (ioctl_request_event) set_inheritance (ioctl_request_event, val); if (ioctl_done_event) set_inheritance (ioctl_done_event, val); if (inuse) set_inheritance (inuse, val); set_inheritance (output_mutex, val); set_inheritance (input_mutex, val); set_inheritance (input_available_event, val); set_inheritance (output_handle, val);}voidfhandler_tty_common::fixup_after_fork (HANDLE parent){ this->fhandler_termios::fixup_after_fork (parent); if (output_done_event) fork_fixup (parent, output_done_event, "output_done_event"); if (ioctl_request_event) fork_fixup (parent, ioctl_request_event, "ioctl_request_event"); if (ioctl_done_event) fork_fixup (parent, ioctl_done_event, "ioctl_done_event"); if (output_mutex) fork_fixup (parent, output_mutex, "output_mutex"); if (input_mutex) fork_fixup (parent, input_mutex, "input_mutex"); if (input_available_event) fork_fixup (parent, input_available_event, "input_available_event"); fork_fixup (parent, inuse, "inuse");}voidfhandler_pty_master::set_close_on_exec (int val){ this->fhandler_tty_common::set_close_on_exec (val); /* FIXME: There is a console handle leak here. */ if (get_ttyp ()->master_pid == GetCurrentProcessId ()) { get_ttyp ()->from_slave = get_handle (); get_ttyp ()->to_slave = get_output_handle (); termios_printf ("from_slave %p, to_slave %p", get_handle (), get_output_handle ()); }}voidfhandler_tty_master::fixup_after_fork (HANDLE child){ this->fhandler_pty_master::fixup_after_fork (child); console->fixup_after_fork (child);}voidfhandler_tty_master::fixup_after_exec (HANDLE){ console->close (); init_console ();}intfhandler_tty_master::init_console (){ console = (fhandler_console *) cygheap->fdtab.build_fhandler (-1, FH_CONSOLE, "/dev/ttym"); if (console == NULL) return -1; console->init (INVALID_HANDLE_VALUE, GENERIC_READ | GENERIC_WRITE, O_BINARY); console->set_r_no_interrupt (1); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -