Skip to content

Commit 746c811

Browse files
committed
Cygwin: console: Allow pasting very long text input.
- Currently, if the text longer than 1024 byte is pasted in console, some of the text is discarded. This patch fixes the issue. Addresses: https://cygwin.com/pipermail/cygwin/2022-June/251764.html
1 parent 27fd806 commit 746c811

File tree

5 files changed

+113
-27
lines changed

5 files changed

+113
-27
lines changed

winsup/cygwin/fhandler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2091,6 +2091,7 @@ class dev_console
20912091
char *cons_rapoi;
20922092
bool cursor_key_app_mode;
20932093
bool disable_master_thread;
2094+
bool master_thread_suspended;
20942095
int num_processed; /* Number of input events in the current input buffer
20952096
already processed by cons_master_thread(). */
20962097

winsup/cygwin/fhandler_console.cc

Lines changed: 94 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,18 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp)
289289
const int additional_space = 128; /* Possible max number of incoming events
290290
during the process. Additional space
291291
should be left for writeback fix. */
292-
const int inrec_size = INREC_SIZE + additional_space;
292+
DWORD inrec_size = INREC_SIZE + additional_space;
293+
INPUT_RECORD *input_rec =
294+
(INPUT_RECORD *) malloc (inrec_size * sizeof (INPUT_RECORD));
295+
INPUT_RECORD *input_tmp =
296+
(INPUT_RECORD *) malloc (inrec_size * sizeof (INPUT_RECORD));
297+
298+
if (!input_rec || !input_tmp)
299+
return; /* Cannot continue */
300+
301+
DWORD inrec_size1 =
302+
wincap.cons_need_small_input_record_buf () ? INREC_SIZE : inrec_size;
303+
293304
struct m
294305
{
295306
inline static size_t bytes (size_t n)
@@ -301,33 +312,62 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp)
301312
while (con.owner == myself->pid)
302313
{
303314
DWORD total_read, n, i;
304-
INPUT_RECORD input_rec[inrec_size];
305315

306316
if (con.disable_master_thread)
307317
{
308318
cygwait (40);
309319
continue;
310320
}
311321

322+
acquire_attach_mutex (mutex_timeout);
323+
GetNumberOfConsoleInputEvents (p->input_handle, &total_read);
324+
release_attach_mutex ();
325+
if (total_read > INREC_SIZE)
326+
{
327+
cygwait (40);
328+
acquire_attach_mutex (mutex_timeout);
329+
GetNumberOfConsoleInputEvents (p->input_handle, &n);
330+
release_attach_mutex ();
331+
if (n < total_read)
332+
{
333+
/* read() seems to be called. Process special keys
334+
in process_input_message (). */
335+
con.master_thread_suspended = true;
336+
continue;
337+
}
338+
total_read = n;
339+
}
340+
con.master_thread_suspended = false;
341+
if (total_read + additional_space > inrec_size)
342+
{
343+
DWORD new_inrec_size = total_read + additional_space;
344+
INPUT_RECORD *new_input_rec = (INPUT_RECORD *)
345+
realloc (input_rec, new_inrec_size * sizeof (INPUT_RECORD));
346+
INPUT_RECORD *new_input_tmp = (INPUT_RECORD *)
347+
realloc (input_tmp, new_inrec_size * sizeof (INPUT_RECORD));
348+
if (new_input_rec && new_input_tmp)
349+
{
350+
inrec_size = new_inrec_size;
351+
input_rec = new_input_rec;
352+
input_tmp = new_input_tmp;
353+
if (!wincap.cons_need_small_input_record_buf ())
354+
inrec_size1 = inrec_size;
355+
}
356+
}
357+
312358
WaitForSingleObject (p->input_mutex, mutex_timeout);
313359
total_read = 0;
314-
bool nowait = false;
315360
switch (cygwait (p->input_handle, (DWORD) 0))
316361
{
317362
case WAIT_OBJECT_0:
318-
acquire_attach_mutex (mutex_timeout);
319-
ReadConsoleInputW (p->input_handle,
320-
input_rec, INREC_SIZE, &total_read);
321-
if (total_read == INREC_SIZE /* Working space full */
322-
&& cygwait (p->input_handle, (DWORD) 0) == WAIT_OBJECT_0)
363+
total_read = 0;
364+
while (cygwait (p->input_handle, (DWORD) 0) == WAIT_OBJECT_0)
323365
{
324-
const int incr = min (con.num_processed, additional_space);
325-
ReadConsoleInputW (p->input_handle,
326-
input_rec + total_read, incr, &n);
327-
/* Discard oldest n events. */
328-
memmove (input_rec, input_rec + n, m::bytes (total_read));
329-
con.num_processed -= n;
330-
nowait = true;
366+
DWORD len;
367+
ReadConsoleInputW (p->input_handle, input_rec + total_read,
368+
min (inrec_size - total_read, inrec_size1),
369+
&len);
370+
total_read += len;
331371
}
332372
release_attach_mutex ();
333373
break;
@@ -416,33 +456,56 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp)
416456
{
417457
do
418458
{
419-
INPUT_RECORD tmp[inrec_size];
420459
/* Writeback input records other than interrupt. */
421460
acquire_attach_mutex (mutex_timeout);
422-
WriteConsoleInputW (p->input_handle, input_rec, total_read, &n);
461+
n = 0;
462+
while (n < total_read)
463+
{
464+
DWORD len;
465+
WriteConsoleInputW (p->input_handle, input_rec + n,
466+
min (total_read - n, inrec_size1), &len);
467+
n += len;
468+
}
423469
/* Check if writeback was successfull. */
424-
PeekConsoleInputW (p->input_handle, tmp, inrec_size, &n);
470+
PeekConsoleInputW (p->input_handle, input_tmp, inrec_size1, &n);
425471
release_attach_mutex ();
426-
if (n < total_read)
472+
if (n < min (total_read, inrec_size1))
427473
break; /* Someone has read input without acquiring
428474
input_mutex. ConEmu cygwin-connector? */
429-
if (inrec_eq (input_rec, tmp, total_read))
475+
if (inrec_eq (input_rec, input_tmp,
476+
min (total_read, inrec_size1)))
430477
break; /* OK */
431478
/* Try to fix */
432479
acquire_attach_mutex (mutex_timeout);
433-
ReadConsoleInputW (p->input_handle, tmp, inrec_size, &n);
480+
n = 0;
481+
while (cygwait (p->input_handle, (DWORD) 0) == WAIT_OBJECT_0)
482+
{
483+
DWORD len;
484+
ReadConsoleInputW (p->input_handle, input_tmp + n,
485+
min (inrec_size - n, inrec_size1), &len);
486+
n += len;
487+
}
434488
release_attach_mutex ();
435489
for (DWORD i = 0, j = 0; j < n; j++)
436-
if (i == total_read || !inrec_eq (input_rec + i, tmp + j, 1))
490+
if (i == total_read
491+
|| !inrec_eq (input_rec + i, input_tmp + j, 1))
437492
{
438493
if (total_read + j - i >= n)
439494
{ /* Something is wrong. Giving up. */
440495
acquire_attach_mutex (mutex_timeout);
441-
WriteConsoleInputW (p->input_handle, tmp, n, &n);
496+
WriteConsoleInputW (p->input_handle, input_tmp, n, &n);
497+
n = 0;
498+
while (n < total_read)
499+
{
500+
DWORD len;
501+
WriteConsoleInputW (p->input_handle, input_rec + n,
502+
min (total_read - n, inrec_size1), &len);
503+
n += len;
504+
}
442505
release_attach_mutex ();
443506
goto skip_writeback;
444507
}
445-
input_rec[total_read + j - i] = tmp[j];
508+
input_rec[total_read + j - i] = input_tmp[j];
446509
}
447510
else
448511
i++;
@@ -452,9 +515,10 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp)
452515
}
453516
skip_writeback:
454517
ReleaseMutex (p->input_mutex);
455-
if (!nowait)
456-
cygwait (40);
518+
cygwait (40);
457519
}
520+
free (input_rec);
521+
free (input_tmp);
458522
}
459523

