Tcl Source Code

Check-in [b14932f43b]
Login

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

Overview
Comment:[Bug 3508771]: Cygwin notifier for handling win32 events
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | core-8-5-branch
Files: files | file ages | folders
SHA1: b14932f43b3c05183e965122071266a06eb9b8ef
User & Date: jan.nijtmans 2012-06-23 07:10:06
Context
2012-06-24
06:00
some wrong versions check-in: eefe38655e user: jan.nijtmans tags: core-8-5-branch
2012-06-23
07:27
[Bug 3508771]: Cygwin notifier for handling win32 events check-in: eb701a2be1 user: jan.nijtmans tags: trunk
07:10
[Bug 3508771]: Cygwin notifier for handling win32 events check-in: b14932f43b user: jan.nijtmans tags: core-8-5-branch
06:59
[Bug 3508771]: Cygwin notifier for handling win32 events check-in: 0741b45cd7 user: jan.nijtmans tags: core-8-4-branch
2012-06-22
18:38
FilesystemRecord structs no longer need refcounting. check-in: 8e03b0f1c9 user: dgp tags: core-8-5-branch
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.






1
2
3
4
5
6
7





2012-06-21  Jan Nijtmans  <[email protected]>

	* win/tclWinReg.c:          [Bug #3362446]: registry keys command fails
	* tests/registry.test:      with 8.5/8.6
	* library/reg/pkgIndex.tcl: registry version to 1.2.2

2012-06-11  Don Porter  <[email protected]>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
2012-06-23  Jan Nijtmans  <[email protected]>

	* unix/tclUnixNotfy.c: [Bug 3508771]: Cygwin notifier for handling
	win32 events.

2012-06-21  Jan Nijtmans  <[email protected]>

	* win/tclWinReg.c:          [Bug #3362446]: registry keys command fails
	* tests/registry.test:      with 8.5/8.6
	* library/reg/pkgIndex.tcl: registry version to 1.2.2

2012-06-11  Don Porter  <[email protected]>

Changes to unix/configure.

6996
6997
6998
6999
7000
7001
7002










7003
7004
7005
7006
7007
7008
7009
fi
echo "$as_me:$LINENO: result: $ac_cv_cygwin" >&5
echo "${ECHO_T}$ac_cv_cygwin" >&6
	    if test "$ac_cv_cygwin" = "no"; then
		{ { echo "$as_me:$LINENO: error: ${CC} is not a cygwin compiler." >&5
echo "$as_me: error: ${CC} is not a cygwin compiler." >&2;}
   { (exit 1); exit 1; }; }










	    fi
	    ;;
	dgux*)
	    SHLIB_CFLAGS="-K PIC"
	    SHLIB_LD='${CC} -G'
	    SHLIB_LD_LIBS=""
	    SHLIB_SUFFIX=".so"







>
>
>
>
>
>
>
>
>
>







6996
6997
6998
6999
7000
7001
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
7013
7014
7015
7016
7017
7018
7019
fi
echo "$as_me:$LINENO: result: $ac_cv_cygwin" >&5
echo "${ECHO_T}$ac_cv_cygwin" >&6
	    if test "$ac_cv_cygwin" = "no"; then
		{ { echo "$as_me:$LINENO: error: ${CC} is not a cygwin compiler." >&5
echo "$as_me: error: ${CC} is not a cygwin compiler." >&2;}
   { (exit 1); exit 1; }; }
	    fi
	    if test "x${TCL_THREADS}" = "x0"; then
		{ { echo "$as_me:$LINENO: error: CYGWIN compile is only supported with --enable-threads" >&5
echo "$as_me: error: CYGWIN compile is only supported with --enable-threads" >&2;}
   { (exit 1); exit 1; }; }
	    fi
	    if test ! -f "../win/tcldde12.dll" -a ! -f "../win/tk84.dll"; then
		{ { echo "$as_me:$LINENO: error: Please configure and make the ../win directory first." >&5
echo "$as_me: error: Please configure and make the ../win directory first." >&2;}
   { (exit 1); exit 1; }; }
	    fi
	    ;;
	dgux*)
	    SHLIB_CFLAGS="-K PIC"
	    SHLIB_LD='${CC} -G'
	    SHLIB_LD_LIBS=""
	    SHLIB_SUFFIX=".so"

Changes to unix/tcl.m4.

1256
1257
1258
1259
1260
1261
1262






1263
1264
1265
1266
1267
1268
1269
		], [],
		ac_cv_cygwin=no,
		ac_cv_cygwin=yes)
	    )
	    if test "$ac_cv_cygwin" = "no"; then
		AC_MSG_ERROR([${CC} is not a cygwin compiler.])
	    fi






	    ;;
	dgux*)
	    SHLIB_CFLAGS="-K PIC"
	    SHLIB_LD='${CC} -G'
	    SHLIB_LD_LIBS=""
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"







