On Thu, 17 Mar 2022 20:40:15 +0200
Orgad Shaneh wrote:
> On Fri, Mar 11, 2022 at 11:36 PM Takashi Yano <takashi.y...@nifty.ne.jp> 
> wrote:
> > I looked into this problem and found the cause.
> > This seems to be due to a bug of fsync(). Cygwin's fsync()
> > flushes the console input buffer unlike linux.
> >
> > I will propose a patch for this issue.
> >
> > --
> > Takashi Yano <takashi.y...@nifty.ne.jp>
> 
> Thank you very much. Looks better now.
> 
> I'm sorry for nudging, but on msys2 I still get frequent mistypes when
> typing fast.
> 
> I (still) don't have a consistent reproduction, but if I get it
> correctly, it looks like one or more characters I type right when the
> prompt appears show up before the buffered characters.
> 
> For instance, I run git fetch, and while it is running I type git
> status, *sometimes* 1-2 characters "pop" to the left, so I get
> something like tgit satus.
> 
> I wasn't able to reproduce it with cygwin, but on msys2 (with cygwin
> 3.3 branch merged in) it happens to me all the time :/

Thansk for the report.

I cloned the msys2-runtime repository from
https://github.com/msys2/msys2-runtime
and applied patches in cygwin-3_3-branch against msys2-3_3_4-release
branch. The patches applied are listed in cygwin-3_3-branch-merged.log
attached. A few patches, which are not actually in cygwin-3_3-branch,
are also applied just for avoiding conflict easily.

However, I cannot reproduce your problem. Have you surely applied the
following patches especially important for this issue?

Could you please also check if the code of cons_master_thread() in
fhandler_console.cc exactly matches with cons_master_thread.cc attached?

commit 4d0721a66f94427fa14601d0c58a0762709b5bf2
Author: Takashi Yano <takashi.y...@nifty.ne.jp>
Date:   Fri Feb 25 17:10:03 2022 +0900

    Cygwin: console: Prevent the order of typeahead input from swapped.

    - If a lot of keys are typed very quickly in the app which does
      not read console, the order of input keys in console input buffer
      occasionally swapped. Although this extremely rarely happens,
      is obviously a bug of cons_master_thread. This patch fixes the
      issue.

commit f48870148c7ebcaf8163b08a040d15ef048f4e94
Author: Takashi Yano <takashi.y...@nifty.ne.jp>
Date:   Mon Feb 28 20:02:01 2022 +0900

    Cygwin: console: Improve the code to avoid typeahead key swapping.

    - The commit "Cygwin: console: Prevent the order of typeahead input
      from swapped." did not fully resolve the issue. If keys are typed
      during input buffer fix, the order of key event may be swapped.
      This patch fixes the issue again.

commit 6e872adb9f153ba0504c898a91ac8dcf0ed7e68a
Author: Takashi Yano <takashi.y...@nifty.ne.jp>
Date:   Wed Mar 2 09:55:52 2022 +0900

    Cygwin: console: Prevent special keys processing from drop.

    - There was a potential risk to drop special key processing when
      process_input_messsage() is called intermittently. This patch
      fixes the issue.

commit d88768187a72662d1692ee279e7dea3e948d256e
Author: Takashi Yano <takashi.y...@nifty.ne.jp>
Date:   Wed Mar 2 11:08:27 2022 +0900

    Cygwin: console: Fix a bug from comparison between int and DWORD.

commit cef38f41f2ce0510855bb4b872c7f6514f6deca5
Author: Takashi Yano <takashi.y...@nifty.ne.jp>
Date:   Wed Mar 2 16:00:31 2022 +0900

    Cygwin: console, pty: Revamp the acquire/release_attach_mutex timing.

    - This patch revises the acquiring/releasing timing for attach_mutex
      to make the period in which it is being acquired shorter. Further,
      acquiring/releasing are added to where they are missing but needed.

-- 
Takashi Yano <takashi.y...@nifty.ne.jp>

Attachment: cygwin-3_3-branch-merged.log
Description: Binary data

/* This thread processes signals derived from input messages.
   Without this thread, those signals can be handled only when
   the process calls read() or select(). This thread reads input
   records, processes signals and removes corresponding record.
   The other input records are kept back for read() or select(). */
