sleepuntil.c revision 05b261ec
1/*
2 *
3Copyright 1992, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24 *
25 * Author:  Keith Packard, MIT X Consortium
26 */
27
28/* dixsleep.c - implement millisecond timeouts for X clients */
29
30#ifdef HAVE_DIX_CONFIG_H
31#include <dix-config.h>
32#endif
33
34#include "sleepuntil.h"
35#include <X11/X.h>
36#include <X11/Xmd.h>
37#include "misc.h"
38#include "windowstr.h"
39#include "dixstruct.h"
40#include "pixmapstr.h"
41#include "scrnintstr.h"
42
43typedef struct _Sertafied {
44    struct _Sertafied	*next;
45    TimeStamp		revive;
46    ClientPtr		pClient;
47    XID			id;
48    void		(*notifyFunc)(
49			ClientPtr /* client */,
50			pointer /* closure */
51			);
52
53    pointer		closure;
54} SertafiedRec, *SertafiedPtr;
55
56static SertafiedPtr pPending;
57static RESTYPE	    SertafiedResType;
58static Bool	    BlockHandlerRegistered;
59static int	    SertafiedGeneration;
60
61static void	    ClientAwaken(
62    ClientPtr /* client */,
63    pointer /* closure */
64);
65static int	    SertafiedDelete(
66    pointer /* value */,
67    XID /* id */
68);
69static void	    SertafiedBlockHandler(
70    pointer /* data */,
71    OSTimePtr /* wt */,
72    pointer /* LastSelectMask */
73);
74static void	    SertafiedWakeupHandler(
75    pointer /* data */,
76    int /* i */,
77    pointer /* LastSelectMask */
78);
79
80_X_EXPORT int
81ClientSleepUntil (client, revive, notifyFunc, closure)
82    ClientPtr	client;
83    TimeStamp	*revive;
84    void	(*notifyFunc)(
85        ClientPtr /* client */,
86        pointer   /* closure */);
87    pointer	closure;
88{
89    SertafiedPtr	pRequest, pReq, pPrev;
90
91    if (SertafiedGeneration != serverGeneration)
92    {
93	SertafiedResType = CreateNewResourceType (SertafiedDelete);
94	if (!SertafiedResType)
95	    return FALSE;
96	SertafiedGeneration = serverGeneration;
97	BlockHandlerRegistered = FALSE;
98    }
99    pRequest = (SertafiedPtr) xalloc (sizeof (SertafiedRec));
100    if (!pRequest)
101	return FALSE;
102    pRequest->pClient = client;
103    pRequest->revive = *revive;
104    pRequest->id = FakeClientID (client->index);
105    pRequest->closure = closure;
106    if (!BlockHandlerRegistered)
107    {
108	if (!RegisterBlockAndWakeupHandlers (SertafiedBlockHandler,
109					     SertafiedWakeupHandler,
110					     (pointer) 0))
111	{
112	    xfree (pRequest);
113	    return FALSE;
114	}
115	BlockHandlerRegistered = TRUE;
116    }
117    pRequest->notifyFunc = 0;
118    if (!AddResource (pRequest->id, SertafiedResType, (pointer) pRequest))
119	return FALSE;
120    if (!notifyFunc)
121	notifyFunc = ClientAwaken;
122    pRequest->notifyFunc = notifyFunc;
123    /* Insert into time-ordered queue, with earliest activation time coming first. */
124    pPrev = 0;
125    for (pReq = pPending; pReq; pReq = pReq->next)
126    {
127	if (CompareTimeStamps (pReq->revive, *revive) == LATER)
128	    break;
129	pPrev = pReq;
130    }
131    if (pPrev)
132	pPrev->next = pRequest;
133    else
134	pPending = pRequest;
135    pRequest->next = pReq;
136    IgnoreClient (client);
137    return TRUE;
138}
139
140static void
141ClientAwaken (client, closure)
142    ClientPtr	client;
143    pointer	closure;
144{
145    if (!client->clientGone)
146	AttendClient (client);
147}
148
149
150static int
151SertafiedDelete (value, id)
152    pointer value;
153    XID id;
154{
155    SertafiedPtr	pRequest = (SertafiedPtr)value;
156    SertafiedPtr	pReq, pPrev;
157
158    pPrev = 0;
159    for (pReq = pPending; pReq; pPrev = pReq, pReq = pReq->next)
160	if (pReq == pRequest)
161	{
162	    if (pPrev)
163		pPrev->next = pReq->next;
164	    else
165		pPending = pReq->next;
166	    break;
167	}
168    if (pRequest->notifyFunc)
169	(*pRequest->notifyFunc) (pRequest->pClient, pRequest->closure);
170    xfree (pRequest);
171    return TRUE;
172}
173
174static void
175SertafiedBlockHandler (data, wt, LastSelectMask)
176    pointer	    data;		/* unused */
177    OSTimePtr	    wt;			/* wait time */
178    pointer	    LastSelectMask;
179{
180    SertafiedPtr	    pReq, pNext;
181    unsigned long	    delay;
182    TimeStamp		    now;
183
184    if (!pPending)
185	return;
186    now.milliseconds = GetTimeInMillis ();
187    now.months = currentTime.months;
188    if ((int) (now.milliseconds - currentTime.milliseconds) < 0)
189	now.months++;
190    for (pReq = pPending; pReq; pReq = pNext)
191    {
192	pNext = pReq->next;
193	if (CompareTimeStamps (pReq->revive, now) == LATER)
194	    break;
195	FreeResource (pReq->id, RT_NONE);
196
197 	/* AttendClient() may have been called via the resource delete
198 	 * function so a client may have input to be processed and so
199 	 *  set delay to 0 to prevent blocking in WaitForSomething().
200 	 */
201 	AdjustWaitForDelay (wt, 0);
202    }
203    pReq = pPending;
204    if (!pReq)
205	return;
206    delay = pReq->revive.milliseconds - now.milliseconds;
207    AdjustWaitForDelay (wt, delay);
208}
209
210static void
211SertafiedWakeupHandler (data, i, LastSelectMask)
212    pointer	    data;
213    int		    i;
214    pointer	    LastSelectMask;
215{
216    SertafiedPtr	pReq, pNext;
217    TimeStamp		now;
218
219    now.milliseconds = GetTimeInMillis ();
220    now.months = currentTime.months;
221    if ((int) (now.milliseconds - currentTime.milliseconds) < 0)
222	now.months++;
223    for (pReq = pPending; pReq; pReq = pNext)
224    {
225	pNext = pReq->next;
226	if (CompareTimeStamps (pReq->revive, now) == LATER)
227	    break;
228	FreeResource (pReq->id, RT_NONE);
229    }
230    if (!pPending)
231    {
232	RemoveBlockAndWakeupHandlers (SertafiedBlockHandler,
233				      SertafiedWakeupHandler,
234				      (pointer) 0);
235	BlockHandlerRegistered = FALSE;
236    }
237}
238