>
>
>
>
>
>







1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
		], [],
		ac_cv_cygwin=no,
		ac_cv_cygwin=yes)
	    )
	    if test "$ac_cv_cygwin" = "no"; then
		AC_MSG_ERROR([${CC} is not a cygwin compiler.])
	    fi
	    if test "x${TCL_THREADS}" = "x0"; then
		AC_MSG_ERROR([CYGWIN compile is only supported with --enable-threads])
	    fi
	    if test ! -f "../win/tcldde12.dll" -a ! -f "../win/tk84.dll"; then
		AC_MSG_ERROR([Please configure and make the ../win directory first.])
	    fi
	    ;;
	dgux*)
	    SHLIB_CFLAGS="-K PIC"
	    SHLIB_LD='${CC} -G'
	    SHLIB_LD_LIBS=""
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"

Changes to unix/tclUnixNotfy.c.

95
96
97
98
99
100
101






102
103
104

105
106
107
108
109
110
111
    struct ThreadSpecificData *nextPtr, *prevPtr;
				/* All threads that are currently waiting on
				 * an event have their ThreadSpecificData
				 * structure on a doubly-linked listed formed
				 * from these pointers. You must hold the
				 * notifierMutex lock before accessing these
				 * fields. */






    Tcl_Condition waitCV;	/* Any other thread alerts a notifier that an
				 * event is ready to be processed by signaling
				 * this condition variable. */

    int eventReady;		/* True if an event is ready to be processed.
				 * Used as condition flag together with waitCV
				 * above. */
#endif
} ThreadSpecificData;

static Tcl_ThreadDataKey dataKey;







>
>
>
>
>
>



>







95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
    struct ThreadSpecificData *nextPtr, *prevPtr;
				/* All threads that are currently waiting on
				 * an event have their ThreadSpecificData
				 * structure on a doubly-linked listed formed
				 * from these pointers. You must hold the
				 * notifierMutex lock before accessing these
				 * fields. */
#ifdef __CYGWIN__
    void *event;     /* Any other thread alerts a notifier
	 * that an event is ready to be processed
	 * by sending this event. */
    void *hwnd;			/* Messaging window. */
#else /* !__CYGWIN__ */
    Tcl_Condition waitCV;	/* Any other thread alerts a notifier that an
				 * event is ready to be processed by signaling
				 * this condition variable. */
#endif /* __CYGWIN__ */
    int eventReady;		/* True if an event is ready to be processed.
				 * Used as condition flag together with waitCV
				 * above. */
#endif
} ThreadSpecificData;

static Tcl_ThreadDataKey dataKey;
200
201
202
203
204
205
206










































207
208
209
210
211
212
213
 *	Returns a handle to the notifier state for this thread.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */











































ClientData
Tcl_InitNotifier(void)
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

#ifdef TCL_THREADS







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







207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
 *	Returns a handle to the notifier state for this thread.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#if defined(TCL_THREADS) && defined(__CYGWIN__)

typedef struct {
    void *hwnd;
    unsigned int *message;
    int wParam;
    int lParam;
    int time;
    int x;
    int y;
} MSG;

typedef struct {
  unsigned int style;
  void *lpfnWndProc;
  int cbClsExtra;
  int cbWndExtra;
  void *hInstance;
  void *hIcon;
  void *hCursor;
  void *hbrBackground;
  void *lpszMenuName;
  void *lpszClassName;
} WNDCLASS;

extern unsigned char __stdcall PeekMessageW(MSG *, void *, int, int, int);
extern unsigned char __stdcall GetMessageW(MSG *, void *, int, int);
extern unsigned char __stdcall TranslateMessage(const MSG *);
extern int __stdcall DispatchMessageW(const MSG *);
extern void __stdcall PostQuitMessage(int);
extern void * __stdcall CreateWindowExW(void *, void *, void *, DWORD, int, int, int, int, void *, void *, void *, void *);
extern unsigned char __stdcall DestroyWindow(void *);
extern unsigned char __stdcall PostMessageW(void *, unsigned int, void *, void *);
extern void *__stdcall RegisterClassW(const WNDCLASS *);
extern DWORD __stdcall DefWindowProcW(void *, int, void *, void *);
extern void *__stdcall CreateEventW(void *, unsigned char, unsigned char, void *);
extern void __stdcall CloseHandle(void *);
extern void __stdcall MsgWaitForMultipleObjects(DWORD, void *, unsigned char, DWORD, DWORD);
extern unsigned char __stdcall ResetEvent(void *);

#endif

ClientData
Tcl_InitNotifier(void)
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

#ifdef TCL_THREADS
304
305
306
307
308
309
310



311

312
313
314
315
316
317
318
	}
    }

    /*
     * Clean up any synchronization objects in the thread local storage.
     */




    Tcl_ConditionFinalize(&(tsdPtr->waitCV));


    Tcl_MutexUnlock(&notifierMutex);
#endif
}

/*
 *----------------------------------------------------------------------







>
>
>

>







353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
	}
    }

    /*
     * Clean up any synchronization objects in the thread local storage.
     */

#ifdef __CYGWIN__
    CloseHandle(tsdPtr->event);
#else /* __CYGWIN__ */
    Tcl_ConditionFinalize(&(tsdPtr->waitCV));
#endif /* __CYGWIN__ */

    Tcl_MutexUnlock(&notifierMutex);
#endif
}

/*
 *----------------------------------------------------------------------
337
338
339
340
341
342
343



344

345
346
347
348
349
350
351
Tcl_AlertNotifier(
    ClientData clientData)
{
#ifdef TCL_THREADS
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
    Tcl_MutexLock(&notifierMutex);
    tsdPtr->eventReady = 1;



    Tcl_ConditionNotify(&tsdPtr->waitCV);

    Tcl_MutexUnlock(&notifierMutex);
#endif
}

/*
 *----------------------------------------------------------------------
 *







>
>
>

>







390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
Tcl_AlertNotifier(
    ClientData clientData)
{
#ifdef TCL_THREADS
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
    Tcl_MutexLock(&notifierMutex);
    tsdPtr->eventReady = 1;
#ifdef __CYGWIN__
    PostMessageW(tsdPtr->hwnd, 1024, 0, 0);
#else
    Tcl_ConditionNotify(&tsdPtr->waitCV);
#endif
    Tcl_MutexUnlock(&notifierMutex);
#endif
}

/*
 *----------------------------------------------------------------------
 *
637
638
639
640
641
642
643

























644
645
646
647
648
649
650
	    (*filePtr->proc)(filePtr->clientData, mask);
	}
	break;
    }
    return 1;
}


























/*
 *----------------------------------------------------------------------
 *
 * Tcl_WaitForEvent --
 *
 *	This function is called by Tcl_DoOneEvent to wait for new events on
 *	the message queue. If the block time is 0, then Tcl_WaitForEvent just







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







694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
	    (*filePtr->proc)(filePtr->clientData, mask);
	}
	break;
    }
    return 1;
}

#if defined(TCL_THREADS) && defined(__CYGWIN__)

static DWORD __stdcall
NotifierProc(
    void *hwnd,
    unsigned int message,
    void *wParam,
    void *lParam)
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (message != 1024) {
	return DefWindowProcW(hwnd, message, wParam, lParam);
    }

    /*
     * Process all of the runnable events.
     */

	tsdPtr->eventReady = 1;
    Tcl_ServiceAll();
    return 0;
}
#endif /* __CYGWIN__ */

/*
 *----------------------------------------------------------------------
 *
 * Tcl_WaitForEvent --
 *
 *	This function is called by Tcl_DoOneEvent to wait for new events on
 *	the message queue. If the block time is 0, then Tcl_WaitForEvent just
665
666
667
668
669
670
671



672
673
674
675
676
677
678
{
    FileHandler *filePtr;
    FileHandlerEvent *fileEvPtr;
    int mask;
    Tcl_Time vTime;
#ifdef TCL_THREADS
    int waitForFiles;



#else
    /*
     * Impl. notes: timeout & timeoutPtr are used if, and only if threads are
     * not enabled. They are the arguments for the regular select() used when
     * the core is not thread-enabled.
     */








>
>
>







747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
{
    FileHandler *filePtr;
    FileHandlerEvent *fileEvPtr;
    int mask;
    Tcl_Time vTime;
#ifdef TCL_THREADS
    int waitForFiles;
# ifdef __CYGWIN__
    MSG msg;
# endif
#else
    /*
     * Impl. notes: timeout & timeoutPtr are used if, and only if threads are
     * not enabled. They are the arguments for the regular select() used when
     * the core is not thread-enabled.
     */

752
753
754
755
756
757
758























759
760
761
762
763
764
765
	tsdPtr->pollState = POLL_WANT;
	timePtr = NULL;
    } else {
	waitForFiles = (tsdPtr->numFdBits > 0);
	tsdPtr->pollState = 0;
    }
























    if (waitForFiles) {
	/*
	 * Add the ThreadSpecificData structure of this thread to the list of
	 * ThreadSpecificData structures of all threads that are waiting on
	 * file events.
	 */








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







837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
	tsdPtr->pollState = POLL_WANT;
	timePtr = NULL;
    } else {
	waitForFiles = (tsdPtr->numFdBits > 0);
	tsdPtr->pollState = 0;
    }

