1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
-
+
|
/*
* tclWinPipe.c --
*
* This file implements the Windows-specific exec pipeline functions,
* the "pipe" channel driver, and the "pid" Tcl command.
*
* Copyright (c) 1996-1997 by Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* RCS: @(#) $Id: tclWinPipe.c,v 1.11.2.1 2000/07/27 01:39:25 hobbs Exp $
* RCS: @(#) $Id: tclWinPipe.c,v 1.11.2.2 2001/04/03 22:54:39 hobbs Exp $
*/
#include "tclWinInt.h"
#include <dos.h>
#include <fcntl.h>
#include <io.h>
|
| ︙ | | |
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
+
+
|
* input. */
HANDLE startWriter; /* Auto-reset event used by the main thread to
* signal when the writer thread should attempt
* to write to the pipe. */
HANDLE startReader; /* Auto-reset event used by the main thread to
* signal when the reader thread should attempt
* to read from the pipe. */
HANDLE stopReader; /* Manual-reset event used to alert the reader
* thread to fall-out and exit */
DWORD writeError; /* An error caused by the last background
* write. Set to 0 if no error has been
* detected. This word is shared with the
* writer thread so access must be
* synchronized with the writable object.
*/
char *writeBuf; /* Current background output buffer.
|
| ︙ | | |
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
|
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
|
+
-
+
|
* stdio of another.
*/
if (!TclInExit()
|| ((GetStdHandle(STD_INPUT_HANDLE) != filePtr->handle)
&& (GetStdHandle(STD_OUTPUT_HANDLE) != filePtr->handle)
&& (GetStdHandle(STD_ERROR_HANDLE) != filePtr->handle))) {
if (filePtr->handle != NULL &&
if (CloseHandle(filePtr->handle) == FALSE) {
CloseHandle(filePtr->handle) == FALSE) {
TclWinConvertError(GetLastError());
ckfree((char *) filePtr);
return -1;
}
}
break;
|
| ︙ | | |
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
|
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
|
-
+
|
* using ab~1.def instead of "a b.default").
*/
BuildCommandLine(execPath, argc, argv, &cmdLine);
if ((*tclWinProcs->createProcessProc)(NULL,
(TCHAR *) Tcl_DStringValue(&cmdLine), NULL, NULL, TRUE,
createFlags, NULL, NULL, &startInfo, &procInfo) == 0) {
(DWORD) createFlags, NULL, NULL, &startInfo, &procInfo) == 0) {
TclWinConvertError(GetLastError());
Tcl_AppendResult(interp, "couldn't execute \"", argv[0],
"\": ", Tcl_PosixError(interp), (char *) NULL);
goto end;
}
/*
|
| ︙ | | |
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
|
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
|
+
|
special++;
}
Tcl_DStringAppend(&ds, start, special - start);
if (quote) {
Tcl_DStringAppend(&ds, "\"", 1);
}
}
Tcl_DStringFree(linePtr);
Tcl_WinUtfToTChar(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), linePtr);
Tcl_DStringFree(&ds);
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | | |
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
|
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
|
+
-
+
-
+
-
+
|
if (readFile != NULL) {
/*
* Start the background reader thread.
*/
infoPtr->readable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->startReader = CreateEvent(NULL, FALSE, FALSE, NULL);
infoPtr->stopReader = CreateEvent(NULL, TRUE, FALSE, NULL);
infoPtr->readThread = CreateThread(NULL, 8000, PipeReaderThread,
infoPtr->readThread = CreateThread(NULL, 512, PipeReaderThread,
infoPtr, 0, &id);
SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_READABLE;
} else {
infoPtr->readThread = 0;
}
if (writeFile != NULL) {
/*
* Start the background writeer thwrite.
* Start the background writer thread.
*/
infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->startWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
infoPtr->writeThread = CreateThread(NULL, 8000, PipeWriterThread,
infoPtr->writeThread = CreateThread(NULL, 512, PipeWriterThread,
infoPtr, 0, &id);
SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_WRITABLE;
}
/*
* For backward compatibility with previous versions of Tcl, we
|
| ︙ | | |
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
|
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
|
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
|
int flags) /* Flags that indicate which side to close. */
{
PipeInfo *pipePtr = (PipeInfo *) instanceData;
Tcl_Channel errChan;
int errorCode, result;
PipeInfo *infoPtr, **nextPtrPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
DWORD exitCode;
errorCode = 0;
if ((!flags || (flags == TCL_CLOSE_READ))
&& (pipePtr->readFile != NULL)) {
/*
* Clean up the background thread if necessary. Note that this
* must be done before we can close the file, since the
* thread may be blocking trying to read from the pipe.
*/
if (pipePtr->readThread) {
/*
* Forcibly terminate the background thread. We cannot rely on the
* thread to cleanly terminate itself because we have no way of
* closing the pipe handle without blocking in the case where the
* thread is in the middle of an I/O operation. Note that we need
* to guard against terminating the thread while it is in the
* middle of Tcl_ThreadAlert because it won't be able to release
* the notifier lock.
* Note that we need to guard against terminating the thread while
* it is in the middle of Tcl_ThreadAlert because it won't be able
* to release the notifier lock.
*/
Tcl_MutexLock(&pipeMutex);
/*
* The thread may already have closed on it's own. Check it's
* exit code.
*/
TerminateThread(pipePtr->readThread, 0);
GetExitCodeThread(pipePtr->readThread, &exitCode);
if (exitCode == STILL_ACTIVE) {
/*
* Wait for the thread to terminate. This ensures that we are
* completely cleaned up before we leave this function.
*/
/*
* Set the stop event so that if the reader thread is blocked
* in PipeReaderThread on WaitForMultipleEvents, it will exit
* cleanly.
*/
SetEvent(pipePtr->stopReader);
/*
* Wait at most 10 milliseconds for the reader thread to close.
*/
WaitForSingleObject(pipePtr->readThread, 10);
GetExitCodeThread(pipePtr->readThread, &exitCode);
if (exitCode == STILL_ACTIVE) {
/*
* 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 not the correct way to do
* this, but will stay here until a better solution is found.
*/
/* BUG: this leaks memory */
TerminateThread(pipePtr->readThread, 0);
/* Wait for the thread to terminate. */
WaitForSingleObject(pipePtr->readThread, INFINITE);
WaitForSingleObject(pipePtr->readThread, INFINITE);
}
}
Tcl_MutexUnlock(&pipeMutex);
CloseHandle(pipePtr->readThread);
CloseHandle(pipePtr->readable);
CloseHandle(pipePtr->startReader);
CloseHandle(pipePtr->stopReader);
pipePtr->readThread = NULL;
}
if (TclpCloseFile(pipePtr->readFile) != 0) {
errorCode = errno;
}
pipePtr->validMask &= ~TCL_READABLE;
pipePtr->readFile = NULL;
|
| ︙ | | |
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
|
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
|
-
+
-
+
|
* Reallocate the buffer to be large enough to hold the data.
*/
if (infoPtr->writeBuf) {
ckfree(infoPtr->writeBuf);
}
infoPtr->writeBufLen = toWrite;
infoPtr->writeBuf = ckalloc(toWrite);
infoPtr->writeBuf = ckalloc((unsigned int) toWrite);
}
memcpy(infoPtr->writeBuf, buf, toWrite);
memcpy(infoPtr->writeBuf, buf, (size_t) toWrite);
infoPtr->toWrite = toWrite;
ResetEvent(infoPtr->writable);
SetEvent(infoPtr->startWriter);
bytesWritten = toWrite;
} else {
/*
* In the blocking case, just try to write the buffer directly.
|
| ︙ | | |
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
|
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
|
-
+
|
Tcl_Pid
Tcl_WaitPid(
Tcl_Pid pid,
int *statPtr,
int options)
{
ProcInfo *infoPtr, **prevPtrPtr;
int flags;
DWORD flags;
Tcl_Pid result;
DWORD ret;
PipeInit();
/*
* If no pid is specified, do nothing.
|
| ︙ | | |
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
|
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
|
-
+
+
+
+
+
-
+
+
+
-
+
+
+
+
+
+
+
+
+
|
*
* Results:
* None.
*
* Side effects:
* Signals the main thread when input become available. May
* cause the main thread to wake up by posting a message. May
* consume one byte from the pipe for each wait operation.
* consume one byte from the pipe for each wait operation. Will
* cause a memory leak of ~4k, if forcefully terminated with
* TerminateThread().
*
*----------------------------------------------------------------------
*/
static DWORD WINAPI
PipeReaderThread(LPVOID arg)
{
PipeInfo *infoPtr = (PipeInfo *)arg;
HANDLE *handle = ((WinFile *) infoPtr->readFile)->handle;
DWORD count, err;
int done = 0;
HANDLE wEvents[2] = {infoPtr->stopReader, infoPtr->startReader};
DWORD dwWait;
while (!done) {
/*
* Wait for the main thread to signal before attempting to wait.
* Wait for the main thread to signal before attempting to wait
* on the pipe becoming readable.
*/
dwWait = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
WaitForSingleObject(infoPtr->startReader, INFINITE);
if (dwWait != (WAIT_OBJECT_0 + 1)) {
/*
* The start event was not signaled. It might be the stop event
* or an error, so exit.
*/
return 0;
}
/*
* Try waiting for 0 bytes. This will block until some data is
* available on NT, but will return immediately on Win 95. So,
* if no data is available after the first read, we block until
* we can read a single byte off of the pipe.
*/
|
| ︙ | | |