3 Copyright 1997, 1998, 2000, 2001, 2002, 2003 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
26 #include "shared_info.h"
27 #include "cygwin/cygserver.h"
28 #include "cygthread.h"
30 /* Tty master stuff */
32 fhandler_tty_master NO_COPY *tty_master;
34 static DWORD WINAPI process_input (void *); // Input queue thread
35 static DWORD WINAPI process_output (void *); // Output queue thread
36 static DWORD WINAPI process_ioctl (void *); // Ioctl requests thread
38 fhandler_tty_master::fhandler_tty_master (int unit)
39 : fhandler_pty_master (FH_TTYM, unit), console (NULL)
44 fhandler_tty_master::set_winsize (bool sendSIGWINCH)
47 console->ioctl (TIOCGWINSZ, &w);
48 get_ttyp ()->winsize = w;
50 tc->kill_pgrp (SIGWINCH);
54 fhandler_tty_master::init (int ntty)
56 termios_printf ("Creating master for tty%d", ntty);
60 termios_printf ("can't create fhandler");
65 memset (&ti, 0, sizeof (ti));
66 console->tcsetattr (0, &ti);
70 cygwin_shared->tty[ttynum]->common_init (this);
74 inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE);
77 h = new cygthread (process_input, cygself, "ttyin");
78 h->SetThreadPriority (THREAD_PRIORITY_HIGHEST);
81 h = new cygthread (process_ioctl, cygself, "ttyioctl");
82 h->SetThreadPriority (THREAD_PRIORITY_HIGHEST);
85 h = new cygthread (process_output, cygself, "ttyout");
86 h->SetThreadPriority (THREAD_PRIORITY_HIGHEST);
93 static class mutex_stack
105 fhandler_tty_common::__acquire_output_mutex (const char *fn, int ln,
109 strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: waiting %d ms", ln, ms);
110 DWORD res = WaitForSingleObject (output_mutex, ms);
111 if (res == WAIT_OBJECT_0)
115 strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: acquired", ln, res);
119 ostack[osi].tname = cygthread::name ();
120 termios_printf ("acquired for %s:%d, osi %d", fn, ln, osi);
128 fhandler_tty_common::__release_output_mutex (const char *fn, int ln)
130 if (ReleaseMutex (output_mutex))
134 strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex released", ln);
138 termios_printf ("released at %s:%d, osi %d", fn, ln, osi);
139 termios_printf (" for %s:%d (%s)", ostack[osi].fn, ostack[osi].ln, ostack[osi].tname);
140 ostack[osi].ln = -ln;
145 /* Process tty input. */
148 fhandler_pty_master::doecho (const void *str, DWORD len)
150 acquire_output_mutex (INFINITE);
151 if (!WriteFile (get_ttyp ()->to_master, str, len, &len, NULL))
152 termios_printf ("Write to %p failed, %E", get_ttyp ()->to_master);
153 // WaitForSingleObject (output_done_event, INFINITE);
154 release_output_mutex ();
158 fhandler_pty_master::accept_input ()
163 (void) WaitForSingleObject (input_mutex, INFINITE);
165 bytes_left = eat_readahead (-1);
169 termios_printf ("sending EOF to slave");
170 get_ttyp ()->read_retval = 0;
178 termios_printf ("about to write %d chars to slave", bytes_left);
179 rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
182 debug_printf ("error writing to pipe %E");
183 get_ttyp ()->read_retval = -1;
188 get_ttyp ()->read_retval = 1;
190 bytes_left -= written;
193 debug_printf ("to_slave pipe is full");
194 puts_readahead (p, bytes_left);
200 SetEvent (input_available_event);
201 ReleaseMutex (input_mutex);
206 process_input (void *)
208 char rawbuf[INP_BUFFER_SIZE];
212 size_t nraw = INP_BUFFER_SIZE;
213 tty_master->console->read ((void *) rawbuf, nraw);
214 (void) tty_master->line_edit (rawbuf, nraw, tty_master->get_ttyp ()->ti);
219 fhandler_pty_master::hit_eof ()
221 if (get_ttyp ()->was_opened && !get_ttyp ()->slave_alive ())
223 /* We have the only remaining open handle to this pty, and
224 the slave pty has been opened at least once. We treat
226 termios_printf ("all other handles closed");
232 /* Process tty output requests */
235 fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on)
238 char outbuf[OUT_BUFFER_SIZE + 1];
248 /* We need to return a left over \n character, resulting from
249 \r\n conversion. Note that we already checked for FLUSHO and
250 output_stopped at the time that we read the character, so we
251 don't check again here. */
261 /* Set RLEN to the number of bytes to read from the pipe. */
263 if (get_ttyp ()->ti.c_oflag & OPOST && get_ttyp ()->ti.c_oflag & ONLCR)
265 /* We are going to expand \n to \r\n, so don't read more than
266 half of the number of bytes requested. */
271 if (rlen > sizeof outbuf)
272 rlen = sizeof outbuf;
274 HANDLE handle = get_io_handle ();
276 n = 0; // get_readahead_into_buffer (outbuf, len);
279 /* Doing a busy wait like this is quite inefficient, but nothing
280 else seems to work completely. Windows should provide some sort
281 of overlapped I/O for pipes, or something, but it doesn't. */
284 if (!PeekNamedPipe (handle, NULL, 0, NULL, &n, NULL))
290 if (n == 0 && is_nonblocking ())
300 if (ReadFile (handle, outbuf, rlen, &n, NULL) == FALSE)
304 termios_printf ("bytes read %u", n);
305 get_ttyp ()->write_error = 0;
306 if (output_done_event != NULL)
307 SetEvent (output_done_event);
309 if (get_ttyp ()->ti.c_lflag & FLUSHO)
315 *optr++ = TIOCPKT_DATA;
317 if (!(get_ttyp ()->ti.c_oflag & OPOST)) // post-process output
319 memcpy (optr, outbuf, n);
322 else // raw output mode
331 if ((get_ttyp ()->ti.c_oflag & ONOCR) && column == 0)
336 if (get_ttyp ()->ti.c_oflag & OCRNL)
342 if (get_ttyp ()->ti.c_oflag & ONLCR)
347 if (get_ttyp ()->ti.c_oflag & ONLRET)
355 /* Don't store data past the end of the user's buffer. This
356 can happen if the user requests a read of 1 byte when
357 doing \r\n expansion. */
358 if (optr - buf >= (int) len)
360 if (*iptr != '\n' || n != 0)
361 system_printf ("internal error: %d unexpected characters", n);
373 if (GetLastError () == ERROR_BROKEN_PIPE)
384 termios_printf ("returning %d", rc);
389 process_output (void *)
391 char buf[OUT_BUFFER_SIZE * 2];
395 int n = tty_master->process_slave_output (buf, OUT_BUFFER_SIZE, 0);
399 termios_printf ("ReadFile %E");
402 n = tty_master->console->write ((void *) buf, (size_t) n);
403 tty_master->get_ttyp ()->write_error = n == -1 ? get_errno () : 0;
408 /* Process tty ioctl requests */
411 process_ioctl (void *)
415 WaitForSingleObject (tty_master->ioctl_request_event, INFINITE);
416 termios_printf ("ioctl() request");
417 tty_master->get_ttyp ()->ioctl_retval =
418 tty_master->console->ioctl (tty_master->get_ttyp ()->cmd,
419 (void *) &tty_master->get_ttyp ()->arg);
420 SetEvent (tty_master->ioctl_done_event);
424 /**********************************************************************/
425 /* Tty slave stuff */
427 fhandler_tty_slave::fhandler_tty_slave (int num)
428 : fhandler_tty_common (FH_TTYS, num)
430 set_r_no_interrupt (1);
433 fhandler_tty_slave::fhandler_tty_slave ()
434 : fhandler_tty_common (FH_TTYS, 0)
436 set_r_no_interrupt (1);
439 /* FIXME: This function needs to close handles when it has
440 a failing condition. */
442 fhandler_tty_slave::open (path_conv *, int flags, mode_t)
444 tcinit (cygwin_shared->tty[ttynum]);
447 tc->set_ctty (ttynum, flags);
449 set_flags ((flags & ~O_TEXT) | O_BINARY);
450 /* Create synchronisation events */
453 /* output_done_event may or may not exist. It will exist if the tty
454 was opened by fhandler_tty_master::init, normally called at
455 startup if use_tty is non-zero. It will not exist if this is a
456 pty opened by fhandler_pty_master::open. In the former case, tty
457 output is handled by a separate thread which controls output. */
458 __small_sprintf (buf, OUTPUT_DONE_EVENT, ttynum);
459 output_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);
461 if (!(output_mutex = get_ttyp ()->open_output_mutex ()))
463 termios_printf ("open output mutex failed, %E");
467 if (!(input_mutex = get_ttyp ()->open_input_mutex ()))
469 termios_printf ("open input mutex failed, %E");
473 __small_sprintf (buf, INPUT_AVAILABLE_EVENT, ttynum);
474 if (!(input_available_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf)))
476 termios_printf ("open input event failed, %E");
481 /* The ioctl events may or may not exist. See output_done_event,
483 __small_sprintf (buf, IOCTL_REQUEST_EVENT, ttynum);
484 ioctl_request_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);
485 __small_sprintf (buf, IOCTL_DONE_EVENT, ttynum);
486 ioctl_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);
488 /* FIXME: Needs a method to eliminate tty races */
490 acquire_output_mutex (500);
491 inuse = get_ttyp ()->create_inuse (TTY_SLAVE_ALIVE);
492 get_ttyp ()->was_opened = TRUE;
493 release_output_mutex ();
496 /* Duplicate tty handles. */
498 if (!get_ttyp ()->from_slave || !get_ttyp ()->to_slave)
500 termios_printf ("tty handles have been closed");
505 HANDLE from_master_local, to_master_local;
507 if (!wincap.has_security () ||
508 cygserver_running == CYGSERVER_UNAVAIL ||
509 !cygserver_attach_tty (&from_master_local, &to_master_local))
511 termios_printf ("cannot dup handles via server. using old method.");
513 HANDLE tty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE,
514 get_ttyp ()->master_pid);
515 termios_printf ("tty own handle %p",tty_owner);
516 if (tty_owner == NULL)
518 termios_printf ("can't open tty (%d) handle process %d",
519 ttynum, get_ttyp ()->master_pid);
524 if (!DuplicateHandle (tty_owner, get_ttyp ()->from_master,
525 hMainProc, &from_master_local, 0, TRUE,
526 DUPLICATE_SAME_ACCESS))
528 termios_printf ("can't duplicate input, %E");
533 if (!DuplicateHandle (tty_owner, get_ttyp ()->to_master,
534 hMainProc, &to_master_local, 0, TRUE,
535 DUPLICATE_SAME_ACCESS))
537 termios_printf ("can't duplicate output, %E");
541 CloseHandle (tty_owner);
544 termios_printf ("duplicated from_master %p->%p from tty_owner",
545 get_ttyp ()->from_master, from_master_local);
546 termios_printf ("duplicated to_master %p->%p from tty_owner",
547 get_ttyp ()->to_master, to_master_local);
549 set_io_handle (from_master_local);
550 set_output_handle (to_master_local);
553 termios_printf ("tty%d opened", ttynum);
559 fhandler_tty_slave::cygserver_attach_tty (LPHANDLE from_master_ptr,
560 LPHANDLE to_master_ptr)
562 if (!from_master_ptr || !to_master_ptr)
565 client_request_attach_tty req ((DWORD) get_ttyp ()->master_pid,
566 (HANDLE) get_ttyp ()->from_master,
567 (HANDLE) get_ttyp ()->to_master);
569 if (req.make_request () == -1 || req.error_code ())
572 *from_master_ptr = req.from_master ();
573 *to_master_ptr = req.to_master ();
578 fhandler_tty_slave::init (HANDLE, DWORD a, mode_t)
582 a &= GENERIC_READ | GENERIC_WRITE;
583 if (a == GENERIC_READ)
585 if (a == GENERIC_WRITE)
587 if (a == (GENERIC_READ | GENERIC_WRITE))
594 fhandler_tty_slave::write (const void *ptr, size_t len)
596 DWORD n, towrite = len;
598 termios_printf ("tty%d, write(%x, %d)", ttynum, ptr, len);
600 acquire_output_mutex (INFINITE);
604 n = min (OUT_BUFFER_SIZE, len);
605 char *buf = (char *)ptr;
606 ptr = (char *) ptr + n;
609 /* Previous write may have set write_error to != 0. Check it here.
610 This is less than optimal, but the alternative slows down tty
611 writes enormously. */
612 if (get_ttyp ()->write_error)
614 set_errno (get_ttyp ()->write_error);
615 towrite = (DWORD) -1;
619 if (WriteFile (get_output_handle (), buf, n, &n, NULL) == FALSE)
621 DWORD err = GetLastError ();
622 termios_printf ("WriteFile failed, %E");
626 err = ERROR_IO_DEVICE;
628 __seterrno_from_win_error (err);
630 raise (SIGHUP); /* FIXME: Should this be SIGTTOU? */
631 towrite = (DWORD) -1;
635 if (output_done_event != NULL)
639 rc = WaitForSingleObject (output_done_event, x);
640 termios_printf ("waited %d ms for output_done_event, WFSO %d", x, rc);
643 release_output_mutex ();
648 fhandler_tty_slave::read (void *ptr, size_t& len)
652 int vtime = 0; /* Initialized to prevent -Wuninitialized warning */
655 char buf[INP_BUFFER_SIZE];
656 char peek_buf[INP_BUFFER_SIZE];
661 termios_printf ("read(%x, %d) handle %p", ptr, len, get_handle ());
663 if ((get_ttyp ()->ti.c_lflag & ICANON))
664 time_to_wait = INFINITE;
667 vmin = get_ttyp ()->ti.c_cc[VMIN];
668 if (vmin > INP_BUFFER_SIZE)
669 vmin = INP_BUFFER_SIZE;
670 vtime = get_ttyp ()->ti.c_cc[VTIME];
678 time_to_wait = !vtime ? INFINITE : 100 * vtime;
681 w4[0] = signal_arrived;
682 w4[1] = input_available_event;
684 DWORD waiter = INFINITE;
687 rc = WaitForMultipleObjects (2, w4, FALSE, waiter);
689 if (rc == WAIT_TIMEOUT)
692 if (rc == WAIT_FAILED)
694 termios_printf ("wait for input event failed, %E");
698 if (rc == WAIT_OBJECT_0)
700 /* if we've received signal after successfully reading some data,
701 just return all data successfully read */
704 set_sig_errno (EINTR);
709 rc = WaitForSingleObject (input_mutex, 1000);
710 if (rc == WAIT_FAILED)
712 termios_printf ("wait for input mutex failed, %E");
715 else if (rc == WAIT_TIMEOUT)
717 termios_printf ("failed to acquire input mutex after input event arrived");
720 if (!PeekNamedPipe (get_handle (), peek_buf, sizeof (peek_buf), &bytes_in_pipe, NULL, NULL))
722 termios_printf ("PeekNamedPipe failed, %E");
727 if (!vmin && !time_to_wait)
729 ReleaseMutex (input_mutex);
730 (ssize_t) len = bytes_in_pipe;
734 readlen = min (bytes_in_pipe, min (len, sizeof (buf)));
736 if (vmin && readlen > (unsigned) vmin)
742 termios_printf ("reading %d bytes (vtime %d)", readlen, vtime);
743 if (ReadFile (get_handle (), buf, readlen, &n, NULL) == FALSE)
745 termios_printf ("read failed, %E");
748 /* MSDN states that 5th prameter can be used to determine total
749 number of bytes in pipe, but for some reason this number doesn't
750 change after successful read. So we have to peek into the pipe
751 again to see if input is still available */
752 if (!PeekNamedPipe (get_handle (), peek_buf, 1, &bytes_in_pipe, NULL, NULL))
754 termios_printf ("PeekNamedPipe failed, %E");
762 memcpy (ptr, buf, n);
763 ptr = (char *) ptr + n;
768 ResetEvent (input_available_event);
770 ReleaseMutex (input_mutex);
772 if (get_ttyp ()->read_retval < 0) // read error
774 set_errno (-get_ttyp ()->read_retval);
778 if (get_ttyp ()->read_retval == 0) //EOF
780 termios_printf ("saw EOF");
783 if (get_ttyp ()->ti.c_lflag & ICANON || is_nonblocking ())
785 if (vmin && totalread >= vmin)
788 /* vmin == 0 && vtime == 0:
789 * we've already read all input, if any, so return immediately
790 * vmin == 0 && vtime > 0:
791 * we've waited for input 10*vtime ms in WFSO(input_available_event),
792 * no matter whether any input arrived, we shouldn't wait any longer,
793 * so return immediately
794 * vmin > 0 && vtime == 0:
795 * here, totalread < vmin, so continue waiting until more data
797 * vmin > 0 && vtime > 0:
798 * similar to the previous here, totalread < vmin, and timer
799 * hadn't expired -- WFSO(input_available_event) != WAIT_TIMEOUT,
800 * so "restart timer" and wait until more data arrive
807 waiter = time_to_wait;
809 termios_printf ("%d=read(%x, %d)", totalread, ptr, len);
810 (ssize_t) len = totalread;
815 fhandler_tty_common::dup (fhandler_base *child)
817 fhandler_tty_slave *fts = (fhandler_tty_slave *) child;
820 fts->ttynum = ttynum;
821 fts->tcinit (get_ttyp ());
824 tc->set_ctty (ttynum, openflags);
828 if (output_done_event == NULL)
829 fts->output_done_event = NULL;
830 else if (!DuplicateHandle (hMainProc, output_done_event, hMainProc,
831 &fts->output_done_event, 0, 1,
832 DUPLICATE_SAME_ACCESS))
837 if (ioctl_request_event == NULL)
838 fts->ioctl_request_event = NULL;
839 else if (!DuplicateHandle (hMainProc, ioctl_request_event, hMainProc,
840 &fts->ioctl_request_event, 0, 1,
841 DUPLICATE_SAME_ACCESS))
846 if (ioctl_done_event == NULL)
847 fts->ioctl_done_event = NULL;
848 else if (!DuplicateHandle (hMainProc, ioctl_done_event, hMainProc,
849 &fts->ioctl_done_event, 0, 1,
850 DUPLICATE_SAME_ACCESS))
855 if (!DuplicateHandle (hMainProc, input_available_event, hMainProc,
856 &fts->input_available_event, 0, 1,
857 DUPLICATE_SAME_ACCESS))
862 if (!DuplicateHandle (hMainProc, output_mutex, hMainProc,
863 &fts->output_mutex, 0, 1,
864 DUPLICATE_SAME_ACCESS))
869 if (!DuplicateHandle (hMainProc, input_mutex, hMainProc,
870 &fts->input_mutex, 0, 1,
871 DUPLICATE_SAME_ACCESS))
876 if (!DuplicateHandle (hMainProc, get_handle (), hMainProc,
878 DUPLICATE_SAME_ACCESS))
883 fts->set_io_handle (nh);
885 if (!DuplicateHandle (hMainProc, get_output_handle (), hMainProc,
887 DUPLICATE_SAME_ACCESS))
892 fts->set_output_handle (nh);
896 else if (!DuplicateHandle (hMainProc, inuse, hMainProc,
898 DUPLICATE_SAME_ACCESS))
907 termios_printf ("dup %d failed in DuplicateHandle, %E", errind);
912 fhandler_tty_slave::tcgetattr (struct termios *t)
914 *t = get_ttyp ()->ti;
919 fhandler_tty_slave::tcsetattr (int, const struct termios *t)
921 acquire_output_mutex (INFINITE);
922 get_ttyp ()->ti = *t;
923 release_output_mutex ();
928 fhandler_tty_slave::tcflush (int)
934 fhandler_tty_slave::ioctl (unsigned int cmd, void *arg)
936 termios_printf ("ioctl (%x)", cmd);
938 if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid
939 && myself->ctty == ttynum && (get_ttyp ()->ti.c_lflag & TOSTOP))
941 /* background process */
942 termios_printf ("bg ioctl pgid %d, tpgid %d, ctty %d",
943 myself->pgid, get_ttyp ()->getpgid (), myself->ctty);
953 set_nonblocking (*(int *) arg);
960 acquire_output_mutex (INFINITE);
962 get_ttyp ()->cmd = cmd;
963 get_ttyp ()->ioctl_retval = 0;
967 get_ttyp ()->arg.winsize = get_ttyp ()->winsize;
968 if (ioctl_request_event)
969 SetEvent (ioctl_request_event);
970 *(struct winsize *) arg = get_ttyp ()->arg.winsize;
971 if (ioctl_done_event)
972 WaitForSingleObject (ioctl_done_event, INFINITE);
973 get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
976 if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
977 || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
979 get_ttyp ()->arg.winsize = *(struct winsize *) arg;
980 if (ioctl_request_event)
982 get_ttyp ()->ioctl_retval = -1;
983 SetEvent (ioctl_request_event);
987 get_ttyp ()->winsize = *(struct winsize *) arg;
988 kill (-get_ttyp ()->getpgid (), SIGWINCH);
990 if (ioctl_done_event)
991 WaitForSingleObject (ioctl_done_event, INFINITE);
996 release_output_mutex ();
999 termios_printf ("%d = ioctl (%x)", get_ttyp ()->ioctl_retval, cmd);
1000 return get_ttyp ()->ioctl_retval;
1003 /*******************************************************
1006 fhandler_pty_master::fhandler_pty_master (DWORD devtype, int unit)
1007 : fhandler_tty_common (devtype, unit)
1012 fhandler_pty_master::open (path_conv *, int flags, mode_t)
1014 ttynum = cygwin_shared->tty.allocate_tty (0);
1018 cygwin_shared->tty[ttynum]->common_init (this);
1019 inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE);
1020 set_flags ((flags & ~O_TEXT) | O_BINARY);
1023 termios_printf ("opened pty master tty%d<%p>", ttynum, this);
1028 fhandler_tty_common::close ()
1030 if (output_done_event && !CloseHandle (output_done_event))
1031 termios_printf ("CloseHandle (output_done_event), %E");
1032 if (ioctl_done_event && !CloseHandle (ioctl_done_event))
1033 termios_printf ("CloseHandle (ioctl_done_event), %E");
1034 if (ioctl_request_event && !CloseHandle (ioctl_request_event))
1035 termios_printf ("CloseHandle (ioctl_request_event), %E");
1036 if (inuse && !CloseHandle (inuse))
1037 termios_printf ("CloseHandle (inuse), %E");
1038 if (!ForceCloseHandle (input_mutex))
1039 termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex);
1040 if (!ForceCloseHandle (output_mutex))
1041 termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
1043 /* Send EOF to slaves if master side is closed */
1044 if (!get_ttyp ()->master_alive ())
1046 termios_printf ("no more masters left. sending EOF" );
1047 SetEvent (input_available_event);
1050 if (!ForceCloseHandle (input_available_event))
1051 termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event);
1052 if (!ForceCloseHandle1 (get_handle (), from_pty))
1053 termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ());
1054 if (!ForceCloseHandle1 (get_output_handle (), to_pty))
1055 termios_printf ("CloseHandle (get_output_handle ()<%p>), %E", get_output_handle ());
1058 termios_printf ("tty%d <%p,%p> closed", ttynum, get_handle (), get_output_handle ());
1063 fhandler_pty_master::close ()
1066 while (accept_input () > 0)
1069 fhandler_tty_common::close ();
1071 if (!get_ttyp ()->master_alive ())
1073 termios_printf ("freeing tty%d (%d)", ttynum, get_ttyp ()->ntty);
1075 if (get_ttyp ()->to_slave)
1076 ForceCloseHandle1 (get_ttyp ()->to_slave, to_slave);
1077 if (get_ttyp ()->from_slave)
1078 ForceCloseHandle1 (get_ttyp ()->from_slave, from_slave);
1080 if (get_ttyp ()->from_master)
1081 CloseHandle (get_ttyp ()->from_master);
1082 if (get_ttyp ()->to_master)
1083 CloseHandle (get_ttyp ()->to_master);
1084 get_ttyp ()->init ();
1091 fhandler_pty_master::write (const void *ptr, size_t len)
1094 char *p = (char *) ptr;
1095 termios ti = tc->ti;
1097 for (i = 0; i < (int) len; i++)
1099 line_edit_status status = line_edit (p++, 1, ti);
1100 if (status > line_edit_signalled)
1102 if (status != line_edit_pipe_full)
1111 fhandler_pty_master::read (void *ptr, size_t& len)
1113 (ssize_t) len = process_slave_output ((char *) ptr, len, pktmode);
1118 fhandler_pty_master::tcgetattr (struct termios *t)
1120 *t = cygwin_shared->tty[ttynum]->ti;
1125 fhandler_pty_master::tcsetattr (int, const struct termios *t)
1127 cygwin_shared->tty[ttynum]->ti = *t;
1132 fhandler_pty_master::tcflush (int)
1138 fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
1143 pktmode = * (int *) arg;
1146 *(struct winsize *) arg = get_ttyp ()->winsize;
1149 if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
1150 || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
1152 get_ttyp ()->winsize = * (struct winsize *) arg;
1153 kill (-get_ttyp ()->getpgid (), SIGWINCH);
1157 set_nonblocking (*(int *) arg);
1167 fhandler_pty_master::ptsname (void)
1169 static char buf[32];
1171 __small_sprintf (buf, "/dev/tty%d", ttynum);
1176 fhandler_tty_common::set_close_on_exec (int val)
1179 fhandler_base::set_close_on_exec (val);
1181 /* FIXME: This is a duplication from fhandler_base::set_close_on_exec.
1182 It is here because we need to specify the "from_pty" stuff here or
1183 we'll get warnings from ForceCloseHandle when debugging. */
1184 set_inheritance (get_io_handle (), val);
1185 set_close_on_exec_flag (val);
1187 if (output_done_event)
1188 set_inheritance (output_done_event, val);
1189 if (ioctl_request_event)
1190 set_inheritance (ioctl_request_event, val);
1191 if (ioctl_done_event)
1192 set_inheritance (ioctl_done_event, val);
1194 set_inheritance (inuse, val);
1195 set_inheritance (output_mutex, val);
1196 set_inheritance (input_mutex, val);
1197 set_inheritance (input_available_event, val);
1198 set_inheritance (output_handle, val);
1202 fhandler_tty_common::fixup_after_fork (HANDLE parent)
1204 fhandler_termios::fixup_after_fork (parent);
1205 if (output_done_event)
1206 fork_fixup (parent, output_done_event, "output_done_event");
1207 if (ioctl_request_event)
1208 fork_fixup (parent, ioctl_request_event, "ioctl_request_event");
1209 if (ioctl_done_event)
1210 fork_fixup (parent, ioctl_done_event, "ioctl_done_event");
1212 fork_fixup (parent, output_mutex, "output_mutex");
1214 fork_fixup (parent, input_mutex, "input_mutex");
1215 if (input_available_event)
1216 fork_fixup (parent, input_available_event, "input_available_event");
1217 fork_fixup (parent, inuse, "inuse");
1221 fhandler_pty_master::set_close_on_exec (int val)
1223 fhandler_tty_common::set_close_on_exec (val);
1225 /* FIXME: There is a console handle leak here. */
1226 if (get_ttyp ()->master_pid == GetCurrentProcessId ())
1228 get_ttyp ()->from_slave = get_handle ();
1229 get_ttyp ()->to_slave = get_output_handle ();
1230 termios_printf ("from_slave %p, to_slave %p", get_handle (),
1231 get_output_handle ());
1236 fhandler_tty_master::fixup_after_fork (HANDLE child)
1238 fhandler_pty_master::fixup_after_fork (child);
1239 console->fixup_after_fork (child);
1243 fhandler_tty_master::fixup_after_exec (HANDLE)
1250 fhandler_tty_master::init_console ()
1252 console = (fhandler_console *) cygheap->fdtab.build_fhandler (-1, FH_CONSOLE, "/dev/ttym");
1253 if (console == NULL)
1256 console->init (INVALID_HANDLE_VALUE, GENERIC_READ | GENERIC_WRITE, O_BINARY);
1257 console->set_r_no_interrupt (1);