Diff
Not logged in

Differences From Artifact [778f870642]:

To Artifact [a5a507f6da]:


120
121
122
123
124
125
126
127

128
129
130
131
132
133
134
135
120
121
122
123
124
125
126

127

128
129
130
131
132
133
134







-
+
-







    HANDLE readable;		/* Manual-reset event to signal when the
				 * reader thread has finished waiting for
				 * input. */
    DWORD writeError;		/* An error caused by the last background
				 * write. Set to 0 if no error has been
				 * detected. This word is shared with the
				 * writer thread so access must be
				 * synchronized with the writable object.
				 * synchronized with the writable object. */
				 */
    char *writeBuf;		/* Current background output buffer. Access is
				 * synchronized with the writable object. */
    int writeBufLen;		/* Size of write buffer. Access is
				 * synchronized with the writable object. */
    int toWrite;		/* Current amount to be written. Access is
				 * synchronized with the writable object. */
    int readFlags;		/* Flags that are shared with the reader
214
215
216
217
218
219
220
221

222
223
224
225
226
227
228
213
214
215
216
217
218
219

220
221
222
223
224
225
226
227







-
+







    PipeGetHandleProc,		/* Get an OS handle from channel. */
    PipeClose2Proc,		/* close2proc */
    PipeBlockModeProc,		/* Set blocking or non-blocking mode.*/
    NULL,			/* flush proc. */
    NULL,			/* handler proc. */
    NULL,			/* wide seek proc */
    PipeThreadActionProc,	/* thread action proc */
    NULL                       /* truncate */
    NULL			/* truncate */
};

/*
 *----------------------------------------------------------------------
 *
 * PipeInit --
 *
1424
1425
1426
1427
1428
1429
1430
1431

1432
1433





1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448

1449

1450
1451

1452
1453
1454
1455

1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470

1471

1472

1473



1474
1475
1476

1477



1478
1479
1480

1481
1482
1483
1484
1485





1486

1487
1488
1489
1490
1491

1492



1493
1494



1495
1496
1497

1498



1499
1500

1501




1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523





1524
1525
1526



1527
1528
1529
1530
1531
1532
1533
1423
1424
1425
1426
1427
1428
1429

1430


1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449

1450

1451
1452

1453
1454
1455
1456

1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471

1472

1473
1474
1475

1476
1477
1478
1479
1480
1481
1482

1483
1484
1485
1486
1487
1488
1489
1490




1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503

1504
1505
1506
1507

1508
1509
1510
1511
1512
1513
1514

1515
1516
1517
1518
1519
1520

1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542




1543
1544
1545
1546
1547



1548
1549
1550
1551
1552
1553
1554
1555
1556
1557







-
+
-
-
+
+
+
+
+














-
+
-
+

-
+



-
+














-
+
-
+

+
-
+
+
+



+
-
+
+
+



+

-
-
-
-
+
+
+
+
+

+





+
-
+
+
+

-
+
+
+



+
-
+
+
+


+
-
+
+
+
+


















-
-
-
-
+
+
+
+
+
-
-
-
+
+
+







 *
 *----------------------------------------------------------------------
 */

