Tcl Source Code

Check-in [b6459ef66c]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Do not reopen a win serial channel for serial detection. There are issues with some Bluetooth virtual com. Fix bug [2413550], patch by Rolf Schroedter
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | core-8-5-branch
Files: files | file ages | folders
SHA1: b6459ef66c2b5e7918fa1e82841b46f0b489531e
User & Date: oehhar 2014-02-24 17:25:08
References
2014-02-25
17:12 Closed ticket [2413550fff]: Avoid double-open of serial ports on Windows plus 8 other changes artifact: 0f7bd6e2f2 user: oehhar
Context
2014-02-26
17:47
New tests covering INPUT_NEED_NL flag handling. One exposes a bug. check-in: 279154c448 user: dgp tags: core-8-5-branch
2014-02-25
08:02
Do not reopen a win serial channel for serial detection. There are issues with some Bluetooth virtua... check-in: eb0919a1ec user: oehhar tags: trunk
2014-02-24
20:53
merge 8.5 check-in: bf1327f687 user: dgp tags: dgp-read-bytes
17:25
Do not reopen a win serial channel for serial detection. There are issues with some Bluetooth virtua... check-in: b6459ef66c user: oehhar tags: core-8-5-branch
2014-02-19
14:10
[1230597] Update test comment. check-in: 0392a86d4d user: dgp tags: core-8-5-branch
2014-02-11
08:53
Changed position of flag evaluation as proposed by Phil Hoffman Closed-Leaf check-in: 024a523361 user: oehhar tags: bug-2413550
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to win/tclWinChan.c.

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
static void		FileSetupProc(ClientData clientData, int flags);
static void		FileWatchProc(ClientData instanceData, int mask);
static void		FileThreadActionProc(ClientData instanceData,
			    int action);
static int		FileTruncateProc(ClientData instanceData,
			    Tcl_WideInt length);
static DWORD		FileGetType(HANDLE handle);

/*
 * This structure describes the channel type structure for file based IO.
 */

static Tcl_ChannelType fileChannelType = {
    "file",			/* Type name. */
    TCL_CHANNEL_VERSION_5,	/* v5 channel */







|







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
static void		FileSetupProc(ClientData clientData, int flags);
static void		FileWatchProc(ClientData instanceData, int mask);
static void		FileThreadActionProc(ClientData instanceData,
			    int action);
static int		FileTruncateProc(ClientData instanceData,
			    Tcl_WideInt length);
static DWORD		FileGetType(HANDLE handle);
static int		NativeIsComPort(CONST TCHAR *nativeName);
/*
 * This structure describes the channel type structure for file based IO.
 */

static Tcl_ChannelType fileChannelType = {
    "file",			/* Type name. */
    TCL_CHANNEL_VERSION_5,	/* v5 channel */
881
882
883
884
885
886
887



























888
889
890
891
892
893
894
	createMode = TRUNCATE_EXISTING;
	break;
    default:
	createMode = OPEN_EXISTING;
	break;
    }




























    /*
     * If the file is being created, get the file attributes from the
     * permissions argument, else use the existing file attributes.
     */

    if (mode & O_CREAT) {
	if (permissions & S_IWRITE) {







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
	createMode = TRUNCATE_EXISTING;
	break;
    default:
	createMode = OPEN_EXISTING;
	break;
    }

    /*
     * [2413550] Avoid double-open of serial ports on Windows
     * Special handling for Windows serial ports by a "name-hint"
     * to directly open it with the OVERLAPPED flag set.
     */

    if( NativeIsComPort(nativeName) ) {

	handle = TclWinSerialOpen(INVALID_HANDLE_VALUE, nativeName, accessMode);
	if (handle == INVALID_HANDLE_VALUE) {
	    TclWinConvertError(GetLastError());
	    if (interp != (Tcl_Interp *) NULL) {
		Tcl_AppendResult(interp, "couldn't open serial \"",
			TclGetString(pathPtr), "\": ",
			Tcl_PosixError(interp), NULL);
	    }
	    return NULL;
	}

	/*
	* For natively named Windows serial ports we are done.
	*/
	channel = TclWinOpenSerialChannel(handle, channelName,
		channelPermissions);

	return channel;
    }
    /*
     * If the file is being created, get the file attributes from the
     * permissions argument, else use the existing file attributes.
     */

    if (mode & O_CREAT) {
	if (permissions & S_IWRITE) {
931
932
933
934
935
936
937




938
939
940
941
942
943
944
945
946
947
948
949
    }

    channel = NULL;

    switch (FileGetType(handle)) {
    case FILE_TYPE_SERIAL:
	/*




	 * Reopen channel for OVERLAPPED operation. Normally this shouldn't
	 * fail, because the channel exists.
	 */

	handle = TclWinSerialReopen(handle, nativeName, accessMode);
	if (handle == INVALID_HANDLE_VALUE) {
	    TclWinConvertError(GetLastError());
	    if (interp != (Tcl_Interp *) NULL) {
		Tcl_AppendResult(interp, "couldn't reopen serial \"",
			TclGetString(pathPtr), "\": ",
			Tcl_PosixError(interp), NULL);
	    }







>
>
>
>




|







958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
    }

    channel = NULL;

    switch (FileGetType(handle)) {
    case FILE_TYPE_SERIAL:
	/*
	 * Natively named serial ports "com1-9", "\\\\.\\comXX" are 
	 * already done with the code above.
	 * Here we handle all other serial port names.
	 *
	 * Reopen channel for OVERLAPPED operation. Normally this shouldn't
	 * fail, because the channel exists.
	 */

	handle = TclWinSerialOpen(handle, nativeName, accessMode);
	if (handle == INVALID_HANDLE_VALUE) {
	    TclWinConvertError(GetLastError());
	    if (interp != (Tcl_Interp *) NULL) {
		Tcl_AppendResult(interp, "couldn't reopen serial \"",
			TclGetString(pathPtr), "\": ",
			Tcl_PosixError(interp), NULL);
	    }
1471
1472
1473
1474
1475
1476
1477
1478
1479




















































































































1480
1481
1482
1483
1484
1485
		type = FILE_TYPE_SERIAL;
	    }
	}
    }

    return type;
}

/*




















































































































 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */








|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






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
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
		type = FILE_TYPE_SERIAL;
	    }
	}
    }

    return type;
}

 /*
 *----------------------------------------------------------------------
 *
 * NativeIsComPort --
 *
 *	Determines if a path refers to a Windows serial port.
 *	A simple and efficient solution is to use a "name hint" to detect 
 *      COM ports by their filename instead of resorting to a syscall 
 *	to detect serialness after the fact.
 *	The following patterns cover common serial port names:
 *	    COM[1-9]:?
 *	    //./COM[0-9]+
 *	    \\.\COM[0-9]+
 *
 * Results:
 *	1 = serial port, 0 = not.
 *
 *----------------------------------------------------------------------
 */

