⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fhandler_tty.cc

📁 cygwin, 著名的在win32下模拟unix操作系统的东东
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* fhandler_tty.cc   Copyright 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license.  Please consult the file "CYGWIN_LICENSE" fordetails. */#include "winsup.h"#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <errno.h>#include <ctype.h>#include <limits.h>#include "cygerrno.h"#include "security.h"#include "fhandler.h"#include "path.h"#include "dtable.h"#include "sigproc.h"#include "pinfo.h"#include "cygheap.h"#include "shared_info.h"#include "cygwin/cygserver.h"#include "cygthread.h"/* Tty master stuff */fhandler_tty_master NO_COPY *tty_master;static DWORD WINAPI process_input (void *);		// Input queue threadstatic DWORD WINAPI process_output (void *);		// Output queue threadstatic DWORD WINAPI process_ioctl (void *);		// Ioctl requests threadfhandler_tty_master::fhandler_tty_master (int unit)  : fhandler_pty_master (FH_TTYM, unit), console (NULL){}intfhandler_tty_master::init (int ntty){  termios_printf ("Creating master for tty%d", ntty);  if (init_console ())    {      termios_printf ("can't create fhandler");      return -1;    }  termios ti;  memset (&ti, 0, sizeof (ti));  console->tcsetattr (0, &ti);  ttynum = ntty;  cygwin_shared->tty[ttynum]->common_init (this);  inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE);  cygthread *h;  h = new cygthread (process_input, cygself, "ttyin");  h->SetThreadPriority (THREAD_PRIORITY_HIGHEST);  h->zap_h ();  h = new cygthread (process_ioctl, cygself, "ttyioctl");  h->SetThreadPriority (THREAD_PRIORITY_HIGHEST);  h->zap_h ();  h = new cygthread (process_output, cygself, "ttyout");  h->SetThreadPriority (THREAD_PRIORITY_HIGHEST);  h->zap_h ();  return 0;}#ifdef DEBUGGINGstatic class mutex_stack{public:  const char *fn;  int ln;  const char *tname;} ostack[100];static int osi;#endif /*DEBUGGING*/DWORDfhandler_tty_common::__acquire_output_mutex (const char *fn, int ln,					   DWORD ms){  if (strace.active)    strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: waiting %d ms", ln, ms);  DWORD res = WaitForSingleObject (output_mutex, ms);  if (res == WAIT_OBJECT_0)    {#ifndef DEBUGGING      if (strace.active)	strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: acquired", ln, res);#else      ostack[osi].fn = fn;      ostack[osi].ln = ln;      ostack[osi].tname = cygthread::name ();      termios_printf ("acquired for %s:%d, osi %d", fn, ln, osi);      osi++;#endif    }  return res;}voidfhandler_tty_common::__release_output_mutex (const char *fn, int ln){  if (ReleaseMutex (output_mutex))    {#ifndef DEBUGGING      if (strace.active)	strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex released", ln);#else      if (osi > 0)	osi--;      termios_printf ("released at %s:%d, osi %d", fn, ln, osi);      termios_printf ("  for %s:%d (%s)", ostack[osi].fn, ostack[osi].ln, ostack[osi].tname);      ostack[osi].ln = -ln;#endif    }}/* Process tty input. */voidfhandler_pty_master::doecho (const void *str, DWORD len){  acquire_output_mutex (INFINITE);  if (!WriteFile (get_ttyp ()->to_master, str, len, &len, NULL))    termios_printf ("Write to %p failed, %E", get_ttyp ()->to_master);//  WaitForSingleObject (output_done_event, INFINITE);  release_output_mutex ();}intfhandler_pty_master::accept_input (){  DWORD bytes_left, written;  DWORD n;  DWORD rc;  char* p;  rc = WaitForSingleObject (input_mutex, INFINITE);  bytes_left = n = eat_readahead (-1);  get_ttyp ()->read_retval = 0;  p = rabuf;  if (n != 0)    {      while (bytes_left > 0)	{	  termios_printf ("about to write %d chars to slave", bytes_left);	  rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);	  if (!rc)	    {	      debug_printf ("error writing to pipe %E");	      break;	    }	  get_ttyp ()->read_retval += written;	  p += written;	  bytes_left -= written;	  if (bytes_left > 0)	    {	      debug_printf ("to_slave pipe is full");	      SetEvent (input_available_event);	      ReleaseMutex (input_mutex);	      Sleep (10);	      rc = WaitForSingleObject (input_mutex, INFINITE);	    }	}    }  else    termios_printf ("sending EOF to slave");  SetEvent (input_available_event);  ReleaseMutex (input_mutex);  return get_ttyp ()->read_retval;}static DWORD WINAPIprocess_input (void *){  char rawbuf[INP_BUFFER_SIZE];  while (1)    {      int nraw = tty_master->console->read ((void *) rawbuf,				      (size_t) INP_BUFFER_SIZE);      (void) tty_master->line_edit (rawbuf, nraw);    }}boolfhandler_pty_master::hit_eof (){  if (get_ttyp ()->was_opened && !get_ttyp ()->slave_alive ())    {      /* We have the only remaining open handle to this pty, and	 the slave pty has been opened at least once.  We treat	 this as EOF.  */      termios_printf ("all other handles closed");      return 1;    }  return 0;}/* Process tty output requests */intfhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on){  size_t rlen;  char outbuf[OUT_BUFFER_SIZE + 1];  DWORD n;  int column = 0;  int rc = 0;  if (len == 0)    goto out;  if (need_nl)    {      /* We need to return a left over \n character, resulting from	 \r\n conversion.  Note that we already checked for FLUSHO and	 output_stopped at the time that we read the character, so we	 don't check again here.  */      buf[0] = '\n';      need_nl = 0;      rc = 1;      goto out;    }  for (;;)    {      /* Set RLEN to the number of bytes to read from the pipe.  */      rlen = len;      if (get_ttyp ()->ti.c_oflag & OPOST && get_ttyp ()->ti.c_oflag & ONLCR)	{	  /* We are going to expand \n to \r\n, so don't read more than	     half of the number of bytes requested.  */	  rlen /= 2;	  if (rlen == 0)	    rlen = 1;	}      if (rlen > sizeof outbuf)	rlen = sizeof outbuf;      HANDLE handle = get_io_handle ();      n = 0; // get_readahead_into_buffer (outbuf, len);      if (!n)	{	  /* Doing a busy wait like this is quite inefficient, but nothing	     else seems to work completely.  Windows should provide some sort	     of overlapped I/O for pipes, or something, but it doesn't.  */	  while (1)	    {	      if (!PeekNamedPipe (handle, NULL, 0, NULL, &n, NULL))		goto err;	      if (n > 0)		break;	      if (hit_eof ())		goto out;	      if (n == 0 && is_nonblocking ())		{		  set_errno (EAGAIN);		  rc = -1;		  break;		}	      Sleep (10);	    }	  if (ReadFile (handle, outbuf, rlen, &n, NULL) == FALSE)	    goto err;	}      termios_printf ("bytes read %u", n);      get_ttyp ()->write_error = 0;      if (output_done_event != NULL)	SetEvent (output_done_event);      if (get_ttyp ()->ti.c_lflag & FLUSHO)	continue;      char *optr;      optr = buf;      if (pktmode_on)	*optr++ = TIOCPKT_DATA;      if (!(get_ttyp ()->ti.c_oflag & OPOST))	// post-process output	{	  memcpy (optr, outbuf, n);	  optr += n;	}      else					// raw output mode	{	  char *iptr = outbuf;	  while (n--)	    {	      switch (*iptr)		{		case '\r':		  if ((get_ttyp ()->ti.c_oflag & ONOCR) && column == 0)		    {		      iptr++;		      continue;		    }		  if (get_ttyp ()->ti.c_oflag & OCRNL)		    *iptr = '\n';		  else		    column = 0;		  break;		case '\n':		  if (get_ttyp ()->ti.c_oflag & ONLCR)		    {		      *optr++ = '\r';		      column = 0;		    }		  if (get_ttyp ()->ti.c_oflag & ONLRET)		    column = 0;		  break;		default:		  column++;		  break;		}	      /* Don't store data past the end of the user's buffer.  This		 can happen if the user requests a read of 1 byte when		 doing \r\n expansion.  */	      if (optr - buf >= (int) len)		{		  if (*iptr != '\n' || n != 0)		    system_printf ("internal error: %d unexpected characters", n);		  need_nl = 1;		  break;		}	      *optr++ = *iptr++;	    }	}      rc = optr - buf;      break;    err:      if (GetLastError () == ERROR_BROKEN_PIPE)	rc = 0;      else	{	  __seterrno ();	  rc = -1;	}      break;    }out:  termios_printf ("returning %d", rc);  return rc;}static DWORD WINAPIprocess_output (void *){  char buf[OUT_BUFFER_SIZE * 2];  for (;;)    {      int n = tty_master->process_slave_output (buf, OUT_BUFFER_SIZE, 0);      if (n <= 0)	{	  if (n < 0)	    termios_printf ("ReadFile %E");	  ExitThread (0);	}      n = tty_master->console->write ((void *) buf, (size_t) n);      tty_master->get_ttyp ()->write_error = n == -1 ? get_errno () : 0;    }}/* Process tty ioctl requests */static DWORD WINAPIprocess_ioctl (void *){  while (1)    {      WaitForSingleObject (tty_master->ioctl_request_event, INFINITE);      termios_printf ("ioctl() request");      tty_master->get_ttyp ()->ioctl_retval =      tty_master->console->ioctl (tty_master->get_ttyp ()->cmd,			     (void *) &tty_master->get_ttyp ()->arg);      SetEvent (tty_master->ioctl_done_event);    }}/**********************************************************************//* Tty slave stuff */fhandler_tty_slave::fhandler_tty_slave (int num)  : fhandler_tty_common (FH_TTYS, num){  set_r_no_interrupt (1);}fhandler_tty_slave::fhandler_tty_slave ()  : fhandler_tty_common (FH_TTYS, 0){  set_r_no_interrupt (1);}/* FIXME: This function needs to close handles when it has   a failing condition. */intfhandler_tty_slave::open (path_conv *, int flags, mode_t){  tcinit (cygwin_shared->tty[ttynum]);  attach_tty (ttynum);  tc->set_ctty (ttynum, flags);  set_flags ((flags & ~O_TEXT) | O_BINARY);  /* Create synchronisation events */  char buf[40];  /* output_done_event may or may not exist.  It will exist if the tty     was opened by fhandler_tty_master::init, normally called at     startup if use_tty is non-zero.  It will not exist if this is a     pty opened by fhandler_pty_master::open.  In the former case, tty     output is handled by a separate thread which controls output.  */  __small_sprintf (buf, OUTPUT_DONE_EVENT, ttynum);  output_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);  if (!(output_mutex = get_ttyp ()->open_output_mutex ()))    {      termios_printf ("open output mutex failed, %E");      __seterrno ();      return 0;    }  if (!(input_mutex = get_ttyp ()->open_input_mutex ()))    {      termios_printf ("open input mutex failed, %E");      __seterrno ();      return 0;    }  __small_sprintf (buf, INPUT_AVAILABLE_EVENT, ttynum);  if (!(input_available_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf)))    {      termios_printf ("open input event failed, %E");      __seterrno ();      return 0;    }  /* The ioctl events may or may not exist.  See output_done_event,     above.  */  __small_sprintf (buf, IOCTL_REQUEST_EVENT, ttynum);  ioctl_request_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);  __small_sprintf (buf, IOCTL_DONE_EVENT, ttynum);  ioctl_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);  /* FIXME: Needs a method to eliminate tty races */  {    acquire_output_mutex (500);    inuse = get_ttyp ()->create_inuse (TTY_SLAVE_ALIVE);    get_ttyp ()->was_opened = TRUE;    release_output_mutex ();  }  /* Duplicate tty handles.  */  if (!get_ttyp ()->from_slave || !get_ttyp ()->to_slave)    {      termios_printf ("tty handles have been closed");      set_errno (EACCES);      return 0;    }  HANDLE from_master_local, to_master_local;  if (!wincap.has_security () ||      cygserver_running == CYGSERVER_UNAVAIL ||      !cygserver_attach_tty (&from_master_local, &to_master_local))    {      termios_printf ("cannot dup handles via server. using old method.");      HANDLE tty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE,				      get_ttyp ()->master_pid);      termios_printf ("tty own handle %p",tty_owner);      if (tty_owner == NULL)	{	  termios_printf ("can't open tty (%d) handle process %d",			  ttynum, get_ttyp ()->master_pid);	  __seterrno ();	  return 0;	}      if (!DuplicateHandle (tty_owner, get_ttyp ()->from_master,			    hMainProc, &from_master_local, 0, TRUE,			    DUPLICATE_SAME_ACCESS))	{	  termios_printf ("can't duplicate input, %E");	  __seterrno ();	  return 0;	}      if (!DuplicateHandle (tty_owner, get_ttyp ()->to_master,			  hMainProc, &to_master_local, 0, TRUE,			  DUPLICATE_SAME_ACCESS))	{	  termios_printf ("can't duplicate output, %E");	  __seterrno ();	  return 0;	}      CloseHandle (tty_owner);    }  termios_printf ("duplicated from_master %p->%p from tty_owner",      get_ttyp ()->from_master, from_master_local);  termios_printf ("duplicated to_master %p->%p from tty_owner",      get_ttyp ()->to_master, to_master_local);  set_io_handle (from_master_local);  set_output_handle (to_master_local);  set_open_status ();  termios_printf ("tty%d opened", ttynum);  return 1;}intfhandler_tty_slave::cygserver_attach_tty (LPHANDLE from_master_ptr,					  LPHANDLE to_master_ptr){  if (!from_master_ptr || !to_master_ptr)    return 0;  client_request_attach_tty req ((DWORD) get_ttyp ()->master_pid,				 (HANDLE) get_ttyp ()->from_master,				 (HANDLE) get_ttyp ()->to_master);  if (req.make_request () == -1 || req.error_code ())    return 0;  *from_master_ptr = req.from_master ();  *to_master_ptr = req.to_master ();  return 1;}voidfhandler_tty_slave::init (HANDLE, DWORD a, mode_t){  int mode = 0;  a &= GENERIC_READ | GENERIC_WRITE;  if (a == GENERIC_READ)    mode = O_RDONLY;  if (a == GENERIC_WRITE)    mode = O_WRONLY;  if (a == (GENERIC_READ | GENERIC_WRITE))    mode = O_RDWR;  open (0, mode);}intfhandler_tty_slave::write (const void *ptr, size_t len){  DWORD n, towrite = len;  termios_printf ("tty%d, write(%x, %d)", ttynum, ptr, len);  acquire_output_mutex (INFINITE);  while (len)    {      n = min (OUT_BUFFER_SIZE, len);      char *buf = (char *)ptr;      ptr = (char *) ptr + n;      len -= n;      /* Previous write may have set write_error to != 0.  Check it here.	 This is less than optimal, but the alternative slows down tty	 writes enormously. */      if (get_ttyp ()->write_error)	{	  set_errno (get_ttyp ()->write_error);	  towrite = (DWORD) -1;	  break;	}      if (WriteFile (get_output_handle (), buf, n, &n, NULL) == FALSE)	{	  DWORD err = GetLastError ();	  termios_printf ("WriteFile failed, %E");	  switch (err)	    {	    case ERROR_NO_DATA:	      err = ERROR_IO_DEVICE;	    default:	      __seterrno_from_win_error (err);	    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -