sleepuntil.c revision 35c4bbdf
105b261ecSmrg/*
205b261ecSmrg *
305b261ecSmrgCopyright 1992, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg *
2505b261ecSmrg * Author:  Keith Packard, MIT X Consortium
2605b261ecSmrg */
2705b261ecSmrg
2805b261ecSmrg/* dixsleep.c - implement millisecond timeouts for X clients */
2905b261ecSmrg
3005b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3105b261ecSmrg#include <dix-config.h>
3205b261ecSmrg#endif
3305b261ecSmrg
3405b261ecSmrg#include "sleepuntil.h"
3505b261ecSmrg#include <X11/X.h>
3605b261ecSmrg#include <X11/Xmd.h>
3705b261ecSmrg#include "misc.h"
3805b261ecSmrg#include "windowstr.h"
3905b261ecSmrg#include "dixstruct.h"
4005b261ecSmrg#include "pixmapstr.h"
4105b261ecSmrg#include "scrnintstr.h"
4205b261ecSmrg
4305b261ecSmrgtypedef struct _Sertafied {
4435c4bbdfSmrg    struct _Sertafied *next;
4535c4bbdfSmrg    TimeStamp revive;
4635c4bbdfSmrg    ClientPtr pClient;
4735c4bbdfSmrg    XID id;
4835c4bbdfSmrg    void (*notifyFunc) (ClientPtr /* client */ ,
4935c4bbdfSmrg                        void *    /* closure */
5035c4bbdfSmrg        );
5135c4bbdfSmrg
5235c4bbdfSmrg    void *closure;
5305b261ecSmrg} SertafiedRec, *SertafiedPtr;
5405b261ecSmrg
5505b261ecSmrgstatic SertafiedPtr pPending;
5635c4bbdfSmrgstatic RESTYPE SertafiedResType;
5735c4bbdfSmrgstatic Bool BlockHandlerRegistered;
5835c4bbdfSmrgstatic int SertafiedGeneration;
5935c4bbdfSmrg
6035c4bbdfSmrgstatic void ClientAwaken(ClientPtr /* client */ ,
6135c4bbdfSmrg                         void *    /* closure */
6235c4bbdfSmrg    );
6335c4bbdfSmrgstatic int SertafiedDelete(void *  /* value */ ,
6435c4bbdfSmrg                           XID     /* id */
6535c4bbdfSmrg    );
6635c4bbdfSmrgstatic void SertafiedBlockHandler(void *    /* data */ ,
6735c4bbdfSmrg                                  OSTimePtr /* wt */ ,
6835c4bbdfSmrg                                  void *    /* LastSelectMask */
6935c4bbdfSmrg    );
7035c4bbdfSmrgstatic void SertafiedWakeupHandler(void *   /* data */ ,
7135c4bbdfSmrg                                   int      /* i */ ,
7235c4bbdfSmrg                                   void *   /* LastSelectMask */
7335c4bbdfSmrg    );
7405b261ecSmrg
756747b715Smrgint
7635c4bbdfSmrgClientSleepUntil(ClientPtr client,
7735c4bbdfSmrg                 TimeStamp *revive,
7835c4bbdfSmrg                 void (*notifyFunc) (ClientPtr, void *), void *closure)
7905b261ecSmrg{
8035c4bbdfSmrg    SertafiedPtr pRequest, pReq, pPrev;
8135c4bbdfSmrg
8235c4bbdfSmrg    if (SertafiedGeneration != serverGeneration) {
8335c4bbdfSmrg        SertafiedResType = CreateNewResourceType(SertafiedDelete,
8435c4bbdfSmrg                                                 "ClientSleep");
8535c4bbdfSmrg        if (!SertafiedResType)
8635c4bbdfSmrg            return FALSE;
8735c4bbdfSmrg        SertafiedGeneration = serverGeneration;
8835c4bbdfSmrg        BlockHandlerRegistered = FALSE;
8905b261ecSmrg    }
9035c4bbdfSmrg    pRequest = malloc(sizeof(SertafiedRec));
9105b261ecSmrg    if (!pRequest)
9235c4bbdfSmrg        return FALSE;
9305b261ecSmrg    pRequest->pClient = client;
9405b261ecSmrg    pRequest->revive = *revive;
9535c4bbdfSmrg    pRequest->id = FakeClientID(client->index);
9605b261ecSmrg    pRequest->closure = closure;
9735c4bbdfSmrg    if (!BlockHandlerRegistered) {
9835c4bbdfSmrg        if (!RegisterBlockAndWakeupHandlers(SertafiedBlockHandler,
9935c4bbdfSmrg                                            SertafiedWakeupHandler,
10035c4bbdfSmrg                                            (void *) 0)) {
10135c4bbdfSmrg            free(pRequest);
10235c4bbdfSmrg            return FALSE;
10335c4bbdfSmrg        }
10435c4bbdfSmrg        BlockHandlerRegistered = TRUE;
10505b261ecSmrg    }
10605b261ecSmrg    pRequest->notifyFunc = 0;
10735c4bbdfSmrg    if (!AddResource(pRequest->id, SertafiedResType, (void *) pRequest))
10835c4bbdfSmrg        return FALSE;
10905b261ecSmrg    if (!notifyFunc)
11035c4bbdfSmrg        notifyFunc = ClientAwaken;
11105b261ecSmrg    pRequest->notifyFunc = notifyFunc;
11205b261ecSmrg    /* Insert into time-ordered queue, with earliest activation time coming first. */
11305b261ecSmrg    pPrev = 0;
11435c4bbdfSmrg    for (pReq = pPending; pReq; pReq = pReq->next) {
11535c4bbdfSmrg        if (CompareTimeStamps(pReq->revive, *revive) == LATER)
11635c4bbdfSmrg            break;
11735c4bbdfSmrg        pPrev = pReq;
11805b261ecSmrg    }
11905b261ecSmrg    if (pPrev)
12035c4bbdfSmrg        pPrev->next = pRequest;
12105b261ecSmrg    else
12235c4bbdfSmrg        pPending = pRequest;
12305b261ecSmrg    pRequest->next = pReq;
12435c4bbdfSmrg    IgnoreClient(client);
12505b261ecSmrg    return TRUE;
12605b261ecSmrg}
12705b261ecSmrg
12805b261ecSmrgstatic void
12935c4bbdfSmrgClientAwaken(ClientPtr client, void *closure)
13005b261ecSmrg{
13105b261ecSmrg    if (!client->clientGone)
13235c4bbdfSmrg        AttendClient(client);
13305b261ecSmrg}
13405b261ecSmrg
13505b261ecSmrgstatic int
13635c4bbdfSmrgSertafiedDelete(void *value, XID id)
13705b261ecSmrg{
13835c4bbdfSmrg    SertafiedPtr pRequest = (SertafiedPtr) value;
13935c4bbdfSmrg    SertafiedPtr pReq, pPrev;
14005b261ecSmrg
14105b261ecSmrg    pPrev = 0;
14205b261ecSmrg    for (pReq = pPending; pReq; pPrev = pReq, pReq = pReq->next)
14335c4bbdfSmrg        if (pReq == pRequest) {
14435c4bbdfSmrg            if (pPrev)
14535c4bbdfSmrg                pPrev->next = pReq->next;
14635c4bbdfSmrg            else
14735c4bbdfSmrg                pPending = pReq->next;
14835c4bbdfSmrg            break;
14935c4bbdfSmrg        }
15005b261ecSmrg    if (pRequest->notifyFunc)
15135c4bbdfSmrg        (*pRequest->notifyFunc) (pRequest->pClient, pRequest->closure);
1526747b715Smrg    free(pRequest);
15305b261ecSmrg    return TRUE;
15405b261ecSmrg}
15505b261ecSmrg
15605b261ecSmrgstatic void
15735c4bbdfSmrgSertafiedBlockHandler(void *data, OSTimePtr wt, void *LastSelectMask)
15805b261ecSmrg{
15935c4bbdfSmrg    SertafiedPtr pReq, pNext;
16035c4bbdfSmrg    unsigned long delay;
16135c4bbdfSmrg    TimeStamp now;
16205b261ecSmrg
16305b261ecSmrg    if (!pPending)
16435c4bbdfSmrg        return;
16535c4bbdfSmrg    now.milliseconds = GetTimeInMillis();
16605b261ecSmrg    now.months = currentTime.months;
16705b261ecSmrg    if ((int) (now.milliseconds - currentTime.milliseconds) < 0)
16835c4bbdfSmrg        now.months++;
16935c4bbdfSmrg    for (pReq = pPending; pReq; pReq = pNext) {
17035c4bbdfSmrg        pNext = pReq->next;
17135c4bbdfSmrg        if (CompareTimeStamps(pReq->revive, now) == LATER)
17235c4bbdfSmrg            break;
17335c4bbdfSmrg        FreeResource(pReq->id, RT_NONE);
17435c4bbdfSmrg
17535c4bbdfSmrg        /* AttendClient() may have been called via the resource delete
17635c4bbdfSmrg         * function so a client may have input to be processed and so
17735c4bbdfSmrg         *  set delay to 0 to prevent blocking in WaitForSomething().
17835c4bbdfSmrg         */
17935c4bbdfSmrg        AdjustWaitForDelay(wt, 0);
18005b261ecSmrg    }
18105b261ecSmrg    pReq = pPending;
18205b261ecSmrg    if (!pReq)
18335c4bbdfSmrg        return;
18405b261ecSmrg    delay = pReq->revive.milliseconds - now.milliseconds;
18535c4bbdfSmrg    AdjustWaitForDelay(wt, delay);
18605b261ecSmrg}
18705b261ecSmrg
18805b261ecSmrgstatic void
18935c4bbdfSmrgSertafiedWakeupHandler(void *data, int i, void *LastSelectMask)
19005b261ecSmrg{
19135c4bbdfSmrg    SertafiedPtr pReq, pNext;
19235c4bbdfSmrg    TimeStamp now;
19305b261ecSmrg
19435c4bbdfSmrg    now.milliseconds = GetTimeInMillis();
19505b261ecSmrg    now.months = currentTime.months;
19605b261ecSmrg    if ((int) (now.milliseconds - currentTime.milliseconds) < 0)
19735c4bbdfSmrg        now.months++;
19835c4bbdfSmrg    for (pReq = pPending; pReq; pReq = pNext) {
19935c4bbdfSmrg        pNext = pReq->next;
20035c4bbdfSmrg        if (CompareTimeStamps(pReq->revive, now) == LATER)
20135c4bbdfSmrg            break;
20235c4bbdfSmrg        FreeResource(pReq->id, RT_NONE);
20305b261ecSmrg    }
20435c4bbdfSmrg    if (!pPending) {
20535c4bbdfSmrg        RemoveBlockAndWakeupHandlers(SertafiedBlockHandler,
20635c4bbdfSmrg                                     SertafiedWakeupHandler, (void *) 0);
20735c4bbdfSmrg        BlockHandlerRegistered = FALSE;
20805b261ecSmrg    }
20905b261ecSmrg}
210