#ifdef __CYGWIN__
	if (!tsdPtr->hwnd) {
		WNDCLASS class;

	    class.style = 0;
	    class.cbClsExtra = 0;
	    class.cbWndExtra = 0;
	    class.hInstance = TclWinGetTclInstance();
	    class.hbrBackground = NULL;
	    class.lpszMenuName = NULL;
	    class.lpszClassName = L"TclNotifier";
	    class.lpfnWndProc = NotifierProc;
	    class.hIcon = NULL;
	    class.hCursor = NULL;

	    RegisterClassW(&class);
	    tsdPtr->hwnd = CreateWindowExW(NULL, class.lpszClassName, class.lpszClassName,
		    0, 0, 0, 0, 0, NULL, NULL, TclWinGetTclInstance(), NULL);
	    tsdPtr->event = CreateEventW(NULL, 1 /* manual */,
		    0 /* !signaled */, NULL);
    }

#endif
    if (waitForFiles) {
	/*
	 * Add the ThreadSpecificData structure of this thread to the list of
	 * ThreadSpecificData structures of all threads that are waiting on
	 * file events.
	 */

777
778
779
780
781
782
783













784

785
786

















787
788
789
790
791
792
793
    }

    FD_ZERO(&(tsdPtr->readyMasks.readable));
    FD_ZERO(&(tsdPtr->readyMasks.writable));
    FD_ZERO(&(tsdPtr->readyMasks.exceptional));

    if (!tsdPtr->eventReady) {













	Tcl_ConditionWait(&tsdPtr->waitCV, &notifierMutex, timePtr);

    }
    tsdPtr->eventReady = 0;


















    if (waitForFiles && tsdPtr->onList) {
	/*
	 * Remove the ThreadSpecificData structure of this thread from the
	 * waiting list. Alert the notifier thread to recompute its select
	 * masks - skipping this caused a hang when trying to close a pipe
	 * which the notifier thread was still doing a select on.







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

>


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







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
922
923
924
925
926
927
928
929
930
931
932
    }

    FD_ZERO(&(tsdPtr->readyMasks.readable));
    FD_ZERO(&(tsdPtr->readyMasks.writable));
    FD_ZERO(&(tsdPtr->readyMasks.exceptional));

    if (!tsdPtr->eventReady) {
#ifdef __CYGWIN__
	if (!PeekMessageW(&msg, NULL, 0, 0, 0)) {
	    DWORD timeout;
	    if (timePtr) {
		timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
	    } else {
		timeout = 0xFFFFFFFF;
	    }
	    Tcl_MutexUnlock(&notifierMutex);
	    MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279);
	    Tcl_MutexLock(&notifierMutex);
	}
#else
	Tcl_ConditionWait(&tsdPtr->waitCV, &notifierMutex, timePtr);
#endif
    }
    tsdPtr->eventReady = 0;

#ifdef __CYGWIN__
    while (PeekMessageW(&msg, NULL, 0, 0, 0)) {
	/*
	 * Retrieve and dispatch the message.
	 */
	DWORD result = GetMessageW(&msg, NULL, 0, 0);
	if (result == 0) {
	    PostQuitMessage(msg.wParam);
	    /* What to do here? */
	} else if (result != (DWORD)-1) {
	    TranslateMessage(&msg);
	    DispatchMessageW(&msg);
	}
    }
    ResetEvent(tsdPtr->event);
#endif

    if (waitForFiles && tsdPtr->onList) {
	/*
	 * Remove the ThreadSpecificData structure of this thread from the
	 * waiting list. Alert the notifier thread to recompute its select
	 * masks - skipping this caused a hang when trying to close a pipe
	 * which the notifier thread was still doing a select on.
1038
1039
1040
1041
1042
1043
1044



1045

1046
1047
1048
1049
1050
1051
1052
		    if (tsdPtr->nextPtr) {
			tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
		    }
		    tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
		    tsdPtr->onList = 0;
		    tsdPtr->pollState = 0;
		}



		Tcl_ConditionNotify(&tsdPtr->waitCV);

	    }
	}
	Tcl_MutexUnlock(&notifierMutex);

	/*
	 * Consume the next byte from the notifier pipe if the pipe was
	 * readable. Note that there may be multiple bytes pending, but to







>
>
>
|
>







1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
		    if (tsdPtr->nextPtr) {
			tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
		    }
		    tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
		    tsdPtr->onList = 0;
		    tsdPtr->pollState = 0;
		}
#ifdef __CYGWIN__
	    PostMessageW(tsdPtr->hwnd, 1024, 0, 0);
#else /* __CYGWIN__ */
	    Tcl_ConditionNotify(&tsdPtr->waitCV);
#endif /* __CYGWIN__ */
	    }
	}
	Tcl_MutexUnlock(&notifierMutex);

	/*
	 * Consume the next byte from the notifier pipe if the pipe was
	 * readable. Note that there may be multiple bytes pending, but to