@@ -47,6 +47,8 @@ details. */
47
47
con.b.srWindow.Top + con.scroll_region.Bottom)
48
48
#define con_is_legacy (shared_console_info && con.is_legacy)
49
49
50
+ #define CONS_THREAD_SYNC " cygcons.thread_sync"
51
+
50
52
const unsigned fhandler_console::MAX_WRITE_CHARS = 16384 ;
51
53
52
54
fhandler_console::console_state NO_COPY *fhandler_console::shared_console_info;
@@ -170,6 +172,143 @@ console_unit::console_unit (HWND me0):
170
172
api_fatal (" console device allocation failure - too many consoles in use, max consoles is 32" );
171
173
}
172
174
175
+ static DWORD WINAPI
176
+ cons_master_thread (VOID *arg)
177
+ {
178
+ fhandler_console *fh = (fhandler_console *) arg;
179
+ tty *ttyp = (tty *) fh->tc ();
180
+ fhandler_console::handle_set_t handle_set;
181
+ fh->get_duplicated_handle_set (&handle_set);
182
+ HANDLE thread_sync_event;
183
+ DuplicateHandle (GetCurrentProcess (), fh->thread_sync_event ,
184
+ GetCurrentProcess (), &thread_sync_event,
185
+ 0 , FALSE , DUPLICATE_SAME_ACCESS);
186
+ SetEvent (thread_sync_event);
187
+ /* Do not touch class members after here because the class instance
188
+ may have been destroyed. */
189
+ fhandler_console::cons_master_thread (&handle_set, ttyp);
190
+ fhandler_console::close_handle_set (&handle_set);
191
+ SetEvent (thread_sync_event);
192
+ CloseHandle (thread_sync_event);
193
+ return 0 ;
194
+ }
195
+
196
+ /* This thread processes signals derived from input messages.
197
+ Without this thread, those signals can be handled only when
198
+ the process calls read() or select(). This thread reads input
199
+ records, processes signals and removes corresponding record.
200
+ The other input records are kept back for read() or select(). */
201
+ void
202
+ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp)
203
+ {
204
+ DWORD output_stopped_at = 0 ;
205
+ while (con.owner == myself->pid )
206
+ {
207
+ DWORD total_read, n, i, j;
208
+ INPUT_RECORD input_rec[INREC_SIZE];
209
+
210
+ WaitForSingleObject (p->input_mutex , INFINITE);
211
+ total_read = 0 ;
212
+ switch (cygwait (p->input_handle , (DWORD) 0 ))
213
+ {
214
+ case WAIT_OBJECT_0:
215
+ ReadConsoleInputA (p->input_handle ,
216
+ input_rec, INREC_SIZE, &total_read);
217
+ break ;
218
+ case WAIT_TIMEOUT:
219
+ case WAIT_SIGNALED:
220
+ case WAIT_CANCELED:
221
+ break ;
222
+ default : /* Error */
223
+ ReleaseMutex (p->input_mutex );
224
+ return ;
225
+ }
226
+ for (i = 0 ; i < total_read; i++)
227
+ {
228
+ const char c = input_rec[i].Event .KeyEvent .uChar .AsciiChar ;
229
+ bool processed = false ;
230
+ termios &ti = ttyp->ti ;
231
+ switch (input_rec[i].EventType )
232
+ {
233
+ case KEY_EVENT:
234
+ if (ti.c_lflag & ISIG)
235
+ {
236
+ int sig = 0 ;
237
+ if (CCEQ (ti.c_cc [VINTR], c))
238
+ sig = SIGINT;
239
+ else if (CCEQ (ti.c_cc [VQUIT], c))
240
+ sig = SIGQUIT;
241
+ else if (CCEQ (ti.c_cc [VSUSP], c))
242
+ sig = SIGTSTP;
243
+ if (sig && input_rec[i].Event .KeyEvent .bKeyDown )
244
+ {
245
+ ttyp->kill_pgrp (sig);
246
+ ttyp->output_stopped = false ;
247
+ /* Discard type ahead input */
248
+ goto skip_writeback;
249
+ }
250
+ }
251
+ if (ti.c_iflag & IXON)
252
+ {
253
+ if (CCEQ (ti.c_cc [VSTOP], c))
254
+ {
255
+ if (!ttyp->output_stopped
256
+ && input_rec[i].Event .KeyEvent .bKeyDown )
257
+ {
258
+ ttyp->output_stopped = true ;
259
+ output_stopped_at = i;
260
+ }
261
+ processed = true ;
262
+ }
263
+ else if (CCEQ (ti.c_cc [VSTART], c))
264
+ {
265
+ restart_output:
266
+ if (input_rec[i].Event .KeyEvent .bKeyDown )
267
+ ttyp->output_stopped = false ;
268
+ processed = true ;
269
+ }
270
+ else if ((ti.c_iflag & IXANY) && ttyp->output_stopped
271
+ && c && i >= output_stopped_at)
272
+ goto restart_output;
273
+ }
274
+ break ;
275
+ case WINDOW_BUFFER_SIZE_EVENT:
276
+ SHORT y = con.dwWinSize .Y ;
277
+ SHORT x = con.dwWinSize .X ;
278
+ con.fillin (p->output_handle );
279
+ if (y != con.dwWinSize .Y || x != con.dwWinSize .X )
280
+ {
281
+ con.scroll_region .Top = 0 ;
282
+ con.scroll_region .Bottom = -1 ;
283
+ if (wincap.has_con_24bit_colors () && !con_is_legacy)
284
+ { /* Fix tab position */
285
+ /* Re-setting ENABLE_VIRTUAL_TERMINAL_PROCESSING
286
+ fixes the tab position. */
287
+ request_xterm_mode_output (false , p);
288
+ request_xterm_mode_output (true , p);
289
+ }
290
+ ttyp->kill_pgrp (SIGWINCH);
291
+ }
292
+ processed = true ;
293
+ break ;
294
+ }
295
+ if (processed)
296
+ { /* Remove corresponding record. */
297
+ for (j = i; j < total_read - 1 ; j++)
298
+ input_rec[j] = input_rec[j + 1 ];
299
+ total_read--;
300
+ i--;
301
+ }
302
+ }
303
+ if (total_read)
304
+ /* Write back input records other than interrupt. */
305
+ WriteConsoleInput (p->input_handle , input_rec, total_read, &n);
306
+ skip_writeback:
307
+ ReleaseMutex (p->input_mutex );
308
+ cygwait (40 );
309
+ }
310
+ }
311
+
173
312
bool
174
313
fhandler_console::set_unit ()
175
314
{
@@ -1194,6 +1333,15 @@ fhandler_console::open (int flags, mode_t)
1194
1333
debug_printf (" opened conin$ %p, conout$ %p" , get_handle (),
1195
1334
get_output_handle ());
1196
1335
1336
+ if (myself->pid == con.owner )
1337
+ {
1338
+ char name[MAX_PATH];
1339
+ shared_name (name, CONS_THREAD_SYNC, get_minor ());
1340
+ thread_sync_event = CreateEvent (NULL , FALSE , FALSE , name);
1341
+ new cygthread (::cons_master_thread, this , " consm" );
1342
+ WaitForSingleObject (thread_sync_event, INFINITE);
1343
+ CloseHandle (thread_sync_event);
1344
+ }
1197
1345
return 1 ;
1198
1346
}
1199
1347
@@ -1230,6 +1378,16 @@ fhandler_console::close ()
1230
1378
1231
1379
release_output_mutex ();
1232
1380
1381
+ if (con.owner == myself->pid )
1382
+ {
1383
+ char name[MAX_PATH];
1384
+ shared_name (name, CONS_THREAD_SYNC, get_minor ());
1385
+ thread_sync_event = OpenEvent (MAXIMUM_ALLOWED, FALSE , name);
1386
+ con.owner = 0 ;
1387
+ WaitForSingleObject (thread_sync_event, INFINITE);
1388
+ CloseHandle (thread_sync_event);
1389
+ }
1390
+
1233
1391
CloseHandle (input_mutex);
1234
1392
input_mutex = NULL ;
1235
1393
CloseHandle (output_mutex);
@@ -1539,7 +1697,7 @@ fhandler_console::tcgetattr (struct termios *t)
1539
1697
}
1540
1698
1541
1699
fhandler_console::fhandler_console (fh_devices unit) :
1542
- fhandler_termios (), input_ready (false ),
1700
+ fhandler_termios (), input_ready (false ), thread_sync_event ( NULL ),
1543
1701
input_mutex (NULL ), output_mutex (NULL )
1544
1702
{
1545
1703
if (unit > 0 )
@@ -3022,6 +3180,14 @@ fhandler_console::write (const void *vsrc, size_t len)
3022
3180
if (bg <= bg_eof)
3023
3181
return (ssize_t ) bg;
3024
3182
3183
+ if (get_ttyp ()->output_stopped && is_nonblocking ())
3184
+ {
3185
+ set_errno (EAGAIN);
3186
+ return -1 ;
3187
+ }
3188
+ while (get_ttyp ()->output_stopped )
3189
+ cygwait (10 );
3190
+
3025
3191
acquire_attach_mutex (INFINITE);
3026
3192
push_process_state process_state (PID_TTYOU);
3027
3193
acquire_output_mutex (INFINITE);
@@ -3352,6 +3518,15 @@ fhandler_console::write (const void *vsrc, size_t len)
3352
3518
return len;
3353
3519
}
3354
3520
3521
+ void
3522
+ fhandler_console::doecho (const void *str, DWORD len)
3523
+ {
3524
+ bool stopped = get_ttyp ()->output_stopped ;
3525
+ get_ttyp ()->output_stopped = false ;
3526
+ write (str, len);
3527
+ get_ttyp ()->output_stopped = stopped;
3528
+ }
3529
+
3355
3530
static const struct {
3356
3531
int vk;
3357
3532
const char *val[4 ];
0 commit comments