| ︙ | | |
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
-
-
-
-
-
-
-
-
-
-
+
+
+
|
#define CONSOLE_BUFFER_SIZE 8000 /* In bytes */
#endif
/*
* Ring buffer for storing data. Actual data is from bufPtr[start]:bufPtr[size-1]
* and bufPtr[0]:bufPtr[length - (size-start)].
*/
#if TCL_MAJOR_VERSION > 8
typedef ptrdiff_t RingSizeT; /* Tcl9 TODO */
#define RingSizeT_MAX PTRDIFF_MAX
#else
typedef int RingSizeT;
#define RingSizeT_MAX INT_MAX
#endif
typedef struct RingBuffer {
char *bufPtr; /* Pointer to buffer storage */
RingSizeT capacity; /* Size of the buffer in RingBufferChar */
RingSizeT start; /* Start of the data within the buffer. */
RingSizeT length; /* Number of RingBufferChar*/
Tcl_Size capacity; /* Size of the buffer in RingBufferChar */
Tcl_Size start; /* Start of the data within the buffer. */
Tcl_Size length; /* Number of RingBufferChar*/
} RingBuffer;
#define RingBufferLength(ringPtr_) ((ringPtr_)->length)
#define RingBufferHasFreeSpace(ringPtr_) ((ringPtr_)->length < (ringPtr_)->capacity)
#define RINGBUFFER_ASSERT(ringPtr_) assert(RingBufferCheck(ringPtr_))
/*
* The Win32 console API does not support non-blocking I/O in any form. Thus
|
| ︙ | | |
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
|
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
|
-
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
|
Tcl_Interp *interp, const char *optionName,
const char *value);
static void ConsoleSetupProc(void *clientData, int flags);
static void ConsoleWatchProc(void *instanceData, int mask);
static void ProcExitHandler(void *clientData);
static void ConsoleThreadActionProc(void *instanceData, int action);
static DWORD ReadConsoleChars(HANDLE hConsole, WCHAR *lpBuffer,
RingSizeT nChars, RingSizeT *nCharsReadPtr);
Tcl_Size nChars, Tcl_Size *nCharsReadPtr);
static DWORD WriteConsoleChars(HANDLE hConsole,
const WCHAR *lpBuffer, RingSizeT nChars,
RingSizeT *nCharsWritten);
static void RingBufferInit(RingBuffer *ringPtr, RingSizeT capacity);
const WCHAR *lpBuffer, Tcl_Size nChars,
Tcl_Size *nCharsWritten);
static void RingBufferInit(RingBuffer *ringPtr, Tcl_Size capacity);
static void RingBufferClear(RingBuffer *ringPtr);
static RingSizeT RingBufferIn(RingBuffer *ringPtr, const char *srcPtr,
RingSizeT srcLen, int partialCopyOk);
static RingSizeT RingBufferOut(RingBuffer *ringPtr, char *dstPtr,
RingSizeT dstCapacity, int partialCopyOk);
static Tcl_Size RingBufferIn(RingBuffer *ringPtr, const char *srcPtr,
Tcl_Size srcLen, int partialCopyOk);
static Tcl_Size RingBufferOut(RingBuffer *ringPtr, char *dstPtr,
Tcl_Size dstCapacity, int partialCopyOk);
static ConsoleHandleInfo *AllocateConsoleHandleInfo(HANDLE consoleHandle,
int permissions);
static ConsoleHandleInfo *FindConsoleInfo(const ConsoleChannelInfo *);
static DWORD WINAPI ConsoleReaderThread(LPVOID arg);
static DWORD WINAPI ConsoleWriterThread(LPVOID arg);
static void NudgeWatchers(HANDLE consoleHandle);
#ifndef NDEBUG
|
| ︙ | | |
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
|
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
|
-
+
-
+
|
*
* Side effects:
* Panics on allocation failure.
*
*------------------------------------------------------------------------
*/
static void
RingBufferInit(RingBuffer *ringPtr, RingSizeT capacity)
RingBufferInit(RingBuffer *ringPtr, Tcl_Size capacity)
{
if (capacity <= 0 || capacity > RingSizeT_MAX) {
if (capacity <= 0 || capacity > TCL_SIZE_MAX) {
Tcl_Panic("Internal error: invalid ring buffer capacity requested.");
}
ringPtr->bufPtr = (char *)Tcl_Alloc(capacity);
ringPtr->capacity = capacity;
ringPtr->start = 0;
ringPtr->length = 0;
}
|
| ︙ | | |
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
|
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
|
-
+
-
+
-
+
-
-
+
+
-
+
|
* Returns number of bytes copied.
*
* Side effects:
* Internal buffer is updated.
*
*------------------------------------------------------------------------
*/
static RingSizeT
static Tcl_Size
RingBufferIn(
RingBuffer *ringPtr,
const char *srcPtr, /* Source to be copied */
RingSizeT srcLen, /* Length of source */
Tcl_Size srcLen, /* Length of source */
int partialCopyOk /* If true, partial copy is permitted */
)
{
RingSizeT freeSpace;
Tcl_Size freeSpace;
RINGBUFFER_ASSERT(ringPtr);
freeSpace = ringPtr->capacity - ringPtr->length;
if (freeSpace < srcLen) {
if (!partialCopyOk) {
return 0;
}
/* Copy only as much as free space allows */
srcLen = freeSpace;
}
if (ringPtr->capacity - ringPtr->start > ringPtr->length) {
/* There is room at the back */
RingSizeT endSpaceStart = ringPtr->start + ringPtr->length;
RingSizeT endSpace = ringPtr->capacity - endSpaceStart;
Tcl_Size endSpaceStart = ringPtr->start + ringPtr->length;
Tcl_Size endSpace = ringPtr->capacity - endSpaceStart;
if (endSpace >= srcLen) {
/* Everything fits at the back */
memmove(endSpaceStart + ringPtr->bufPtr, srcPtr, srcLen);
} else {
/* srcLen > endSpace */
memmove(endSpaceStart + ringPtr->bufPtr, srcPtr, endSpace);
memmove(ringPtr->bufPtr, endSpace + srcPtr, srcLen - endSpace);
}
} else {
/* No room at the back. Existing data wrap to front. */
RingSizeT wrapLen =
Tcl_Size wrapLen =
ringPtr->start + ringPtr->length - ringPtr->capacity;
memmove(wrapLen + ringPtr->bufPtr, srcPtr, srcLen);
}
ringPtr->length += srcLen;
RINGBUFFER_ASSERT(ringPtr);
|
| ︙ | | |
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
|
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
|
-
+
-
+
-
+
|
* Returns number of bytes copied or removed.
*
* Side effects:
* Internal buffer is updated.
*
*------------------------------------------------------------------------
*/
static RingSizeT
static Tcl_Size
RingBufferOut(RingBuffer *ringPtr,
char *dstPtr, /* Buffer for output data. May be NULL */
RingSizeT dstCapacity, /* Size of buffer */
Tcl_Size dstCapacity, /* Size of buffer */
int partialCopyOk) /* If true, return what's available */
{
RingSizeT leadLen;
Tcl_Size leadLen;
RINGBUFFER_ASSERT(ringPtr);
if (dstCapacity > ringPtr->length) {
if (dstPtr && !partialCopyOk) {
return 0;
}
|
| ︙ | | |
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
|
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
|
-
+
|
}
if (leadLen >= dstCapacity) {
if (dstPtr) {
memmove(dstPtr, ringPtr->start + ringPtr->bufPtr, dstCapacity);
}
ringPtr->start += dstCapacity;
} else {
RingSizeT wrapLen = dstCapacity - leadLen;
Tcl_Size wrapLen = dstCapacity - leadLen;
if (dstPtr) {
memmove(dstPtr,
ringPtr->start + ringPtr->bufPtr,
leadLen);
memmove(
leadLen + dstPtr, ringPtr->bufPtr, wrapLen);
}
|
| ︙ | | |
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
|
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
|
-
-
+
+
|
*
*------------------------------------------------------------------------
*/
static DWORD
ReadConsoleChars(
HANDLE hConsole,
WCHAR *lpBuffer,
RingSizeT nChars,
RingSizeT *nCharsReadPtr)
Tcl_Size nChars,
Tcl_Size *nCharsReadPtr)
{
DWORD nRead;
BOOL result;
/*
* If user types a Ctrl-Break or Ctrl-C, ReadConsole will return success
* with ntchars == 0 and GetLastError() will be ERROR_OPERATION_ABORTED.
|
| ︙ | | |
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
|
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
|
-
-
+
+
|
*------------------------------------------------------------------------
*/
static DWORD
WriteConsoleChars(
HANDLE hConsole,
const WCHAR *lpBuffer,
RingSizeT nChars,
RingSizeT *nCharsWrittenPtr)
Tcl_Size nChars,
Tcl_Size *nCharsWrittenPtr)
{
DWORD nCharsWritten;
BOOL result;
/* See comments in ReadConsoleChars, not sure that applies here */
nCharsWritten = (DWORD)-1;
result = WriteConsoleW(hConsole, lpBuffer, nChars, &nCharsWritten, NULL);
|
| ︙ | | |
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
|
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
|
-
+
|
char *bufPtr, /* Where to store data read. */
int bufSize, /* How much space is available in the
* buffer? */
int *errorCode) /* Where to store error code. */
{
ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
ConsoleHandleInfo *handleInfoPtr;
RingSizeT numRead;
Tcl_Size numRead;
if (chanInfoPtr->handle == INVALID_HANDLE_VALUE) {
return 0; /* EOF */
}
*errorCode = 0;
|
| ︙ | | |
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
|
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
|
-
+
|
* reader thread which handles these case rather than dealing with
* them here (which is a little trickier than it might sound.)
*/
if ((1 & (ptrdiff_t)bufPtr) == 0 /* aligned buffer */
&& bufSize > 1 /* Not single byte read */
) {
DWORD lastError;
RingSizeT numChars;
Tcl_Size numChars;
ReleaseSRWLockExclusive(&handleInfoPtr->lock);
lastError = ReadConsoleChars(chanInfoPtr->handle,
(WCHAR *)bufPtr,
bufSize / sizeof(WCHAR),
&numChars);
/* NOTE lock released so DON'T break. Return instead */
if (lastError != ERROR_SUCCESS) {
|
| ︙ | | |
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
|
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
|
-
+
|
void *instanceData, /* Console state. */
const char *buf, /* The data buffer. */
int toWrite, /* How many bytes to write? */
int *errorCode) /* Where to store error code. */
{
ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
ConsoleHandleInfo *handleInfoPtr;
RingSizeT numWritten;
Tcl_Size numWritten;
*errorCode = 0;
if (chanInfoPtr->handle == INVALID_HANDLE_VALUE) {
/* Some other thread would have *previously* closed the stdio handle */
*errorCode = EPIPE;
return -1;
|
| ︙ | | |
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
|
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
|
-
-
+
+
|
static DWORD WINAPI
ConsoleReaderThread(
LPVOID arg)
{
ConsoleHandleInfo *handleInfoPtr = (ConsoleHandleInfo *) arg;
ConsoleHandleInfo **iterator;
char inputChars[200]; /* Temporary buffer */
RingSizeT inputLen = 0;
RingSizeT inputOffset = 0;
Tcl_Size inputLen = 0;
Tcl_Size inputOffset = 0;
/*
* Keep looping until one of the following happens.
* - there are no more channels listening on the console
* - the console handle has been closed
*/
|
| ︙ | | |
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
|
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
|
-
+
|
* copy that. Else check if there has been an error. In both cases
* notify the interp threads.
*/
if (inputLen > 0 || handleInfoPtr->lastError != 0) {
HANDLE consoleHandle;
if (inputLen > 0) {
/* Private buffer has data. Copy it over. */
RingSizeT nStored;
Tcl_Size nStored;
assert((inputLen - inputOffset) > 0);
nStored = RingBufferIn(&handleInfoPtr->buffer,
inputOffset + inputChars,
inputLen - inputOffset,
1);
|
| ︙ | | |
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
|
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
|
-
+
|
*/
static DWORD WINAPI
ConsoleWriterThread(LPVOID arg)
{
ConsoleHandleInfo *handleInfoPtr = (ConsoleHandleInfo *) arg;
ConsoleHandleInfo **iterator;
BOOL success;
RingSizeT numBytes;
Tcl_Size numBytes;
/*
* This buffer size has no relation really with the size of the shared
* buffer. Could be bigger or smaller. Make larger as multiple threads
* could potentially be writing to it.
*/
char buffer[2*CONSOLE_BUFFER_SIZE];
|
| ︙ | | |
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
|
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
|
-
+
|
RingBufferOut(&handleInfoPtr->buffer, buffer, numBytes, 0);
consoleHandle = handleInfoPtr->console;
WakeConditionVariable(&handleInfoPtr->interpThreadCV);
ReleaseSRWLockExclusive(&handleInfoPtr->lock);
offset = 0;
while (numBytes > 0) {
RingSizeT numWChars = numBytes / sizeof(WCHAR);
Tcl_Size numWChars = numBytes / sizeof(WCHAR);
DWORD status;
status = WriteConsoleChars(handleInfoPtr->console,
(WCHAR *)(offset + buffer),
numWChars,
&numWChars);
if (status != 0) {
/* Only overwrite if no previous error */
|
| ︙ | | |