static int
NativeIsComPort(
    const TCHAR *nativePath)	/* Path of file to access, native encoding. */
{
    /*
     * Use wide-char or plain character case-insensitive comparison
     */
    if (tclWinProcs->useWide) {
	const WCHAR *p = (const WCHAR *) nativePath;
	int i, len = wcslen(p);

	/*
	 * 1. Look for com[1-9]:?
	 */

	if ( (len >= 4) && (len <= 5) 
		&& (_wcsnicmp(p, L"com", 3) == 0) ) {
	    /*
	    * The 4th character must be a digit 1..9 optionally followed by a ":"
	    */

	    if ( (p[3] < L'1') || (p[3] > L'9') ) {
		return 0;
	    }
	    if ( (len == 5) && (p[4] != L':') ) {
		return 0;
	    }
	    return 1;
	}

	/*
	 * 2. Look for //./com[0-9]+ or \\.\com[0-9]+
	 */

	if ( (len >= 8) && ( 
		   (_wcsnicmp(p, L"//./com", 7) == 0)
		|| (_wcsnicmp(p, L"\\\\.\\com", 7) == 0) ) )
	{
	    /*
	    * Charaters 8..end must be a digits 0..9
	    */

	    for ( i=7; i<len; i++ ) {
		if ( (p[i] < '0') || (p[i] > '9') ) {
		    return 0;
		}
	    }
	    return 1;
	}

    } else {
	const char *p = (const char *) nativePath;
	int   i, len = strlen(p);

	/*
	 * 1. Look for com[1-9]:?
	 */

	if ( (len >= 4) && (len <= 5) 
		&& (strnicmp(p, "com", 3) == 0) ) {
	    /*
	    * The 4th character must be a digit 1..9 optionally followed by a ":"
	    */

	    if ( (p[3] < '1') || (p[3] > '9') ) {
		return 0;
	    }
	    if ( (len == 5) && (p[4] != ':') ) {
		return 0;
	    }
	    return 1;
	}

	/*
	 * 2. Look for //./com[0-9]+ or \\.\com[0-9]+
	 */

	if ( (len >= 8) && ( 
		   (strnicmp(p, "//./com", 7) == 0)
		|| (strnicmp(p, "\\\\.\\com", 7) == 0) ) )
	{
	    /*
	    * Charaters 8..end must be a digits 0..9
	    */

	    for ( i=7; i<len; i++ ) {
		if ( (p[i] < '0') || (p[i] > '9') ) {
		    return 0;
		}
	    }
	    return 1;
	}
    }
    return 0;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */

Changes to win/tclWinInt.h.

183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
MODULE_SCOPE Tcl_Channel TclWinOpenConsoleChannel(HANDLE handle,
			    char *channelName, int permissions);
MODULE_SCOPE Tcl_Channel TclWinOpenFileChannel(HANDLE handle, char *channelName,
			    int permissions, int appendMode);
MODULE_SCOPE Tcl_Channel TclWinOpenSerialChannel(HANDLE handle,
			    char *channelName, int permissions);
MODULE_SCOPE void	TclWinResetInterfaceEncodings();
MODULE_SCOPE HANDLE	TclWinSerialReopen(HANDLE handle, CONST TCHAR *name,
			    DWORD access);
MODULE_SCOPE int	TclWinSymLinkCopyDirectory(CONST TCHAR* LinkOriginal,
			    CONST TCHAR* LinkCopy);
MODULE_SCOPE int	TclWinSymLinkDelete(CONST TCHAR* LinkOriginal, 
			    int linkOnly);
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
MODULE_SCOPE void	TclWinFreeAllocCache(void);







|







183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
MODULE_SCOPE Tcl_Channel TclWinOpenConsoleChannel(HANDLE handle,
			    char *channelName, int permissions);
MODULE_SCOPE Tcl_Channel TclWinOpenFileChannel(HANDLE handle, char *channelName,
			    int permissions, int appendMode);
MODULE_SCOPE Tcl_Channel TclWinOpenSerialChannel(HANDLE handle,
			    char *channelName, int permissions);
MODULE_SCOPE void	TclWinResetInterfaceEncodings();
MODULE_SCOPE HANDLE	TclWinSerialOpen(HANDLE handle, CONST TCHAR *name,
			    DWORD access);
MODULE_SCOPE int	TclWinSymLinkCopyDirectory(CONST TCHAR* LinkOriginal,
			    CONST TCHAR* LinkCopy);
MODULE_SCOPE int	TclWinSymLinkDelete(CONST TCHAR* LinkOriginal, 
			    int linkOnly);
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
MODULE_SCOPE void	TclWinFreeAllocCache(void);

Changes to win/tclWinSerial.c.

1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
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

    return 0;
}