void
fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp)
{
  const int additional_space = 128; /* Possible max number of incoming events
				       during the process. Additional space
				       should be left for writeback fix. */
  const int inrec_size = INREC_SIZE + additional_space;
  struct m
  {
    inline static size_t bytes (size_t n)
      {
	return sizeof (INPUT_RECORD) * n;
      }
  };
  termios &ti = ttyp->ti;
  while (con.owner == myself->pid)
    {
      DWORD total_read, n, i;
      INPUT_RECORD input_rec[inrec_size];

      if (con.disable_master_thread)
	{
	  cygwait (40);
	  continue;
	}

      WaitForSingleObject (p->input_mutex, mutex_timeout);
      total_read = 0;
      bool nowait = false;
      switch (cygwait (p->input_handle, (DWORD) 0))
	{
	case WAIT_OBJECT_0:
	  acquire_attach_mutex (mutex_timeout);
	  ReadConsoleInputW (p->input_handle,
			     input_rec, INREC_SIZE, &total_read);
	  if (total_read == INREC_SIZE /* Working space full */
	      && cygwait (p->input_handle, (DWORD) 0) == WAIT_OBJECT_0)
	    {
	      const int incr = min (con.num_processed, additional_space);
	      ReadConsoleInputW (p->input_handle,
				 input_rec + total_read, incr, &n);
	      /* Discard oldest n events. */
	      memmove (input_rec, input_rec + n, m::bytes (total_read));
	      con.num_processed -= n;
	      nowait = true;
	    }
	  release_attach_mutex ();
	  break;
	case WAIT_TIMEOUT:
	  con.num_processed = 0;
	case WAIT_SIGNALED:
	case WAIT_CANCELED:
	  break;
	default: /* Error */
	  ReleaseMutex (p->input_mutex);
	  return;
	}
      /* If ENABLE_VIRTUAL_TERMINAL_INPUT is not set, changing
	 window height does not generate WINDOW_BUFFER_SIZE_EVENT.
	 Therefore, check windows size every time here. */
      if (!wincap.has_con_24bit_colors () || con_is_legacy)
	{
	  SHORT y = con.dwWinSize.Y;
	  SHORT x = con.dwWinSize.X;
	  con.fillin (p->output_handle);
	  if (y != con.dwWinSize.Y || x != con.dwWinSize.X)
	    {
	      con.scroll_region.Top = 0;
	      con.scroll_region.Bottom = -1;
	      ttyp->kill_pgrp (SIGWINCH);
	    }
	}
      for (i = con.num_processed; i < total_read; i++)
	{
	  wchar_t wc;
	  char c;
	  bool processed = false;
	  switch (input_rec[i].EventType)
	    {
	    case KEY_EVENT:
	      if (!input_rec[i].Event.KeyEvent.bKeyDown)
		continue;
	      wc = input_rec[i].Event.KeyEvent.uChar.UnicodeChar;
	      if (!wc || (wint_t) wc >= 0x80)
		continue;
	      c = (char) wc;
	      switch (process_sigs (c, ttyp, NULL))
		{
		case signalled:
		case not_signalled_but_done:
		case done_with_debugger:
		  processed = true;
		  ttyp->output_stopped = false;
		  if (ti.c_lflag & NOFLSH)
		    goto remove_record;
		  con.num_processed = 0;
		  goto skip_writeback;
		default: /* not signalled */
		  break;
		}
	      processed = process_stop_start (c, ttyp);
	      break;
	    case WINDOW_BUFFER_SIZE_EVENT:
	      SHORT y = con.dwWinSize.Y;
	      SHORT x = con.dwWinSize.X;
	      con.fillin (p->output_handle);
	      if (y != con.dwWinSize.Y || x != con.dwWinSize.X)
		{
		  con.scroll_region.Top = 0;
		  con.scroll_region.Bottom = -1;
		  if (wincap.has_con_24bit_colors () && !con_is_legacy)
		    fix_tab_position (p->output_handle);
		  ttyp->kill_pgrp (SIGWINCH);
		}
	      processed = true;
	      break;
	    }
remove_record:
	  if (processed)
	    { /* Remove corresponding record. */
	      if (total_read > i + 1)
		memmove (input_rec + i, input_rec + i + 1,
			 m::bytes (total_read - i - 1));
	      total_read--;
	      i--;
	    }
	}
      con.num_processed = total_read;
      if (total_read)
	{
	  do
	    {
	      INPUT_RECORD tmp[inrec_size];
	      /* Writeback input records other than interrupt. */
	      acquire_attach_mutex (mutex_timeout);
	      WriteConsoleInputW (p->input_handle, input_rec, total_read, &n);
	      /* Check if writeback was successfull. */
	      PeekConsoleInputW (p->input_handle, tmp, inrec_size, &n);
	      release_attach_mutex ();
	      if (n < total_read)
		break; /* Someone has read input without acquiring
			  input_mutex. ConEmu cygwin-connector? */
	      if (memcmp (input_rec, tmp, m::bytes (total_read)) == 0)
		break; /* OK */
	      /* Try to fix */
	      DWORD incr = n - total_read;
	      DWORD ofst;
	      for (ofst = 1; ofst <= incr; ofst++)
		if (memcmp (input_rec, tmp + ofst, m::bytes (total_read)) == 0)
		  {
		    acquire_attach_mutex (mutex_timeout);
		    ReadConsoleInputW (p->input_handle, tmp, inrec_size, &n);
		    release_attach_mutex ();
		    memcpy (input_rec, tmp + ofst, m::bytes (total_read));
		    memcpy (input_rec + total_read, tmp, m::bytes (ofst));
		    if (n > ofst + total_read)
		      memcpy (input_rec + total_read + ofst,
			      tmp + ofst + total_read,
			      m::bytes (n - (ofst + total_read)));
		    total_read = n;
		    break;
		  }
	      if (ofst > incr)
		break; /* Writeback was not atomic. Or someone has read
			  input without acquiring input_mutex.
			  Giving up because hard to fix. */
	    }
	  while (true);
	}
skip_writeback:
      ReleaseMutex (p->input_mutex);
      if (!nowait)
	cygwait (40);
    }
}
-- 
Problem reports:      https://cygwin.com/problems.html
FAQ:                  https://cygwin.com/faq/
Documentation:        https://cygwin.com/docs.html
Unsubscribe info:     https://cygwin.com/ml/#unsubscribe-simple

Reply via email to