static const char *
BuildCmdLineBypassBS(
    const char *current,
    const char **bspos
    const char **bspos)
) {
    /* mark first backslash possition */
{
    /*
     * Mark first backslash position.
     */

    if (!*bspos) {
	*bspos = current;
    }
    do {
	current++;
    } while (*current == '\\');
    return current;
}

static void
QuoteCmdLineBackslash(
    Tcl_DString *dsPtr,
    const char *start,
    const char *current,
    const char *bspos
    const char *bspos)
) {
{
    if (!bspos) {
	if (current > start) { /* part before current (special) */
	if (current > start) {	/* part before current (special) */
	    Tcl_DStringAppend(dsPtr, start, (int) (current - start));
	}
    } else {
    	if (bspos > start) { /* part before first backslash */
    	if (bspos > start) {	/* part before first backslash */
	    Tcl_DStringAppend(dsPtr, start, (int) (bspos - start));
	}
	while (bspos++ < current) { /* each backslash twice */
	    TclDStringAppendLiteral(dsPtr, "\\\\");
	}
    }
}

static const char *
QuoteCmdLinePart(
    Tcl_DString *dsPtr,
    const char *start,
    const char *special,
    const char *specMetaChars,
    const char **bspos
    const char **bspos)
) {
{
    if (!*bspos) {
	/*
	/* rest before special (before quote) */
	 * Rest before special (before quote).
	 */

	QuoteCmdLineBackslash(dsPtr, start, special, NULL);
	start = special;
    } else {
	/*
	/* rest before first backslash and backslashes into new quoted block */
	 * Rest before first backslash and backslashes into new quoted block.
	 */

	QuoteCmdLineBackslash(dsPtr, start, *bspos, NULL);
	start = *bspos;
    }

    /*
     * escape all special chars enclosed in quotes like `"..."`, note that here we
     * don't must escape `\` (with `\`), because it's outside of the main quotes,
     * so `\` remains `\`, but important - not at end of part, because results as
     * before the quote,  so `%\%\` should be escaped as `"%\%"\\`).
     * escape all special chars enclosed in quotes like `"..."`, note that
     * here we don't must escape `\` (with `\`), because it's outside of the
     * main quotes, so `\` remains `\`, but important - not at end of part,
     * because results as before the quote, so `%\%\` should be escaped as
     * `"%\%"\\`).
     */

    TclDStringAppendLiteral(dsPtr, "\""); /* opening escape quote-char */
    do {
    	*bspos = NULL;
	special++;
	if (*special == '\\') {
	    /*
	    /* bypass backslashes (and mark first backslash possition)*/
	     * Bypass backslashes (and mark first backslash position).
	     */

	    special = BuildCmdLineBypassBS(special, bspos);
	    if (*special == '\0') break;
	    if (*special == '\0') {
		break;
	    }
	}
    } while (*special && strchr(specMetaChars, *special));
    if (!*bspos) {
	/*
	/* unescaped rest before quote */
	 * Unescaped rest before quote.
	 */

	QuoteCmdLineBackslash(dsPtr, start, special, NULL);
    } else {
	/*
	/* unescaped rest before first backslash (rather belongs to the main block) */
	 * Unescaped rest before first backslash (rather belongs to the main
	 * block).
	 */

	QuoteCmdLineBackslash(dsPtr, start, *bspos, NULL);
    }
    TclDStringAppendLiteral(dsPtr, "\""); /* closing escape quote-char */
    return special;
}

static void
BuildCommandLine(
    const char *executable,	/* Full path of executable (including
				 * extension). Replacement for argv[0]. */
    int argc,			/* Number of arguments. */
    const char **argv,		/* Argument strings in UTF. */
    Tcl_DString *linePtr)	/* Initialized Tcl_DString that receives the
				 * command line (WCHAR). */
{
    const char *arg, *start, *special, *bspos;
    int quote = 0, i;
    Tcl_DString ds;

    /* characters to enclose in quotes if unpaired quote flag set */
    static const char specMetaChars[] = "&|^<>!()%";
    /* character to enclose in quotes in any case (regardless unpaired-flag) */
    static const char specMetaChars[] = "&|^<>!()%";
				/* Characters to enclose in quotes if unpaired
				 * quote flag set. */
    static const char specMetaChars2[] = "%";
				/* Character to enclose in quotes in any case
    static const char specMetaChars2[] = "%";

    /* Quote flags:
				 * (regardless of unpaired-flag). */
    /*
     * Quote flags:
     *   CL_ESCAPE   - escape argument;
     *   CL_QUOTE    - enclose in quotes;
     *   CL_UNPAIRED - previous arguments chain contains unpaired quote-char;
     */
    enum {CL_ESCAPE = 1, CL_QUOTE = 2, CL_UNPAIRED = 4};

    Tcl_DStringInit(&ds);
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560



1561
1562



1563
1564
1565


1566
1567
1568
1569
1570
1571
1572

1573
1574
1575
1576

1577
1578
1579
1580
1581

1582
1583
1584
1585
1586
1587
1588
1589
1590

1591



1592
1593
1594

1595



1596
1597
1598
1599

1600




1601

1602



1603
1604



1605
1606
1607




1608
1609






1610
1611


1612



1613
1614
1615
1616


1617




1618
1619
1620







1621
1622
1623


1624




1625
1626
1627







1628
1629
1630


1631
1632





1633
1634


1635




1636
1637

1638
1639

1640



1641
1642
1643
1644
1645
1646
1647
1575
1576
1577
1578
1579
1580
1581



1582
1583
1584


1585
1586
1587
1588


1589
1590
1591
1592
1593
1594
1595
1596

1597
1598
1599
1600

1601
1602
1603
1604
1605

1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616

1617
1618
1619
1620
1621
1622
1623

1624
1625
1626
1627
1628
1629
1630
1631

1632
1633
1634
1635
1636
1637

1638
1639
1640
1641

1642
1643
1644
1645
1646
1647
1648
1649
1650
1651


1652
1653
1654
1655
1656
1657
1658
1659
1660
1661

1662
1663
1664
1665
1666
1667
1668
1669
1670

1671
1672
1673
1674
1675


1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687

1688
1689
1690
1691
1692


1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704


1705
1706
1707
1708
1709
1710
1711
1712
1713

1714
1715
1716
1717
1718

1719
1720
1721
1722

1723
1724
1725
1726
1727
1728
1729
1730
1731
1732







-
-
-
+
+
+
-
-
+
+
+

-
-
+
+






-
+



-
+




-
+









+
-
+
+
+



+
-
+
+
+




+
-
+
+
+
+

+
-
+
+
+

-
+
+
+



+
+
+
+
-
-
+
+
+
+
+
+


+
+
-
+
+
+




+
+
-
+
+
+
+

-
-
+
+
+
+
+
+
+



+
+
-
+
+
+
+

-
-
+
+
+
+
+
+
+



+
+
-
-
+
+
+
+
+


+
+
-
+
+
+
+

-
+


+
-
+
+
+








	quote &= ~(CL_ESCAPE|CL_QUOTE); /* reset escape flags */
	bspos = NULL;
	if (arg[0] == '\0') {
	    quote = CL_QUOTE;
	} else {
	    for (start = arg;
		*start != '\0' &&
		    (quote & (CL_ESCAPE|CL_QUOTE)) != (CL_ESCAPE|CL_QUOTE);
		start++
		    *start != '\0' &&
			(quote & (CL_ESCAPE|CL_QUOTE)) != (CL_ESCAPE|CL_QUOTE);
		    start++) {
	    ) {
		if (*start & 0x80) continue;
		if (*start & 0x80) {
		    continue;
		}
		if (TclIsSpaceProc(*start)) {
		    quote |= CL_QUOTE; /* quote only */
		    if (bspos) { /* if backslash found - escape & quote */
		    quote |= CL_QUOTE;	/* quote only */
		    if (bspos) {	/* if backslash found, escape & quote */
			quote |= CL_ESCAPE;
			break;
		    }
		    continue;
		}
		if (strchr(specMetaChars, *start)) {
		    quote |= (CL_ESCAPE|CL_QUOTE); /*escape & quote */
		    quote |= (CL_ESCAPE|CL_QUOTE); /* escape & quote */
		    break;
		}
		if (*start == '"') {
		    quote |= CL_ESCAPE; /* escape only */
		    quote |= CL_ESCAPE;		/* escape only */
		    continue;
		}
		if (*start == '\\') {
		    bspos = start;
		    if (quote & CL_QUOTE) { /* if quote - escape & quote */
		    if (quote & CL_QUOTE) {	/* if quote, escape & quote */
			quote |= CL_ESCAPE;
			break;
		    }
		    continue;
		}
	    }
	    bspos = NULL;
	}
	if (quote & CL_QUOTE) {
	    /*
	    /* start of argument (main opening quote-char) */
	     * Start of argument (main opening quote-char).
	     */

	    TclDStringAppendLiteral(&ds, "\"");
	}
	if (!(quote & CL_ESCAPE)) {
	    /*
	    /* nothing to escape */
	     * Nothing to escape.
	     */

	    Tcl_DStringAppend(&ds, arg, -1);
	} else {
	    start = arg;
	    for (special = arg; *special != '\0'; ) {
		/*
		/* position of `\` is important before quote or at end (equal `\"` because quoted) */
		 * Position of `\` is important before quote or at end (equal
		 * `\"` because quoted).
		 */

		if (*special == '\\') {
		    /*
		    /* bypass backslashes (and mark first backslash possition)*/
		     * Bypass backslashes (and mark first backslash position)
		     */

		    special = BuildCmdLineBypassBS(special, &bspos);
		    if (*special == '\0') break;
		    if (*special == '\0') {
			break;
		    }
		}
		/* ["] */
		if (*special == '"') {
		    /*
		     * Invert the unpaired flag - observe unpaired quotes
		     */

		    quote ^= CL_UNPAIRED; /* invert unpaired flag - observe unpaired quotes */
		    /* add part before (and escape backslashes before quote) */
		    quote ^= CL_UNPAIRED;

		    /*
		     * Add part before (and escape backslashes before quote).
		     */

		    QuoteCmdLineBackslash(&ds, start, special, bspos);
		    bspos = NULL;

		    /*
		    /* escape using backslash */
		     * Escape using backslash
		     */

		    TclDStringAppendLiteral(&ds, "\\\"");
		    start = ++special;
		    continue;
		}

		/*
		/* unpaired (escaped) quote causes special handling on meta-chars */
		 * Unpaired (escaped) quote causes special handling on
		 * meta-chars
		 */

		if ((quote & CL_UNPAIRED) && strchr(specMetaChars, *special)) {
		    special = QuoteCmdLinePart(&ds, start, special, specMetaChars, &bspos);
		    /* start to current or first backslash */
		    special = QuoteCmdLinePart(&ds, start, special,
			    specMetaChars, &bspos);

		    /*
		     * Start to current or first backslash
		     */

		    start = !bspos ? special : bspos;
		    continue;
		}

		/*
		/* special case for % - should be enclosed always (paired also) */
		 * Special case for % - should be enclosed always (paired
		 * also)
		 */

		if (strchr(specMetaChars2, *special)) {
		    special = QuoteCmdLinePart(&ds, start, special, specMetaChars2, &bspos);
		    /* start to current or first backslash */
		    special = QuoteCmdLinePart(&ds, start, special,
			    specMetaChars2, &bspos);

		    /*
		     * Start to current or first backslash.
		     */

		    start = !bspos ? special : bspos;
		    continue;
		}

		/*
		/* other not special (and not meta) character */
		bspos = NULL; /* reset last backslash possition (not interesting) */
		 * Other not special (and not meta) character
		 */

		bspos = NULL;		/* reset last backslash position (not
					 * interesting) */
		special++;
	    }

	    /*
	    /* rest of argument (and escape backslashes before closing main quote) */
	     * Rest of argument (and escape backslashes before closing main
	     * quote)
	     */

	    QuoteCmdLineBackslash(&ds, start, special,
	    	(quote & CL_QUOTE) ? bspos : NULL);
		    (quote & CL_QUOTE) ? bspos : NULL);
	}
	if (quote & CL_QUOTE) {
	    /*
	    /* end of argument (main closing quote-char) */
	     * End of argument (main closing quote-char)
	     */

	    TclDStringAppendLiteral(&ds, "\"");
	}
    }
    Tcl_DStringFree(linePtr);
    Tcl_WinUtfToTChar(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), linePtr);
    Tcl_DStringFree(&ds);
}
2171
2172
2173
2174
2175
2176
2177
2178
2179



2180
2181
2182
2183
2184
2185
2186
2256
2257
2258
2259
2260
2261
2262


2263
2264
2265
2266
2267
2268
2269
2270
2271
2272







-
-
+
+
+







    PipeInfo *infoPtr = (PipeInfo *) instanceData;
    WinFile *filePtr = (WinFile*) infoPtr->writeFile;
    DWORD bytesWritten, timeout;

    *errorCode = 0;

    /* avoid blocking if pipe-thread exited */
    timeout = ((infoPtr->flags & PIPE_ASYNC) || !TclPipeThreadIsAlive(&infoPtr->writeTI)
	|| TclInExit() || TclInThreadExit()) ? 0 : INFINITE;
    timeout = ((infoPtr->flags & PIPE_ASYNC)
	    || !TclPipeThreadIsAlive(&infoPtr->writeTI)
	    || TclInExit() || TclInThreadExit()) ? 0 : INFINITE;
    if (WaitForSingleObject(infoPtr->writable, timeout) == WAIT_TIMEOUT) {
	/*
	 * The writer thread is blocked waiting for a write to complete and
	 * the channel is in non-blocking mode.
	 */

	errno = EWOULDBLOCK;
2358
2359
2360
2361
2362
2363
2364

2365
2366
2367
2368
2369
2370
2371
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458







+







     * Since most of the work is handled by the background threads, we just
     * need to update the watchMask and then force the notifier to poll once.
     */

    infoPtr->watchMask = mask & infoPtr->validMask;
    if (infoPtr->watchMask) {
	Tcl_Time blockTime = { 0, 0 };

	if (!oldMask) {
	    infoPtr->nextPtr = tsdPtr->firstPipePtr;
	    tsdPtr->firstPipePtr = infoPtr;
	}
	Tcl_SetMaxBlockTime(&blockTime);
    } else {
	if (oldMask) {
2827
2828
2829
2830
2831
2832
2833
2834

2835
2836
2837
2838
2839
2840
2841
2842
2843
2844

2845
2846
2847
2848
2849
2850
2851

2852
2853
2854
2855
2856
2857
2858
2914
2915
2916
2917
2918
2919
2920

2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938

2939
2940
2941
2942
2943
2944
2945
2946







-
+










+






-
+







 *----------------------------------------------------------------------
 */

static DWORD WINAPI
PipeReaderThread(
    LPVOID arg)
{
    TclPipeThreadInfo *pipeTI = (TclPipeThreadInfo *)arg;
    TclPipeThreadInfo *pipeTI = (TclPipeThreadInfo *) arg;
    PipeInfo *infoPtr = NULL; /* access info only after success init/wait */
    HANDLE handle = NULL;
    DWORD count, err;
    int done = 0;

    while (!done) {
	/*
	 * Wait for the main thread to signal before attempting to wait on the
	 * pipe becoming readable.
	 */

	if (!TclPipeThreadWaitForSignal(&pipeTI)) {
	    /* exit */
	    break;
	}

	if (!infoPtr) {
	    infoPtr = (PipeInfo *)pipeTI->clientData;
	    infoPtr = (PipeInfo *) pipeTI->clientData;
	    handle = ((WinFile *) infoPtr->readFile)->handle;
	}

	/*
	 * Try waiting for 0 bytes. This will block until some data is
	 * available on NT, but will return immediately on Win 95. So, if no
	 * data is available after the first read, we block until we can read
3191
3192
3193
3194
3195
3196
3197
3198

3199
3200
3201
3202
3203
3204
3205
3279
3280
3281
3282
3283
3284
3285

3286
3287
3288
3289
3290
3291
3292
3293







-
+







    HANDLE wakeEvent)
{
    TclPipeThreadInfo *pipeTI;
#ifndef _PTI_USE_CKALLOC
    pipeTI = malloc(sizeof(TclPipeThreadInfo));
#else
    pipeTI = Tcl_Alloc(sizeof(TclPipeThreadInfo));
#endif
#endif /* !_PTI_USE_CKALLOC */
    pipeTI->evControl = CreateEvent(NULL, FALSE, FALSE, NULL);
    pipeTI->state = PTI_STATE_IDLE;
    pipeTI->clientData = clientData;
    pipeTI->evWakeUp = wakeEvent;
    return (*pipeTIPtr = pipeTI);
}

3230
3231
3232
3233
3234
3235
3236

3237
3238
3239
3240

3241
3242
3243
3244










3245
3246


3247

3248

3249

3250
3251
3252
3253
3254
3255

3256
3257
3258

3259
3260
3261
3262










3263
3264
3265

3266



3267
3268
3269
3270





3271
3272
3273
3274
3275
3276
3277
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330




3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344

3345

3346
3347
3348
3349

3350
3351
3352
3353
3354
3355
3356
3357
3358




3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372

3373
3374
3375
3376
3377


3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389







+




+
-
-
-
-
+
+
+
+
+
+
+
+
+
+


+
+
-
+
-
+

+

-




+



+
-
-
-
-
+
+
+
+
+
+
+
+
+
+



+
-
+
+
+


-
-
+
+
+
+
+







    HANDLE wakeEvent;

    if (!pipeTI) {
	return 0;
    }

    wakeEvent = pipeTI->evWakeUp;

    /*
     * Wait for the main thread to signal before attempting to do the work.
     */

    /*
    /* reset work state of thread (idle/waiting) */
    if ((state = InterlockedCompareExchange(&pipeTI->state,
	    PTI_STATE_IDLE, PTI_STATE_WORK)) & (PTI_STATE_STOP|PTI_STATE_END)) {
	/* end of work, check the owner of structure */
     * Reset work state of thread (idle/waiting)
     */

    state = InterlockedCompareExchange(&pipeTI->state, PTI_STATE_IDLE,
	    PTI_STATE_WORK);
    if (state & (PTI_STATE_STOP|PTI_STATE_END)) {
	/*
	 * End of work, check the owner of structure.
	 */

	goto end;
    }

    /*
    /* entering wait */
     * Entering wait
    waitResult = WaitForSingleObject(pipeTI->evControl, INFINITE);
     */

    waitResult = WaitForSingleObject(pipeTI->evControl, INFINITE);
    if (waitResult != WAIT_OBJECT_0) {

	/*
	 * The control event was not signaled, so end of work (unexpected
	 * behaviour, main thread can be dead?).
	 */

	goto end;
    }

    /*
    /* try to set work state of thread */
    if ((state = InterlockedCompareExchange(&pipeTI->state,
	    PTI_STATE_WORK, PTI_STATE_IDLE)) & (PTI_STATE_STOP|PTI_STATE_END)) {
	/* end of work */
     * Try to set work state of thread
     */

    state = InterlockedCompareExchange(&pipeTI->state, PTI_STATE_WORK,
	    PTI_STATE_IDLE);
    if (state & (PTI_STATE_STOP|PTI_STATE_END)) {
	/*
	 * End of work
	 */

	goto end;
    }

    /*
    /* signaled to work */
     * Signaled to work.
     */

    return 1;

end:
    /* end of work, check the owner of the TI structure */
  end:
    /*
     * End of work, check the owner of the TI structure.
     */

    if (state != PTI_STATE_STOP) {
	*pipeTIPtr = NULL;
    } else {
    	pipeTI->evWakeUp = NULL;
    }
    if (wakeEvent) {
    	SetEvent(wakeEvent);
3293
3294
3295
3296
3297
3298
3299
3300


3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314



3315
3316
3317
3318



3319

3320

3321

3322
3323

3324
3325
3326
3327
3328
3329
3330
3331
3332








3333
3334
3335
3336
3337
3338
3339
3405
3406
3407
3408
3409
3410
3411

3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423




3424
3425
3426




3427
3428
3429

3430
3431
3432

3433


3434

3435
3436






3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451







-
+
+










-
-
-
-
+
+
+
-
-
-
-
+
+
+
-
+

+
-
+
-
-
+
-


-
-
-
-
-
-
+
+
+
+
+
+
+
+







 *	1 if signaled (or pipe-thread is down), 0 if pipe thread still working.
 *
 *----------------------------------------------------------------------
 */

int
TclPipeThreadStopSignal(
    TclPipeThreadInfo **pipeTIPtr, HANDLE wakeEvent)
    TclPipeThreadInfo **pipeTIPtr,
    HANDLE wakeEvent)
{
    TclPipeThreadInfo *pipeTI = *pipeTIPtr;
    HANDLE evControl;
    int state;

    if (!pipeTI) {
	return 1;
    }
    evControl = pipeTI->evControl;
    pipeTI->evWakeUp = wakeEvent;
    switch (
	(state = InterlockedCompareExchange(&pipeTI->state,
	    PTI_STATE_STOP, PTI_STATE_IDLE))
    ) {
    state = InterlockedCompareExchange(&pipeTI->state, PTI_STATE_STOP,
	    PTI_STATE_IDLE);
    switch (state) {

	case PTI_STATE_IDLE:

	    /* Thread was idle/waiting, notify it goes teardown */
    case PTI_STATE_IDLE:
	/*
	 * Thread was idle/waiting, notify it goes teardown
	    SetEvent(evControl);
	 */

	SetEvent(evControl);
	    *pipeTIPtr = NULL;
	*pipeTIPtr = NULL;

	case PTI_STATE_DOWN:
    case PTI_STATE_DOWN:

	return 1;

	default:
	    /*
	     * Thread works currently, we should try to end it, own the TI structure
	     * (because of possible sharing the joint structures with thread)
	     */
	    InterlockedExchange(&pipeTI->state, PTI_STATE_END);
    default:
	/*
	 * Thread works currently, we should try to end it, own the TI
	 * structure (because of possible sharing the joint structures with
	 * thread)
	 */

	InterlockedExchange(&pipeTI->state, PTI_STATE_END);
	break;
    }

    return 0;
}

/*
3368
3369
3370
3371
3372
3373
3374

3375
3376
3377
3378
3379
3380
3381




3382
3383
3384
3385
3386






3387

3388
3389





3390
3391
3392
3393
3394






3395
3396
3397




3398

3399
3400



3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413














3414

3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430

3431
3432
3433
3434
3435
3436
3437
3438
3439
3440

3441
3442
3443
3444
3445


3446
3447

3448

3449

3450

3451
3452
3453
3454
3455
3456





3457
3458

3459
3460
3461
3462



3463
3464
3465
3466
3467
3468
3469
3470
3471











3472
3473
3474
3475


3476
3477


3478
3479
3480
3481
3482



3483
3484
3485

3486




3487
3488
3489
3490
3491

3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503

3504
3505

3506
3507

3508
3509
3510
3511
3512
3513
3514
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490




3491
3492
3493
3494





3495
3496
3497
3498
3499
3500
3501
3502


3503
3504
3505
3506
3507
3508
3509



3510
3511
3512
3513
3514
3515
3516


3517
3518
3519
3520
3521
3522


3523
3524
3525
3526
3527
3528










3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542

3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557

3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573


3574
3575
3576
3577
3578

3579

3580
3581
3582
3583





3584
3585
3586
3587
3588


3589
3590



3591
3592
3593
3594








3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608

3609
3610
3611

3612
3613
3614
3615



3616
3617
3618

3619
3620
3621

3622
3623
3624
3625
3626
3627
3628
3629

3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641

3642
3643

3644
3645

3646
3647
3648
3649
3650
3651
3652
3653







+



-
-
-
-
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+

+
-
-
+
+
+
+
+


-
-
-
+
+
+
+
+
+

-
-
+
+
+
+

+
-
-
+
+
+



-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+














-

+










+



-
-
+
+


+
-
+
-
+

+

-
-
-
-
-
+
+
+
+
+
-
-
+

-
-
-
+
+
+

-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+



-
+
+

-
+
+


-
-
-
+
+
+
-


+
-
+
+
+
+




-
+











-
+

-
+

-
+








    if (!pipeTI) {
	return;
    }
    pipeTI = *pipeTIPtr;
    evControl = pipeTI->evControl;
    pipeTI->evWakeUp = NULL;

    /*
     * Try to sane stop the pipe worker, corresponding its current state
     */
    switch (
	(state = InterlockedCompareExchange(&pipeTI->state,
	    PTI_STATE_STOP, PTI_STATE_IDLE))
    ) {

    state = InterlockedCompareExchange(&pipeTI->state, PTI_STATE_STOP,
	    PTI_STATE_IDLE);
    switch (state) {

	case PTI_STATE_IDLE:

	    /* Thread was idle/waiting, notify it goes teardown */
	    SetEvent(evControl);
    case PTI_STATE_IDLE:
	/*
	 * Thread was idle/waiting, notify it goes teardown
	 */

	SetEvent(evControl);

	/*
	    /* we don't need to wait for it at all, thread frees himself (owns the TI structure) */
	    pipeTI = NULL;
	 * We don't need to wait for it at all, thread frees himself (owns the
	 * TI structure)
	 */

	pipeTI = NULL;
	break;

	case PTI_STATE_STOP:
	    /* already stopped, thread frees himself (owns the TI structure) */
	    pipeTI = NULL;
    case PTI_STATE_STOP:
	/*
	 * Already stopped, thread frees himself (owns the TI structure)
	 */

	pipeTI = NULL;
	break;
	case PTI_STATE_DOWN:
	    /* Thread already down (?), do nothing */
    case PTI_STATE_DOWN:
	/*
	 * Thread already down (?), do nothing
	 */

	/*
	    /* we don't need to wait for it, but we should free pipeTI */
	    hThread = NULL;
	 * We don't need to wait for it, but we should free pipeTI
	 */
	hThread = NULL;
	break;

	/* case PTI_STATE_WORK: */
	default:
	    /*
	     * Thread works currently, we should try to end it, own the TI structure
	     * (because of possible sharing the joint structures with thread)
	     */
	    if ((state = InterlockedCompareExchange(&pipeTI->state,
		    PTI_STATE_END, PTI_STATE_WORK)) == PTI_STATE_DOWN
	    ) {
		/* we don't need to wait for it, but we should free pipeTI */
		hThread = NULL;
    default:
	/*
	 * Thread works currently, we should try to end it, own the TI
	 * structure (because of possible sharing the joint structures with
	 * thread)
	 */

	state = InterlockedCompareExchange(&pipeTI->state, PTI_STATE_END,
		PTI_STATE_WORK);
	if (state == PTI_STATE_DOWN) {
	    /*
	     * We don't need to wait for it, but we should free pipeTI
	     */
	    hThread = NULL;
	    };
	}
	break;
    }

    if (pipeTI && hThread) {
	DWORD exitCode;

	/*
	 * The thread may already have closed on its own. Check its exit
	 * code.
	 */

	GetExitCodeThread(hThread, &exitCode);

	if (exitCode == STILL_ACTIVE) {

	    int inExit = (TclInExit() || TclInThreadExit());

	    /*
	     * Set the stop event so that if the pipe thread is blocked
	     * somewhere, it may hereafter sane exit cleanly.
	     */

	    SetEvent(evControl);

	    /*
	     * Cancel all sync-IO of this thread (may be blocked there).
	     */

	    CancelSynchronousIo(hThread);

	    /*
	     * Wait at most 20 milliseconds for the reader thread to
	     * close (regarding TIP#398-fast-exit).
	     * Wait at most 20 milliseconds for the reader thread to close
	     * (regarding TIP#398-fast-exit).
	     */

	    /*
	    /* if we want TIP#398-fast-exit. */
	     * If we want TIP#398-fast-exit.
	    if (WaitForSingleObject(hThread, inExit ? 0 : 20) == WAIT_TIMEOUT) {
	     */

	    if (WaitForSingleObject(hThread, inExit ? 0 : 20) == WAIT_TIMEOUT) {
		/*
		 * The thread must be blocked waiting for the pipe to
		 * become readable in ReadFile(). There isn't a clean way
		 * to exit the thread from this condition. We should
		 * terminate the child process instead to get the reader
		 * thread to fall out of ReadFile with a FALSE. (below) is
		 * The thread must be blocked waiting for the pipe to become
		 * readable in ReadFile(). There isn't a clean way to exit the
		 * thread from this condition. We should terminate the child
		 * process instead to get the reader thread to fall out of
		 * ReadFile with a FALSE. (below) is not the correct way to do
		 * not the correct way to do this, but will stay here
		 * until a better solution is found.
		 * this, but will stay here until a better solution is found.
		 *
		 * Note that we need to guard against terminating the
		 * thread while it is in the middle of Tcl_ThreadAlert
		 * because it won't be able to release the notifier lock.
		 * Note that we need to guard against terminating the thread
		 * while it is in the middle of Tcl_ThreadAlert because it
		 * won't be able to release the notifier lock.
		 *
		 * Also note that terminating threads during their initialization or teardown phase
		 * may result in ntdll.dll's LoaderLock to remain locked indefinitely.
		 * This causes ntdll.dll's LdrpInitializeThread() to deadlock trying to acquire LoaderLock.
		 * LdrpInitializeThread() is executed within new threads to perform
		 * initialization and to execute DllMain() of all loaded dlls.
		 * As a result, all new threads are deadlocked in their initialization phase and never execute,
		 * even though CreateThread() reports successful thread creation.
		 * This results in a very weird process-wide behavior, which is extremely hard to debug.
		 * Also note that terminating threads during their
		 * initialization or teardown phase may result in ntdll.dll's
		 * LoaderLock to remain locked indefinitely.  This causes
		 * ntdll.dll's LdrpInitializeThread() to deadlock trying to
		 * acquire LoaderLock.  LdrpInitializeThread() is executed
		 * within new threads to perform initialization and to execute
		 * DllMain() of all loaded dlls.  As a result, all new threads
		 * are deadlocked in their initialization phase and never
		 * execute, even though CreateThread() reports successful
		 * thread creation.  This results in a very weird process-wide
		 * behavior, which is extremely hard to debug.
		 *
		 * THREADS SHOULD NEVER BE TERMINATED. Period.
		 *
		 * But for now, check if thread is exiting, and if so, let it die peacefully.
		 * But for now, check if thread is exiting, and if so, let it
		 * die peacefully.
		 *
		 * Also don't terminate if in exit (otherwise deadlocked in ntdll.dll's).
		 * Also don't terminate if in exit (otherwise deadlocked in
		 * ntdll.dll's).
		 */

		if ( pipeTI->state != PTI_STATE_DOWN
		  && WaitForSingleObject(hThread,
			inExit ? 50 : 5000) != WAIT_OBJECT_0
		if (pipeTI->state != PTI_STATE_DOWN
			&& WaitForSingleObject(hThread,
				inExit ? 50 : 5000) != WAIT_OBJECT_0) {
		) {
		    /* BUG: this leaks memory */
		    if (inExit || !TerminateThread(hThread, 0)) {
			/*
			/* in exit or terminate fails, just give thread a chance to exit */
			 * in exit or terminate fails, just give thread a
			 * chance to exit
			 */

			if (InterlockedExchange(&pipeTI->state,
				PTI_STATE_STOP) != PTI_STATE_DOWN) {
			    pipeTI = NULL;
			}
		    };
		    }
		}
	    }
	}
    }

    *pipeTIPtr = NULL;
    if (pipeTI) {
	if (pipeTI->evWakeUp) {
	    SetEvent(pipeTI->evWakeUp);
	}
	CloseHandle(pipeTI->evControl);
#   ifndef _PTI_USE_CKALLOC
#ifndef _PTI_USE_CKALLOC
	free(pipeTI);
#   else
#else
	Tcl_Free(pipeTI);
#   endif
#endif /* !_PTI_USE_CKALLOC */
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclPipeThreadExit --
3529
3530
3531
3532
3533
3534
3535

3536
3537
3538
3539
3540

3541
3542
3543
3544
3545
3546


3547
3548
3549
3550
3551

3552
3553

3554
3555
3556
3557

3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685


3686
3687
3688
3689
3690
3691

3692
3693

3694
3695
3696
3697

3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708







+





+




-
-
+
+




-
+

-
+



-
+











void
TclPipeThreadExit(
    TclPipeThreadInfo **pipeTIPtr)
{
    LONG state;
    TclPipeThreadInfo *pipeTI = *pipeTIPtr;

    /*
     * If state of thread was set to stop (exactly), we can sane free its info
     * structure, otherwise it is shared with main thread, so main thread will
     * own it.
     */

    if (!pipeTI) {
	return;
    }
    *pipeTIPtr = NULL;
    if ((state = InterlockedExchange(&pipeTI->state,
	    PTI_STATE_DOWN)) == PTI_STATE_STOP) {
    state = InterlockedExchange(&pipeTI->state, PTI_STATE_DOWN);
    if (state == PTI_STATE_STOP) {
	CloseHandle(pipeTI->evControl);
	if (pipeTI->evWakeUp) {
	    SetEvent(pipeTI->evWakeUp);
	}
#   ifndef _PTI_USE_CKALLOC
#ifndef _PTI_USE_CKALLOC
	free(pipeTI);
#   else
#else
	Tcl_Free(pipeTI);
	/* be sure all subsystems used are finalized */
	Tcl_FinalizeThread();
#   endif
#endif /* !_PTI_USE_CKALLOC */
    }
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */