1/*
2 * tclWinPipe.c --
3 *
4 *	This file implements the Windows-specific exec pipeline functions, the
5 *	"pipe" channel driver, and the "pid" Tcl command.
6 *
7 * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
8 *
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 *
12 * RCS: @(#) $Id: tclWinPipe.c,v 1.65.4.1 2010/01/31 23:51:37 nijtmans Exp $
13 */
14
15#include "tclWinInt.h"
16
17#include <sys/stat.h>
18
19/*
20 * The following variable is used to tell whether this module has been
21 * initialized.
22 */
23
24static int initialized = 0;
25
26/*
27 * The pipeMutex locks around access to the initialized and procList
28 * variables, and it is used to protect background threads from being
29 * terminated while they are using APIs that hold locks.
30 */
31
32TCL_DECLARE_MUTEX(pipeMutex)
33
34/*
35 * The following defines identify the various types of applications that run
36 * under windows. There is special case code for the various types.
37 */
38
39#define APPL_NONE	0
40#define APPL_DOS	1
41#define APPL_WIN3X	2
42#define APPL_WIN32	3
43
44/*
45 * The following constants and structures are used to encapsulate the state of
46 * various types of files used in a pipeline. This used to have a 1 && 2 that
47 * supported Win32s.
48 */
49
50#define WIN_FILE	3	/* Basic Win32 file. */
51
52/*
53 * This structure encapsulates the common state associated with all file types
54 * used in a pipeline.
55 */
56
57typedef struct WinFile {
58    int type;			/* One of the file types defined above. */
59    HANDLE handle;		/* Open file handle. */
60} WinFile;
61
62/*
63 * This list is used to map from pids to process handles.
64 */
65
66typedef struct ProcInfo {
67    HANDLE hProcess;
68    DWORD dwProcessId;
69    struct ProcInfo *nextPtr;
70} ProcInfo;
71
72static ProcInfo *procList;
73
74/*
75 * Bit masks used in the flags field of the PipeInfo structure below.
76 */
77
78#define PIPE_PENDING	(1<<0)	/* Message is pending in the queue. */
79#define PIPE_ASYNC	(1<<1)	/* Channel is non-blocking. */
80
81/*
82 * Bit masks used in the sharedFlags field of the PipeInfo structure below.
83 */
84
85#define PIPE_EOF	(1<<2)	/* Pipe has reached EOF. */
86#define PIPE_EXTRABYTE	(1<<3)	/* The reader thread has consumed one byte. */
87
88/*
89 * This structure describes per-instance data for a pipe based channel.
90 */
91
92typedef struct PipeInfo {
93    struct PipeInfo *nextPtr;	/* Pointer to next registered pipe. */
94    Tcl_Channel channel;	/* Pointer to channel structure. */
95    int validMask;		/* OR'ed combination of TCL_READABLE,
96				 * TCL_WRITABLE, or TCL_EXCEPTION: indicates
97				 * which operations are valid on the file. */
98    int watchMask;		/* OR'ed combination of TCL_READABLE,
99				 * TCL_WRITABLE, or TCL_EXCEPTION: indicates
100				 * which events should be reported. */
101    int flags;			/* State flags, see above for a list. */
102    TclFile readFile;		/* Output from pipe. */
103    TclFile writeFile;		/* Input from pipe. */
104    TclFile errorFile;		/* Error output from pipe. */
105    int numPids;		/* Number of processes attached to pipe. */
106    Tcl_Pid *pidPtr;		/* Pids of attached processes. */
107    Tcl_ThreadId threadId;	/* Thread to which events should be reported.
108				 * This value is used by the reader/writer
109				 * threads. */
110    HANDLE writeThread;		/* Handle to writer thread. */
111    HANDLE readThread;		/* Handle to reader thread. */
112    HANDLE writable;		/* Manual-reset event to signal when the
113				 * writer thread has finished waiting for the
114				 * current buffer to be written. */
115    HANDLE readable;		/* Manual-reset event to signal when the
116				 * reader thread has finished waiting for
117				 * input. */
118    HANDLE startWriter;		/* Auto-reset event used by the main thread to
119				 * signal when the writer thread should
120				 * attempt to write to the pipe. */
121    HANDLE stopWriter;		/* Manual-reset event used to alert the reader
122				 * thread to fall-out and exit */
123    HANDLE startReader;		/* Auto-reset event used by the main thread to
124				 * signal when the reader thread should
125				 * attempt to read from the pipe. */
126    HANDLE stopReader;		/* Manual-reset event used to alert the reader
127				 * thread to fall-out and exit */
128    DWORD writeError;		/* An error caused by the last background
129				 * write. Set to 0 if no error has been
130				 * detected. This word is shared with the
131				 * writer thread so access must be
132				 * synchronized with the writable object.
133				 */
134    char *writeBuf;		/* Current background output buffer. Access is
135				 * synchronized with the writable object. */
136    int writeBufLen;		/* Size of write buffer. Access is
137				 * synchronized with the writable object. */
138    int toWrite;		/* Current amount to be written. Access is
139				 * synchronized with the writable object. */
140    int readFlags;		/* Flags that are shared with the reader
141				 * thread. Access is synchronized with the
142				 * readable object.  */
143    char extraByte;		/* Buffer for extra character consumed by
144				 * reader thread. This byte is shared with the
145				 * reader thread so access must be
146				 * synchronized with the readable object. */
147} PipeInfo;
148
149typedef struct ThreadSpecificData {
150    /*
151     * The following pointer refers to the head of the list of pipes that are
152     * being watched for file events.
153     */
154
155    PipeInfo *firstPipePtr;
156} ThreadSpecificData;
157
158static Tcl_ThreadDataKey dataKey;
159
160/*
161 * The following structure is what is added to the Tcl event queue when pipe
162 * events are generated.
163 */
164
165typedef struct PipeEvent {
166    Tcl_Event header;		/* Information that is standard for all
167				 * events. */
168    PipeInfo *infoPtr;		/* Pointer to pipe info structure. Note that
169				 * we still have to verify that the pipe
170				 * exists before dereferencing this
171				 * pointer. */
172} PipeEvent;
173
174/*
175 * Declarations for functions used only in this file.
176 */
177
178static int		ApplicationType(Tcl_Interp *interp,
179			    const char *fileName, char *fullName);
180static void		BuildCommandLine(const char *executable, int argc,
181			    const char **argv, Tcl_DString *linePtr);
182static BOOL		HasConsole(void);
183static int		PipeBlockModeProc(ClientData instanceData, int mode);
184static void		PipeCheckProc(ClientData clientData, int flags);
185static int		PipeClose2Proc(ClientData instanceData,
186			    Tcl_Interp *interp, int flags);
187static int		PipeEventProc(Tcl_Event *evPtr, int flags);
188static int		PipeGetHandleProc(ClientData instanceData,
189			    int direction, ClientData *handlePtr);
190static void		PipeInit(void);
191static int		PipeInputProc(ClientData instanceData, char *buf,
192			    int toRead, int *errorCode);
193static int		PipeOutputProc(ClientData instanceData,
194			    const char *buf, int toWrite, int *errorCode);
195static DWORD WINAPI	PipeReaderThread(LPVOID arg);
196static void		PipeSetupProc(ClientData clientData, int flags);
197static void		PipeWatchProc(ClientData instanceData, int mask);
198static DWORD WINAPI	PipeWriterThread(LPVOID arg);
199static int		TempFileName(WCHAR name[MAX_PATH]);
200static int		WaitForRead(PipeInfo *infoPtr, int blocking);
201static void		PipeThreadActionProc(ClientData instanceData,
202			    int action);
203
204/*
205 * This structure describes the channel type structure for command pipe based
206 * I/O.
207 */
208
209static Tcl_ChannelType pipeChannelType = {
210    "pipe",			/* Type name. */
211    TCL_CHANNEL_VERSION_5,	/* v5 channel */
212    TCL_CLOSE2PROC,		/* Close proc. */
213    PipeInputProc,		/* Input proc. */
214    PipeOutputProc,		/* Output proc. */
215    NULL,			/* Seek proc. */
216    NULL,			/* Set option proc. */
217    NULL,			/* Get option proc. */
218    PipeWatchProc,		/* Set up notifier to watch the channel. */
219    PipeGetHandleProc,		/* Get an OS handle from channel. */
220    PipeClose2Proc,		/* close2proc */
221    PipeBlockModeProc,		/* Set blocking or non-blocking mode.*/
222    NULL,			/* flush proc. */
223    NULL,			/* handler proc. */
224    NULL,			/* wide seek proc */
225    PipeThreadActionProc,	/* thread action proc */
226    NULL,                       /* truncate */
227};
228
229/*
230 *----------------------------------------------------------------------
231 *
232 * PipeInit --
233 *
234 *	This function initializes the static variables for this file.
235 *
236 * Results:
237 *	None.
238 *
239 * Side effects:
240 *	Creates a new event source.
241 *
242 *----------------------------------------------------------------------
243 */
244
245static void
246PipeInit(void)
247{
248    ThreadSpecificData *tsdPtr;
249
250    /*
251     * Check the initialized flag first, then check again in the mutex. This
252     * is a speed enhancement.
253     */
254
255    if (!initialized) {
256	Tcl_MutexLock(&pipeMutex);
257	if (!initialized) {
258	    initialized = 1;
259	    procList = NULL;
260	}
261	Tcl_MutexUnlock(&pipeMutex);
262    }
263
264    tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
265    if (tsdPtr == NULL) {
266	tsdPtr = TCL_TSD_INIT(&dataKey);
267	tsdPtr->firstPipePtr = NULL;
268	Tcl_CreateEventSource(PipeSetupProc, PipeCheckProc, NULL);
269    }
270}
271
272/*
273 *----------------------------------------------------------------------
274 *
275 * TclpFinalizePipes --
276 *
277 *	This function is called from Tcl_FinalizeThread to finalize the
278 *	platform specific pipe subsystem.
279 *
280 * Results:
281 *	None.
282 *
283 * Side effects:
284 *	Removes the pipe event source.
285 *
286 *----------------------------------------------------------------------
287 */
288
289void
290TclpFinalizePipes(void)
291{
292    ThreadSpecificData *tsdPtr;
293
294    tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
295    if (tsdPtr != NULL) {
296	Tcl_DeleteEventSource(PipeSetupProc, PipeCheckProc, NULL);
297    }
298}
299
300/*
301 *----------------------------------------------------------------------
302 *
303 * PipeSetupProc --
304 *
305 *	This function is invoked before Tcl_DoOneEvent blocks waiting for an
306 *	event.
307 *
308 * Results:
309 *	None.
310 *
311 * Side effects:
312 *	Adjusts the block time if needed.
313 *
314 *----------------------------------------------------------------------
315 */
316
317void
318PipeSetupProc(
319    ClientData data,		/* Not used. */
320    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */
321{
322    PipeInfo *infoPtr;
323    Tcl_Time blockTime = { 0, 0 };
324    int block = 1;
325    WinFile *filePtr;
326    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
327
328    if (!(flags & TCL_FILE_EVENTS)) {
329	return;
330    }
331
332    /*
333     * Look to see if any events are already pending.  If they are, poll.
334     */
335
336    for (infoPtr = tsdPtr->firstPipePtr; infoPtr != NULL;
337	    infoPtr = infoPtr->nextPtr) {
338	if (infoPtr->watchMask & TCL_WRITABLE) {
339	    filePtr = (WinFile*) infoPtr->writeFile;
340	    if (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT) {
341		block = 0;
342	    }
343	}
344	if (infoPtr->watchMask & TCL_READABLE) {
345	    filePtr = (WinFile*) infoPtr->readFile;
346	    if (WaitForRead(infoPtr, 0) >= 0) {
347		block = 0;
348	    }
349	}
350    }
351    if (!block) {
352	Tcl_SetMaxBlockTime(&blockTime);
353    }
354}
355
356/*
357 *----------------------------------------------------------------------
358 *
359 * PipeCheckProc --
360 *
361 *	This function is called by Tcl_DoOneEvent to check the pipe event
362 *	source for events.
363 *
364 * Results:
365 *	None.
366 *
367 * Side effects:
368 *	May queue an event.
369 *
370 *----------------------------------------------------------------------
371 */
372
373static void
374PipeCheckProc(
375    ClientData data,		/* Not used. */
376    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */
377{
378    PipeInfo *infoPtr;
379    PipeEvent *evPtr;
380    WinFile *filePtr;
381    int needEvent;
382    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
383
384    if (!(flags & TCL_FILE_EVENTS)) {
385	return;
386    }
387
388    /*
389     * Queue events for any ready pipes that don't already have events queued.
390     */
391
392    for (infoPtr = tsdPtr->firstPipePtr; infoPtr != NULL;
393	    infoPtr = infoPtr->nextPtr) {
394	if (infoPtr->flags & PIPE_PENDING) {
395	    continue;
396	}
397
398	/*
399	 * Queue an event if the pipe is signaled for reading or writing.
400	 */
401
402	needEvent = 0;
403	filePtr = (WinFile*) infoPtr->writeFile;
404	if ((infoPtr->watchMask & TCL_WRITABLE) &&
405		(WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT)) {
406	    needEvent = 1;
407	}
408
409	filePtr = (WinFile*) infoPtr->readFile;
410	if ((infoPtr->watchMask & TCL_READABLE) &&
411		(WaitForRead(infoPtr, 0) >= 0)) {
412	    needEvent = 1;
413	}
414
415	if (needEvent) {
416	    infoPtr->flags |= PIPE_PENDING;
417	    evPtr = (PipeEvent *) ckalloc(sizeof(PipeEvent));
418	    evPtr->header.proc = PipeEventProc;
419	    evPtr->infoPtr = infoPtr;
420	    Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
421	}
422    }
423}
424
425/*
426 *----------------------------------------------------------------------
427 *
428 * TclWinMakeFile --
429 *
430 *	This function constructs a new TclFile from a given data and type
431 *	value.
432 *
433 * Results:
434 *	Returns a newly allocated WinFile as a TclFile.
435 *
436 * Side effects:
437 *	None.
438 *
439 *----------------------------------------------------------------------
440 */
441
442TclFile
443TclWinMakeFile(
444    HANDLE handle)		/* Type-specific data. */
445{
446    WinFile *filePtr;
447
448    filePtr = (WinFile *) ckalloc(sizeof(WinFile));
449    filePtr->type = WIN_FILE;
450    filePtr->handle = handle;
451
452    return (TclFile)filePtr;
453}
454
455/*
456 *----------------------------------------------------------------------
457 *
458 * TempFileName --
459 *
460 *	Gets a temporary file name and deals with the fact that the temporary
461 *	file path provided by Windows may not actually exist if the TMP or
462 *	TEMP environment variables refer to a non-existent directory.
463 *
464 * Results:
465 *	0 if error, non-zero otherwise. If non-zero is returned, the name
466 *	buffer will be filled with a name that can be used to construct a
467 *	temporary file.
468 *
469 * Side effects:
470 *	None.
471 *
472 *----------------------------------------------------------------------
473 */
474
475static int
476TempFileName(
477    WCHAR name[MAX_PATH])	/* Buffer in which name for temporary file
478				 * gets stored. */
479{
480    TCHAR *prefix;
481
482    prefix = (tclWinProcs->useWide) ? (TCHAR *) L"TCL" : (TCHAR *) "TCL";
483    if ((*tclWinProcs->getTempPathProc)(MAX_PATH, name) != 0) {
484	if ((*tclWinProcs->getTempFileNameProc)((TCHAR *) name, prefix, 0,
485		name) != 0) {
486	    return 1;
487	}
488    }
489    if (tclWinProcs->useWide) {
490	((WCHAR *) name)[0] = '.';
491	((WCHAR *) name)[1] = '\0';
492    } else {
493	((char *) name)[0] = '.';
494	((char *) name)[1] = '\0';
495    }
496    return (*tclWinProcs->getTempFileNameProc)((TCHAR *) name, prefix, 0,
497	    name);
498}
499
500/*
501 *----------------------------------------------------------------------
502 *
503 * TclpMakeFile --
504 *
505 *	Make a TclFile from a channel.
506 *
507 * Results:
508 *	Returns a new TclFile or NULL on failure.
509 *
510 * Side effects:
511 *	None.
512 *
513 *----------------------------------------------------------------------
514 */
515
516TclFile
517TclpMakeFile(
518    Tcl_Channel channel,	/* Channel to get file from. */
519    int direction)		/* Either TCL_READABLE or TCL_WRITABLE. */
520{
521    HANDLE handle;
522
523    if (Tcl_GetChannelHandle(channel, direction,
524	    (ClientData *) &handle) == TCL_OK) {
525	return TclWinMakeFile(handle);
526    } else {
527	return (TclFile) NULL;
528    }
529}
530
531/*
532 *----------------------------------------------------------------------
533 *
534 * TclpOpenFile --
535 *
536 *	This function opens files for use in a pipeline.
537 *
538 * Results:
539 *	Returns a newly allocated TclFile structure containing the file
540 *	handle.
541 *
542 * Side effects:
543 *	None.
544 *
545 *----------------------------------------------------------------------
546 */
547
548TclFile
549TclpOpenFile(
550    const char *path,		/* The name of the file to open. */
551    int mode)			/* In what mode to open the file? */
552{
553    HANDLE handle;
554    DWORD accessMode, createMode, shareMode, flags;
555    Tcl_DString ds;
556    const TCHAR *nativePath;
557
558    /*
559     * Map the access bits to the NT access mode.
560     */
561
562    switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) {
563    case O_RDONLY:
564	accessMode = GENERIC_READ;
565	break;
566    case O_WRONLY:
567	accessMode = GENERIC_WRITE;
568	break;
569    case O_RDWR:
570	accessMode = (GENERIC_READ | GENERIC_WRITE);
571	break;
572    default:
573	TclWinConvertError(ERROR_INVALID_FUNCTION);
574	return NULL;
575    }
576
577    /*
578     * Map the creation flags to the NT create mode.
579     */
580
581    switch (mode & (O_CREAT | O_EXCL | O_TRUNC)) {
582    case (O_CREAT | O_EXCL):
583    case (O_CREAT | O_EXCL | O_TRUNC):
584	createMode = CREATE_NEW;
585	break;
586    case (O_CREAT | O_TRUNC):
587	createMode = CREATE_ALWAYS;
588	break;
589    case O_CREAT:
590	createMode = OPEN_ALWAYS;
591	break;
592    case O_TRUNC:
593    case (O_TRUNC | O_EXCL):
594	createMode = TRUNCATE_EXISTING;
595	break;
596    default:
597	createMode = OPEN_EXISTING;
598	break;
599    }
600
601    nativePath = Tcl_WinUtfToTChar(path, -1, &ds);
602
603    /*
604     * If the file is not being created, use the existing file attributes.
605     */
606
607    flags = 0;
608    if (!(mode & O_CREAT)) {
609	flags = (*tclWinProcs->getFileAttributesProc)(nativePath);
610	if (flags == 0xFFFFFFFF) {
611	    flags = 0;
612	}
613    }
614
615    /*
616     * Set up the file sharing mode.  We want to allow simultaneous access.
617     */
618
619    shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
620
621    /*
622     * Now we get to create the file.
623     */
624
625    handle = (*tclWinProcs->createFileProc)(nativePath, accessMode,
626	    shareMode, NULL, createMode, flags, NULL);
627    Tcl_DStringFree(&ds);
628
629    if (handle == INVALID_HANDLE_VALUE) {
630	DWORD err;
631
632	err = GetLastError();
633	if ((err & 0xffffL) == ERROR_OPEN_FAILED) {
634	    err = (mode & O_CREAT) ? ERROR_FILE_EXISTS : ERROR_FILE_NOT_FOUND;
635	}
636	TclWinConvertError(err);
637	return NULL;
638    }
639
640    /*
641     * Seek to the end of file if we are writing.
642     */
643
644    if (mode & (O_WRONLY|O_APPEND)) {
645	SetFilePointer(handle, 0, NULL, FILE_END);
646    }
647
648    return TclWinMakeFile(handle);
649}
650
651/*
652 *----------------------------------------------------------------------
653 *
654 * TclpCreateTempFile --
655 *
656 *	This function opens a unique file with the property that it will be
657 *	deleted when its file handle is closed. The temporary file is created
658 *	in the system temporary directory.
659 *
660 * Results:
661 *	Returns a valid TclFile, or NULL on failure.
662 *
663 * Side effects:
664 *	Creates a new temporary file.
665 *
666 *----------------------------------------------------------------------
667 */
668
669TclFile
670TclpCreateTempFile(
671    const char *contents)	/* String to write into temp file, or NULL. */
672{
673    WCHAR name[MAX_PATH];
674    const char *native;
675    Tcl_DString dstring;
676    HANDLE handle;
677
678    if (TempFileName(name) == 0) {
679	return NULL;
680    }
681
682    handle = (*tclWinProcs->createFileProc)((TCHAR *) name,
683	    GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
684	    FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, NULL);
685    if (handle == INVALID_HANDLE_VALUE) {
686	goto error;
687    }
688
689    /*
690     * Write the file out, doing line translations on the way.
691     */
692
693    if (contents != NULL) {
694	DWORD result, length;
695	const char *p;
696
697	/*
698	 * Convert the contents from UTF to native encoding
699	 */
700
701	native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring);
702
703	for (p = native; *p != '\0'; p++) {
704	    if (*p == '\n') {
705		length = p - native;
706		if (length > 0) {
707		    if (!WriteFile(handle, native, length, &result, NULL)) {
708			goto error;
709		    }
710		}
711		if (!WriteFile(handle, "\r\n", 2, &result, NULL)) {
712		    goto error;
713		}
714		native = p+1;
715	    }
716	}
717	length = p - native;
718	if (length > 0) {
719	    if (!WriteFile(handle, native, length, &result, NULL)) {
720		goto error;
721	    }
722	}
723	Tcl_DStringFree(&dstring);
724	if (SetFilePointer(handle, 0, NULL, FILE_BEGIN) == 0xFFFFFFFF) {
725	    goto error;
726	}
727    }
728
729    return TclWinMakeFile(handle);
730
731  error:
732    /*
733     * Free the native representation of the contents if necessary.
734     */
735
736    if (contents != NULL) {
737	Tcl_DStringFree(&dstring);
738    }
739
740    TclWinConvertError(GetLastError());
741    CloseHandle(handle);
742    (*tclWinProcs->deleteFileProc)((TCHAR *) name);
743    return NULL;
744}
745
746/*
747 *----------------------------------------------------------------------
748 *
749 * TclpTempFileName --
750 *
751 *	This function returns a unique filename.
752 *
753 * Results:
754 *	Returns a valid Tcl_Obj* with refCount 0, or NULL on failure.
755 *
756 * Side effects:
757 *	None.
758 *
759 *----------------------------------------------------------------------
760 */
761
762Tcl_Obj *
763TclpTempFileName(void)
764{
765    WCHAR fileName[MAX_PATH];
766
767    if (TempFileName(fileName) == 0) {
768	return NULL;
769    }
770
771    return TclpNativeToNormalized((ClientData) fileName);
772}
773
774/*
775 *----------------------------------------------------------------------
776 *
777 * TclpCreatePipe --
778 *
779 *	Creates an anonymous pipe.
780 *
781 * Results:
782 *	Returns 1 on success, 0 on failure.
783 *
784 * Side effects:
785 *	Creates a pipe.
786 *
787 *----------------------------------------------------------------------
788 */
789
790int
791TclpCreatePipe(
792    TclFile *readPipe,		/* Location to store file handle for read side
793				 * of pipe. */
794    TclFile *writePipe)		/* Location to store file handle for write
795				 * side of pipe. */
796{
797    HANDLE readHandle, writeHandle;
798
799    if (CreatePipe(&readHandle, &writeHandle, NULL, 0) != 0) {
800	*readPipe = TclWinMakeFile(readHandle);
801	*writePipe = TclWinMakeFile(writeHandle);
802	return 1;
803    }
804
805    TclWinConvertError(GetLastError());
806    return 0;
807}
808
809/*
810 *----------------------------------------------------------------------
811 *
812 * TclpCloseFile --
813 *
814 *	Closes a pipeline file handle. These handles are created by
815 *	TclpOpenFile, TclpCreatePipe, or TclpMakeFile.
816 *
817 * Results:
818 *	0 on success, -1 on failure.
819 *
820 * Side effects:
821 *	The file is closed and deallocated.
822 *
823 *----------------------------------------------------------------------
824 */
825
826int
827TclpCloseFile(
828    TclFile file)		/* The file to close. */
829{
830    WinFile *filePtr = (WinFile *) file;
831
832    switch (filePtr->type) {
833    case WIN_FILE:
834	/*
835	 * Don't close the Win32 handle if the handle is a standard channel
836	 * during the thread exit process. Otherwise, one thread may kill the
837	 * stdio of another.
838	 */
839
840	if (!TclInThreadExit()
841		|| ((GetStdHandle(STD_INPUT_HANDLE) != filePtr->handle)
842		    && (GetStdHandle(STD_OUTPUT_HANDLE) != filePtr->handle)
843		    && (GetStdHandle(STD_ERROR_HANDLE) != filePtr->handle))) {
844	    if (filePtr->handle != NULL &&
845		    CloseHandle(filePtr->handle) == FALSE) {
846		TclWinConvertError(GetLastError());
847		ckfree((char *) filePtr);
848		return -1;
849	    }
850	}
851	break;
852
853    default:
854	Tcl_Panic("TclpCloseFile: unexpected file type");
855    }
856
857    ckfree((char *) filePtr);
858    return 0;
859}
860
861/*
862 *--------------------------------------------------------------------------
863 *
864 * TclpGetPid --
865 *
866 *	Given a HANDLE to a child process, return the process id for that
867 *	child process.
868 *
869 * Results:
870 *	Returns the process id for the child process. If the pid was not known
871 *	by Tcl, either because the pid was not created by Tcl or the child
872 *	process has already been reaped, -1 is returned.
873 *
874 * Side effects:
875 *	None.
876 *
877 *--------------------------------------------------------------------------
878 */
879
880unsigned long
881TclpGetPid(
882    Tcl_Pid pid)		/* The HANDLE of the child process. */
883{
884    ProcInfo *infoPtr;
885
886    PipeInit();
887
888    Tcl_MutexLock(&pipeMutex);
889    for (infoPtr = procList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) {
890	if (infoPtr->hProcess == (HANDLE) pid) {
891	    Tcl_MutexUnlock(&pipeMutex);
892	    return infoPtr->dwProcessId;
893	}
894    }
895    Tcl_MutexUnlock(&pipeMutex);
896    return (unsigned long) -1;
897}
898
899/*
900 *----------------------------------------------------------------------
901 *
902 * TclpCreateProcess --
903 *
904 *	Create a child process that has the specified files as its standard
905 *	input, output, and error. The child process runs asynchronously under
906 *	Windows NT and Windows 9x, and runs with the same environment
907 *	variables as the creating process.
908 *
909 *	The complete Windows search path is searched to find the specified
910 *	executable. If an executable by the given name is not found,
911 *	automatically tries appending ".com", ".exe", and ".bat" to the
912 *	executable name.
913 *
914 * Results:
915 *	The return value is TCL_ERROR and an error message is left in the
916 *	interp's result if there was a problem creating the child process.
917 *	Otherwise, the return value is TCL_OK and *pidPtr is filled with the
918 *	process id of the child process.
919 *
920 * Side effects:
921 *	A process is created.
922 *
923 *----------------------------------------------------------------------
924 */
925
926int
927TclpCreateProcess(
928    Tcl_Interp *interp,		/* Interpreter in which to leave errors that
929				 * occurred when creating the child process.
930				 * Error messages from the child process
931				 * itself are sent to errorFile. */
932    int argc,			/* Number of arguments in following array. */
933    const char **argv,		/* Array of argument strings. argv[0] contains
934				 * the name of the executable converted to
935				 * native format (using the
936				 * Tcl_TranslateFileName call). Additional
937				 * arguments have not been converted. */
938    TclFile inputFile,		/* If non-NULL, gives the file to use as input
939				 * for the child process. If inputFile file is
940				 * not readable or is NULL, the child will
941				 * receive no standard input. */
942    TclFile outputFile,		/* If non-NULL, gives the file that receives
943				 * output from the child process. If
944				 * outputFile file is not writeable or is
945				 * NULL, output from the child will be
946				 * discarded. */
947    TclFile errorFile,		/* If non-NULL, gives the file that receives
948				 * errors from the child process. If errorFile
949				 * file is not writeable or is NULL, errors
950				 * from the child will be discarded. errorFile
951				 * may be the same as outputFile. */
952    Tcl_Pid *pidPtr)		/* If this function is successful, pidPtr is
953				 * filled with the process id of the child
954				 * process. */
955{
956    int result, applType, createFlags;
957    Tcl_DString cmdLine;	/* Complete command line (TCHAR). */
958    STARTUPINFOA startInfo;
959    PROCESS_INFORMATION procInfo;
960    SECURITY_ATTRIBUTES secAtts;
961    HANDLE hProcess, h, inputHandle, outputHandle, errorHandle;
962    char execPath[MAX_PATH * TCL_UTF_MAX];
963    WinFile *filePtr;
964
965    PipeInit();
966
967    applType = ApplicationType(interp, argv[0], execPath);
968    if (applType == APPL_NONE) {
969	return TCL_ERROR;
970    }
971
972    result = TCL_ERROR;
973    Tcl_DStringInit(&cmdLine);
974    hProcess = GetCurrentProcess();
975
976    /*
977     * STARTF_USESTDHANDLES must be used to pass handles to child process.
978     * Using SetStdHandle() and/or dup2() only works when a console mode
979     * parent process is spawning an attached console mode child process.
980     */
981
982    ZeroMemory(&startInfo, sizeof(startInfo));
983    startInfo.cb = sizeof(startInfo);
984    startInfo.dwFlags	= STARTF_USESTDHANDLES;
985    startInfo.hStdInput	= INVALID_HANDLE_VALUE;
986    startInfo.hStdOutput= INVALID_HANDLE_VALUE;
987    startInfo.hStdError = INVALID_HANDLE_VALUE;
988
989    secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);
990    secAtts.lpSecurityDescriptor = NULL;
991    secAtts.bInheritHandle = TRUE;
992
993    /*
994     * We have to check the type of each file, since we cannot duplicate some
995     * file types.
996     */
997
998    inputHandle = INVALID_HANDLE_VALUE;
999    if (inputFile != NULL) {
1000	filePtr = (WinFile *)inputFile;
1001	if (filePtr->type == WIN_FILE) {
1002	    inputHandle = filePtr->handle;
1003	}
1004    }
1005    outputHandle = INVALID_HANDLE_VALUE;
1006    if (outputFile != NULL) {
1007	filePtr = (WinFile *)outputFile;
1008	if (filePtr->type == WIN_FILE) {
1009	    outputHandle = filePtr->handle;
1010	}
1011    }
1012    errorHandle = INVALID_HANDLE_VALUE;
1013    if (errorFile != NULL) {
1014	filePtr = (WinFile *)errorFile;
1015	if (filePtr->type == WIN_FILE) {
1016	    errorHandle = filePtr->handle;
1017	}
1018    }
1019
1020    /*
1021     * Duplicate all the handles which will be passed off as stdin, stdout and
1022     * stderr of the child process. The duplicate handles are set to be
1023     * inheritable, so the child process can use them.
1024     */
1025
1026    if (inputHandle == INVALID_HANDLE_VALUE) {
1027	/*
1028	 * If handle was not set, stdin should return immediate EOF. Under
1029	 * Windows95, some applications (both 16 and 32 bit!) cannot read from
1030	 * the NUL device; they read from console instead. When running tk,
1031	 * this is fatal because the child process would hang forever waiting
1032	 * for EOF from the unmapped console window used by the helper
1033	 * application.
1034	 *
1035	 * Fortunately, the helper application detects a closed pipe as an
1036	 * immediate EOF and can pass that information to the child process.
1037	 */
1038
1039	if (CreatePipe(&startInfo.hStdInput, &h, &secAtts, 0) != FALSE) {
1040	    CloseHandle(h);
1041	}
1042    } else {
1043	DuplicateHandle(hProcess, inputHandle, hProcess, &startInfo.hStdInput,
1044		0, TRUE, DUPLICATE_SAME_ACCESS);
1045    }
1046    if (startInfo.hStdInput == INVALID_HANDLE_VALUE) {
1047	TclWinConvertError(GetLastError());
1048	Tcl_AppendResult(interp, "couldn't duplicate input handle: ",
1049		Tcl_PosixError(interp), (char *) NULL);
1050	goto end;
1051    }
1052
1053    if (outputHandle == INVALID_HANDLE_VALUE) {
1054	/*
1055	 * If handle was not set, output should be sent to an infinitely deep
1056	 * sink. Under Windows 95, some 16 bit applications cannot have stdout
1057	 * redirected to NUL; they send their output to the console instead.
1058	 * Some applications, like "more" or "dir /p", when outputting
1059	 * multiple pages to the console, also then try and read from the
1060	 * console to go the next page. When running tk, this is fatal because
1061	 * the child process would hang forever waiting for input from the
1062	 * unmapped console window used by the helper application.
1063	 *
1064	 * Fortunately, the helper application will detect a closed pipe as a
1065	 * sink.
1066	 */
1067
1068	if ((TclWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS)
1069		&& (applType == APPL_DOS)) {
1070	    if (CreatePipe(&h, &startInfo.hStdOutput, &secAtts, 0) != FALSE) {
1071		CloseHandle(h);
1072	    }
1073	} else {
1074	    startInfo.hStdOutput = CreateFileA("NUL:", GENERIC_WRITE, 0,
1075		    &secAtts, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1076	}
1077    } else {
1078	DuplicateHandle(hProcess, outputHandle, hProcess,
1079		&startInfo.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
1080    }
1081    if (startInfo.hStdOutput == INVALID_HANDLE_VALUE) {
1082	TclWinConvertError(GetLastError());
1083	Tcl_AppendResult(interp, "couldn't duplicate output handle: ",
1084		Tcl_PosixError(interp), (char *) NULL);
1085	goto end;
1086    }
1087
1088    if (errorHandle == INVALID_HANDLE_VALUE) {
1089	/*
1090	 * If handle was not set, errors should be sent to an infinitely deep
1091	 * sink.
1092	 */
1093
1094	startInfo.hStdError = CreateFileA("NUL:", GENERIC_WRITE, 0,
1095		&secAtts, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1096    } else {
1097	DuplicateHandle(hProcess, errorHandle, hProcess, &startInfo.hStdError,
1098		0, TRUE, DUPLICATE_SAME_ACCESS);
1099    }
1100    if (startInfo.hStdError == INVALID_HANDLE_VALUE) {
1101	TclWinConvertError(GetLastError());
1102	Tcl_AppendResult(interp, "couldn't duplicate error handle: ",
1103		Tcl_PosixError(interp), (char *) NULL);
1104	goto end;
1105    }
1106
1107    /*
1108     * If we do not have a console window, then we must run DOS and WIN32
1109     * console mode applications as detached processes. This tells the loader
1110     * that the child application should not inherit the console, and that it
1111     * should not create a new console window for the child application. The
1112     * child application should get its stdio from the redirection handles
1113     * provided by this application, and run in the background.
1114     *
1115     * If we are starting a GUI process, they don't automatically get a
1116     * console, so it doesn't matter if they are started as foreground or
1117     * detached processes. The GUI window will still pop up to the foreground.
1118     */
1119
1120    if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
1121	if (HasConsole()) {
1122	    createFlags = 0;
1123	} else if (applType == APPL_DOS) {
1124	    /*
1125	     * Under NT, 16-bit DOS applications will not run unless they can
1126	     * be attached to a console. If we are running without a console,
1127	     * run the 16-bit program as an normal process inside of a hidden
1128	     * console application, and then run that hidden console as a
1129	     * detached process.
1130	     */
1131
1132	    startInfo.wShowWindow = SW_HIDE;
1133	    startInfo.dwFlags |= STARTF_USESHOWWINDOW;
1134	    createFlags = CREATE_NEW_CONSOLE;
1135	    Tcl_DStringAppend(&cmdLine, "cmd.exe /c", -1);
1136	} else {
1137	    createFlags = DETACHED_PROCESS;
1138	}
1139    } else {
1140	if (HasConsole()) {
1141	    createFlags = 0;
1142	} else {
1143	    createFlags = DETACHED_PROCESS;
1144	}
1145
1146	if (applType == APPL_DOS) {
1147	    /*
1148	     * Under Windows 95, 16-bit DOS applications do not work well with
1149	     * pipes:
1150	     *
1151	     * 1. EOF on a pipe between a detached 16-bit DOS application and
1152	     * another application is not seen at the other end of the pipe,
1153	     * so the listening process blocks forever on reads. This inablity
1154	     * to detect EOF happens when either a 16-bit app or the 32-bit
1155	     * app is the listener.
1156	     *
1157	     * 2. If a 16-bit DOS application (detached or not) blocks when
1158	     * writing to a pipe, it will never wake up again, and it
1159	     * eventually brings the whole system down around it.
1160	     *
1161	     * The 16-bit application is run as a normal process inside of a
1162	     * hidden helper console app, and this helper may be run as a
1163	     * detached process. If any of the stdio handles is a pipe, the
1164	     * helper application accumulates information into temp files and
1165	     * forwards it to or from the DOS application as appropriate.
1166	     * This means that DOS apps must receive EOF from a stdin pipe
1167	     * before they will actually begin, and must finish generating
1168	     * stdout or stderr before the data will be sent to the next stage
1169	     * of the pipe.
1170	     *
1171	     * The helper app should be located in the same directory as the
1172	     * tcl dll.
1173	     */
1174	    Tcl_Obj *tclExePtr, *pipeDllPtr;
1175	    char *start, *end;
1176	    int i, fileExists;
1177	    Tcl_DString pipeDll;
1178
1179	    if (createFlags != 0) {
1180		startInfo.wShowWindow = SW_HIDE;
1181		startInfo.dwFlags |= STARTF_USESHOWWINDOW;
1182		createFlags = CREATE_NEW_CONSOLE;
1183	    }
1184
1185	    Tcl_DStringInit(&pipeDll);
1186	    Tcl_DStringAppend(&pipeDll, TCL_PIPE_DLL, -1);
1187	    tclExePtr = TclGetObjNameOfExecutable();
1188	    Tcl_IncrRefCount(tclExePtr);
1189	    start = Tcl_GetStringFromObj(tclExePtr, &i);
1190	    for (end = start + (i-1); end > start; end--) {
1191		if (*end == '/') {
1192		    break;
1193		}
1194	    }
1195	    if (*end != '/') {
1196		Tcl_AppendResult(interp, "no / in executable path name \"",
1197			start, "\"", (char *) NULL);
1198		Tcl_DecrRefCount(tclExePtr);
1199		Tcl_DStringFree(&pipeDll);
1200		goto end;
1201	    }
1202	    i = (end - start) + 1;
1203	    pipeDllPtr = Tcl_NewStringObj(start, i);
1204	    Tcl_AppendToObj(pipeDllPtr, Tcl_DStringValue(&pipeDll), -1);
1205	    Tcl_IncrRefCount(pipeDllPtr);
1206	    if (Tcl_FSConvertToPathType(interp, pipeDllPtr) != TCL_OK) {
1207		Tcl_Panic("Tcl_FSConvertToPathType failed");
1208	    }
1209	    fileExists = (Tcl_FSAccess(pipeDllPtr, F_OK) == 0);
1210	    if (!fileExists) {
1211		Tcl_AppendResult(interp, "Tcl pipe dll \"",
1212			Tcl_DStringValue(&pipeDll), "\" not found",
1213			(char *) NULL);
1214		Tcl_DecrRefCount(tclExePtr);
1215		Tcl_DecrRefCount(pipeDllPtr);
1216		Tcl_DStringFree(&pipeDll);
1217		goto end;
1218	    }
1219	    Tcl_DStringAppend(&cmdLine, Tcl_DStringValue(&pipeDll), -1);
1220	    Tcl_DecrRefCount(tclExePtr);
1221	    Tcl_DecrRefCount(pipeDllPtr);
1222	    Tcl_DStringFree(&pipeDll);
1223	}
1224    }
1225
1226    /*
1227     * cmdLine gets the full command line used to invoke the executable,
1228     * including the name of the executable itself. The command line arguments
1229     * in argv[] are stored in cmdLine separated by spaces. Special characters
1230     * in individual arguments from argv[] must be quoted when being stored in
1231     * cmdLine.
1232     *
1233     * When calling any application, bear in mind that arguments that specify
1234     * a path name are not converted. If an argument contains forward slashes
1235     * as path separators, it may or may not be recognized as a path name,
1236     * depending on the program. In general, most applications accept forward
1237     * slashes only as option delimiters and backslashes only as paths.
1238     *
1239     * Additionally, when calling a 16-bit dos or windows application, all
1240     * path names must use the short, cryptic, path format (e.g., using
1241     * ab~1.def instead of "a b.default").
1242     */
1243
1244    BuildCommandLine(execPath, argc, argv, &cmdLine);
1245
1246    if ((*tclWinProcs->createProcessProc)(NULL,
1247	    (TCHAR *) Tcl_DStringValue(&cmdLine), NULL, NULL, TRUE,
1248	    (DWORD) createFlags, NULL, NULL, &startInfo, &procInfo) == 0) {
1249	TclWinConvertError(GetLastError());
1250	Tcl_AppendResult(interp, "couldn't execute \"", argv[0],
1251		"\": ", Tcl_PosixError(interp), (char *) NULL);
1252	goto end;
1253    }
1254
1255    /*
1256     * This wait is used to force the OS to give some time to the DOS process.
1257     */
1258
1259    if (applType == APPL_DOS) {
1260	WaitForSingleObject(procInfo.hProcess, 50);
1261    }
1262
1263    /*
1264     * "When an application spawns a process repeatedly, a new thread instance
1265     * will be created for each process but the previous instances may not be
1266     * cleaned up. This results in a significant virtual memory loss each time
1267     * the process is spawned. If there is a WaitForInputIdle() call between
1268     * CreateProcess() and CloseHandle(), the problem does not occur." PSS ID
1269     * Number: Q124121
1270     */
1271
1272    WaitForInputIdle(procInfo.hProcess, 5000);
1273    CloseHandle(procInfo.hThread);
1274
1275    *pidPtr = (Tcl_Pid) procInfo.hProcess;
1276    if (*pidPtr != 0) {
1277	TclWinAddProcess(procInfo.hProcess, procInfo.dwProcessId);
1278    }
1279    result = TCL_OK;
1280
1281  end:
1282    Tcl_DStringFree(&cmdLine);
1283    if (startInfo.hStdInput != INVALID_HANDLE_VALUE) {
1284	CloseHandle(startInfo.hStdInput);
1285    }
1286    if (startInfo.hStdOutput != INVALID_HANDLE_VALUE) {
1287	CloseHandle(startInfo.hStdOutput);
1288    }
1289    if (startInfo.hStdError != INVALID_HANDLE_VALUE) {
1290	CloseHandle(startInfo.hStdError);
1291    }
1292    return result;
1293}
1294
1295
1296/*
1297 *----------------------------------------------------------------------
1298 *
1299 * HasConsole --
1300 *
1301 *	Determines whether the current application is attached to a console.
1302 *
1303 * Results:
1304 *	Returns TRUE if this application has a console, else FALSE.
1305 *
1306 * Side effects:
1307 *	None.
1308 *
1309 *----------------------------------------------------------------------
1310 */
1311
1312static BOOL
1313HasConsole(void)
1314{
1315    HANDLE handle;
1316
1317    handle = CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
1318	    NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1319
1320    if (handle != INVALID_HANDLE_VALUE) {
1321	CloseHandle(handle);
1322	return TRUE;
1323    } else {
1324	return FALSE;
1325    }
1326}
1327
1328/*
1329 *--------------------------------------------------------------------
1330 *
1331 * ApplicationType --
1332 *
1333 *	Search for the specified program and identify if it refers to a DOS,
1334 *	Windows 3.X, or Win32 program.	Used to determine how to invoke a
1335 *	program, or if it can even be invoked.
1336 *
1337 *	It is possible to almost positively identify DOS and Windows
1338 *	applications that contain the appropriate magic numbers. However, DOS
1339 *	.com files do not seem to contain a magic number; if the program name
1340 *	ends with .com and could not be identified as a Windows .com file, it
1341 *	will be assumed to be a DOS application, even if it was just random
1342 *	data. If the program name does not end with .com, no such assumption
1343 *	is made.
1344 *
1345 *	The Win32 function GetBinaryType incorrectly identifies any junk file
1346 *	that ends with .exe as a dos executable and some executables that
1347 *	don't end with .exe as not executable. Plus it doesn't exist under
1348 *	win95, so I won't feel bad about reimplementing functionality.
1349 *
1350 * Results:
1351 *	The return value is one of APPL_DOS, APPL_WIN3X, or APPL_WIN32 if the
1352 *	filename referred to the corresponding application type. If the file
1353 *	name could not be found or did not refer to any known application
1354 *	type, APPL_NONE is returned and an error message is left in interp.
1355 *	.bat files are identified as APPL_DOS.
1356 *
1357 * Side effects:
1358 *	None.
1359 *
1360 *----------------------------------------------------------------------
1361 */
1362
1363static int
1364ApplicationType(
1365    Tcl_Interp *interp,		/* Interp, for error message. */
1366    const char *originalName,	/* Name of the application to find. */
1367    char fullName[])		/* Filled with complete path to
1368				 * application. */
1369{
1370    int applType, i, nameLen, found;
1371    HANDLE hFile;
1372    TCHAR *rest;
1373    char *ext;
1374    char buf[2];
1375    DWORD attr, read;
1376    IMAGE_DOS_HEADER header;
1377    Tcl_DString nameBuf, ds;
1378    const TCHAR *nativeName;
1379    WCHAR nativeFullPath[MAX_PATH];
1380    static char extensions[][5] = {"", ".com", ".exe", ".bat"};
1381
1382    /*
1383     * Look for the program as an external program. First try the name as it
1384     * is, then try adding .com, .exe, and .bat, in that order, to the name,
1385     * looking for an executable.
1386     *
1387     * Using the raw SearchPath() function doesn't do quite what is necessary.
1388     * If the name of the executable already contains a '.' character, it will
1389     * not try appending the specified extension when searching (in other
1390     * words, SearchPath will not find the program "a.b.exe" if the arguments
1391     * specified "a.b" and ".exe"). So, first look for the file as it is
1392     * named. Then manually append the extensions, looking for a match.
1393     */
1394
1395    applType = APPL_NONE;
1396    Tcl_DStringInit(&nameBuf);
1397    Tcl_DStringAppend(&nameBuf, originalName, -1);
1398    nameLen = Tcl_DStringLength(&nameBuf);
1399
1400    for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
1401	Tcl_DStringSetLength(&nameBuf, nameLen);
1402	Tcl_DStringAppend(&nameBuf, extensions[i], -1);
1403	nativeName = Tcl_WinUtfToTChar(Tcl_DStringValue(&nameBuf),
1404		Tcl_DStringLength(&nameBuf), &ds);
1405	found = (*tclWinProcs->searchPathProc)(NULL, nativeName, NULL,
1406		MAX_PATH, nativeFullPath, &rest);
1407	Tcl_DStringFree(&ds);
1408	if (found == 0) {
1409	    continue;
1410	}
1411
1412	/*
1413	 * Ignore matches on directories or data files, return if identified a
1414	 * known type.
1415	 */
1416
1417	attr = (*tclWinProcs->getFileAttributesProc)((TCHAR *) nativeFullPath);
1418	if ((attr == 0xffffffff) || (attr & FILE_ATTRIBUTE_DIRECTORY)) {
1419	    continue;
1420	}
1421	strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds));
1422	Tcl_DStringFree(&ds);
1423
1424	ext = strrchr(fullName, '.');
1425	if ((ext != NULL) && (strcasecmp(ext, ".bat") == 0)) {
1426	    applType = APPL_DOS;
1427	    break;
1428	}
1429
1430	hFile = (*tclWinProcs->createFileProc)((TCHAR *) nativeFullPath,
1431		GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
1432		FILE_ATTRIBUTE_NORMAL, NULL);
1433	if (hFile == INVALID_HANDLE_VALUE) {
1434	    continue;
1435	}
1436
1437	header.e_magic = 0;
1438	ReadFile(hFile, (void *) &header, sizeof(header), &read, NULL);
1439	if (header.e_magic != IMAGE_DOS_SIGNATURE) {
1440	    /*
1441	     * Doesn't have the magic number for relocatable executables. If
1442	     * filename ends with .com, assume it's a DOS application anyhow.
1443	     * Note that we didn't make this assumption at first, because some
1444	     * supposed .com files are really 32-bit executables with all the
1445	     * magic numbers and everything.
1446	     */
1447
1448	    CloseHandle(hFile);
1449	    if ((ext != NULL) && (strcasecmp(ext, ".com") == 0)) {
1450		applType = APPL_DOS;
1451		break;
1452	    }
1453	    continue;
1454	}
1455	if (header.e_lfarlc != sizeof(header)) {
1456	    /*
1457	     * All Windows 3.X and Win32 and some DOS programs have this value
1458	     * set here. If it doesn't, assume that since it already had the
1459	     * other magic number it was a DOS application.
1460	     */
1461
1462	    CloseHandle(hFile);
1463	    applType = APPL_DOS;
1464	    break;
1465	}
1466
1467	/*
1468	 * The DWORD at header.e_lfanew points to yet another magic number.
1469	 */
1470
1471	buf[0] = '\0';
1472	SetFilePointer(hFile, header.e_lfanew, NULL, FILE_BEGIN);
1473	ReadFile(hFile, (void *) buf, 2, &read, NULL);
1474	CloseHandle(hFile);
1475
1476	if ((buf[0] == 'N') && (buf[1] == 'E')) {
1477	    applType = APPL_WIN3X;
1478	} else if ((buf[0] == 'P') && (buf[1] == 'E')) {
1479	    applType = APPL_WIN32;
1480	} else {
1481	    /*
1482	     * Strictly speaking, there should be a test that there is an 'L'
1483	     * and 'E' at buf[0..1], to identify the type as DOS, but of
1484	     * course we ran into a DOS executable that _doesn't_ have the
1485	     * magic number - specifically, one compiled using the Lahey
1486	     * Fortran90 compiler.
1487	     */
1488
1489	    applType = APPL_DOS;
1490	}
1491	break;
1492    }
1493    Tcl_DStringFree(&nameBuf);
1494
1495    if (applType == APPL_NONE) {
1496	TclWinConvertError(GetLastError());
1497	Tcl_AppendResult(interp, "couldn't execute \"", originalName,
1498		"\": ", Tcl_PosixError(interp), (char *) NULL);
1499	return APPL_NONE;
1500    }
1501
1502    if ((applType == APPL_DOS) || (applType == APPL_WIN3X)) {
1503	/*
1504	 * Replace long path name of executable with short path name for
1505	 * 16-bit applications. Otherwise the application may not be able to
1506	 * correctly parse its own command line to separate off the
1507	 * application name from the arguments.
1508	 */
1509
1510	(*tclWinProcs->getShortPathNameProc)((TCHAR *) nativeFullPath,
1511		nativeFullPath, MAX_PATH);
1512	strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds));
1513	Tcl_DStringFree(&ds);
1514    }
1515    return applType;
1516}
1517
1518/*
1519 *----------------------------------------------------------------------
1520 *
1521 * BuildCommandLine --
1522 *
1523 *	The command line arguments are stored in linePtr separated by spaces,
1524 *	in a form that CreateProcess() understands. Special characters in
1525 *	individual arguments from argv[] must be quoted when being stored in
1526 *	cmdLine.
1527 *
1528 * Results:
1529 *	None.
1530 *
1531 * Side effects:
1532 *	None.
1533 *
1534 *----------------------------------------------------------------------
1535 */
1536
1537static void
1538BuildCommandLine(
1539    const char *executable,	/* Full path of executable (including
1540				 * extension). Replacement for argv[0]. */
1541    int argc,			/* Number of arguments. */
1542    const char **argv,		/* Argument strings in UTF. */
1543    Tcl_DString *linePtr)	/* Initialized Tcl_DString that receives the
1544				 * command line (TCHAR). */
1545{
1546    const char *arg, *start, *special;
1547    int quote, i;
1548    Tcl_DString ds;
1549
1550    Tcl_DStringInit(&ds);
1551
1552    /*
1553     * Prime the path. Add a space separator if we were primed with something.
1554     */
1555
1556    Tcl_DStringAppend(&ds, Tcl_DStringValue(linePtr), -1);
1557    if (Tcl_DStringLength(linePtr) > 0) {
1558	Tcl_DStringAppend(&ds, " ", 1);
1559    }
1560
1561    for (i = 0; i < argc; i++) {
1562	if (i == 0) {
1563	    arg = executable;
1564	} else {
1565	    arg = argv[i];
1566	    Tcl_DStringAppend(&ds, " ", 1);
1567	}
1568
1569	quote = 0;
1570	if (arg[0] == '\0') {
1571	    quote = 1;
1572	} else {
1573	    int count;
1574	    Tcl_UniChar ch;
1575	    for (start = arg; *start != '\0'; start += count) {
1576		count = Tcl_UtfToUniChar(start, &ch);
1577		if (Tcl_UniCharIsSpace(ch)) {	/* INTL: ISO space. */
1578		    quote = 1;
1579		    break;
1580		}
1581	    }
1582	}
1583	if (quote) {
1584	    Tcl_DStringAppend(&ds, "\"", 1);
1585	}
1586	start = arg;
1587	for (special = arg; ; ) {
1588	    if ((*special == '\\') && (special[1] == '\\' ||
1589		    special[1] == '"' || (quote && special[1] == '\0'))) {
1590		Tcl_DStringAppend(&ds, start, (int) (special - start));
1591		start = special;
1592		while (1) {
1593		    special++;
1594		    if (*special == '"' || (quote && *special == '\0')) {
1595			/*
1596			 * N backslashes followed a quote -> insert N * 2 + 1
1597			 * backslashes then a quote.
1598			 */
1599
1600			Tcl_DStringAppend(&ds, start,
1601				(int) (special - start));
1602			break;
1603		    }
1604		    if (*special != '\\') {
1605			break;
1606		    }
1607		}
1608		Tcl_DStringAppend(&ds, start, (int) (special - start));
1609		start = special;
1610	    }
1611	    if (*special == '"') {
1612		Tcl_DStringAppend(&ds, start, (int) (special - start));
1613		Tcl_DStringAppend(&ds, "\\\"", 2);
1614		start = special + 1;
1615	    }
1616	    if (*special == '\0') {
1617		break;
1618	    }
1619	    special++;
1620	}
1621	Tcl_DStringAppend(&ds, start, (int) (special - start));
1622	if (quote) {
1623	    Tcl_DStringAppend(&ds, "\"", 1);
1624	}
1625    }
1626    Tcl_DStringFree(linePtr);
1627    Tcl_WinUtfToTChar(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), linePtr);
1628    Tcl_DStringFree(&ds);
1629}
1630
1631/*
1632 *----------------------------------------------------------------------
1633 *
1634 * TclpCreateCommandChannel --
1635 *
1636 *	This function is called by Tcl_OpenCommandChannel to perform the
1637 *	platform specific channel initialization for a command channel.
1638 *
1639 * Results:
1640 *	Returns a new channel or NULL on failure.
1641 *
1642 * Side effects:
1643 *	Allocates a new channel.
1644 *
1645 *----------------------------------------------------------------------
1646 */
1647
1648Tcl_Channel
1649TclpCreateCommandChannel(
1650    TclFile readFile,		/* If non-null, gives the file for reading. */
1651    TclFile writeFile,		/* If non-null, gives the file for writing. */
1652    TclFile errorFile,		/* If non-null, gives the file where errors
1653				 * can be read. */
1654    int numPids,		/* The number of pids in the pid array. */
1655    Tcl_Pid *pidPtr)		/* An array of process identifiers. */
1656{
1657    char channelName[16 + TCL_INTEGER_SPACE];
1658    int channelId;
1659    DWORD id;
1660    PipeInfo *infoPtr = (PipeInfo *) ckalloc((unsigned) sizeof(PipeInfo));
1661
1662    PipeInit();
1663
1664    infoPtr->watchMask = 0;
1665    infoPtr->flags = 0;
1666    infoPtr->readFlags = 0;
1667    infoPtr->readFile = readFile;
1668    infoPtr->writeFile = writeFile;
1669    infoPtr->errorFile = errorFile;
1670    infoPtr->numPids = numPids;
1671    infoPtr->pidPtr = pidPtr;
1672    infoPtr->writeBuf = 0;
1673    infoPtr->writeBufLen = 0;
1674    infoPtr->writeError = 0;
1675    infoPtr->channel = (Tcl_Channel) NULL;
1676
1677    /*
1678     * Use one of the fds associated with the channel as the channel id.
1679     */
1680
1681    if (readFile) {
1682	channelId = (int) ((WinFile*)readFile)->handle;
1683    } else if (writeFile) {
1684	channelId = (int) ((WinFile*)writeFile)->handle;
1685    } else if (errorFile) {
1686	channelId = (int) ((WinFile*)errorFile)->handle;
1687    } else {
1688	channelId = 0;
1689    }
1690
1691    infoPtr->validMask = 0;
1692
1693    infoPtr->threadId = Tcl_GetCurrentThread();
1694
1695    if (readFile != NULL) {
1696	/*
1697	 * Start the background reader thread.
1698	 */
1699
1700	infoPtr->readable = CreateEvent(NULL, TRUE, TRUE, NULL);
1701	infoPtr->startReader = CreateEvent(NULL, FALSE, FALSE, NULL);
1702	infoPtr->stopReader = CreateEvent(NULL, TRUE, FALSE, NULL);
1703	infoPtr->readThread = CreateThread(NULL, 256, PipeReaderThread,
1704		infoPtr, 0, &id);
1705	SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
1706	infoPtr->validMask |= TCL_READABLE;
1707    } else {
1708	infoPtr->readThread = 0;
1709    }
1710    if (writeFile != NULL) {
1711	/*
1712	 * Start the background writer thread.
1713	 */
1714
1715	infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL);
1716	infoPtr->startWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
1717	infoPtr->stopWriter = CreateEvent(NULL, TRUE, FALSE, NULL);
1718	infoPtr->writeThread = CreateThread(NULL, 256, PipeWriterThread,
1719		infoPtr, 0, &id);
1720	SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
1721	infoPtr->validMask |= TCL_WRITABLE;
1722    }
1723
1724    /*
1725     * For backward compatibility with previous versions of Tcl, we use
1726     * "file%d" as the base name for pipes even though it would be more
1727     * natural to use "pipe%d". Use the pointer to keep the channel names
1728     * unique, in case channels share handles (stdin/stdout).
1729     */
1730
1731    wsprintfA(channelName, "file%lx", infoPtr);
1732    infoPtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName,
1733	    (ClientData) infoPtr, infoPtr->validMask);
1734
1735    /*
1736     * Pipes have AUTO translation mode on Windows and ^Z eof char, which
1737     * means that a ^Z will be appended to them at close. This is needed for
1738     * Windows programs that expect a ^Z at EOF.
1739     */
1740
1741    Tcl_SetChannelOption((Tcl_Interp *) NULL, infoPtr->channel,
1742	    "-translation", "auto");
1743    Tcl_SetChannelOption((Tcl_Interp *) NULL, infoPtr->channel,
1744	    "-eofchar", "\032 {}");
1745    return infoPtr->channel;
1746}
1747
1748/*
1749 *----------------------------------------------------------------------
1750 *
1751 * TclGetAndDetachPids --
1752 *
1753 *	Stores a list of the command PIDs for a command channel in the
1754 *	interp's result.
1755 *
1756 * Results:
1757 *	None.
1758 *
1759 * Side effects:
1760 *	Modifies the interp's result.
1761 *
1762 *----------------------------------------------------------------------
1763 */
1764
1765void
1766TclGetAndDetachPids(
1767    Tcl_Interp *interp,
1768    Tcl_Channel chan)
1769{
1770    PipeInfo *pipePtr;
1771    const Tcl_ChannelType *chanTypePtr;
1772    int i;
1773    char buf[TCL_INTEGER_SPACE];
1774
1775    /*
1776     * Punt if the channel is not a command channel.
1777     */
1778
1779    chanTypePtr = Tcl_GetChannelType(chan);
1780    if (chanTypePtr != &pipeChannelType) {
1781	return;
1782    }
1783
1784    pipePtr = (PipeInfo *) Tcl_GetChannelInstanceData(chan);
1785    for (i = 0; i < pipePtr->numPids; i++) {
1786	wsprintfA(buf, "%lu", TclpGetPid(pipePtr->pidPtr[i]));
1787	Tcl_AppendElement(interp, buf);
1788	Tcl_DetachPids(1, &(pipePtr->pidPtr[i]));
1789    }
1790    if (pipePtr->numPids > 0) {
1791	ckfree((char *) pipePtr->pidPtr);
1792	pipePtr->numPids = 0;
1793    }
1794}
1795
1796/*
1797 *----------------------------------------------------------------------
1798 *
1799 * PipeBlockModeProc --
1800 *
1801 *	Set blocking or non-blocking mode on channel.
1802 *
1803 * Results:
1804 *	0 if successful, errno when failed.
1805 *
1806 * Side effects:
1807 *	Sets the device into blocking or non-blocking mode.
1808 *
1809 *----------------------------------------------------------------------
1810 */
1811
1812static int
1813PipeBlockModeProc(
1814    ClientData instanceData,	/* Instance data for channel. */
1815    int mode)			/* TCL_MODE_BLOCKING or
1816				 * TCL_MODE_NONBLOCKING. */
1817{
1818    PipeInfo *infoPtr = (PipeInfo *) instanceData;
1819
1820    /*
1821     * Pipes on Windows can not be switched between blocking and nonblocking,
1822     * hence we have to emulate the behavior. This is done in the input
1823     * function by checking against a bit in the state. We set or unset the
1824     * bit here to cause the input function to emulate the correct behavior.
1825     */
1826
1827    if (mode == TCL_MODE_NONBLOCKING) {
1828	infoPtr->flags |= PIPE_ASYNC;
1829    } else {
1830	infoPtr->flags &= ~(PIPE_ASYNC);
1831    }
1832    return 0;
1833}
1834
1835/*
1836 *----------------------------------------------------------------------
1837 *
1838 * PipeClose2Proc --
1839 *
1840 *	Closes a pipe based IO channel.
1841 *
1842 * Results:
1843 *	0 on success, errno otherwise.
1844 *
1845 * Side effects:
1846 *	Closes the physical channel.
1847 *
1848 *----------------------------------------------------------------------
1849 */
1850
1851static int
1852PipeClose2Proc(
1853    ClientData instanceData,	/* Pointer to PipeInfo structure. */
1854    Tcl_Interp *interp,		/* For error reporting. */
1855    int flags)			/* Flags that indicate which side to close. */
1856{
1857    PipeInfo *pipePtr = (PipeInfo *) instanceData;
1858    Tcl_Channel errChan;
1859    int errorCode, result;
1860    PipeInfo *infoPtr, **nextPtrPtr;
1861    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
1862    DWORD exitCode;
1863
1864    errorCode = 0;
1865    result = 0;
1866
1867    if ((!flags || flags == TCL_CLOSE_READ) && (pipePtr->readFile != NULL)) {
1868	/*
1869	 * Clean up the background thread if necessary. Note that this must be
1870	 * done before we can close the file, since the thread may be blocking
1871	 * trying to read from the pipe.
1872	 */
1873
1874	if (pipePtr->readThread) {
1875	    /*
1876	     * The thread may already have closed on its own. Check its exit
1877	     * code.
1878	     */
1879
1880	    GetExitCodeThread(pipePtr->readThread, &exitCode);
1881
1882	    if (exitCode == STILL_ACTIVE) {
1883		/*
1884		 * Set the stop event so that if the reader thread is blocked
1885		 * in PipeReaderThread on WaitForMultipleEvents, it will exit
1886		 * cleanly.
1887		 */
1888
1889		SetEvent(pipePtr->stopReader);
1890
1891		/*
1892		 * Wait at most 20 milliseconds for the reader thread to
1893		 * close.
1894		 */
1895
1896		if (WaitForSingleObject(pipePtr->readThread,
1897			20) == WAIT_TIMEOUT) {
1898		    /*
1899		     * The thread must be blocked waiting for the pipe to
1900		     * become readable in ReadFile(). There isn't a clean way
1901		     * to exit the thread from this condition. We should
1902		     * terminate the child process instead to get the reader
1903		     * thread to fall out of ReadFile with a FALSE. (below) is
1904		     * not the correct way to do this, but will stay here
1905		     * until a better solution is found.
1906		     *
1907		     * Note that we need to guard against terminating the
1908		     * thread while it is in the middle of Tcl_ThreadAlert
1909		     * because it won't be able to release the notifier lock.
1910		     */
1911
1912		    Tcl_MutexLock(&pipeMutex);
1913
1914		    /* BUG: this leaks memory */
1915		    TerminateThread(pipePtr->readThread, 0);
1916		    Tcl_MutexUnlock(&pipeMutex);
1917		}
1918	    }
1919
1920	    CloseHandle(pipePtr->readThread);
1921	    CloseHandle(pipePtr->readable);
1922	    CloseHandle(pipePtr->startReader);
1923	    CloseHandle(pipePtr->stopReader);
1924	    pipePtr->readThread = NULL;
1925	}
1926	if (TclpCloseFile(pipePtr->readFile) != 0) {
1927	    errorCode = errno;
1928	}
1929	pipePtr->validMask &= ~TCL_READABLE;
1930	pipePtr->readFile = NULL;
1931    }
1932    if ((!flags || flags & TCL_CLOSE_WRITE)
1933	    && (pipePtr->writeFile != NULL)) {
1934	if (pipePtr->writeThread) {
1935	    /*
1936	     * Wait for the writer thread to finish the current buffer, then
1937	     * terminate the thread and close the handles. If the channel is
1938	     * nonblocking, there should be no pending write operations.
1939	     */
1940
1941	    WaitForSingleObject(pipePtr->writable, INFINITE);
1942
1943	    /*
1944	     * The thread may already have closed on it's own. Check its exit
1945	     * code.
1946	     */
1947
1948	    GetExitCodeThread(pipePtr->writeThread, &exitCode);
1949
1950	    if (exitCode == STILL_ACTIVE) {
1951		/*
1952		 * Set the stop event so that if the reader thread is blocked
1953		 * in PipeReaderThread on WaitForMultipleEvents, it will exit
1954		 * cleanly.
1955		 */
1956
1957		SetEvent(pipePtr->stopWriter);
1958
1959		/*
1960		 * Wait at most 20 milliseconds for the reader thread to
1961		 * close.
1962		 */
1963
1964		if (WaitForSingleObject(pipePtr->writeThread,
1965			20) == WAIT_TIMEOUT) {
1966		    /*
1967		     * The thread must be blocked waiting for the pipe to
1968		     * consume input in WriteFile(). There isn't a clean way
1969		     * to exit the thread from this condition. We should
1970		     * terminate the child process instead to get the writer
1971		     * thread to fall out of WriteFile with a FALSE. (below)
1972		     * is not the correct way to do this, but will stay here
1973		     * until a better solution is found.
1974		     *
1975		     * Note that we need to guard against terminating the
1976		     * thread while it is in the middle of Tcl_ThreadAlert
1977		     * because it won't be able to release the notifier lock.
1978		     */
1979
1980		    Tcl_MutexLock(&pipeMutex);
1981
1982		    /* BUG: this leaks memory */
1983		    TerminateThread(pipePtr->writeThread, 0);
1984		    Tcl_MutexUnlock(&pipeMutex);
1985		}
1986	    }
1987
1988	    CloseHandle(pipePtr->writeThread);
1989	    CloseHandle(pipePtr->writable);
1990	    CloseHandle(pipePtr->startWriter);
1991	    CloseHandle(pipePtr->stopWriter);
1992	    pipePtr->writeThread = NULL;
1993	}
1994	if (TclpCloseFile(pipePtr->writeFile) != 0) {
1995	    if (errorCode == 0) {
1996		errorCode = errno;
1997	    }
1998	}
1999	pipePtr->validMask &= ~TCL_WRITABLE;
2000	pipePtr->writeFile = NULL;
2001    }
2002
2003    pipePtr->watchMask &= pipePtr->validMask;
2004
2005    /*
2006     * Don't free the channel if any of the flags were set.
2007     */
2008
2009    if (flags) {
2010	return errorCode;
2011    }
2012
2013    /*
2014     * Remove the file from the list of watched files.
2015     */
2016
2017    for (nextPtrPtr = &(tsdPtr->firstPipePtr), infoPtr = *nextPtrPtr;
2018	    infoPtr != NULL;
2019	    nextPtrPtr = &infoPtr->nextPtr, infoPtr = *nextPtrPtr) {
2020	if (infoPtr == (PipeInfo *)pipePtr) {
2021	    *nextPtrPtr = infoPtr->nextPtr;
2022	    break;
2023	}
2024    }
2025
2026    if ((pipePtr->flags & PIPE_ASYNC) || TclInExit()) {
2027	/*
2028	 * If the channel is non-blocking or Tcl is being cleaned up, just
2029	 * detach the children PIDs, reap them (important if we are in a
2030	 * dynamic load module), and discard the errorFile.
2031	 */
2032
2033	Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr);
2034	Tcl_ReapDetachedProcs();
2035
2036	if (pipePtr->errorFile) {
2037	    if (TclpCloseFile(pipePtr->errorFile) != 0) {
2038		if (errorCode == 0) {
2039		    errorCode = errno;
2040		}
2041	    }
2042	}
2043	result = 0;
2044    } else {
2045	/*
2046	 * Wrap the error file into a channel and give it to the cleanup
2047	 * routine.
2048	 */
2049
2050	if (pipePtr->errorFile) {
2051	    WinFile *filePtr;
2052
2053	    filePtr = (WinFile*)pipePtr->errorFile;
2054	    errChan = Tcl_MakeFileChannel((ClientData) filePtr->handle,
2055		    TCL_READABLE);
2056	    ckfree((char *) filePtr);
2057	} else {
2058	    errChan = NULL;
2059	}
2060
2061	result = TclCleanupChildren(interp, pipePtr->numPids,
2062		pipePtr->pidPtr, errChan);
2063    }
2064
2065    if (pipePtr->numPids > 0) {
2066	ckfree((char *) pipePtr->pidPtr);
2067    }
2068
2069    if (pipePtr->writeBuf != NULL) {
2070	ckfree(pipePtr->writeBuf);
2071    }
2072
2073    ckfree((char*) pipePtr);
2074
2075    if (errorCode == 0) {
2076	return result;
2077    }
2078    return errorCode;
2079}
2080
2081/*
2082 *----------------------------------------------------------------------
2083 *
2084 * PipeInputProc --
2085 *
2086 *	Reads input from the IO channel into the buffer given. Returns count
2087 *	of how many bytes were actually read, and an error indication.
2088 *
2089 * Results:
2090 *	A count of how many bytes were read is returned and an error
2091 *	indication is returned in an output argument.
2092 *
2093 * Side effects:
2094 *	Reads input from the actual channel.
2095 *
2096 *----------------------------------------------------------------------
2097 */
2098
2099static int
2100PipeInputProc(
2101    ClientData instanceData,	/* Pipe state. */
2102    char *buf,			/* Where to store data read. */
2103    int bufSize,		/* How much space is available in the
2104				 * buffer? */
2105    int *errorCode)		/* Where to store error code. */
2106{
2107    PipeInfo *infoPtr = (PipeInfo *) instanceData;
2108    WinFile *filePtr = (WinFile*) infoPtr->readFile;
2109    DWORD count, bytesRead = 0;
2110    int result;
2111
2112    *errorCode = 0;
2113    /*
2114     * Synchronize with the reader thread.
2115     */
2116
2117    result = WaitForRead(infoPtr, (infoPtr->flags & PIPE_ASYNC) ? 0 : 1);
2118
2119    /*
2120     * If an error occurred, return immediately.
2121     */
2122
2123    if (result == -1) {
2124	*errorCode = errno;
2125	return -1;
2126    }
2127
2128    if (infoPtr->readFlags & PIPE_EXTRABYTE) {
2129	/*
2130	 * The reader thread consumed 1 byte as a side effect of waiting so we
2131	 * need to move it into the buffer.
2132	 */
2133
2134	*buf = infoPtr->extraByte;
2135	infoPtr->readFlags &= ~PIPE_EXTRABYTE;
2136	buf++;
2137	bufSize--;
2138	bytesRead = 1;
2139
2140	/*
2141	 * If further read attempts would block, return what we have.
2142	 */
2143
2144	if (result == 0) {
2145	    return bytesRead;
2146	}
2147    }
2148
2149    /*
2150     * Attempt to read bufSize bytes. The read will return immediately if
2151     * there is any data available. Otherwise it will block until at least one
2152     * byte is available or an EOF occurs.
2153     */
2154
2155    if (ReadFile(filePtr->handle, (LPVOID) buf, (DWORD) bufSize, &count,
2156	    (LPOVERLAPPED) NULL) == TRUE) {
2157	return bytesRead + count;
2158    } else if (bytesRead) {
2159	/*
2160	 * Ignore errors if we have data to return.
2161	 */
2162
2163	return bytesRead;
2164    }
2165
2166    TclWinConvertError(GetLastError());
2167    if (errno == EPIPE) {
2168	infoPtr->readFlags |= PIPE_EOF;
2169	return 0;
2170    }
2171    *errorCode = errno;
2172    return -1;
2173}
2174
2175/*
2176 *----------------------------------------------------------------------
2177 *
2178 * PipeOutputProc --
2179 *
2180 *	Writes the given output on the IO channel. Returns count of how many
2181 *	characters were actually written, and an error indication.
2182 *
2183 * Results:
2184 *	A count of how many characters were written is returned and an error
2185 *	indication is returned in an output argument.
2186 *
2187 * Side effects:
2188 *	Writes output on the actual channel.
2189 *
2190 *----------------------------------------------------------------------
2191 */
2192
2193static int
2194PipeOutputProc(
2195    ClientData instanceData,	/* Pipe state. */
2196    const char *buf,		/* The data buffer. */
2197    int toWrite,		/* How many bytes to write? */
2198    int *errorCode)		/* Where to store error code. */
2199{
2200    PipeInfo *infoPtr = (PipeInfo *) instanceData;
2201    WinFile *filePtr = (WinFile*) infoPtr->writeFile;
2202    DWORD bytesWritten, timeout;
2203
2204    *errorCode = 0;
2205    timeout = (infoPtr->flags & PIPE_ASYNC) ? 0 : INFINITE;
2206    if (WaitForSingleObject(infoPtr->writable, timeout) == WAIT_TIMEOUT) {
2207	/*
2208	 * The writer thread is blocked waiting for a write to complete and
2209	 * the channel is in non-blocking mode.
2210	 */
2211
2212	errno = EAGAIN;
2213	goto error;
2214    }
2215
2216    /*
2217     * Check for a background error on the last write.
2218     */
2219
2220    if (infoPtr->writeError) {
2221	TclWinConvertError(infoPtr->writeError);
2222	infoPtr->writeError = 0;
2223	goto error;
2224    }
2225
2226    if (infoPtr->flags & PIPE_ASYNC) {
2227	/*
2228	 * The pipe is non-blocking, so copy the data into the output buffer
2229	 * and restart the writer thread.
2230	 */
2231
2232	if (toWrite > infoPtr->writeBufLen) {
2233	    /*
2234	     * Reallocate the buffer to be large enough to hold the data.
2235	     */
2236
2237	    if (infoPtr->writeBuf) {
2238		ckfree(infoPtr->writeBuf);
2239	    }
2240	    infoPtr->writeBufLen = toWrite;
2241	    infoPtr->writeBuf = ckalloc((unsigned int) toWrite);
2242	}
2243	memcpy(infoPtr->writeBuf, buf, (size_t) toWrite);
2244	infoPtr->toWrite = toWrite;
2245	ResetEvent(infoPtr->writable);
2246	SetEvent(infoPtr->startWriter);
2247	bytesWritten = toWrite;
2248    } else {
2249	/*
2250	 * In the blocking case, just try to write the buffer directly. This
2251	 * avoids an unnecessary copy.
2252	 */
2253
2254	if (WriteFile(filePtr->handle, (LPVOID) buf, (DWORD) toWrite,
2255		&bytesWritten, (LPOVERLAPPED) NULL) == FALSE) {
2256	    TclWinConvertError(GetLastError());
2257	    goto error;
2258	}
2259    }
2260    return bytesWritten;
2261
2262  error:
2263    *errorCode = errno;
2264    return -1;
2265
2266}
2267
2268/*
2269 *----------------------------------------------------------------------
2270 *
2271 * PipeEventProc --
2272 *
2273 *	This function is invoked by Tcl_ServiceEvent when a file event reaches
2274 *	the front of the event queue. This function invokes Tcl_NotifyChannel
2275 *	on the pipe.
2276 *
2277 * Results:
2278 *	Returns 1 if the event was handled, meaning it should be removed from
2279 *	the queue. Returns 0 if the event was not handled, meaning it should
2280 *	stay on the queue. The only time the event isn't handled is if the
2281 *	TCL_FILE_EVENTS flag bit isn't set.
2282 *
2283 * Side effects:
2284 *	Whatever the notifier callback does.
2285 *
2286 *----------------------------------------------------------------------
2287 */
2288
2289static int
2290PipeEventProc(
2291    Tcl_Event *evPtr,		/* Event to service. */
2292    int flags)			/* Flags that indicate what events to
2293				 * handle, such as TCL_FILE_EVENTS. */
2294{
2295    PipeEvent *pipeEvPtr = (PipeEvent *)evPtr;
2296    PipeInfo *infoPtr;
2297    WinFile *filePtr;
2298    int mask;
2299    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
2300
2301    if (!(flags & TCL_FILE_EVENTS)) {
2302	return 0;
2303    }
2304
2305    /*
2306     * Search through the list of watched pipes for the one whose handle
2307     * matches the event. We do this rather than simply dereferencing the
2308     * handle in the event so that pipes can be deleted while the event is in
2309     * the queue.
2310     */
2311
2312    for (infoPtr = tsdPtr->firstPipePtr; infoPtr != NULL;
2313	    infoPtr = infoPtr->nextPtr) {
2314	if (pipeEvPtr->infoPtr == infoPtr) {
2315	    infoPtr->flags &= ~(PIPE_PENDING);
2316	    break;
2317	}
2318    }
2319
2320    /*
2321     * Remove stale events.
2322     */
2323
2324    if (!infoPtr) {
2325	return 1;
2326    }
2327
2328    /*
2329     * Check to see if the pipe is readable. Note that we can't tell if a pipe
2330     * is writable, so we always report it as being writable unless we have
2331     * detected EOF.
2332     */
2333
2334    filePtr = (WinFile*) ((PipeInfo*)infoPtr)->writeFile;
2335    mask = 0;
2336    if ((infoPtr->watchMask & TCL_WRITABLE) &&
2337	    (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT)) {
2338	mask = TCL_WRITABLE;
2339    }
2340
2341    filePtr = (WinFile*) ((PipeInfo*)infoPtr)->readFile;
2342    if ((infoPtr->watchMask & TCL_READABLE) && (WaitForRead(infoPtr,0) >= 0)) {
2343	if (infoPtr->readFlags & PIPE_EOF) {
2344	    mask = TCL_READABLE;
2345	} else {
2346	    mask |= TCL_READABLE;
2347	}
2348    }
2349
2350    /*
2351     * Inform the channel of the events.
2352     */
2353
2354    Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask & mask);
2355    return 1;
2356}
2357
2358/*
2359 *----------------------------------------------------------------------
2360 *
2361 * PipeWatchProc --
2362 *
2363 *	Called by the notifier to set up to watch for events on this channel.
2364 *
2365 * Results:
2366 *	None.
2367 *
2368 * Side effects:
2369 *	None.
2370 *
2371 *----------------------------------------------------------------------
2372 */
2373
2374static void
2375PipeWatchProc(
2376    ClientData instanceData,	/* Pipe state. */
2377    int mask)			/* What events to watch for, OR-ed combination
2378				 * of TCL_READABLE, TCL_WRITABLE and
2379				 * TCL_EXCEPTION. */
2380{
2381    PipeInfo **nextPtrPtr, *ptr;
2382    PipeInfo *infoPtr = (PipeInfo *) instanceData;
2383    int oldMask = infoPtr->watchMask;
2384    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
2385
2386    /*
2387     * Since most of the work is handled by the background threads, we just
2388     * need to update the watchMask and then force the notifier to poll once.
2389     */
2390
2391    infoPtr->watchMask = mask & infoPtr->validMask;
2392    if (infoPtr->watchMask) {
2393	Tcl_Time blockTime = { 0, 0 };
2394	if (!oldMask) {
2395	    infoPtr->nextPtr = tsdPtr->firstPipePtr;
2396	    tsdPtr->firstPipePtr = infoPtr;
2397	}
2398	Tcl_SetMaxBlockTime(&blockTime);
2399    } else {
2400	if (oldMask) {
2401	    /*
2402	     * Remove the pipe from the list of watched pipes.
2403	     */
2404
2405	    for (nextPtrPtr = &(tsdPtr->firstPipePtr), ptr = *nextPtrPtr;
2406		    ptr != NULL;
2407		    nextPtrPtr = &ptr->nextPtr, ptr = *nextPtrPtr) {
2408		if (infoPtr == ptr) {
2409		    *nextPtrPtr = ptr->nextPtr;
2410		    break;
2411		}
2412	    }
2413	}
2414    }
2415}
2416
2417/*
2418 *----------------------------------------------------------------------
2419 *
2420 * PipeGetHandleProc --
2421 *
2422 *	Called from Tcl_GetChannelHandle to retrieve OS handles from inside a
2423 *	command pipeline based channel.
2424 *
2425 * Results:
2426 *	Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if there is no
2427 *	handle for the specified direction.
2428 *
2429 * Side effects:
2430 *	None.
2431 *
2432 *----------------------------------------------------------------------
2433 */
2434
2435static int
2436PipeGetHandleProc(
2437    ClientData instanceData,	/* The pipe state. */
2438    int direction,		/* TCL_READABLE or TCL_WRITABLE */
2439    ClientData *handlePtr)	/* Where to store the handle.  */
2440{
2441    PipeInfo *infoPtr = (PipeInfo *) instanceData;
2442    WinFile *filePtr;
2443
2444    if (direction == TCL_READABLE && infoPtr->readFile) {
2445	filePtr = (WinFile*) infoPtr->readFile;
2446	*handlePtr = (ClientData) filePtr->handle;
2447	return TCL_OK;
2448    }
2449    if (direction == TCL_WRITABLE && infoPtr->writeFile) {
2450	filePtr = (WinFile*) infoPtr->writeFile;
2451	*handlePtr = (ClientData) filePtr->handle;
2452	return TCL_OK;
2453    }
2454    return TCL_ERROR;
2455}
2456
2457/*
2458 *----------------------------------------------------------------------
2459 *
2460 * Tcl_WaitPid --
2461 *
2462 *	Emulates the waitpid system call.
2463 *
2464 * Results:
2465 *	Returns 0 if the process is still alive, -1 on an error, or the pid on
2466 *	a clean close.
2467 *
2468 * Side effects:
2469 *	Unless WNOHANG is set and the wait times out, the process information
2470 *	record will be deleted and the process handle will be closed.
2471 *
2472 *----------------------------------------------------------------------
2473 */
2474
2475Tcl_Pid
2476Tcl_WaitPid(
2477    Tcl_Pid pid,
2478    int *statPtr,
2479    int options)
2480{
2481    ProcInfo *infoPtr = NULL, **prevPtrPtr;
2482    DWORD flags;
2483    Tcl_Pid result;
2484    DWORD ret, exitCode;
2485
2486    PipeInit();
2487
2488    /*
2489     * If no pid is specified, do nothing.
2490     */
2491
2492    if (pid == 0) {
2493	*statPtr = 0;
2494	return 0;
2495    }
2496
2497    /*
2498     * Find the process and cut it from the process list.
2499     */
2500
2501    Tcl_MutexLock(&pipeMutex);
2502    prevPtrPtr = &procList;
2503    for (infoPtr = procList; infoPtr != NULL;
2504	    prevPtrPtr = &infoPtr->nextPtr, infoPtr = infoPtr->nextPtr) {
2505	 if (infoPtr->hProcess == (HANDLE) pid) {
2506	    *prevPtrPtr = infoPtr->nextPtr;
2507	    break;
2508	}
2509    }
2510    Tcl_MutexUnlock(&pipeMutex);
2511
2512    /*
2513     * If the pid is not one of the processes we know about (we started it)
2514     * then do nothing.
2515     */
2516
2517    if (infoPtr == NULL) {
2518	*statPtr = 0;
2519	return 0;
2520    }
2521
2522    /*
2523     * Officially "wait" for it to finish. We either poll (WNOHANG) or wait
2524     * for an infinite amount of time.
2525     */
2526
2527    if (options & WNOHANG) {
2528	flags = 0;
2529    } else {
2530	flags = INFINITE;
2531    }
2532    ret = WaitForSingleObject(infoPtr->hProcess, flags);
2533    if (ret == WAIT_TIMEOUT) {
2534	*statPtr = 0;
2535	if (options & WNOHANG) {
2536	    /*
2537	     * Re-insert this infoPtr back on the list.
2538	     */
2539
2540	    Tcl_MutexLock(&pipeMutex);
2541	    infoPtr->nextPtr = procList;
2542	    procList = infoPtr;
2543	    Tcl_MutexUnlock(&pipeMutex);
2544	    return 0;
2545	} else {
2546	    result = 0;
2547	}
2548    } else if (ret == WAIT_OBJECT_0) {
2549	GetExitCodeProcess(infoPtr->hProcess, &exitCode);
2550
2551	/*
2552	 * Does the exit code look like one of the exception codes?
2553	 */
2554
2555	switch (exitCode) {
2556	case EXCEPTION_FLT_DENORMAL_OPERAND:
2557	case EXCEPTION_FLT_DIVIDE_BY_ZERO:
2558	case EXCEPTION_FLT_INEXACT_RESULT:
2559	case EXCEPTION_FLT_INVALID_OPERATION:
2560	case EXCEPTION_FLT_OVERFLOW:
2561	case EXCEPTION_FLT_STACK_CHECK:
2562	case EXCEPTION_FLT_UNDERFLOW:
2563	case EXCEPTION_INT_DIVIDE_BY_ZERO:
2564	case EXCEPTION_INT_OVERFLOW:
2565	    *statPtr = 0xC0000000 | SIGFPE;
2566	    break;
2567
2568	case EXCEPTION_PRIV_INSTRUCTION:
2569	case EXCEPTION_ILLEGAL_INSTRUCTION:
2570	    *statPtr = 0xC0000000 | SIGILL;
2571	    break;
2572
2573	case EXCEPTION_ACCESS_VIOLATION:
2574	case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
2575	case EXCEPTION_STACK_OVERFLOW:
2576	case EXCEPTION_NONCONTINUABLE_EXCEPTION:
2577	case EXCEPTION_INVALID_DISPOSITION:
2578	case EXCEPTION_GUARD_PAGE:
2579	case EXCEPTION_INVALID_HANDLE:
2580	    *statPtr = 0xC0000000 | SIGSEGV;
2581	    break;
2582
2583	case EXCEPTION_DATATYPE_MISALIGNMENT:
2584	    *statPtr = 0xC0000000 | SIGBUS;
2585	    break;
2586
2587	case EXCEPTION_BREAKPOINT:
2588	case EXCEPTION_SINGLE_STEP:
2589	    *statPtr = 0xC0000000 | SIGTRAP;
2590	    break;
2591
2592	case CONTROL_C_EXIT:
2593	    *statPtr = 0xC0000000 | SIGINT;
2594	    break;
2595
2596	default:
2597	    /*
2598	     * Non-exceptional, normal, exit code. Note that the exit code is
2599	     * truncated to a signed short range [-32768,32768) whether it
2600	     * fits into this range or not.
2601	     *
2602	     * BUG: Even though the exit code is a DWORD, it is understood by
2603	     * convention to be a signed integer, yet there isn't enough room
2604	     * to fit this into the POSIX style waitstatus mask without
2605	     * truncating it.
2606	     */
2607
2608	    *statPtr = exitCode;
2609	    break;
2610	}
2611	result = pid;
2612    } else {
2613	errno = ECHILD;
2614	*statPtr = 0xC0000000 | ECHILD;
2615	result = (Tcl_Pid) -1;
2616    }
2617
2618    /*
2619     * Officially close the process handle.
2620     */
2621
2622    CloseHandle(infoPtr->hProcess);
2623    ckfree((char*)infoPtr);
2624
2625    return result;
2626}
2627
2628/*
2629 *----------------------------------------------------------------------
2630 *
2631 * TclWinAddProcess --
2632 *
2633 *	Add a process to the process list so that we can use Tcl_WaitPid on
2634 *	the process.
2635 *
2636 * Results:
2637 *	None
2638 *
2639 * Side effects:
2640 *	Adds the specified process handle to the process list so Tcl_WaitPid
2641 *	knows about it.
2642 *
2643 *----------------------------------------------------------------------
2644 */
2645
2646void
2647TclWinAddProcess(
2648    void *hProcess,		/* Handle to process */
2649    unsigned long id)	/* Global process identifier */
2650{
2651    ProcInfo *procPtr = (ProcInfo *) ckalloc(sizeof(ProcInfo));
2652
2653    PipeInit();
2654
2655    procPtr->hProcess = hProcess;
2656    procPtr->dwProcessId = id;
2657    Tcl_MutexLock(&pipeMutex);
2658    procPtr->nextPtr = procList;
2659    procList = procPtr;
2660    Tcl_MutexUnlock(&pipeMutex);
2661}
2662
2663/*
2664 *----------------------------------------------------------------------
2665 *
2666 * Tcl_PidObjCmd --
2667 *
2668 *	This function is invoked to process the "pid" Tcl command. See the
2669 *	user documentation for details on what it does.
2670 *
2671 * Results:
2672 *	A standard Tcl result.
2673 *
2674 * Side effects:
2675 *	See the user documentation.
2676 *
2677 *----------------------------------------------------------------------
2678 */
2679
2680	/* ARGSUSED */
2681int
2682Tcl_PidObjCmd(
2683    ClientData dummy,		/* Not used. */
2684    Tcl_Interp *interp,		/* Current interpreter. */
2685    int objc,			/* Number of arguments. */
2686    Tcl_Obj *const *objv)	/* Argument strings. */
2687{
2688    Tcl_Channel chan;
2689    const Tcl_ChannelType *chanTypePtr;
2690    PipeInfo *pipePtr;
2691    int i;
2692    Tcl_Obj *resultPtr;
2693    char buf[TCL_INTEGER_SPACE];
2694
2695    if (objc > 2) {
2696	Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");
2697	return TCL_ERROR;
2698    }
2699    if (objc == 1) {
2700	wsprintfA(buf, "%lu", (unsigned long) getpid());
2701	Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, -1));
2702    } else {
2703	chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[1], NULL),
2704		NULL);
2705	if (chan == (Tcl_Channel) NULL) {
2706	    return TCL_ERROR;
2707	}
2708	chanTypePtr = Tcl_GetChannelType(chan);
2709	if (chanTypePtr != &pipeChannelType) {
2710	    return TCL_OK;
2711	}
2712
2713	pipePtr = (PipeInfo *) Tcl_GetChannelInstanceData(chan);
2714	resultPtr = Tcl_NewObj();
2715	for (i = 0; i < pipePtr->numPids; i++) {
2716	    wsprintfA(buf, "%lu", TclpGetPid(pipePtr->pidPtr[i]));
2717	    Tcl_ListObjAppendElement(/*interp*/ NULL, resultPtr,
2718		    Tcl_NewStringObj(buf, -1));
2719	}
2720	Tcl_SetObjResult(interp, resultPtr);
2721    }
2722    return TCL_OK;
2723}
2724
2725/*
2726 *----------------------------------------------------------------------
2727 *
2728 * WaitForRead --
2729 *
2730 *	Wait until some data is available, the pipe is at EOF or the reader
2731 *	thread is blocked waiting for data (if the channel is in non-blocking
2732 *	mode).
2733 *
2734 * Results:
2735 *	Returns 1 if pipe is readable. Returns 0 if there is no data on the
2736 *	pipe, but there is buffered data. Returns -1 if an error occurred. If
2737 *	an error occurred, the threads may not be synchronized.
2738 *
2739 * Side effects:
2740 *	Updates the shared state flags and may consume 1 byte of data from the
2741 *	pipe. If no error occurred, the reader thread is blocked waiting for a
2742 *	signal from the main thread.
2743 *
2744 *----------------------------------------------------------------------
2745 */
2746
2747static int
2748WaitForRead(
2749    PipeInfo *infoPtr,		/* Pipe state. */
2750    int blocking)		/* Indicates whether call should be blocking
2751				 * or not. */
2752{
2753    DWORD timeout, count;
2754    HANDLE *handle = ((WinFile *) infoPtr->readFile)->handle;
2755
2756    while (1) {
2757	/*
2758	 * Synchronize with the reader thread.
2759	 */
2760
2761	timeout = blocking ? INFINITE : 0;
2762	if (WaitForSingleObject(infoPtr->readable, timeout) == WAIT_TIMEOUT) {
2763	    /*
2764	     * The reader thread is blocked waiting for data and the channel
2765	     * is in non-blocking mode.
2766	     */
2767
2768	    errno = EAGAIN;
2769	    return -1;
2770	}
2771
2772	/*
2773	 * At this point, the two threads are synchronized, so it is safe to
2774	 * access shared state.
2775	 */
2776
2777	/*
2778	 * If the pipe has hit EOF, it is always readable.
2779	 */
2780
2781	if (infoPtr->readFlags & PIPE_EOF) {
2782	    return 1;
2783	}
2784
2785	/*
2786	 * Check to see if there is any data sitting in the pipe.
2787	 */
2788
2789	if (PeekNamedPipe(handle, (LPVOID) NULL, (DWORD) 0,
2790		(LPDWORD) NULL, &count, (LPDWORD) NULL) != TRUE) {
2791	    TclWinConvertError(GetLastError());
2792
2793	    /*
2794	     * Check to see if the peek failed because of EOF.
2795	     */
2796
2797	    if (errno == EPIPE) {
2798		infoPtr->readFlags |= PIPE_EOF;
2799		return 1;
2800	    }
2801
2802	    /*
2803	     * Ignore errors if there is data in the buffer.
2804	     */
2805
2806	    if (infoPtr->readFlags & PIPE_EXTRABYTE) {
2807		return 0;
2808	    } else {
2809		return -1;
2810	    }
2811	}
2812
2813	/*
2814	 * We found some data in the pipe, so it must be readable.
2815	 */
2816
2817	if (count > 0) {
2818	    return 1;
2819	}
2820
2821	/*
2822	 * The pipe isn't readable, but there is some data sitting in the
2823	 * buffer, so return immediately.
2824	 */
2825
2826	if (infoPtr->readFlags & PIPE_EXTRABYTE) {
2827	    return 0;
2828	}
2829
2830	/*
2831	 * There wasn't any data available, so reset the thread and try again.
2832	 */
2833
2834	ResetEvent(infoPtr->readable);
2835	SetEvent(infoPtr->startReader);
2836    }
2837}
2838
2839/*
2840 *----------------------------------------------------------------------
2841 *
2842 * PipeReaderThread --
2843 *
2844 *	This function runs in a separate thread and waits for input to become
2845 *	available on a pipe.
2846 *
2847 * Results:
2848 *	None.
2849 *
2850 * Side effects:
2851 *	Signals the main thread when input become available. May cause the
2852 *	main thread to wake up by posting a message. May consume one byte from
2853 *	the pipe for each wait operation. Will cause a memory leak of ~4k, if
2854 *	forcefully terminated with TerminateThread().
2855 *
2856 *----------------------------------------------------------------------
2857 */
2858
2859static DWORD WINAPI
2860PipeReaderThread(
2861    LPVOID arg)
2862{
2863    PipeInfo *infoPtr = (PipeInfo *)arg;
2864    HANDLE *handle = ((WinFile *) infoPtr->readFile)->handle;
2865    DWORD count, err;
2866    int done = 0;
2867    HANDLE wEvents[2];
2868    DWORD waitResult;
2869
2870    wEvents[0] = infoPtr->stopReader;
2871    wEvents[1] = infoPtr->startReader;
2872
2873    while (!done) {
2874	/*
2875	 * Wait for the main thread to signal before attempting to wait on the
2876	 * pipe becoming readable.
2877	 */
2878
2879	waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
2880
2881	if (waitResult != (WAIT_OBJECT_0 + 1)) {
2882	    /*
2883	     * The start event was not signaled. It might be the stop event or
2884	     * an error, so exit.
2885	     */
2886
2887	    break;
2888	}
2889
2890	/*
2891	 * Try waiting for 0 bytes. This will block until some data is
2892	 * available on NT, but will return immediately on Win 95. So, if no
2893	 * data is available after the first read, we block until we can read
2894	 * a single byte off of the pipe.
2895	 */
2896
2897	if (ReadFile(handle, NULL, 0, &count, NULL) == FALSE ||
2898		PeekNamedPipe(handle, NULL, 0, NULL, &count, NULL) == FALSE) {
2899	    /*
2900	     * The error is a result of an EOF condition, so set the EOF bit
2901	     * before signalling the main thread.
2902	     */
2903
2904	    err = GetLastError();
2905	    if (err == ERROR_BROKEN_PIPE) {
2906		infoPtr->readFlags |= PIPE_EOF;
2907		done = 1;
2908	    } else if (err == ERROR_INVALID_HANDLE) {
2909		break;
2910	    }
2911	} else if (count == 0) {
2912	    if (ReadFile(handle, &(infoPtr->extraByte), 1, &count, NULL)
2913		    != FALSE) {
2914		/*
2915		 * One byte was consumed as a side effect of waiting for the
2916		 * pipe to become readable.
2917		 */
2918
2919		infoPtr->readFlags |= PIPE_EXTRABYTE;
2920	    } else {
2921		err = GetLastError();
2922		if (err == ERROR_BROKEN_PIPE) {
2923		    /*
2924		     * The error is a result of an EOF condition, so set the
2925		     * EOF bit before signalling the main thread.
2926		     */
2927
2928		    infoPtr->readFlags |= PIPE_EOF;
2929		    done = 1;
2930		} else if (err == ERROR_INVALID_HANDLE) {
2931		    break;
2932		}
2933	    }
2934	}
2935
2936
2937	/*
2938	 * Signal the main thread by signalling the readable event and then
2939	 * waking up the notifier thread.
2940	 */
2941
2942	SetEvent(infoPtr->readable);
2943
2944	/*
2945	 * Alert the foreground thread. Note that we need to treat this like a
2946	 * critical section so the foreground thread does not terminate this
2947	 * thread while we are holding a mutex in the notifier code.
2948	 */
2949
2950	Tcl_MutexLock(&pipeMutex);
2951	if (infoPtr->threadId != NULL) {
2952	    /*
2953	     * TIP #218. When in flight ignore the event, no one will receive
2954	     * it anyway.
2955	     */
2956
2957	    Tcl_ThreadAlert(infoPtr->threadId);
2958	}
2959	Tcl_MutexUnlock(&pipeMutex);
2960    }
2961
2962    return 0;
2963}
2964
2965/*
2966 *----------------------------------------------------------------------
2967 *
2968 * PipeWriterThread --
2969 *
2970 *	This function runs in a separate thread and writes data onto a pipe.
2971 *
2972 * Results:
2973 *	Always returns 0.
2974 *
2975 * Side effects:
2976 *	Signals the main thread when an output operation is completed. May
2977 *	cause the main thread to wake up by posting a message.
2978 *
2979 *----------------------------------------------------------------------
2980 */
2981
2982static DWORD WINAPI
2983PipeWriterThread(
2984    LPVOID arg)
2985{
2986    PipeInfo *infoPtr = (PipeInfo *)arg;
2987    HANDLE *handle = ((WinFile *) infoPtr->writeFile)->handle;
2988    DWORD count, toWrite;
2989    char *buf;
2990    int done = 0;
2991    HANDLE wEvents[2];
2992    DWORD waitResult;
2993
2994    wEvents[0] = infoPtr->stopWriter;
2995    wEvents[1] = infoPtr->startWriter;
2996
2997    while (!done) {
2998	/*
2999	 * Wait for the main thread to signal before attempting to write.
3000	 */
3001
3002	waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
3003
3004	if (waitResult != (WAIT_OBJECT_0 + 1)) {
3005	    /*
3006	     * The start event was not signaled. It might be the stop event or
3007	     * an error, so exit.
3008	     */
3009
3010	    break;
3011	}
3012
3013	buf = infoPtr->writeBuf;
3014	toWrite = infoPtr->toWrite;
3015
3016	/*
3017	 * Loop until all of the bytes are written or an error occurs.
3018	 */
3019
3020	while (toWrite > 0) {
3021	    if (WriteFile(handle, buf, toWrite, &count, NULL) == FALSE) {
3022		infoPtr->writeError = GetLastError();
3023		done = 1;
3024		break;
3025	    } else {
3026		toWrite -= count;
3027		buf += count;
3028	    }
3029	}
3030
3031	/*
3032	 * Signal the main thread by signalling the writable event and then
3033	 * waking up the notifier thread.
3034	 */
3035
3036	SetEvent(infoPtr->writable);
3037
3038	/*
3039	 * Alert the foreground thread. Note that we need to treat this like a
3040	 * critical section so the foreground thread does not terminate this
3041	 * thread while we are holding a mutex in the notifier code.
3042	 */
3043
3044	Tcl_MutexLock(&pipeMutex);
3045	if (infoPtr->threadId != NULL) {
3046	    /*
3047	     * TIP #218. When in flight ignore the event, no one will receive
3048	     * it anyway.
3049	     */
3050
3051	    Tcl_ThreadAlert(infoPtr->threadId);
3052	}
3053	Tcl_MutexUnlock(&pipeMutex);
3054    }
3055
3056    return 0;
3057}
3058
3059/*
3060 *----------------------------------------------------------------------
3061 *
3062 * PipeThreadActionProc --
3063 *
3064 *	Insert or remove any thread local refs to this channel.
3065 *
3066 * Results:
3067 *	None.
3068 *
3069 * Side effects:
3070 *	Changes thread local list of valid channels.
3071 *
3072 *----------------------------------------------------------------------
3073 */
3074
3075static void
3076PipeThreadActionProc(
3077    ClientData instanceData,
3078    int action)
3079{
3080    PipeInfo *infoPtr = (PipeInfo *) instanceData;
3081
3082    /*
3083     * We do not access firstPipePtr in the thread structures. This is not for
3084     * all pipes managed by the thread, but only those we are watching.
3085     * Removal of the filevent handlers before transfer thus takes care of
3086     * this structure.
3087     */
3088
3089    Tcl_MutexLock(&pipeMutex);
3090    if (action == TCL_CHANNEL_THREAD_INSERT) {
3091	/*
3092	 * We can't copy the thread information from the channel when the
3093	 * channel is created. At this time the channel back pointer has not
3094	 * been set yet. However in that case the threadId has already been
3095	 * set by TclpCreateCommandChannel itself, so the structure is still
3096	 * good.
3097	 */
3098
3099	PipeInit();
3100	if (infoPtr->channel != NULL) {
3101	    infoPtr->threadId = Tcl_GetChannelThread(infoPtr->channel);
3102	}
3103    } else {
3104	infoPtr->threadId = NULL;
3105    }
3106    Tcl_MutexUnlock(&pipeMutex);
3107}
3108
3109/*
3110 * Local Variables:
3111 * mode: c
3112 * c-basic-offset: 4
3113 * fill-column: 78
3114 * End:
3115 */
3116