summaryrefslogtreecommitdiffstats
path: root/unix/tkUnixXId.c
diff options
context:
space:
mode:
authorgeorgeps <georgeps>2008-08-19 15:57:02 (GMT)
committergeorgeps <georgeps>2008-08-19 15:57:02 (GMT)
commit9f59ca1a1428d923b1fe05bd7f35ca4928f45a3a (patch)
treeb1e53e0de0b255f429de64f67616a78d1cbb794b /unix/tkUnixXId.c
parent942dae95fd234537e55861dafd2750bc7618b038 (diff)
downloadtk-9f59ca1a1428d923b1fe05bd7f35ca4928f45a3a.zip
tk-9f59ca1a1428d923b1fe05bd7f35ca4928f45a3a.tar.gz
tk-9f59ca1a1428d923b1fe05bd7f35ca4928f45a3a.tar.bz2
XID cleanup patch. Missed during the first commit, sorry.
Diffstat (limited to 'unix/tkUnixXId.c')
-rw-r--r--unix/tkUnixXId.c473
1 files changed, 6 insertions, 467 deletions
diff --git a/unix/tkUnixXId.c b/unix/tkUnixXId.c
index 0131181..65d0a64 100644
--- a/unix/tkUnixXId.c
+++ b/unix/tkUnixXId.c
@@ -1,188 +1,17 @@
/*
* tkUnixXId.c --
*
- * This file provides a replacement function for the default X resource
- * allocator (_XAllocID). The problem with the default allocator is that
- * it never re-uses ids, which causes long-lived applications to crash
- * when X resource identifiers wrap around. The replacement functions in
- * this file re-use old identifiers to prevent this problem.
- *
- * The code in this file is based on similar implementations by
- * George C. Kaplan and Michael Hoegeman.
- *
* Copyright (c) 1993 The Regents of the University of California.
* Copyright (c) 1994-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: tkUnixXId.c,v 1.11 2008/04/27 22:39:14 dkf Exp $
+ * RCS: @(#) $Id: tkUnixXId.c,v 1.12 2008/08/19 15:57:02 georgeps Exp $
*/
-/*
- * The definition below is needed on some systems so that we can access the
- * resource_alloc field of Display structures in order to replace the resource
- * allocator.
- */
-
-#define XLIB_ILLEGAL_ACCESS 1
-
#include "tkUnixInt.h"
-/*
- * A structure of the following type is used to hold one or more available
- * resource identifiers. There is a list of these structures for each display.
- */
-
-#define IDS_PER_STACK 10
-typedef struct TkIdStack {
- XID ids[IDS_PER_STACK]; /* Array of free identifiers. */
- int numUsed; /* Indicates how many of the entries in ids
- * are currently in use. */
- TkDisplay *dispPtr; /* Display to which ids belong. */
- struct TkIdStack *nextPtr; /* Next bunch of free identifiers for the same
- * display. */
-} TkIdStack;
-
-/*
- * Forward declarations for functions defined in this file:
- */
-
-static XID AllocXId(Display *display);
-static Tk_RestrictAction CheckRestrictProc(ClientData clientData,
- XEvent *eventPtr);
-static void WindowIdCleanup(ClientData clientData);
-static void WindowIdCleanup2(ClientData clientData);
-
-/*
- *----------------------------------------------------------------------
- *
- * TkInitXId --
- *
- * This function is called to initialize the id allocator for a given
- * display.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The official allocator for the display is set up to be AllocXId.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkInitXId(
- TkDisplay *dispPtr) /* Tk's information about the display. */
-{
- dispPtr->idStackPtr = NULL;
- dispPtr->defaultAllocProc = (XID (*) (Display *display))
- dispPtr->display->resource_alloc;
- dispPtr->display->resource_alloc = AllocXId;
- dispPtr->windowStackPtr = NULL;
- dispPtr->idCleanupScheduled = (Tcl_TimerToken) 0;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkFreeXId --
- *
- * This function is called to free resources for the id allocator for a
- * given display.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Frees the id and window stack pools.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkFreeXId(
- TkDisplay *dispPtr) /* Tk's information about the display. */
-{
- TkIdStack *stackPtr, *freePtr;
-
- if (dispPtr->idCleanupScheduled) {
- Tcl_DeleteTimerHandler(dispPtr->idCleanupScheduled);
- }
-
- for (stackPtr = dispPtr->idStackPtr; stackPtr != NULL; ) {
- freePtr = stackPtr;
- stackPtr = stackPtr->nextPtr;
- ckfree((char *) freePtr);
- }
- dispPtr->idStackPtr = NULL;
-
- for (stackPtr = dispPtr->windowStackPtr; stackPtr != NULL; ) {
- freePtr = stackPtr;
- stackPtr = stackPtr->nextPtr;
- ckfree((char *) freePtr);
- }
- dispPtr->windowStackPtr = NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * AllocXId --
- *
- * This function is invoked by Xlib as the resource allocator for a
- * display.
- *
- * Results:
- * The return value is an X resource identifier that isn't currently in
- * use.
- *
- * Side effects:
- * The identifier is removed from the stack of free identifiers, if it
- * was previously on the stack.
- *
- *----------------------------------------------------------------------
- */
-
-static XID
-AllocXId(
- Display *display) /* Display for which to allocate. */
-{
- TkDisplay *dispPtr;
- TkIdStack *stackPtr;
-
- /*
- * Find Tk's information about the display.
- */
-
- dispPtr = TkGetDisplay(display);
-
- /*
- * If the topmost chunk on the stack is empty then free it. Then check for
- * a free id on the stack and return it if it exists.
- */
-
- stackPtr = dispPtr->idStackPtr;
- if (stackPtr != NULL) {
- while (stackPtr->numUsed == 0) {
- dispPtr->idStackPtr = stackPtr->nextPtr;
- ckfree((char *) stackPtr);
- stackPtr = dispPtr->idStackPtr;
- if (stackPtr == NULL) {
- goto defAlloc;
- }
- }
- stackPtr->numUsed--;
- return stackPtr->ids[stackPtr->numUsed];
- }
-
- /*
- * No free ids in the stack: just get one from the default allocator.
- */
-
- defAlloc:
- return (*dispPtr->defaultAllocProc)(display);
-}
/*
*----------------------------------------------------------------------
@@ -207,268 +36,15 @@ Tk_FreeXId(
Display *display, /* Display for which xid was allocated. */
XID xid) /* Identifier that is no longer in use. */
{
- TkDisplay *dispPtr;
- TkIdStack *stackPtr;
-
/*
- * Find Tk's information about the display.
+ * This does nothing, because the XC-MISC extension takes care of
+ * freeing XIDs for us. It has been a standard X11 extension for
+ * about 15 years as of 2008. Keith Packard and another X.org
+ * developer suggested that we remove the previous code that used:
+ * #define XLIB_ILLEGAL_ACCESS.
*/
-
- dispPtr = TkGetDisplay(display);
-
- /*
- * Add a new chunk to the stack if the current chunk is full.
- */
-
- stackPtr = dispPtr->idStackPtr;
- if ((stackPtr == NULL) || (stackPtr->numUsed >= IDS_PER_STACK)) {
- stackPtr = (TkIdStack *) ckalloc(sizeof(TkIdStack));
- stackPtr->numUsed = 0;
- stackPtr->dispPtr = dispPtr;
- stackPtr->nextPtr = dispPtr->idStackPtr;
- dispPtr->idStackPtr = stackPtr;
- }
-
- /*
- * Add the id to the current chunk.
- */
-
- stackPtr->ids[stackPtr->numUsed] = xid;
- stackPtr->numUsed++;
}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkFreeWindowId --
- *
- * This function is invoked instead of TkFreeXId for window ids. See
- * below for the reason why.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The id given by w will eventually be freed, so that it can be reused
- * for other resources.
- *
- * Design:
- * Freeing window ids is very tricky because there could still be events
- * pending for a window in the event queue (or even in the server) at the
- * time the window is destroyed. If the window id were to get reused
- * immediately for another window, old events could "drop in" on the new
- * window, causing unexpected behavior.
- *
- * Thus we have to wait to re-use a window id until we know that there
- * are no events left for it. Right now this is done in two steps. First,
- * we wait until we know that the server has seen the XDestroyWindow
- * request, so we can be sure that it won't generate more events for the
- * window and that any existing events are in our queue. Second, we make
- * sure that there are no events whatsoever in our queue (this is
- * conservative but safe).
- *
- * The first step is done by remembering the request id of the
- * XDestroyWindow request and using LastKnownRequestProcessed to see what
- * events the server has processed. If multiple windows get destroyed at
- * about the same time, we just remember the most recent request number
- * for any of them (again, conservative but safe).
- *
- * There are a few other complications as well. When Tk destroys a
- * sub-tree of windows, it only issues a single XDestroyWindow call, at
- * the very end for the root of the subtree. We can't free any of the
- * window ids until the final XDestroyWindow call. To make sure that this
- * happens, we have to keep track of deletions in progress, hence the
- * need for the "destroyCount" field of the display.
- *
- * One final problem. Some servers, like Sun X11/News servers still seem
- * to have problems with ids getting reused too quickly. I'm not
- * completely sure why this is a problem, but delaying the recycling of
- * ids appears to eliminate it. Therefore, we wait an additional few
- * seconds, even after "the coast is clear" before reusing the ids.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkFreeWindowId(
- TkDisplay *dispPtr, /* Display that w belongs to. */
- Window w) /* X identifier for window on dispPtr. */
-{
- TkIdStack *stackPtr;
-
- /*
- * Put the window id on a separate stack of window ids, rather than the
- * main stack, so it won't get reused right away. Add a new chunk to the
- * stack if the current chunk is full.
- */
-
- stackPtr = dispPtr->windowStackPtr;
- if ((stackPtr == NULL) || (stackPtr->numUsed >= IDS_PER_STACK)) {
- stackPtr = (TkIdStack *) ckalloc(sizeof(TkIdStack));
- stackPtr->numUsed = 0;
- stackPtr->dispPtr = dispPtr;
- stackPtr->nextPtr = dispPtr->windowStackPtr;
- dispPtr->windowStackPtr = stackPtr;
- }
-
- /*
- * Add the id to the current chunk.
- */
-
- stackPtr->ids[stackPtr->numUsed] = w;
- stackPtr->numUsed++;
-
- /*
- * Schedule a call to WindowIdCleanup if one isn't already scheduled.
- */
-
- if (!dispPtr->idCleanupScheduled) {
- dispPtr->idCleanupScheduled = Tcl_CreateTimerHandler(100,
- WindowIdCleanup, dispPtr);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * WindowIdCleanup --
- *
- * See if we can now free up all the accumulated ids of deleted windows.
- *
- * Results:
- * None.
- *
- * Side effects:
- * If it's safe to move the window ids back to the main free list, we
- * schedule this to happen after a few mores seconds of delay. If it's
- * not safe to move them yet, a timer handler gets invoked to try again
- * later.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-WindowIdCleanup(
- ClientData clientData) /* Pointer to TkDisplay for display */
-{
- TkDisplay *dispPtr = clientData;
- int anyEvents, delta;
- Tk_RestrictProc *oldProc;
- ClientData oldData;
- static Tcl_Time timeout = {0, 0};
-
- dispPtr->idCleanupScheduled = (Tcl_TimerToken) 0;
-
- /*
- * See if it's safe to recycle the window ids. It's safe if:
- * (a) no deletions are in progress.
- * (b) the server has seen all of the requests up to the last
- * XDestroyWindow request.
- * (c) there are no events in the event queue; the only way to test for
- * this right now is to create a restrict proc that will filter the
- * events, then call Tcl_DoOneEvent to see if the function gets
- * invoked.
- */
-
- if (dispPtr->destroyCount > 0) {
- goto tryAgain;
- }
- delta = LastKnownRequestProcessed(dispPtr->display)
- - dispPtr->lastDestroyRequest;
- if (delta < 0) {
- XSync(dispPtr->display, False);
- }
- anyEvents = 0;
- oldProc = Tk_RestrictEvents(CheckRestrictProc, &anyEvents, &oldData);
- TkUnixDoOneXEvent(&timeout);
- Tk_RestrictEvents(oldProc, oldData, &oldData);
- if (anyEvents) {
- goto tryAgain;
- }
-
- /*
- * These ids look safe to recycle, but we still need to delay a bit more
- * (see comments for TkFreeWindowId). Schedule the final freeing.
- */
-
- if (dispPtr->windowStackPtr != NULL) {
- Tcl_CreateTimerHandler(5000, WindowIdCleanup2,
- dispPtr->windowStackPtr);
- dispPtr->windowStackPtr = NULL;
- }
- return;
-
- /*
- * It's still not safe to free up the ids. Try again a bit later.
- */
-
- tryAgain:
- dispPtr->idCleanupScheduled = Tcl_CreateTimerHandler(500,
- WindowIdCleanup, dispPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * WindowIdCleanup2 --
- *
- * This function is the last one in the chain that recycles window ids.
- * It takes all of the ids indicated by its argument and adds them back
- * to the main id free list.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Window ids get added to the main free list for their display.
- *
- *----------------------------------------------------------------------
- */
-static void
-WindowIdCleanup2(
- ClientData clientData) /* Pointer to TkIdStack list. */
-{
- TkIdStack *stackPtr = clientData;
- TkIdStack *lastPtr;
-
- lastPtr = stackPtr;
- while (lastPtr->nextPtr != NULL) {
- lastPtr = lastPtr->nextPtr;
- }
- lastPtr->nextPtr = stackPtr->dispPtr->idStackPtr;
- stackPtr->dispPtr->idStackPtr = stackPtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CheckRestrictProc --
- *
- * This function is a restrict function, called by Tcl_DoOneEvent to
- * filter X events. All it does is to set a flag to indicate that there
- * are X events present.
- *
- * Results:
- * Sets the integer pointed to by the argument, then returns
- * TK_DEFER_EVENT.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static Tk_RestrictAction
-CheckRestrictProc(
- ClientData clientData, /* Pointer to flag to set. */
- XEvent *eventPtr) /* Event to filter; not used. */
-{
- int *flag = clientData;
-
- *flag = 1;
- return TK_DEFER_EVENT;
-}
/*
*----------------------------------------------------------------------
@@ -524,44 +100,7 @@ Tk_FreePixmap(
XFreePixmap(display, pixmap);
Tk_FreeXId(display, (XID) pixmap);
}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkpWindowWasRecentlyDeleted --
- *
- * Checks whether the window was recently deleted. This is called by the
- * generic error handler to detect asynchronous notification of errors
- * due to operations by Tk on a window that was already deleted by the
- * server.
- *
- * Results:
- * 1 if the window was deleted recently, 0 otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkpWindowWasRecentlyDeleted(
- Window win, /* The window to check for. */
- TkDisplay *dispPtr) /* The window belongs to this display. */
-{
- TkIdStack *stackPtr;
- int i;
- for (stackPtr = dispPtr->windowStackPtr; stackPtr != NULL;
- stackPtr = stackPtr->nextPtr) {
- for (i = 0; i < stackPtr->numUsed; i++) {
- if ((Window) stackPtr->ids[i] == win) {
- return 1;
- }
- }
- }
- return 0;
-}
/*
*----------------------------------------------------------------------