/*
 *----------------------------------------------------------------------
 *
 * TclWinSerialReopen --
 *
 *	Reopens the serial port with the OVERLAPPED FLAG set
 *
 * Results:
 *	Returns the new handle, or INVALID_HANDLE_VALUE. Normally there
 *	shouldn't be any error, because the same channel has previously been
 *	succeesfully opened.
 *
 * Side effects:
 *	May close the original handle
 *
 *----------------------------------------------------------------------
 */

HANDLE
TclWinSerialReopen(
    HANDLE handle,
    CONST TCHAR *name,
    DWORD access)
{
    SerialInit();









    /*
     * Multithreaded I/O needs the overlapped flag set otherwise
     * ClearCommError blocks under Windows NT/2000 until serial output is
     * finished
     */

    if (CloseHandle(handle) == FALSE) {
	return INVALID_HANDLE_VALUE;
    }
    handle = (*tclWinProcs->createFileProc)(name, access, 0, 0,
	    OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);

    return handle;
}

/*
 *----------------------------------------------------------------------
 *
 * TclWinOpenSerialChannel --







|

|


|
<
|


|





|





>
>
>
>
>
>
>
>







<
<
<


>







1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418

1419
1420
1421
1422
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

    return 0;
}

/*
 *----------------------------------------------------------------------
 *
 * TclWinSerialOpen --
 *
 *	Opens or Reopens the serial port with the OVERLAPPED FLAG set
 *
 * Results:
 *	Returns the new handle, or INVALID_HANDLE_VALUE. 

 *	If an existing channel is specified it is closed and reopened.
 *
 * Side effects:
 *	May close/reopen the original handle
 *
 *----------------------------------------------------------------------
 */

HANDLE
TclWinSerialOpen(
    HANDLE handle,
    CONST TCHAR *name,
    DWORD access)
{
    SerialInit();

    /*
     * If an open channel is specified, close it
     */

    if ( handle != INVALID_HANDLE_VALUE && CloseHandle(handle) == FALSE) {
	return INVALID_HANDLE_VALUE;
    }

    /*
     * Multithreaded I/O needs the overlapped flag set otherwise
     * ClearCommError blocks under Windows NT/2000 until serial output is
     * finished
     */




    handle = (*tclWinProcs->createFileProc)(name, access, 0, 0,
	    OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);

    return handle;
}

/*
 *----------------------------------------------------------------------
 *
 * TclWinOpenSerialChannel --