36
36
* multiple Tcl channels corresponding to a single console handle.
37
37
*
38
38
* - Even with multiple threads, more than one file event handler is
39
- * unlikely. It does not make sense for multiple threads to register
40
- * handlers for stdin because the input would be randomly fragmented amongst
41
- * the threads.
39
+ * unlikely. It does not make sense for multiple threads to register
40
+ * handlers for stdin because the input would be randomly fragmented amongst
41
+ * the threads.
42
42
*
43
43
* Various design factors are driven by the above, e.g. use of lists instead
44
44
* of hash tables (at most 3 console handles) and use of global instead of
58
58
*
59
59
* If multiple threads are reading from stdin, the input is sprayed in
60
60
* random fashion. This is not good application design and hence no plan to
61
- * address this (not clear what should be done even in theory)
61
+ * address this (not clear what should be done even in theory).
62
62
*
63
63
* For output, we do not restrict all output to the console writer threads.
64
64
* See ConsoleOutputProc for the conditions.
@@ -94,14 +94,18 @@ static int gInitialized = 0;
94
94
* and bufPtr[0]:bufPtr[length - (size-start)].
95
95
*/
96
96
typedef struct RingBuffer {
97
- char * bufPtr ; /* Pointer to buffer storage */
98
- Tcl_Size capacity ; /* Size of the buffer in RingBufferChar */
99
- Tcl_Size start ; /* Start of the data within the buffer. */
100
- Tcl_Size length ; /* Number of RingBufferChar*/
97
+ char * bufPtr ; /* Pointer to buffer storage */
98
+ Tcl_Size capacity ; /* Size of the buffer in RingBufferChar */
99
+ Tcl_Size start ; /* Start of the data within the buffer. */
100
+ Tcl_Size length ; /* Number of RingBufferChar*/
101
101
} RingBuffer ;
102
- #define RingBufferLength (ringPtr_ ) ((ringPtr_)->length)
103
- #define RingBufferHasFreeSpace (ringPtr_ ) ((ringPtr_)->length < (ringPtr_)->capacity)
104
- #define RINGBUFFER_ASSERT (ringPtr_ ) assert(RingBufferCheck(ringPtr_))
102
+
103
+ #define RingBufferLength (ringPtr_ ) \
104
+ ((ringPtr_)->length)
105
+ #define RingBufferHasFreeSpace (ringPtr_ ) \
106
+ ((ringPtr_)->length < (ringPtr_)->capacity)
107
+ #define RINGBUFFER_ASSERT (ringPtr_ ) \
108
+ assert(RingBufferCheck(ringPtr_))
105
109
106
110
/*
107
111
* The Win32 console API does not support non-blocking I/O in any form. Thus
@@ -126,28 +130,34 @@ typedef struct RingBuffer {
126
130
*/
127
131
typedef struct ConsoleHandleInfo {
128
132
struct ConsoleHandleInfo * nextPtr ; /* Process-global list of consoles */
129
- HANDLE console ; /* Console handle */
130
- HANDLE consoleThread ; /* Handle to thread doing actual i/o on the console */
131
- SRWLOCK lock ; /* Controls access to this structure.
132
- * Cheaper than CRITICAL_SECTION but note does not
133
- * support recursive locks or Try* style attempts.*/
133
+ HANDLE console ; /* Console handle */
134
+ HANDLE consoleThread ; /* Handle to thread doing actual i/o on the
135
+ * console */
136
+ SRWLOCK lock ; /* Controls access to this structure. Cheaper
137
+ * than CRITICAL_SECTION but note does not
138
+ * support recursive locks or Try* style
139
+ * attempts. */
134
140
CONDITION_VARIABLE consoleThreadCV ;/* For awakening console thread */
135
141
CONDITION_VARIABLE interpThreadCV ; /* For awakening interpthread(s) */
136
- RingBuffer buffer ; /* Buffer for data transferred between console
137
- * threads and Tcl threads. For input consoles,
138
- * written by the console thread and read by Tcl
139
- * threads. The converse for output threads */
140
- DWORD initMode ; /* Initial console mode. */
141
- DWORD lastError ; /* An error caused by the last background
142
- * operation. Set to 0 if no error has been
143
- * detected. */
144
- int numRefs ; /* See comments above */
145
- int permissions ; /* TCL_READABLE for input consoles, TCL_WRITABLE
146
- * for output. Only one or the other can be set. */
147
- int flags ;
148
- #define CONSOLE_DATA_AWAITED 0x0001 /* An interpreter is awaiting data */
142
+ RingBuffer buffer ; /* Buffer for data transferred between console
143
+ * threads and Tcl threads. For input consoles,
144
+ * written by the console thread and read by Tcl
145
+ * threads. The converse for output threads */
146
+ DWORD initMode ; /* Initial console mode. */
147
+ DWORD lastError ; /* An error caused by the last background
148
+ * operation. Set to 0 if no error has been
149
+ * detected. */
150
+ int numRefs ; /* See comments above */
151
+ int permissions ; /* TCL_READABLE for input consoles,
152
+ * TCL_WRITABLE for output. Only one or the
153
+ * other can be set. */
154
+ int flags ; /* State flags */
149
155
} ConsoleHandleInfo ;
150
156
157
+ enum ConsoleHandleInfoFlags {
158
+ CONSOLE_DATA_AWAITED = 1 /* An interpreter is awaiting data */
159
+ };
160
+
151
161
/*
152
162
* This structure describes per-instance data for a console based channel.
153
163
*
@@ -190,11 +200,14 @@ typedef struct ConsoleChannelInfo {
190
200
* TCL_WRITABLE, or TCL_EXCEPTION: indicates
191
201
* which events should be reported. */
192
202
int flags ; /* State flags */
193
- #define CONSOLE_EVENT_QUEUED 0x0001 /* Notification event already queued */
194
- #define CONSOLE_ASYNC 0x0002 /* Channel is non-blocking. */
195
- #define CONSOLE_READ_OPS 0x0004 /* Channel supports read-related ops. */
196
203
} ConsoleChannelInfo ;
197
204
205
+ enum ConsoleChannelInfoFlags {
206
+ CONSOLE_EVENT_QUEUED = 1 , /* Notification event already queued */
207
+ CONSOLE_ASYNC = 2 , /* Channel is non-blocking. */
208
+ CONSOLE_READ_OPS = 4 /* Channel supports read-related ops. */
209
+ };
210
+
198
211
/*
199
212
* The following structure is what is added to the Tcl event queue when
200
213
* console events are generated.
@@ -424,7 +437,7 @@ RingBufferIn(
424
437
} else {
425
438
/* No room at the back. Existing data wrap to front. */
426
439
Tcl_Size wrapLen =
427
- ringPtr -> start + ringPtr -> length - ringPtr -> capacity ;
440
+ ringPtr -> start + ringPtr -> length - ringPtr -> capacity ;
428
441
memmove (wrapLen + ringPtr -> bufPtr , srcPtr , srcLen );
429
442
}
430
443
@@ -484,11 +497,8 @@ RingBufferOut(
484
497
} else {
485
498
Tcl_Size wrapLen = dstCapacity - leadLen ;
486
499
if (dstPtr ) {
487
- memmove (dstPtr ,
488
- ringPtr -> start + ringPtr -> bufPtr ,
489
- leadLen );
490
- memmove (
491
- leadLen + dstPtr , ringPtr -> bufPtr , wrapLen );
500
+ memmove (dstPtr , ringPtr -> start + ringPtr -> bufPtr , leadLen );
501
+ memmove (leadLen + dstPtr , ringPtr -> bufPtr , wrapLen );
492
502
}
493
503
ringPtr -> start = wrapLen ;
494
504
}
@@ -539,7 +549,6 @@ ReadConsoleChars(
539
549
Tcl_Size * nCharsReadPtr )
540
550
{
541
551
DWORD nRead ;
542
- BOOL result ;
543
552
544
553
/*
545
554
* If user types a Ctrl-Break or Ctrl-C, ReadConsole will return success
@@ -561,17 +570,15 @@ ReadConsoleChars(
561
570
* or https://github.com/microsoft/terminal/issues/12143
562
571
*/
563
572
nRead = (DWORD )- 1 ;
564
- result = ReadConsoleW (hConsole , lpBuffer , nChars , & nRead , NULL );
565
- if (result ) {
566
- if ((nRead == 0 || nRead == (DWORD )- 1 )
567
- && GetLastError () == ERROR_OPERATION_ABORTED ) {
568
- nRead = 0 ;
569
- }
570
- * nCharsReadPtr = nRead ;
571
- return 0 ;
572
- } else {
573
+ if (!ReadConsoleW (hConsole , lpBuffer , nChars , & nRead , NULL )) {
573
574
return GetLastError ();
574
575
}
576
+ if ((nRead == 0 || nRead == (DWORD )- 1 )
577
+ && GetLastError () == ERROR_OPERATION_ABORTED ) {
578
+ nRead = 0 ;
579
+ }
580
+ * nCharsReadPtr = nRead ;
581
+ return 0 ;
575
582
}
576
583
577
584
/*
@@ -600,20 +607,17 @@ WriteConsoleChars(
600
607
Tcl_Size * nCharsWrittenPtr )
601
608
{
602
609
DWORD nCharsWritten ;
603
- BOOL result ;
604
610
605
611
/* See comments in ReadConsoleChars, not sure that applies here */
606
612
nCharsWritten = (DWORD )- 1 ;
607
- result = WriteConsoleW (hConsole , lpBuffer , nChars , & nCharsWritten , NULL );
608
- if (result ) {
609
- if (nCharsWritten == (DWORD ) - 1 ) {
610
- nCharsWritten = 0 ;
611
- }
612
- * nCharsWrittenPtr = nCharsWritten ;
613
- return 0 ;
614
- } else {
613
+ if (!WriteConsoleW (hConsole , lpBuffer , nChars , & nCharsWritten , NULL )) {
615
614
return GetLastError ();
616
615
}
616
+ if (nCharsWritten == (DWORD ) - 1 ) {
617
+ nCharsWritten = 0 ;
618
+ }
619
+ * nCharsWrittenPtr = nCharsWritten ;
620
+ return 0 ;
617
621
}
618
622
619
623
/*
@@ -787,8 +791,7 @@ ConsoleSetupProc(
787
791
788
792
for (chanInfoPtr = gWatchingChannelList ; block && chanInfoPtr != NULL ;
789
793
chanInfoPtr = chanInfoPtr -> nextWatchingChannelPtr ) {
790
- ConsoleHandleInfo * handleInfoPtr ;
791
- handleInfoPtr = FindConsoleInfo (chanInfoPtr );
794
+ ConsoleHandleInfo * handleInfoPtr = FindConsoleInfo (chanInfoPtr );
792
795
if (handleInfoPtr != NULL ) {
793
796
AcquireSRWLockShared (& handleInfoPtr -> lock );
794
797
/* Remember at most one of READABLE, WRITABLE set */
@@ -1562,10 +1565,9 @@ ConsoleGetHandleProc(
1562
1565
1563
1566
if (chanInfoPtr -> handle == INVALID_HANDLE_VALUE ) {
1564
1567
return TCL_ERROR ;
1565
- } else {
1566
- * handlePtr = chanInfoPtr -> handle ;
1567
- return TCL_OK ;
1568
1568
}
1569
+ * handlePtr = chanInfoPtr -> handle ;
1570
+ return TCL_OK ;
1569
1571
}
1570
1572
1571
1573
/*
@@ -1583,8 +1585,8 @@ ConsoleGetHandleProc(
1583
1585
*
1584
1586
*------------------------------------------------------------------------
1585
1587
*/
1586
- static int
1587
- ConsoleDataAvailable (
1588
+ static int
1589
+ ConsoleDataAvailable (
1588
1590
HANDLE consoleHandle )
1589
1591
{
1590
1592
INPUT_RECORD input [10 ];
@@ -1617,7 +1619,7 @@ ConsoleGetHandleProc(
1617
1619
}
1618
1620
return 0 ;
1619
1621
}
1620
-
1622
+
1621
1623
/*
1622
1624
*----------------------------------------------------------------------
1623
1625
*
@@ -1634,7 +1636,6 @@ ConsoleGetHandleProc(
1634
1636
*
1635
1637
*----------------------------------------------------------------------
1636
1638
*/
1637
-
1638
1639
static DWORD WINAPI
1639
1640
ConsoleReaderThread (
1640
1641
LPVOID arg )
@@ -1968,7 +1969,6 @@ ConsoleWriterThread(
1968
1969
ReleaseSRWLockExclusive (& gConsoleLock );
1969
1970
1970
1971
RingBufferClear (& handleInfoPtr -> buffer );
1971
-
1972
1972
Tcl_Free (handleInfoPtr );
1973
1973
1974
1974
return 0 ;
@@ -2023,12 +2023,12 @@ AllocateConsoleHandleInfo(
2023
2023
SetConsoleMode (consoleHandle , consoleMode );
2024
2024
}
2025
2025
handleInfoPtr -> consoleThread = CreateThread (
2026
- NULL , /* default security descriptor */
2027
- 2 * CONSOLE_BUFFER_SIZE , /* Stack size - gets rounded up to granularity */
2028
- permissions == TCL_READABLE ? ConsoleReaderThread : ConsoleWriterThread ,
2029
- handleInfoPtr , /* Pass to thread */
2030
- 0 , /* Flags - no special cases */
2031
- NULL ); /* Don't care about thread id */
2026
+ NULL , /* default security descriptor */
2027
+ 2 * CONSOLE_BUFFER_SIZE , /* Stack size - gets rounded up to granularity */
2028
+ permissions == TCL_READABLE ? ConsoleReaderThread : ConsoleWriterThread ,
2029
+ handleInfoPtr , /* Pass to thread */
2030
+ 0 , /* Flags - no special cases */
2031
+ NULL ); /* Don't care about thread id */
2032
2032
if (handleInfoPtr -> consoleThread == NULL ) {
2033
2033
/* Note - SRWLock and condition variables do not need finalization */
2034
2034
RingBufferClear (& handleInfoPtr -> buffer );
@@ -2071,14 +2071,15 @@ FindConsoleInfo(
2071
2071
const ConsoleChannelInfo * chanInfoPtr )
2072
2072
{
2073
2073
ConsoleHandleInfo * handleInfoPtr ;
2074
- for (handleInfoPtr = gConsoleHandleInfoList ; handleInfoPtr ; handleInfoPtr = handleInfoPtr -> nextPtr ) {
2074
+ for (handleInfoPtr = gConsoleHandleInfoList ; handleInfoPtr ;
2075
+ handleInfoPtr = handleInfoPtr -> nextPtr ) {
2075
2076
if (handleInfoPtr -> console == chanInfoPtr -> handle ) {
2076
2077
return handleInfoPtr ;
2077
2078
}
2078
2079
}
2079
2080
return NULL ;
2080
2081
}
2081
-
2082
+
2082
2083
/*
2083
2084
*----------------------------------------------------------------------
2084
2085
*
@@ -2258,7 +2259,7 @@ ConsoleThreadActionProc(
2258
2259
*/
2259
2260
static int
2260
2261
ConsoleSetOptionProc (
2261
- void * instanceData , /* File state. */
2262
+ void * instanceData , /* File state. */
2262
2263
Tcl_Interp * interp , /* For error reporting - can be NULL. */
2263
2264
const char * optionName , /* Which option to set? */
2264
2265
const char * value ) /* New value for option. */
@@ -2347,7 +2348,7 @@ ConsoleSetOptionProc(
2347
2348
2348
2349
static int
2349
2350
ConsoleGetOptionProc (
2350
- void * instanceData , /* File state. */
2351
+ void * instanceData , /* File state. */
2351
2352
Tcl_Interp * interp , /* For error reporting - can be NULL. */
2352
2353
const char * optionName , /* Option to get. */
2353
2354
Tcl_DString * dsPtr ) /* Where to store value(s). */
0 commit comments