| ︙ | | |
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
* to do read/write operation. Additionally
* used as signal to stop (state set to -1) */
volatile LONG state; /* Indicates current state of the thread */
ClientData clientData; /* Referenced data of the main thread */
} PipeThreadInfo;
/* If pipe-workers will use some tcl subsystem, we can use ckalloc without
* more overhead for finalize thread (should be executed anyway)
*
* #define _PTI_USE_CKALLOC 1
*/
/*
* State of the pipe-worker.
*
* State PTI_STATE_STOP possible from idle state only, worker owns TI structure.
* Otherwise PTI_STATE_END used (main thread hold ownership of the TI).
*/
#define PTI_STATE_IDLE 0
#define PTI_STATE_WORK 1
#define PTI_STATE_STOP 2
#define PTI_STATE_END 4
#define PTI_STATE_DOWN 8
#define PTI_STATE_IDLE 0 /* idle or not yet initialzed */
#define PTI_STATE_WORK 1 /* in work */
#define PTI_STATE_STOP 2 /* thread should stop work (owns TI structure) */
#define PTI_STATE_END 4 /* thread should stop work (worker is busy) */
#define PTI_STATE_DOWN 8 /* worker is down */
PipeThreadInfo *
PipeThreadCreateTI(
PipeThreadInfo **pipeTIPtr,
ClientData clientData)
{
PipeThreadInfo *pipeTI;
#ifndef _PTI_USE_CKALLOC
pipeTI = malloc(sizeof(PipeThreadInfo));
#else
pipeTI = ckalloc(sizeof(PipeThreadInfo));
#endif
pipeTI->evControl = CreateEvent(NULL, FALSE, FALSE, NULL);
pipeTI->state = PTI_STATE_IDLE;
pipeTI->clientData = clientData;
return (*pipeTIPtr = pipeTI);
}
int
PipeThreadWaitForSignal(
PipeThreadInfo **pipeTIPtr)
{
PipeThreadInfo *pipeTI = *pipeTIPtr;
LONG state;
|
| ︙ | | |
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
|
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
|
-
+
|
/*
* Wait at most 20 milliseconds for the reader thread to
* close (regarding TIP#398-fast-exit).
*/
/* if we want TIP#398-fast-exit. */
if (WaitForSingleObject(hThread,
TclInExit() ? 0 : 0) == WAIT_TIMEOUT) {
TclInExit() ? 0 : 20) == WAIT_TIMEOUT) {
/*
* The thread must be blocked waiting for the pipe to
* become readable in ReadFile(). There isn't a clean way
* to exit the thread from this condition. We should
* terminate the child process instead to get the reader
* thread to fall out of ReadFile with a FALSE. (below) is
|
| ︙ | | |
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
|
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
|
+
+
+
+
|
}
}
}
*pipeTIPtr = NULL;
if (pipeTI) {
CloseHandle(pipeTI->evControl);
#ifndef _PTI_USE_CKALLOC
free(pipeTI);
#else
ckfree(pipeTI);
#endif
}
}
void
PipeThreadExit(
PipeThreadInfo **pipeTIPtr)
{
|
| ︙ | | |
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
|
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
|
+
+
+
+
+
+
|
if (!pipeTI) {
return;
}
*pipeTIPtr = NULL;
if ((state = InterlockedExchange(&pipeTI->state,
PTI_STATE_DOWN)) == PTI_STATE_STOP) {
CloseHandle(pipeTI->evControl);
#ifndef _PTI_USE_CKALLOC
free(pipeTI);
#else
ckfree(pipeTI);
/* be sure all subsystems used are finalized */
Tcl_FinalizeThread();
#endif
}
}
typedef struct PipeInfo {
struct PipeInfo *nextPtr; /* Pointer to next registered pipe. */
Tcl_Channel channel; /* Pointer to channel structure. */
int validMask; /* OR'ed combination of TCL_READABLE,
|
| ︙ | | |
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
|
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
|
-
-
-
-
-
-
+
-
-
-
-
-
-
+
|
infoPtr->threadId = Tcl_GetCurrentThread();
if (readFile != NULL) {
/*
* Start the background reader thread.
*/
PipeThreadInfo *pipeTI = ckalloc(sizeof(PipeThreadInfo));
pipeTI->evControl = CreateEvent(NULL, FALSE, FALSE, NULL);
pipeTI->state = PTI_STATE_IDLE;
pipeTI->clientData = infoPtr;
infoPtr->readTI = pipeTI;
infoPtr->readable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->readThread = CreateThread(NULL, 256, PipeReaderThread,
pipeTI, 0, &id);
PipeThreadCreateTI(&infoPtr->readTI, infoPtr), 0, &id);
SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_READABLE;
} else {
infoPtr->readTI = NULL;
infoPtr->readThread = 0;
}
if (writeFile != NULL) {
/*
* Start the background writer thread.
*/
PipeThreadInfo *pipeTI = ckalloc(sizeof(PipeThreadInfo));
pipeTI->evControl = CreateEvent(NULL, FALSE, FALSE, NULL);
pipeTI->state = PTI_STATE_IDLE;
pipeTI->clientData = infoPtr;
infoPtr->writeTI = pipeTI;
infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->writeThread = CreateThread(NULL, 256, PipeWriterThread,
pipeTI, 0, &id);
PipeThreadCreateTI(&infoPtr->writeTI, infoPtr), 0, &id);
SetThreadPriority(infoPtr->writeThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_WRITABLE;
} else {
infoPtr->writeTI = NULL;
infoPtr->writeThread = 0;
}
|
| ︙ | | |
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
|
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
|
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
+
-
+
-
-
+
+
|
pipePtr->validMask &= ~TCL_READABLE;
pipePtr->readFile = NULL;
}
if ((!flags || flags & TCL_CLOSE_WRITE)
&& (pipePtr->writeFile != NULL)) {
if (pipePtr->writeThread) {
/* Notify thread we will stop work and check it still seems to work */
if (!PipeThreadStopSignal(&pipePtr->writeTI)) {
/*
* Wait for the writer thread to finish the current buffer, then
* terminate the thread and close the handles. If the channel is
* nonblocking or may block during exit, bail out since the worker
* thread is not interruptible and we want TIP#398-fast-exit.
*/
if ((pipePtr->flags & PIPE_ASYNC) || TclInExit()) {
/*
* Wait for the writer thread to finish the current buffer, then
* terminate the thread and close the handles. If the channel is
* nonblocking or may block during exit, bail out since the worker
* thread is not interruptible and we want TIP#398-fast-exit.
*/
if ((pipePtr->flags & PIPE_ASYNC) && TclInExit()) {
/* give it a chance to leave honorably */
if (WaitForSingleObject(pipePtr->writable, 0) == WAIT_TIMEOUT) {
return EWOULDBLOCK;
}
/* give it a chance to leave honorably */
PipeThreadStopSignal(&pipePtr->writeTI);
if (WaitForSingleObject(pipePtr->writable, 20) == WAIT_TIMEOUT) {
return EWOULDBLOCK;
}
} else {
} else {
WaitForSingleObject(pipePtr->writable, INFINITE);
WaitForSingleObject(pipePtr->writable, INFINITE);
}
}
}
PipeThreadStop(&pipePtr->writeTI, pipePtr->writeThread);
CloseHandle(pipePtr->writable);
CloseHandle(pipePtr->writeThread);
pipePtr->writeThread = NULL;
}
if (TclpCloseFile(pipePtr->writeFile) != 0) {
|
| ︙ | | |
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
|
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
|
-
+
+
+
+
+
|
static DWORD WINAPI
PipeWriterThread(
LPVOID arg)
{
PipeThreadInfo *pipeTI = (PipeThreadInfo *)arg;
PipeInfo *infoPtr = NULL; /* access info only after success init/wait */
HANDLE handle = NULL;
HANDLE handle = NULL, writable = NULL;
DWORD count, toWrite;
char *buf;
int done = 0;
while (!done) {
/*
* Wait for the main thread to signal before attempting to write.
*/
if (!PipeThreadWaitForSignal(&pipeTI)) {
/* exit */
if (writable) {
SetEvent(writable);
}
break;
}
if (!infoPtr) {
infoPtr = (PipeInfo *)pipeTI->clientData;
handle = ((WinFile *) infoPtr->writeFile)->handle;
writable = infoPtr->writable;
}
buf = infoPtr->writeBuf;
toWrite = infoPtr->toWrite;
/*
* Loop until all of the bytes are written or an error occurs.
|
| ︙ | | |
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
|
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
|
-
+
|
}
/*
* Signal the main thread by signalling the writable event and then
* waking up the notifier thread.
*/
SetEvent(infoPtr->writable);
SetEvent(writable);
/*
* Alert the foreground thread. Note that we need to treat this like a
* critical section so the foreground thread does not terminate this
* thread while we are holding a mutex in the notifier code.
*/
|
| ︙ | | |