460524
bool
@@ -549,6 +613,7 @@ fhandler_console::setup ()
549613
shared_console_info->tty_min_state.is_console = true;
550614
con.cursor_key_app_mode = false;
551615
con.disable_master_thread = true;
616+
con.master_thread_suspended = false;
552617
con.num_processed = 0;
553618
}
554619
}
@@ -602,6 +667,8 @@ fhandler_console::set_input_mode (tty::cons_mode m, const termios *t,
602667
break;
603668
case tty::cygwin:
604669
flags |= ENABLE_WINDOW_INPUT;
670+
if (con.master_thread_suspended)
671+
flags |= ENABLE_PROCESSED_INPUT;
605672
if (wincap.has_con_24bit_colors () && !con_is_legacy)
606673
flags |= ENABLE_VIRTUAL_TERMINAL_INPUT;
607674
else
@@ -4173,5 +4240,5 @@ fhandler_console::close_handle_set (handle_set_t *p)
41734240
bool
41744241
fhandler_console::need_console_handler ()
41754242
{
4176-
return con.disable_master_thread;
4243+
return con.disable_master_thread || con.master_thread_suspended;
41774244
}

winsup/cygwin/release/3.3.6

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ Bug Fixes
2222
if events are inquired in multiple pollfd entries on the same fd
2323
at the same time.
2424
Addresses: https://cygwin.com/pipermail/cygwin/2022-June/251732.html
25+
26+
- Fix a console problem that the text longer than 1024 bytes cannot
27+
be pasted correctly.
28+
Addresses: https://cygwin.com/pipermail/cygwin/2022-June/251764.html

winsup/cygwin/wincap.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
4545
has_query_process_handle_info:false,
4646
has_con_broken_tabs:false,
4747
has_broken_attach_console:true,
48+
cons_need_small_input_record_buf:true,
4849
},
4950
};
5051

