Diff
Not logged in

Differences From Artifact [739ee4fc67]:

To Artifact [776baef933]:


1
2
3
4
5
6
7
8
9
10
11
12
13

14
15

16
17
18
19
20
21
22
23
24
25
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18

19
20
21
22
23
24
25












-
+


+


-







/*
 * tclUnixNotify.c --
 *
 *	This file contains the implementation of the select()-based
 *	Unix-specific notifier, which is the lowest-level part of the Tcl
 *	event loop. This file works together with generic/tclNotify.c.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclUnixNotfy.c,v 1.29 2005/11/02 23:26:50 dkf Exp $
 * RCS: @(#) $Id: tclUnixNotfy.c,v 1.30 2005/11/27 02:33:50 das Exp $
 */

#include "tclInt.h"
#ifndef HAVE_COREFOUNDATION	/* Darwin/Mac OS X CoreFoundation notifier is
				 * in tclMacOSXNotify.c */
#include "tclInt.h"
#include <signal.h>

/*
 * This code does deep stub magic to allow replacement of the notifier at
 * runtime.
 */

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
56
57
58
59
60
61
62

63
64
65
66
67
68
69







-







				 * the FileHandler structure for the file
				 * (can't point directly to the FileHandler
				 * structure because it could go away while
				 * the event is queued). */
} FileHandlerEvent;

/*
 *
 * The following structure contains a set of select() masks to track readable,
 * writable, and exceptional conditions.
 */

typedef struct SelectMasks {
    fd_set readable;
    fd_set writable;
95
96
97
98
99
100
101
102

103
104
105
106
107
108
109
94
95
96
97
98
99
100

101
102
103
104
105
106
107
108







-
+







    unsigned int pollState;	/* pollState is used to implement a polling
				 * handshake between each thread and the
				 * notifier thread. Bits defined below. */
    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
				 * 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
160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
159
160
161
162
163
164
165

166
167
168
169
170
171
172
173







-
+







 * initializing the triggerPipe and right before the notifier thread
 * terminates.
 */

static Tcl_Condition notifierCV;

/*
 * The pollState bits:
 * The pollState bits
 *	POLL_WANT is set by each thread before it waits on its condition
 *		variable. It is checked by the notifier before it does select.
 *	POLL_DONE is set by the notifier if it goes into select after seeing
 *		POLL_WANT. The idea is to ensure it tries a select with the
 *		same bits the initial thread had set.
 */

273
274
275
276
277
278
279

280
281

282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299

300
301
302

303
304
305
306
307
308
309
272
273
274
275
276
277
278
279
280

281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302

303
304
305
306
307
308
309
310







+

-
+


















+


-
+







    /*
     * If this is the last thread to use the notifier, close the notifier pipe
     * and wait for the background thread to terminate.
     */

    if (notifierCount == 0) {
	int result;

	if (triggerPipe < 0) {
	    Tcl_Panic("Tcl_FinalizeNotifier: notifier pipe not initialized");
	    Tcl_Panic("Tcl_FinalizeNotifier: notifier pipe not initialized.");
	}

	/*
	 * Send "q" message to the notifier thread so that it will terminate.
	 * The notifier will return from its call to select() and notice that
	 * a "q" message has arrived, it will then close its side of the pipe
	 * and terminate its thread. Note the we can not just close the pipe
	 * and check for EOF in the notifier thread because if a background
	 * child process was created with exec, select() would not register
	 * the EOF on the pipe until the child processes had terminated. [Bug:
	 * 4139] [Bug: 1222872]
	 */

	write(triggerPipe, "q", 1);
	close(triggerPipe);
	while(triggerPipe >= 0) {
	    Tcl_ConditionWait(&notifierCV, &notifierMutex, NULL);
	}

	result = Tcl_JoinThread(notifierThread, NULL);
	if (result) {
	    Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread");
	    Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread.");
	}
    }

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

427
428
429
430
431
432
433
434


435
436
437
438
439
440
441
428
429
430
431
432
433
434

435
436
437
438
439
440
441
442
443







-
+
+







    Tcl_FileProc *proc,		/* Function to call for each selected
				 * event. */
    ClientData clientData)	/* Arbitrary data to pass to proc. */
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
    FileHandler *filePtr;

    if (tclStubs.tcl_CreateFileHandler != tclOriginalNotifier.createFileHandlerProc) {
    if (tclStubs.tcl_CreateFileHandler !=
	    tclOriginalNotifier.createFileHandlerProc) {
	tclStubs.tcl_CreateFileHandler(fd, mask, proc, clientData);
	return;
    }

    for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
	    filePtr = filePtr->nextPtr) {
	if (filePtr->fd == fd) {
498
499
500
501
502
503
504
505


506
507
508
509
510
511
512
513
514
515

516
517
518
519
520
521
522
500
501
502
503
504
505
506

507
508
509
510
511
512
513
514
515
516
517

518
519
520
521
522
523
524
525







-
+
+









-
+







    int fd)			/* Stream id for which to remove callback
				 * function. */
{
    FileHandler *filePtr, *prevPtr;
    int i;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (tclStubs.tcl_DeleteFileHandler != tclOriginalNotifier.deleteFileHandlerProc) {
    if (tclStubs.tcl_DeleteFileHandler !=
	    tclOriginalNotifier.deleteFileHandlerProc) {
	tclStubs.tcl_DeleteFileHandler(fd);
	return;
    }

    /*
     * Find the entry for the given file (and return if there isn't one).
     */

    for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ;
	    prevPtr = filePtr, filePtr = filePtr->nextPtr) {
	 prevPtr = filePtr, filePtr = filePtr->nextPtr) {
	if (filePtr == NULL) {
	    return;
	}
	if (filePtr->fd == fd) {
	    break;
	}
    }