@@ -75,6 +76,7 @@ wincaps wincap_8 __attribute__((section (".cygwin_dll_common"), shared)) = {
7576
has_query_process_handle_info:true,
7677
has_con_broken_tabs:false,
7778
has_broken_attach_console:false,
79+
cons_need_small_input_record_buf:false,
7880
},
7981
};
8082

@@ -105,6 +107,7 @@ wincaps wincap_8_1 __attribute__((section (".cygwin_dll_common"), shared)) = {
105107
has_query_process_handle_info:true,
106108
has_con_broken_tabs:false,
107109
has_broken_attach_console:false,
110+
cons_need_small_input_record_buf:false,
108111
},
109112
};
110113

@@ -135,6 +138,7 @@ wincaps wincap_10_1507 __attribute__((section (".cygwin_dll_common"), shared))
135138
has_query_process_handle_info:true,
136139
has_con_broken_tabs:false,
137140
has_broken_attach_console:false,
141+
cons_need_small_input_record_buf:false,
138142
},
139143
};
140144

@@ -165,6 +169,7 @@ wincaps wincap_10_1607 __attribute__((section (".cygwin_dll_common"), shared))
165169
has_query_process_handle_info:true,
166170
has_con_broken_tabs:false,
167171
has_broken_attach_console:false,
172+
cons_need_small_input_record_buf:false,
168173
},
169174
};
170175

@@ -195,6 +200,7 @@ wincaps wincap_10_1703 __attribute__((section (".cygwin_dll_common"), shared)) =
195200
has_query_process_handle_info:true,
196201
has_con_broken_tabs:true,
197202
has_broken_attach_console:false,
203+
cons_need_small_input_record_buf:false,
198204
},
199205
};
200206

@@ -225,6 +231,7 @@ wincaps wincap_10_1709 __attribute__((section (".cygwin_dll_common"), shared)) =
225231
has_query_process_handle_info:true,
226232
has_con_broken_tabs:true,
227233
has_broken_attach_console:false,
234+
cons_need_small_input_record_buf:false,
228235
},
229236
};
230237

@@ -255,6 +262,7 @@ wincaps wincap_10_1803 __attribute__((section (".cygwin_dll_common"), shared)) =
255262
has_query_process_handle_info:true,
256263
has_con_broken_tabs:true,
257264
has_broken_attach_console:false,
265+
cons_need_small_input_record_buf:false,
258266
},
259267
};
260268

@@ -285,6 +293,7 @@ wincaps wincap_10_1809 __attribute__((section (".cygwin_dll_common"), shared)) =
285293
has_query_process_handle_info:true,
286294
has_con_broken_tabs:true,
287295
has_broken_attach_console:false,
296+
cons_need_small_input_record_buf:false,
288297
},
289298
};
290299

@@ -315,6 +324,7 @@ wincaps wincap_10_1903 __attribute__((section (".cygwin_dll_common"), shared)) =
315324
has_query_process_handle_info:true,
316325
has_con_broken_tabs:true,
317326
has_broken_attach_console:false,
327+
cons_need_small_input_record_buf:false,
318328
},
319329
};
320330

@@ -345,6 +355,7 @@ wincaps wincap_10_2004 __attribute__((section (".cygwin_dll_common"), shared)) =
345355
has_query_process_handle_info:true,
346356
has_con_broken_tabs:true,
347357
has_broken_attach_console:false,
358+
cons_need_small_input_record_buf:false,
348359
},
349360
};
350361

@@ -375,6 +386,7 @@ wincaps wincap_11 __attribute__((section (".cygwin_dll_common"), shared)) = {
375386
has_query_process_handle_info:true,
376387
has_con_broken_tabs:false,
377388
has_broken_attach_console:false,
389+
cons_need_small_input_record_buf:false,
378390
},
379391
};
380392

winsup/cygwin/wincap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct wincaps
3939
unsigned has_query_process_handle_info : 1;
4040
unsigned has_con_broken_tabs : 1;
4141
unsigned has_broken_attach_console : 1;
42+
unsigned cons_need_small_input_record_buf : 1;
4243
};
4344
};
4445

@@ -97,6 +98,7 @@ class wincapc
9798
bool IMPLEMENT (has_query_process_handle_info)
9899
bool IMPLEMENT (has_con_broken_tabs)
99100
bool IMPLEMENT (has_broken_attach_console)
101+
bool IMPLEMENT (cons_need_small_input_record_buf)
100102

101103
void disable_case_sensitive_dirs ()
102104
{

0 commit comments

Comments
 (0)