1/*
2
3Copyright 1991, 1993, 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
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27
28Copyright 1991, 1993 by Digital Equipment Corporation, Maynard, Massachusetts,
29and Olivetti Research Limited, Cambridge, England.
30
31                        All Rights Reserved
32
33Permission to use, copy, modify, and distribute this software and its
34documentation for any purpose and without fee is hereby granted,
35provided that the above copyright notice appear in all copies and that
36both that copyright notice and this permission notice appear in
37supporting documentation, and that the names of Digital or Olivetti
38not be used in advertising or publicity pertaining to distribution of the
39software without specific, written prior permission.  Digital and Olivetti
40make no representations about the suitability of this software
41for any purpose.  It is provided "as is" without express or implied warranty.
42
43DIGITAL AND OLIVETTI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
44SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
45FITNESS, IN NO EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR
46CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
47USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
48OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
49PERFORMANCE OF THIS SOFTWARE.
50
51*/
52
53#ifdef HAVE_DIX_CONFIG_H
54#include <dix-config.h>
55#endif
56
57#include <string.h>
58
59#include <X11/X.h>
60#include <X11/Xproto.h>
61#include <X11/Xmd.h>
62#include "scrnintstr.h"
63#include "os.h"
64#include "extnsionst.h"
65#include "dixstruct.h"
66#include "pixmapstr.h"
67#include "resource.h"
68#include "opaque.h"
69#include <X11/extensions/syncproto.h>
70#include "syncsrv.h"
71#include "syncsdk.h"
72#include "protocol-versions.h"
73
74#include <stdio.h>
75#if !defined(WIN32)
76#include <sys/time.h>
77#endif
78
79#include "modinit.h"
80
81/*
82 * Local Global Variables
83 */
84static int      SyncEventBase;
85static int      SyncErrorBase;
86static RESTYPE  RTCounter = 0;
87static RESTYPE  RTAwait;
88static RESTYPE  RTAlarm;
89static RESTYPE  RTAlarmClient;
90static RESTYPE  RTFence;
91static int SyncNumSystemCounters = 0;
92static SyncCounter **SysCounterList = NULL;
93static int SyncNumInvalidCounterWarnings = 0;
94#define MAX_INVALID_COUNTER_WARNINGS	   5
95
96static const char *WARN_INVALID_COUNTER_COMPARE =
97"Warning: Non-counter XSync object using Counter-only\n"
98"         comparison.  Result will never be true.\n";
99
100static const char *WARN_INVALID_COUNTER_ALARM =
101"Warning: Non-counter XSync object used in alarm.  This is\n"
102"         the result of a programming error in the X server.\n";
103
104#define IsSystemCounter(pCounter) \
105    (pCounter && (pCounter->sync.client == NULL))
106
107/* these are all the alarm attributes that pertain to the alarm's trigger */
108#define XSyncCAAllTrigger \
109    (XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType)
110
111static void SyncComputeBracketValues(SyncCounter *);
112
113static void SyncInitServerTime(void);
114
115static void SyncInitIdleTime(void);
116
117static Bool
118SyncCheckWarnIsCounter(const SyncObject* pSync, const char *warning)
119{
120    if (pSync && (SYNC_COUNTER != pSync->type))
121    {
122	if (SyncNumInvalidCounterWarnings++ < MAX_INVALID_COUNTER_WARNINGS)
123	{
124	    ErrorF("%s", warning);
125	    ErrorF("         Counter type: %d\n", pSync->type);
126	}
127
128	return FALSE;
129    }
130
131    return TRUE;
132}
133
134/*  Each counter maintains a simple linked list of triggers that are
135 *  interested in the counter.  The two functions below are used to
136 *  delete and add triggers on this list.
137 */
138static void
139SyncDeleteTriggerFromSyncObject(SyncTrigger *pTrigger)
140{
141    SyncTriggerList *pCur;
142    SyncTriggerList *pPrev;
143    SyncCounter *pCounter;
144
145    /* pSync needs to be stored in pTrigger before calling here. */
146
147    if (!pTrigger->pSync)
148	return;
149
150    pPrev = NULL;
151    pCur = pTrigger->pSync->pTriglist;
152
153    while (pCur)
154    {
155	if (pCur->pTrigger == pTrigger)
156	{
157	    if (pPrev)
158		pPrev->next = pCur->next;
159	    else
160		pTrigger->pSync->pTriglist = pCur->next;
161
162	    free(pCur);
163	    break;
164	}
165
166	pPrev = pCur;
167	pCur = pCur->next;
168    }
169
170    if (SYNC_COUNTER == pTrigger->pSync->type)
171    {
172	pCounter = (SyncCounter *)pTrigger->pSync;
173
174	if (IsSystemCounter(pCounter))
175	    SyncComputeBracketValues(pCounter);
176    } else if (SYNC_FENCE == pTrigger->pSync->type) {
177	SyncFence* pFence = (SyncFence*) pTrigger->pSync;
178	pFence->funcs.DeleteTrigger(pTrigger);
179    }
180}
181
182
183static int
184SyncAddTriggerToSyncObject(SyncTrigger *pTrigger)
185{
186    SyncTriggerList *pCur;
187    SyncCounter *pCounter;
188
189    if (!pTrigger->pSync)
190	return Success;
191
192    /* don't do anything if it's already there */
193    for (pCur = pTrigger->pSync->pTriglist; pCur; pCur = pCur->next)
194    {
195	if (pCur->pTrigger == pTrigger)
196	    return Success;
197    }
198
199    if (!(pCur = malloc(sizeof(SyncTriggerList))))
200	return BadAlloc;
201
202    pCur->pTrigger = pTrigger;
203    pCur->next = pTrigger->pSync->pTriglist;
204    pTrigger->pSync->pTriglist = pCur;
205
206    if (SYNC_COUNTER == pTrigger->pSync->type)
207    {
208	pCounter = (SyncCounter *)pTrigger->pSync;
209
210	if (IsSystemCounter(pCounter))
211	    SyncComputeBracketValues(pCounter);
212    } else if (SYNC_FENCE == pTrigger->pSync->type) {
213	SyncFence* pFence = (SyncFence*) pTrigger->pSync;
214	pFence->funcs.AddTrigger(pTrigger);
215    }
216
217    return Success;
218}
219
220
221/*  Below are five possible functions that can be plugged into
222 *  pTrigger->CheckTrigger for counter sync objects, corresponding to
223 *  the four possible test-types, and the one possible function that
224 *  can be plugged into pTrigger->CheckTrigger for fence sync objects.
225 *  These functions are called after the sync object's state changes
226 *  but are also passed the old state so they can inspect both the old
227 *  and new values.  (PositiveTransition and NegativeTransition need to
228 *  see both pieces of information.)  These functions return the truth
229 *  value of the trigger.
230 *
231 *  All of them include the condition pTrigger->pSync == NULL.
232 *  This is because the spec says that a trigger with a sync value
233 *  of None is always TRUE.
234 */
235
236static Bool
237SyncCheckTriggerPositiveComparison(SyncTrigger *pTrigger, CARD64 oldval)
238{
239    SyncCounter *pCounter;
240
241    /* Non-counter sync objects should never get here because they
242     * never trigger this comparison. */
243    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
244	return FALSE;
245
246    pCounter = (SyncCounter *)pTrigger->pSync;
247
248    return (pCounter == NULL ||
249	    XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value));
250}
251
252static Bool
253SyncCheckTriggerNegativeComparison(SyncTrigger *pTrigger,  CARD64 oldval)
254{
255    SyncCounter *pCounter;
256
257    /* Non-counter sync objects should never get here because they
258     * never trigger this comparison. */
259    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
260	return FALSE;
261
262    pCounter = (SyncCounter *)pTrigger->pSync;
263
264    return (pCounter == NULL ||
265	    XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value));
266}
267
268static Bool
269SyncCheckTriggerPositiveTransition(SyncTrigger *pTrigger, CARD64 oldval)
270{
271    SyncCounter *pCounter;
272
273    /* Non-counter sync objects should never get here because they
274     * never trigger this comparison. */
275    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
276	return FALSE;
277
278    pCounter = (SyncCounter *)pTrigger->pSync;
279
280    return (pCounter == NULL ||
281	    (XSyncValueLessThan(oldval, pTrigger->test_value) &&
282	     XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value)));
283}
284
285static Bool
286SyncCheckTriggerNegativeTransition(SyncTrigger *pTrigger, CARD64 oldval)
287{
288    SyncCounter *pCounter;
289
290    /* Non-counter sync objects should never get here because they
291     * never trigger this comparison. */
292    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
293	return FALSE;
294
295    pCounter = (SyncCounter *)pTrigger->pSync;
296
297    return (pCounter == NULL ||
298	    (XSyncValueGreaterThan(oldval, pTrigger->test_value) &&
299	     XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value)));
300}
301
302static Bool
303SyncCheckTriggerFence(SyncTrigger *pTrigger, CARD64 unused)
304{
305    SyncFence* pFence = (SyncFence*) pTrigger->pSync;
306    (void)unused;
307
308    return (pFence == NULL ||
309	    pFence->funcs.CheckTriggered(pFence));
310}
311
312static int
313SyncInitTrigger(ClientPtr client, SyncTrigger *pTrigger, XID syncObject,
314		RESTYPE resType, Mask changes)
315{
316    SyncObject *pSync = pTrigger->pSync;
317    SyncCounter *pCounter = NULL;
318    int		rc;
319    Bool	newSyncObject = FALSE;
320
321    if (changes & XSyncCACounter)
322    {
323	if (syncObject == None)
324	    pSync = NULL;
325	else if (Success != (rc = dixLookupResourceByType ((pointer *)&pSync,
326				syncObject, resType, client, DixReadAccess)))
327	{
328	    client->errorValue = syncObject;
329	    return rc;
330	}
331	if (pSync != pTrigger->pSync)
332	{ /* new counter for trigger */
333	    SyncDeleteTriggerFromSyncObject(pTrigger);
334	    pTrigger->pSync = pSync;
335	    newSyncObject = TRUE;
336	}
337    }
338
339    /* if system counter, ask it what the current value is */
340
341    if (pSync && SYNC_COUNTER == pSync->type)
342    {
343	pCounter = (SyncCounter *)pSync;
344
345	if (IsSystemCounter(pCounter))
346	{
347	    (*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
348						      &pCounter->value);
349	}
350    }
351
352    if (changes & XSyncCAValueType)
353    {
354	if (pTrigger->value_type != XSyncRelative &&
355	    pTrigger->value_type != XSyncAbsolute)
356	{
357	    client->errorValue = pTrigger->value_type;
358	    return BadValue;
359	}
360    }
361
362    if (changes & XSyncCATestType)
363    {
364
365	if (pSync && SYNC_FENCE == pSync->type)
366	{
367	    pTrigger->CheckTrigger = SyncCheckTriggerFence;
368	}
369	else
370	{
371	    /* select appropriate CheckTrigger function */
372
373	    switch (pTrigger->test_type)
374	    {
375	    case XSyncPositiveTransition:
376		pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition;
377		break;
378	    case XSyncNegativeTransition:
379		pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition;
380		break;
381	    case XSyncPositiveComparison:
382		pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison;
383		break;
384	    case XSyncNegativeComparison:
385		pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison;
386		break;
387	    default:
388		client->errorValue = pTrigger->test_type;
389		return BadValue;
390	    }
391	}
392    }
393
394    if (changes & (XSyncCAValueType | XSyncCAValue))
395    {
396	if (pTrigger->value_type == XSyncAbsolute)
397	    pTrigger->test_value = pTrigger->wait_value;
398	else /* relative */
399	{
400	    Bool overflow;
401	    if (pCounter == NULL)
402		return BadMatch;
403
404	    XSyncValueAdd(&pTrigger->test_value, pCounter->value,
405			  pTrigger->wait_value, &overflow);
406	    if (overflow)
407	    {
408		client->errorValue = XSyncValueHigh32(pTrigger->wait_value);
409		return BadValue;
410	    }
411	}
412    }
413
414    /*  we wait until we're sure there are no errors before registering
415     *  a new counter on a trigger
416     */
417    if (newSyncObject)
418    {
419	if ((rc = SyncAddTriggerToSyncObject(pTrigger)) != Success)
420	    return rc;
421    }
422    else if (pCounter && IsSystemCounter(pCounter))
423    {
424	SyncComputeBracketValues(pCounter);
425    }
426
427    return Success;
428}
429
430/*  AlarmNotify events happen in response to actions taken on an Alarm or
431 *  the counter used by the alarm.  AlarmNotify may be sent to multiple
432 *  clients.  The alarm maintains a list of clients interested in events.
433 */
434static void
435SyncSendAlarmNotifyEvents(SyncAlarm *pAlarm)
436{
437    SyncAlarmClientList *pcl;
438    xSyncAlarmNotifyEvent ane;
439    SyncTrigger *pTrigger = &pAlarm->trigger;
440    SyncCounter *pCounter;
441
442    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
443	return;
444
445    pCounter = (SyncCounter *)pTrigger->pSync;
446
447    UpdateCurrentTime();
448
449    ane.type = SyncEventBase + XSyncAlarmNotify;
450    ane.kind = XSyncAlarmNotify;
451    ane.alarm = pAlarm->alarm_id;
452    if (pTrigger->pSync && SYNC_COUNTER == pTrigger->pSync->type)
453    {
454	ane.counter_value_hi = XSyncValueHigh32(pCounter->value);
455	ane.counter_value_lo = XSyncValueLow32(pCounter->value);
456    }
457    else
458    { /* XXX what else can we do if there's no counter? */
459	ane.counter_value_hi = ane.counter_value_lo = 0;
460    }
461
462    ane.alarm_value_hi = XSyncValueHigh32(pTrigger->test_value);
463    ane.alarm_value_lo = XSyncValueLow32(pTrigger->test_value);
464    ane.time = currentTime.milliseconds;
465    ane.state = pAlarm->state;
466
467    /* send to owner */
468    if (pAlarm->events)
469	WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane);
470
471    /* send to other interested clients */
472    for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next)
473	WriteEventsToClient(pcl->client, 1, (xEvent *) &ane);
474}
475
476
477/*  CounterNotify events only occur in response to an Await.  The events
478 *  go only to the Awaiting client.
479 */
480static void
481SyncSendCounterNotifyEvents(ClientPtr client, SyncAwait **ppAwait,
482			    int num_events)
483{
484    xSyncCounterNotifyEvent *pEvents, *pev;
485    int i;
486
487    if (client->clientGone)
488	return;
489    pev = pEvents = malloc(num_events * sizeof(xSyncCounterNotifyEvent));
490    if (!pEvents)
491	return;
492    UpdateCurrentTime();
493    for (i = 0; i < num_events; i++, ppAwait++, pev++)
494    {
495	SyncTrigger *pTrigger = &(*ppAwait)->trigger;
496	pev->type = SyncEventBase + XSyncCounterNotify;
497	pev->kind = XSyncCounterNotify;
498	pev->counter = pTrigger->pSync->id;
499	pev->wait_value_lo = XSyncValueLow32(pTrigger->test_value);
500	pev->wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
501	if (SYNC_COUNTER == pTrigger->pSync->type)
502	{
503	    SyncCounter *pCounter = (SyncCounter *)pTrigger->pSync;
504
505	    pev->counter_value_lo = XSyncValueLow32(pCounter->value);
506	    pev->counter_value_hi = XSyncValueHigh32(pCounter->value);
507	}
508	else
509	{
510	    pev->counter_value_lo = 0;
511	    pev->counter_value_hi = 0;
512	}
513
514	pev->time = currentTime.milliseconds;
515	pev->count = num_events - i - 1; /* events remaining */
516	pev->destroyed = pTrigger->pSync->beingDestroyed;
517    }
518    /* swapping will be taken care of by this */
519    WriteEventsToClient(client, num_events, (xEvent *)pEvents);
520    free(pEvents);
521}
522
523
524/* This function is called when an alarm's counter is destroyed.
525 * It is plugged into pTrigger->CounterDestroyed (for alarm triggers).
526 */
527static void
528SyncAlarmCounterDestroyed(SyncTrigger *pTrigger)
529{
530    SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
531
532    pAlarm->state = XSyncAlarmInactive;
533    SyncSendAlarmNotifyEvents(pAlarm);
534    pTrigger->pSync = NULL;
535}
536
537
538/*  This function is called when an alarm "goes off."
539 *  It is plugged into pTrigger->TriggerFired (for alarm triggers).
540 */
541static void
542SyncAlarmTriggerFired(SyncTrigger *pTrigger)
543{
544    SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
545    SyncCounter *pCounter;
546    CARD64 new_test_value;
547
548    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
549	return;
550
551    pCounter = (SyncCounter *)pTrigger->pSync;
552
553    /* no need to check alarm unless it's active */
554    if (pAlarm->state != XSyncAlarmActive)
555	return;
556
557    /*  " if the counter value is None, or if the delta is 0 and
558     *    the test-type is PositiveComparison or NegativeComparison,
559     *    no change is made to value (test-value) and the alarm
560     *    state is changed to Inactive before the event is generated."
561     */
562    if (pCounter == NULL
563	|| (XSyncValueIsZero(pAlarm->delta)
564	    && (pAlarm->trigger.test_type == XSyncPositiveComparison
565		|| pAlarm->trigger.test_type == XSyncNegativeComparison)))
566	pAlarm->state = XSyncAlarmInactive;
567
568    new_test_value = pAlarm->trigger.test_value;
569
570    if (pAlarm->state == XSyncAlarmActive)
571    {
572	Bool overflow;
573	CARD64 oldvalue;
574	SyncTrigger *paTrigger = &pAlarm->trigger;
575	SyncCounter *paCounter;
576
577	if (!SyncCheckWarnIsCounter(paTrigger->pSync,
578				    WARN_INVALID_COUNTER_ALARM))
579	    return;
580
581	paCounter = (SyncCounter *)pTrigger->pSync;
582
583	/* "The alarm is updated by repeatedly adding delta to the
584	 *  value of the trigger and re-initializing it until it
585	 *  becomes FALSE."
586	 */
587	oldvalue = paTrigger->test_value;
588
589	/* XXX really should do something smarter here */
590
591	do
592	{
593	    XSyncValueAdd(&paTrigger->test_value, paTrigger->test_value,
594			  pAlarm->delta, &overflow);
595	} while (!overflow &&
596	      (*paTrigger->CheckTrigger)(paTrigger,
597					paCounter->value));
598
599	new_test_value = paTrigger->test_value;
600	paTrigger->test_value = oldvalue;
601
602	/* "If this update would cause value to fall outside the range
603	 *  for an INT64...no change is made to value (test-value) and
604	 *  the alarm state is changed to Inactive before the event is
605	 *  generated."
606	 */
607	if (overflow)
608	{
609	    new_test_value = oldvalue;
610	    pAlarm->state = XSyncAlarmInactive;
611	}
612    }
613    /*  The AlarmNotify event has to have the "new state of the alarm"
614     *  which we can't be sure of until this point.  However, it has
615     *  to have the "old" trigger test value.  That's the reason for
616     *  all the newvalue/oldvalue shuffling above.  After we send the
617     *  events, give the trigger its new test value.
618     */
619    SyncSendAlarmNotifyEvents(pAlarm);
620    pTrigger->test_value = new_test_value;
621}
622
623
624/*  This function is called when an Await unblocks, either as a result
625 *  of the trigger firing OR the counter being destroyed.
626 *  It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed
627 *  (for Await triggers).
628 */
629static void
630SyncAwaitTriggerFired(SyncTrigger *pTrigger)
631{
632    SyncAwait *pAwait = (SyncAwait *)pTrigger;
633    int numwaits;
634    SyncAwaitUnion *pAwaitUnion;
635    SyncAwait **ppAwait;
636    int num_events = 0;
637
638    pAwaitUnion = (SyncAwaitUnion *)pAwait->pHeader;
639    numwaits = pAwaitUnion->header.num_waitconditions;
640    ppAwait = malloc(numwaits * sizeof(SyncAwait *));
641    if (!ppAwait)
642	goto bail;
643
644    pAwait = &(pAwaitUnion+1)->await;
645
646    /* "When a client is unblocked, all the CounterNotify events for
647     *  the Await request are generated contiguously. If count is 0
648     *  there are no more events to follow for this request. If
649     *  count is n, there are at least n more events to follow."
650     *
651     *  Thus, it is best to find all the counters for which events
652     *  need to be sent first, so that an accurate count field can
653     *  be stored in the events.
654     */
655    for ( ; numwaits; numwaits--, pAwait++)
656    {
657	CARD64 diff;
658	Bool overflow, diffgreater, diffequal;
659
660	/* "A CounterNotify event with the destroyed flag set to TRUE is
661	 *  always generated if the counter for one of the triggers is
662	 *  destroyed."
663	 */
664	if (pAwait->trigger.pSync->beingDestroyed)
665	{
666	    ppAwait[num_events++] = pAwait;
667	    continue;
668	}
669
670	if (SYNC_COUNTER == pAwait->trigger.pSync->type)
671	{
672	    SyncCounter *pCounter = (SyncCounter *) pAwait->trigger.pSync;
673
674	    /* "The difference between the counter and the test value is
675	     *  calculated by subtracting the test value from the value of
676	     *  the counter."
677	     */
678	    XSyncValueSubtract(&diff, pCounter->value,
679			       pAwait->trigger.test_value, &overflow);
680
681	    /* "If the difference lies outside the range for an INT64, an
682	     *  event is not generated."
683	     */
684	    if (overflow)
685		continue;
686	    diffgreater = XSyncValueGreaterThan(diff, pAwait->event_threshold);
687	    diffequal   = XSyncValueEqual(diff, pAwait->event_threshold);
688
689	    /* "If the test-type is PositiveTransition or
690	     *  PositiveComparison, a CounterNotify event is generated if
691	     *  the difference is at least event-threshold. If the test-type
692	     *  is NegativeTransition or NegativeComparison, a CounterNotify
693	     *  event is generated if the difference is at most
694	     *  event-threshold."
695	     */
696
697	    if ( ((pAwait->trigger.test_type == XSyncPositiveComparison ||
698		   pAwait->trigger.test_type == XSyncPositiveTransition)
699		  && (diffgreater || diffequal))
700		 ||
701		 ((pAwait->trigger.test_type == XSyncNegativeComparison ||
702		   pAwait->trigger.test_type == XSyncNegativeTransition)
703		  && (!diffgreater) /* less or equal */
704		 )
705	       )
706	    {
707		ppAwait[num_events++] = pAwait;
708	    }
709	}
710    }
711    if (num_events)
712	SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait,
713				    num_events);
714    free(ppAwait);
715
716bail:
717    /* unblock the client */
718    AttendClient(pAwaitUnion->header.client);
719    /* delete the await */
720    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
721}
722
723
724/*  This function should always be used to change a counter's value so that
725 *  any triggers depending on the counter will be checked.
726 */
727void
728SyncChangeCounter(SyncCounter *pCounter, CARD64 newval)
729{
730    SyncTriggerList       *ptl, *pnext;
731    CARD64 oldval;
732
733    oldval = pCounter->value;
734    pCounter->value = newval;
735
736    /* run through triggers to see if any become true */
737    for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext)
738    {
739	pnext = ptl->next;
740	if ((*ptl->pTrigger->CheckTrigger)(ptl->pTrigger, oldval))
741	    (*ptl->pTrigger->TriggerFired)(ptl->pTrigger);
742    }
743
744    if (IsSystemCounter(pCounter))
745    {
746	SyncComputeBracketValues(pCounter);
747    }
748}
749
750
751/* loosely based on dix/events.c/EventSelectForWindow */
752static Bool
753SyncEventSelectForAlarm(SyncAlarm *pAlarm, ClientPtr client, Bool wantevents)
754{
755    SyncAlarmClientList *pClients;
756
757    if (client == pAlarm->client) /* alarm owner */
758    {
759	pAlarm->events = wantevents;
760	return Success;
761    }
762
763    /* see if the client is already on the list (has events selected) */
764
765    for (pClients = pAlarm->pEventClients; pClients;
766	 pClients = pClients->next)
767    {
768	if (pClients->client == client)
769	{
770	    /* client's presence on the list indicates desire for
771	     * events.  If the client doesn't want events, remove it
772	     * from the list.  If the client does want events, do
773	     * nothing, since it's already got them.
774	     */
775	    if (!wantevents)
776	    {
777		FreeResource(pClients->delete_id, RT_NONE);
778	    }
779	    return Success;
780	}
781    }
782
783    /*  if we get here, this client does not currently have
784     *  events selected on the alarm
785     */
786
787    if (!wantevents)
788	/* client doesn't want events, and we just discovered that it
789	 * doesn't have them, so there's nothing to do.
790	 */
791	return Success;
792
793    /* add new client to pAlarm->pEventClients */
794
795    pClients = malloc(sizeof(SyncAlarmClientList));
796    if (!pClients)
797	return BadAlloc;
798
799    /*  register it as a resource so it will be cleaned up
800     *  if the client dies
801     */
802
803    pClients->delete_id = FakeClientID(client->index);
804
805    /* link it into list after we know all the allocations succeed */
806    pClients->next = pAlarm->pEventClients;
807    pAlarm->pEventClients = pClients;
808    pClients->client = client;
809
810    if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm))
811	return BadAlloc;
812
813    return Success;
814}
815
816/*
817 * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm
818 */
819static int
820SyncChangeAlarmAttributes(ClientPtr client, SyncAlarm *pAlarm, Mask mask,
821			  CARD32 *values)
822{
823    int		   status;
824    XSyncCounter   counter;
825    Mask	   origmask = mask;
826
827    counter =
828	pAlarm->trigger.pSync ? pAlarm->trigger.pSync->id : None;
829
830    while (mask)
831    {
832	int    index2 = lowbit(mask);
833	mask &= ~index2;
834	switch (index2)
835	{
836	  case XSyncCACounter:
837	    mask &= ~XSyncCACounter;
838	    /* sanity check in SyncInitTrigger */
839	    counter = *values++;
840	    break;
841
842	  case XSyncCAValueType:
843	    mask &= ~XSyncCAValueType;
844	    /* sanity check in SyncInitTrigger */
845	    pAlarm->trigger.value_type = *values++;
846	    break;
847
848	  case XSyncCAValue:
849	    mask &= ~XSyncCAValue;
850	    XSyncIntsToValue(&pAlarm->trigger.wait_value, values[1], values[0]);
851	    values += 2;
852	    break;
853
854	  case XSyncCATestType:
855	    mask &= ~XSyncCATestType;
856	    /* sanity check in SyncInitTrigger */
857	    pAlarm->trigger.test_type = *values++;
858	    break;
859
860	  case XSyncCADelta:
861	    mask &= ~XSyncCADelta;
862	    XSyncIntsToValue(&pAlarm->delta, values[1], values[0]);
863	    values += 2;
864	    break;
865
866	  case XSyncCAEvents:
867	    mask &= ~XSyncCAEvents;
868	    if ((*values != xTrue) && (*values != xFalse))
869	    {
870		client->errorValue = *values;
871		return BadValue;
872	    }
873	    status = SyncEventSelectForAlarm(pAlarm, client,
874					     (Bool)(*values++));
875	    if (status != Success)
876		return status;
877	    break;
878
879	  default:
880	    client->errorValue = mask;
881	    return BadValue;
882	}
883    }
884
885    /* "If the test-type is PositiveComparison or PositiveTransition
886     *  and delta is less than zero, or if the test-type is
887     *  NegativeComparison or NegativeTransition and delta is
888     *  greater than zero, a Match error is generated."
889     */
890    if (origmask & (XSyncCADelta|XSyncCATestType))
891    {
892	CARD64 zero;
893	XSyncIntToValue(&zero, 0);
894	if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) ||
895	      (pAlarm->trigger.test_type == XSyncPositiveTransition))
896	     && XSyncValueLessThan(pAlarm->delta, zero))
897	    ||
898	    (((pAlarm->trigger.test_type == XSyncNegativeComparison) ||
899	      (pAlarm->trigger.test_type == XSyncNegativeTransition))
900	     && XSyncValueGreaterThan(pAlarm->delta, zero))
901	   )
902	{
903	    return BadMatch;
904	}
905    }
906
907    /* postpone this until now, when we're sure nothing else can go wrong */
908    if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter,
909			     origmask & XSyncCAAllTrigger)) != Success)
910	return status;
911
912    /* XXX spec does not really say to do this - needs clarification */
913    pAlarm->state = XSyncAlarmActive;
914    return Success;
915}
916
917static SyncObject *
918SyncCreate(ClientPtr client, XID id, unsigned char type)
919{
920    SyncObject *pSync;
921
922    switch (type) {
923    case SYNC_COUNTER:
924	pSync = malloc(sizeof(SyncCounter));
925	break;
926    case SYNC_FENCE:
927	pSync = (SyncObject*)dixAllocateObjectWithPrivates(SyncFence,
928							   PRIVATE_SYNC_FENCE);
929	break;
930    default:
931	return NULL;
932    }
933
934    if (!pSync)
935	return NULL;
936
937    pSync->client = client;
938    pSync->id = id;
939    pSync->pTriglist = NULL;
940    pSync->beingDestroyed = FALSE;
941    pSync->type = type;
942
943    return pSync;
944}
945
946
947static SyncCounter *
948SyncCreateCounter(ClientPtr client, XSyncCounter id, CARD64 initialvalue)
949{
950    SyncCounter *pCounter;
951
952    if (!(pCounter = (SyncCounter *)SyncCreate(client,
953					       id,
954					       SYNC_COUNTER)))
955	return NULL;
956
957    pCounter->value = initialvalue;
958    pCounter->pSysCounterInfo = NULL;
959
960    if (!AddResource(id, RTCounter, (pointer) pCounter))
961	return NULL;
962
963    return pCounter;
964}
965
966static int FreeCounter(void *, XID);
967
968/*
969 * ***** System Counter utilities
970 */
971
972pointer
973SyncCreateSystemCounter(
974	char *name,
975	CARD64 initial,
976	CARD64 resolution,
977	SyncCounterType counterType,
978	void (*QueryValue)(pointer /* pCounter */,
979	      	           CARD64 * /* pValue_return */),
980	void (*BracketValues)(pointer /* pCounter */,
981	       	              CARD64 * /* pbracket_less */,
982	                      CARD64 * /* pbracket_greater */)
983	)
984{
985    SyncCounter    *pCounter;
986
987    SysCounterList = realloc(SysCounterList,
988			    (SyncNumSystemCounters+1)*sizeof(SyncCounter *));
989    if (!SysCounterList)
990	return NULL;
991
992    /* this function may be called before SYNC has been initialized, so we
993     * have to make sure RTCounter is created.
994     */
995    if (RTCounter == 0)
996    {
997	RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
998	if (RTCounter == 0)
999	{
1000	    return NULL;
1001	}
1002    }
1003
1004    pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial);
1005
1006    if (pCounter)
1007    {
1008	SysCounterInfo *psci;
1009
1010	psci = malloc(sizeof(SysCounterInfo));
1011	if (!psci)
1012	{
1013	    FreeResource(pCounter->sync.id, RT_NONE);
1014	    return pCounter;
1015	}
1016	pCounter->pSysCounterInfo = psci;
1017	psci->name = name;
1018	psci->resolution = resolution;
1019	psci->counterType = counterType;
1020	psci->QueryValue = QueryValue;
1021	psci->BracketValues = BracketValues;
1022	XSyncMaxValue(&psci->bracket_greater);
1023	XSyncMinValue(&psci->bracket_less);
1024	SysCounterList[SyncNumSystemCounters++] = pCounter;
1025    }
1026    return pCounter;
1027}
1028
1029void
1030SyncDestroySystemCounter(pointer pSysCounter)
1031{
1032    SyncCounter *pCounter = (SyncCounter *)pSysCounter;
1033    FreeResource(pCounter->sync.id, RT_NONE);
1034}
1035
1036static void
1037SyncComputeBracketValues(SyncCounter *pCounter)
1038{
1039    SyncTriggerList *pCur;
1040    SyncTrigger *pTrigger;
1041    SysCounterInfo *psci;
1042    CARD64 *pnewgtval = NULL;
1043    CARD64 *pnewltval = NULL;
1044    SyncCounterType ct;
1045
1046    if (!pCounter)
1047	return;
1048
1049    psci = pCounter->pSysCounterInfo;
1050    ct = pCounter->pSysCounterInfo->counterType;
1051    if (ct == XSyncCounterNeverChanges)
1052	return;
1053
1054    XSyncMaxValue(&psci->bracket_greater);
1055    XSyncMinValue(&psci->bracket_less);
1056
1057    for (pCur = pCounter->sync.pTriglist; pCur; pCur = pCur->next)
1058    {
1059	pTrigger = pCur->pTrigger;
1060
1061        if (pTrigger->test_type == XSyncPositiveComparison &&
1062	    ct != XSyncCounterNeverIncreases)
1063	{
1064	    if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
1065		XSyncValueLessThan(pTrigger->test_value,
1066				   psci->bracket_greater))
1067	    {
1068		psci->bracket_greater = pTrigger->test_value;
1069		pnewgtval = &psci->bracket_greater;
1070	    }
1071	}
1072	else if (pTrigger->test_type == XSyncNegativeComparison &&
1073		 ct != XSyncCounterNeverDecreases)
1074	{
1075	    if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
1076		XSyncValueGreaterThan(pTrigger->test_value,
1077				      psci->bracket_less))
1078	    {
1079		psci->bracket_less = pTrigger->test_value;
1080		pnewltval = &psci->bracket_less;
1081	    }
1082	}
1083	else if (pTrigger->test_type == XSyncNegativeTransition &&
1084		   ct != XSyncCounterNeverIncreases)
1085	{
1086	    if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
1087		XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less))
1088	    {
1089		psci->bracket_less = pTrigger->test_value;
1090		pnewltval = &psci->bracket_less;
1091	    } else if (XSyncValueEqual(pCounter->value, pTrigger->test_value) &&
1092		       XSyncValueLessThan(pTrigger->test_value,
1093					  psci->bracket_greater))
1094	    {
1095	        /*
1096		 * The value is exactly equal to our threshold.  We want one
1097		 * more event in the positive direction to ensure we pick up
1098		 * when the value *exceeds* this threshold.
1099		 */
1100	        psci->bracket_greater = pTrigger->test_value;
1101		pnewgtval = &psci->bracket_greater;
1102	    }
1103	}
1104        else if (pTrigger->test_type == XSyncPositiveTransition &&
1105		  ct != XSyncCounterNeverDecreases)
1106	{
1107	    if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
1108		XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater))
1109	    {
1110		psci->bracket_greater = pTrigger->test_value;
1111		pnewgtval = &psci->bracket_greater;
1112	    } else if (XSyncValueEqual(pCounter->value, pTrigger->test_value) &&
1113		       XSyncValueGreaterThan(pTrigger->test_value,
1114					     psci->bracket_less))
1115	    {
1116	        /*
1117		 * The value is exactly equal to our threshold.  We want one
1118		 * more event in the negative direction to ensure we pick up
1119		 * when the value is less than this threshold.
1120		 */
1121	        psci->bracket_less = pTrigger->test_value;
1122		pnewltval = &psci->bracket_less;
1123	    }
1124	}
1125    } /* end for each trigger */
1126
1127    if (pnewgtval || pnewltval)
1128    {
1129	(*psci->BracketValues)((pointer)pCounter, pnewltval, pnewgtval);
1130    }
1131}
1132
1133/*
1134 * *****  Resource delete functions
1135 */
1136
1137/* ARGSUSED */
1138static int
1139FreeAlarm(void *addr, XID id)
1140{
1141    SyncAlarm      *pAlarm = (SyncAlarm *) addr;
1142
1143    pAlarm->state = XSyncAlarmDestroyed;
1144
1145    SyncSendAlarmNotifyEvents(pAlarm);
1146
1147    /* delete event selections */
1148
1149    while (pAlarm->pEventClients)
1150	FreeResource(pAlarm->pEventClients->delete_id, RT_NONE);
1151
1152    SyncDeleteTriggerFromSyncObject(&pAlarm->trigger);
1153
1154    free(pAlarm);
1155    return Success;
1156}
1157
1158
1159/*
1160 * ** Cleanup after the destruction of a Counter
1161 */
1162/* ARGSUSED */
1163static int
1164FreeCounter(void *env, XID id)
1165{
1166    SyncCounter     *pCounter = (SyncCounter *) env;
1167    SyncTriggerList *ptl, *pnext;
1168
1169    pCounter->sync.beingDestroyed = TRUE;
1170    /* tell all the counter's triggers that the counter has been destroyed */
1171    for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext)
1172    {
1173	(*ptl->pTrigger->CounterDestroyed)(ptl->pTrigger);
1174	pnext = ptl->next;
1175	free(ptl); /* destroy the trigger list as we go */
1176    }
1177    if (IsSystemCounter(pCounter))
1178    {
1179	int i, found = 0;
1180
1181	free(pCounter->pSysCounterInfo);
1182
1183	/* find the counter in the list of system counters and remove it */
1184
1185	if (SysCounterList)
1186	{
1187	    for (i = 0; i < SyncNumSystemCounters; i++)
1188	    {
1189		if (SysCounterList[i] == pCounter)
1190		{
1191		    found = i;
1192		    break;
1193		}
1194	    }
1195	    if (found < (SyncNumSystemCounters-1))
1196	    {
1197		for (i = found; i < SyncNumSystemCounters-1; i++)
1198		{
1199		    SysCounterList[i] = SysCounterList[i+1];
1200		}
1201	    }
1202	}
1203	SyncNumSystemCounters--;
1204    }
1205    free(pCounter);
1206    return Success;
1207}
1208
1209/*
1210 * ** Cleanup after Await
1211 */
1212/* ARGSUSED */
1213static int
1214FreeAwait(void *addr, XID id)
1215{
1216    SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr;
1217    SyncAwait *pAwait;
1218    int numwaits;
1219
1220    pAwait = &(pAwaitUnion+1)->await; /* first await on list */
1221
1222    /* remove triggers from counters */
1223
1224    for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits;
1225	 numwaits--, pAwait++)
1226    {
1227	/* If the counter is being destroyed, FreeCounter will delete
1228	 * the trigger list itself, so don't do it here.
1229	 */
1230	SyncObject *pSync = pAwait->trigger.pSync;
1231	if (pSync && !pSync->beingDestroyed)
1232	    SyncDeleteTriggerFromSyncObject(&pAwait->trigger);
1233    }
1234    free(pAwaitUnion);
1235    return Success;
1236}
1237
1238/* loosely based on dix/events.c/OtherClientGone */
1239static int
1240FreeAlarmClient(void *value, XID id)
1241{
1242    SyncAlarm *pAlarm = (SyncAlarm *)value;
1243    SyncAlarmClientList *pCur, *pPrev;
1244
1245    for (pPrev = NULL, pCur = pAlarm->pEventClients;
1246	 pCur;
1247	 pPrev = pCur, pCur = pCur->next)
1248    {
1249	if (pCur->delete_id == id)
1250	{
1251	    if (pPrev)
1252		pPrev->next = pCur->next;
1253	    else
1254		pAlarm->pEventClients = pCur->next;
1255	    free(pCur);
1256	    return Success;
1257	}
1258    }
1259    FatalError("alarm client not on event list");
1260    /*NOTREACHED*/
1261}
1262
1263
1264/*
1265 * *****  Proc functions
1266 */
1267
1268
1269/*
1270 * ** Initialize the extension
1271 */
1272static int
1273ProcSyncInitialize(ClientPtr client)
1274{
1275    xSyncInitializeReply  rep;
1276    int   n;
1277
1278    REQUEST_SIZE_MATCH(xSyncInitializeReq);
1279
1280    memset(&rep, 0, sizeof(xSyncInitializeReply));
1281    rep.type = X_Reply;
1282    rep.sequenceNumber = client->sequence;
1283    rep.majorVersion = SERVER_SYNC_MAJOR_VERSION;
1284    rep.minorVersion = SERVER_SYNC_MINOR_VERSION;
1285    rep.length = 0;
1286
1287    if (client->swapped)
1288    {
1289	swaps(&rep.sequenceNumber, n);
1290    }
1291    WriteToClient(client, sizeof(rep), (char *) &rep);
1292    return Success;
1293}
1294
1295/*
1296 * ** Get list of system counters available through the extension
1297 */
1298static int
1299ProcSyncListSystemCounters(ClientPtr client)
1300{
1301    xSyncListSystemCountersReply  rep;
1302    int i, len;
1303    xSyncSystemCounter *list = NULL, *walklist = NULL;
1304
1305    REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
1306
1307    rep.type = X_Reply;
1308    rep.sequenceNumber = client->sequence;
1309    rep.nCounters = SyncNumSystemCounters;
1310
1311    for (i = len = 0; i < SyncNumSystemCounters; i++)
1312    {
1313	char *name = SysCounterList[i]->pSysCounterInfo->name;
1314	/* pad to 4 byte boundary */
1315	len += pad_to_int32(sz_xSyncSystemCounter + strlen(name));
1316    }
1317
1318    if (len)
1319    {
1320	walklist = list = malloc(len);
1321	if (!list)
1322	    return BadAlloc;
1323    }
1324
1325    rep.length = bytes_to_int32(len);
1326
1327    if (client->swapped)
1328    {
1329	char n;
1330	swaps(&rep.sequenceNumber, n);
1331	swapl(&rep.length, n);
1332	swapl(&rep.nCounters, n);
1333    }
1334
1335    for (i = 0; i < SyncNumSystemCounters; i++)
1336    {
1337	int namelen;
1338	char *pname_in_reply;
1339	SysCounterInfo *psci = SysCounterList[i]->pSysCounterInfo;
1340
1341	walklist->counter = SysCounterList[i]->sync.id;
1342	walklist->resolution_hi = XSyncValueHigh32(psci->resolution);
1343	walklist->resolution_lo = XSyncValueLow32(psci->resolution);
1344	namelen = strlen(psci->name);
1345	walklist->name_length = namelen;
1346
1347	if (client->swapped)
1348	{
1349	    char n;
1350	    swapl(&walklist->counter, n);
1351	    swapl(&walklist->resolution_hi, n);
1352	    swapl(&walklist->resolution_lo, n);
1353	    swaps(&walklist->name_length, n);
1354	}
1355
1356	pname_in_reply = ((char *)walklist) + sz_xSyncSystemCounter;
1357	strncpy(pname_in_reply, psci->name, namelen);
1358	walklist = (xSyncSystemCounter *) (((char *)walklist) +
1359				pad_to_int32(sz_xSyncSystemCounter + namelen));
1360    }
1361
1362    WriteToClient(client, sizeof(rep), (char *) &rep);
1363    if (len)
1364    {
1365	WriteToClient(client, len, (char *) list);
1366	free(list);
1367    }
1368
1369    return Success;
1370}
1371
1372/*
1373 * ** Set client Priority
1374 */
1375static int
1376ProcSyncSetPriority(ClientPtr client)
1377{
1378    REQUEST(xSyncSetPriorityReq);
1379    ClientPtr priorityclient;
1380    int rc;
1381
1382    REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
1383
1384    if (stuff->id == None)
1385	priorityclient = client;
1386    else {
1387	rc = dixLookupClient(&priorityclient, stuff->id, client,
1388			     DixSetAttrAccess);
1389	if (rc != Success)
1390	    return rc;
1391    }
1392
1393    if (priorityclient->priority != stuff->priority)
1394    {
1395	priorityclient->priority = stuff->priority;
1396
1397	/*  The following will force the server back into WaitForSomething
1398	 *  so that the change in this client's priority is immediately
1399	 *  reflected.
1400	 */
1401	isItTimeToYield = TRUE;
1402	dispatchException |= DE_PRIORITYCHANGE;
1403    }
1404    return Success;
1405}
1406
1407/*
1408 * ** Get client Priority
1409 */
1410static int
1411ProcSyncGetPriority(ClientPtr client)
1412{
1413    REQUEST(xSyncGetPriorityReq);
1414    xSyncGetPriorityReply rep;
1415    ClientPtr priorityclient;
1416    int rc;
1417
1418    REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
1419
1420    if (stuff->id == None)
1421	priorityclient = client;
1422    else {
1423	rc = dixLookupClient(&priorityclient, stuff->id, client,
1424			     DixGetAttrAccess);
1425	if (rc != Success)
1426	    return rc;
1427    }
1428
1429    rep.type = X_Reply;
1430    rep.length = 0;
1431    rep.sequenceNumber = client->sequence;
1432    rep.priority = priorityclient->priority;
1433
1434    if (client->swapped)
1435    {
1436	char n;
1437	swaps(&rep.sequenceNumber, n);
1438	swapl(&rep.priority, n);
1439    }
1440
1441    WriteToClient(client, sizeof(xSyncGetPriorityReply), (char *) &rep);
1442
1443    return Success;
1444}
1445
1446/*
1447 * ** Create a new counter
1448 */
1449static int
1450ProcSyncCreateCounter(ClientPtr client)
1451{
1452    REQUEST(xSyncCreateCounterReq);
1453    CARD64          initial;
1454
1455    REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
1456
1457    LEGAL_NEW_RESOURCE(stuff->cid, client);
1458
1459    XSyncIntsToValue(&initial, stuff->initial_value_lo, stuff->initial_value_hi);
1460    if (!SyncCreateCounter(client, stuff->cid, initial))
1461	return BadAlloc;
1462
1463    return Success;
1464}
1465
1466/*
1467 * ** Set Counter value
1468 */
1469static int
1470ProcSyncSetCounter(ClientPtr client)
1471{
1472    REQUEST(xSyncSetCounterReq);
1473    SyncCounter    *pCounter;
1474    CARD64	   newvalue;
1475    int	rc;
1476
1477    REQUEST_SIZE_MATCH(xSyncSetCounterReq);
1478
1479    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
1480				 client, DixWriteAccess);
1481    if (rc != Success)
1482	return rc;
1483
1484    if (IsSystemCounter(pCounter))
1485    {
1486	client->errorValue = stuff->cid;
1487	return BadAccess;
1488    }
1489
1490    XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
1491    SyncChangeCounter(pCounter, newvalue);
1492    return Success;
1493}
1494
1495/*
1496 * ** Change Counter value
1497 */
1498static int
1499ProcSyncChangeCounter(ClientPtr client)
1500{
1501    REQUEST(xSyncChangeCounterReq);
1502    SyncCounter    *pCounter;
1503    CARD64          newvalue;
1504    Bool	    overflow;
1505    int	rc;
1506
1507    REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
1508
1509    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
1510				 client, DixWriteAccess);
1511    if (rc != Success)
1512	return rc;
1513
1514    if (IsSystemCounter(pCounter))
1515    {
1516	client->errorValue = stuff->cid;
1517	return BadAccess;
1518    }
1519
1520    XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
1521    XSyncValueAdd(&newvalue, pCounter->value, newvalue, &overflow);
1522    if (overflow)
1523    {
1524	/* XXX 64 bit value can't fit in 32 bits; do the best we can */
1525	client->errorValue = stuff->value_hi;
1526	return BadValue;
1527    }
1528    SyncChangeCounter(pCounter, newvalue);
1529    return Success;
1530}
1531
1532/*
1533 * ** Destroy a counter
1534 */
1535static int
1536ProcSyncDestroyCounter(ClientPtr client)
1537{
1538    REQUEST(xSyncDestroyCounterReq);
1539    SyncCounter    *pCounter;
1540    int rc;
1541
1542    REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
1543
1544    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter, RTCounter,
1545				 client, DixDestroyAccess);
1546    if (rc != Success)
1547	return rc;
1548
1549    if (IsSystemCounter(pCounter))
1550    {
1551	client->errorValue = stuff->counter;
1552	return BadAccess;
1553    }
1554    FreeResource(pCounter->sync.id, RT_NONE);
1555    return Success;
1556}
1557
1558static SyncAwaitUnion*
1559SyncAwaitPrologue(ClientPtr client, int items)
1560{
1561    SyncAwaitUnion *pAwaitUnion;
1562
1563    /*  all the memory for the entire await list is allocated
1564     *  here in one chunk
1565     */
1566    pAwaitUnion = malloc((items+1) * sizeof(SyncAwaitUnion));
1567    if (!pAwaitUnion)
1568	return NULL;
1569
1570    /* first item is the header, remainder are real wait conditions */
1571
1572    pAwaitUnion->header.delete_id = FakeClientID(client->index);
1573    pAwaitUnion->header.client = client;
1574    pAwaitUnion->header.num_waitconditions = 0;
1575
1576    if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion))
1577	return NULL;
1578
1579    return pAwaitUnion;
1580}
1581
1582static void
1583SyncAwaitEpilogue(ClientPtr client, int items, SyncAwaitUnion *pAwaitUnion)
1584{
1585    SyncAwait *pAwait;
1586    int i;
1587
1588    IgnoreClient(client);
1589
1590    /* see if any of the triggers are already true */
1591
1592    pAwait = &(pAwaitUnion+1)->await; /* skip over header */
1593    for (i = 0; i < items; i++, pAwait++)
1594    {
1595	CARD64 value;
1596
1597	/*  don't have to worry about NULL counters because the request
1598	 *  errors before we get here out if they occur
1599	 */
1600	switch (pAwait->trigger.pSync->type) {
1601	case SYNC_COUNTER:
1602	    value = ((SyncCounter *)pAwait->trigger.pSync)->value;
1603	    break;
1604	default:
1605	    XSyncIntToValue(&value, 0);
1606	}
1607
1608	if ((*pAwait->trigger.CheckTrigger)(&pAwait->trigger, value))
1609	{
1610	    (*pAwait->trigger.TriggerFired)(&pAwait->trigger);
1611	    break; /* once is enough */
1612	}
1613    }
1614}
1615
1616/*
1617 * ** Await
1618 */
1619static int
1620ProcSyncAwait(ClientPtr client)
1621{
1622    REQUEST(xSyncAwaitReq);
1623    int             len, items;
1624    int             i;
1625    xSyncWaitCondition *pProtocolWaitConds;
1626    SyncAwaitUnion *pAwaitUnion;
1627    SyncAwait	   *pAwait;
1628    int		   status;
1629
1630    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
1631
1632    len = client->req_len << 2;
1633    len -= sz_xSyncAwaitReq;
1634    items = len / sz_xSyncWaitCondition;
1635
1636    if (items * sz_xSyncWaitCondition != len)
1637    {
1638	return BadLength;
1639    }
1640    if (items == 0)
1641    {
1642	client->errorValue = items; /* XXX protocol change */
1643	return BadValue;
1644    }
1645
1646    if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
1647	return BadAlloc;
1648
1649    /* don't need to do any more memory allocation for this request! */
1650
1651    pProtocolWaitConds = (xSyncWaitCondition *) & stuff[1];
1652
1653    pAwait = &(pAwaitUnion+1)->await; /* skip over header */
1654    for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++)
1655    {
1656	if (pProtocolWaitConds->counter == None) /* XXX protocol change */
1657	{
1658	    /*  this should take care of removing any triggers created by
1659	     *  this request that have already been registered on sync objects
1660	     */
1661	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
1662	    client->errorValue = pProtocolWaitConds->counter;
1663	    return SyncErrorBase + XSyncBadCounter;
1664	}
1665
1666	/* sanity checks are in SyncInitTrigger */
1667	pAwait->trigger.pSync = NULL;
1668	pAwait->trigger.value_type = pProtocolWaitConds->value_type;
1669	XSyncIntsToValue(&pAwait->trigger.wait_value,
1670			 pProtocolWaitConds->wait_value_lo,
1671			 pProtocolWaitConds->wait_value_hi);
1672	pAwait->trigger.test_type = pProtocolWaitConds->test_type;
1673
1674	status = SyncInitTrigger(client, &pAwait->trigger,
1675				 pProtocolWaitConds->counter, RTCounter,
1676				 XSyncCAAllTrigger);
1677	if (status != Success)
1678	{
1679	    /*  this should take care of removing any triggers created by
1680	     *  this request that have already been registered on sync objects
1681	     */
1682	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
1683	    return status;
1684	}
1685	/* this is not a mistake -- same function works for both cases */
1686	pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
1687	pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
1688	XSyncIntsToValue(&pAwait->event_threshold,
1689			 pProtocolWaitConds->event_threshold_lo,
1690			 pProtocolWaitConds->event_threshold_hi);
1691	pAwait->pHeader = &pAwaitUnion->header;
1692	pAwaitUnion->header.num_waitconditions++;
1693    }
1694
1695    SyncAwaitEpilogue(client, items, pAwaitUnion);
1696
1697    return Success;
1698}
1699
1700
1701/*
1702 * ** Query a counter
1703 */
1704static int
1705ProcSyncQueryCounter(ClientPtr client)
1706{
1707    REQUEST(xSyncQueryCounterReq);
1708    xSyncQueryCounterReply rep;
1709    SyncCounter    *pCounter;
1710    int rc;
1711
1712    REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
1713
1714    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter,
1715				 RTCounter, client, DixReadAccess);
1716    if (rc != Success)
1717	return rc;
1718
1719    rep.type = X_Reply;
1720    rep.length = 0;
1721    rep.sequenceNumber = client->sequence;
1722
1723    /* if system counter, ask it what the current value is */
1724
1725    if (IsSystemCounter(pCounter))
1726    {
1727	(*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
1728						  &pCounter->value);
1729    }
1730
1731    rep.value_hi = XSyncValueHigh32(pCounter->value);
1732    rep.value_lo = XSyncValueLow32(pCounter->value);
1733    if (client->swapped)
1734    {
1735	char n;
1736	swaps(&rep.sequenceNumber, n);
1737	swapl(&rep.length, n);
1738	swapl(&rep.value_hi, n);
1739	swapl(&rep.value_lo, n);
1740    }
1741    WriteToClient(client, sizeof(xSyncQueryCounterReply), (char *) &rep);
1742    return Success;
1743}
1744
1745
1746/*
1747 * ** Create Alarm
1748 */
1749static int
1750ProcSyncCreateAlarm(ClientPtr client)
1751{
1752    REQUEST(xSyncCreateAlarmReq);
1753    SyncAlarm      *pAlarm;
1754    int             status;
1755    unsigned long   len, vmask;
1756    SyncTrigger	    *pTrigger;
1757
1758    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
1759
1760    LEGAL_NEW_RESOURCE(stuff->id, client);
1761
1762    vmask = stuff->valueMask;
1763    len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq));
1764    /* the "extra" call to Ones accounts for the presence of 64 bit values */
1765    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
1766	return BadLength;
1767
1768    if (!(pAlarm = malloc(sizeof(SyncAlarm))))
1769    {
1770	return BadAlloc;
1771    }
1772
1773    /* set up defaults */
1774
1775    pTrigger = &pAlarm->trigger;
1776    pTrigger->pSync = NULL;
1777    pTrigger->value_type = XSyncAbsolute;
1778    XSyncIntToValue(&pTrigger->wait_value, 0L);
1779    pTrigger->test_type = XSyncPositiveComparison;
1780    pTrigger->TriggerFired = SyncAlarmTriggerFired;
1781    pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed;
1782    status = SyncInitTrigger(client, pTrigger, None, RTCounter,
1783			     XSyncCAAllTrigger);
1784    if (status != Success)
1785    {
1786	free(pAlarm);
1787	return status;
1788    }
1789
1790    pAlarm->client = client;
1791    pAlarm->alarm_id = stuff->id;
1792    XSyncIntToValue(&pAlarm->delta, 1L);
1793    pAlarm->events = TRUE;
1794    pAlarm->state = XSyncAlarmInactive;
1795    pAlarm->pEventClients = NULL;
1796    status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
1797				       (CARD32 *)&stuff[1]);
1798    if (status != Success)
1799    {
1800	free(pAlarm);
1801	return status;
1802    }
1803
1804    if (!AddResource(stuff->id, RTAlarm, pAlarm))
1805	return BadAlloc;
1806
1807    /*  see if alarm already triggered.  NULL counter will not trigger
1808     *  in CreateAlarm and sets alarm state to Inactive.
1809     */
1810
1811    if (!pTrigger->pSync)
1812    {
1813	pAlarm->state = XSyncAlarmInactive; /* XXX protocol change */
1814    }
1815    else
1816    {
1817	SyncCounter *pCounter;
1818
1819	if (!SyncCheckWarnIsCounter(pTrigger->pSync,
1820				    WARN_INVALID_COUNTER_ALARM))
1821	{
1822	    FreeResource(stuff->id, RT_NONE);
1823	    return BadAlloc;
1824	}
1825
1826	pCounter = (SyncCounter *)pTrigger->pSync;
1827
1828	if ((*pTrigger->CheckTrigger)(pTrigger, pCounter->value))
1829	    (*pTrigger->TriggerFired)(pTrigger);
1830    }
1831
1832    return Success;
1833}
1834
1835/*
1836 * ** Change Alarm
1837 */
1838static int
1839ProcSyncChangeAlarm(ClientPtr client)
1840{
1841    REQUEST(xSyncChangeAlarmReq);
1842    SyncAlarm   *pAlarm;
1843    SyncCounter *pCounter = NULL;
1844    long        vmask;
1845    int         len, status;
1846
1847    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
1848
1849    status = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
1850				     client, DixWriteAccess);
1851    if (status != Success)
1852	return status;
1853
1854    vmask = stuff->valueMask;
1855    len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq));
1856    /* the "extra" call to Ones accounts for the presence of 64 bit values */
1857    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
1858	return BadLength;
1859
1860    if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
1861					    (CARD32 *)&stuff[1])) != Success)
1862	return status;
1863
1864    if (SyncCheckWarnIsCounter(pAlarm->trigger.pSync,
1865			       WARN_INVALID_COUNTER_ALARM))
1866	pCounter = (SyncCounter *)pAlarm->trigger.pSync;
1867
1868    /*  see if alarm already triggered.  NULL counter WILL trigger
1869     *  in ChangeAlarm.
1870     */
1871
1872    if (!pCounter ||
1873	(*pAlarm->trigger.CheckTrigger)(&pAlarm->trigger, pCounter->value))
1874    {
1875	(*pAlarm->trigger.TriggerFired)(&pAlarm->trigger);
1876    }
1877    return Success;
1878}
1879
1880static int
1881ProcSyncQueryAlarm(ClientPtr client)
1882{
1883    REQUEST(xSyncQueryAlarmReq);
1884    SyncAlarm      *pAlarm;
1885    xSyncQueryAlarmReply rep;
1886    SyncTrigger    *pTrigger;
1887    int rc;
1888
1889    REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
1890
1891    rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
1892				 client, DixReadAccess);
1893    if (rc != Success)
1894	return rc;
1895
1896    rep.type = X_Reply;
1897    rep.length = bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply));
1898    rep.sequenceNumber = client->sequence;
1899
1900    pTrigger = &pAlarm->trigger;
1901    rep.counter = (pTrigger->pSync) ? pTrigger->pSync->id : None;
1902
1903#if 0 /* XXX unclear what to do, depends on whether relative value-types
1904       * are "consumed" immediately and are considered absolute from then
1905       * on.
1906       */
1907    rep.value_type = pTrigger->value_type;
1908    rep.wait_value_hi = XSyncValueHigh32(pTrigger->wait_value);
1909    rep.wait_value_lo = XSyncValueLow32(pTrigger->wait_value);
1910#else
1911    rep.value_type = XSyncAbsolute;
1912    rep.wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
1913    rep.wait_value_lo = XSyncValueLow32(pTrigger->test_value);
1914#endif
1915
1916    rep.test_type = pTrigger->test_type;
1917    rep.delta_hi = XSyncValueHigh32(pAlarm->delta);
1918    rep.delta_lo = XSyncValueLow32(pAlarm->delta);
1919    rep.events = pAlarm->events;
1920    rep.state = pAlarm->state;
1921
1922    if (client->swapped)
1923    {
1924	char n;
1925	swaps(&rep.sequenceNumber, n);
1926	swapl(&rep.length, n);
1927	swapl(&rep.counter, n);
1928	swapl(&rep.wait_value_hi, n);
1929	swapl(&rep.wait_value_lo, n);
1930	swapl(&rep.test_type, n);
1931	swapl(&rep.delta_hi, n);
1932	swapl(&rep.delta_lo, n);
1933    }
1934
1935    WriteToClient(client, sizeof(xSyncQueryAlarmReply), (char *) &rep);
1936    return Success;
1937}
1938
1939static int
1940ProcSyncDestroyAlarm(ClientPtr client)
1941{
1942    SyncAlarm *pAlarm;
1943    int rc;
1944    REQUEST(xSyncDestroyAlarmReq);
1945
1946    REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
1947
1948    rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
1949				 client, DixDestroyAccess);
1950    if (rc != Success)
1951	return rc;
1952
1953    FreeResource(stuff->alarm, RT_NONE);
1954    return Success;
1955}
1956
1957static int
1958ProcSyncCreateFence(ClientPtr client)
1959{
1960    REQUEST(xSyncCreateFenceReq);
1961    DrawablePtr pDraw;
1962    SyncFence *pFence;
1963    int rc;
1964
1965    REQUEST_SIZE_MATCH(xSyncCreateFenceReq);
1966
1967    rc = dixLookupDrawable(&pDraw, stuff->d, client, M_ANY, DixGetAttrAccess);
1968    if (rc != Success)
1969	return rc;
1970
1971    LEGAL_NEW_RESOURCE(stuff->fid, client);
1972
1973    if (!(pFence = (SyncFence *)SyncCreate(client,
1974					   stuff->fid,
1975					   SYNC_FENCE)))
1976	return BadAlloc;
1977
1978    miSyncInitFence(pDraw->pScreen, pFence, stuff->initially_triggered);
1979
1980    if (!AddResource(stuff->fid, RTFence, (pointer) pFence))
1981	return BadAlloc;
1982
1983    return client->noClientException;
1984}
1985
1986static int
1987FreeFence(void *obj, XID id)
1988{
1989    SyncFence *pFence = (SyncFence *) obj;
1990
1991    miSyncDestroyFence(pFence);
1992
1993    return Success;
1994}
1995
1996int SyncVerifyFence(SyncFence **ppSyncFence, XID fid,
1997		    ClientPtr client, Mask mode)
1998{
1999    int rc = dixLookupResourceByType((pointer *)ppSyncFence, fid, RTFence,
2000				     client, mode);
2001
2002    if (rc != Success)
2003	client->errorValue = fid;
2004
2005    return rc;
2006}
2007
2008static int
2009ProcSyncTriggerFence(ClientPtr client)
2010{
2011    REQUEST(xSyncTriggerFenceReq);
2012    SyncFence *pFence;
2013    int rc;
2014
2015    REQUEST_SIZE_MATCH(xSyncTriggerFenceReq);
2016
2017    rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
2018				 client, DixWriteAccess);
2019    if (rc != Success)
2020	return rc;
2021
2022    miSyncTriggerFence(pFence);
2023
2024    return client->noClientException;
2025}
2026
2027static int
2028ProcSyncResetFence(ClientPtr client)
2029{
2030    REQUEST(xSyncResetFenceReq);
2031    SyncFence *pFence;
2032    int rc;
2033
2034    REQUEST_SIZE_MATCH(xSyncResetFenceReq);
2035
2036    rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
2037				 client, DixWriteAccess);
2038    if (rc != Success)
2039	return rc;
2040
2041    if (pFence->funcs.CheckTriggered(pFence) != TRUE)
2042	return BadMatch;
2043
2044    pFence->funcs.Reset(pFence);
2045
2046    return client->noClientException;
2047}
2048
2049static int
2050ProcSyncDestroyFence(ClientPtr client)
2051{
2052    REQUEST(xSyncDestroyFenceReq);
2053    SyncFence *pFence;
2054    int rc;
2055
2056    REQUEST_SIZE_MATCH(xSyncDestroyFenceReq);
2057
2058    rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
2059				 client, DixDestroyAccess);
2060    if (rc != Success)
2061	return rc;
2062
2063    FreeResource(stuff->fid, RT_NONE);
2064    return client->noClientException;
2065}
2066
2067static int
2068ProcSyncQueryFence(ClientPtr client)
2069{
2070    REQUEST(xSyncQueryFenceReq);
2071    xSyncQueryFenceReply rep;
2072    SyncFence *pFence;
2073    int rc;
2074
2075    REQUEST_SIZE_MATCH(xSyncQueryFenceReq);
2076
2077    rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid,
2078				 RTFence, client, DixReadAccess);
2079    if (rc != Success)
2080	return rc;
2081
2082    rep.type = X_Reply;
2083    rep.length = 0;
2084    rep.sequenceNumber = client->sequence;
2085
2086    rep.triggered = pFence->funcs.CheckTriggered(pFence);
2087
2088    if (client->swapped)
2089    {
2090	char n;
2091	swaps(&rep.sequenceNumber, n);
2092	swapl(&rep.length, n);
2093    }
2094
2095    WriteToClient(client, sizeof(xSyncQueryFenceReply), (char *) &rep);
2096    return client->noClientException;
2097}
2098
2099static int
2100ProcSyncAwaitFence(ClientPtr client)
2101{
2102    REQUEST(xSyncAwaitFenceReq);
2103    SyncAwaitUnion *pAwaitUnion;
2104    SyncAwait *pAwait;
2105    /* Use CARD32 rather than XSyncFence because XIDs are hard-coded to
2106     * CARD32 in protocol definitions */
2107    CARD32 *pProtocolFences;
2108    int status;
2109    int len;
2110    int items;
2111    int i;
2112
2113    REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
2114
2115    len = client->req_len << 2;
2116    len -= sz_xSyncAwaitFenceReq;
2117    items = len / sizeof(CARD32);
2118
2119    if (items * sizeof(CARD32) != len)
2120    {
2121	return BadLength;
2122    }
2123    if (items == 0)
2124    {
2125	client->errorValue = items;
2126	return BadValue;
2127    }
2128
2129    if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
2130	return BadAlloc;
2131
2132    /* don't need to do any more memory allocation for this request! */
2133
2134    pProtocolFences = (CARD32 *) & stuff[1];
2135
2136    pAwait = &(pAwaitUnion+1)->await; /* skip over header */
2137    for (i = 0; i < items; i++, pProtocolFences++, pAwait++)
2138    {
2139	if (*pProtocolFences == None)
2140	{
2141	    /*  this should take care of removing any triggers created by
2142	     *  this request that have already been registered on sync objects
2143	     */
2144	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
2145	    client->errorValue = *pProtocolFences;
2146	    return SyncErrorBase + XSyncBadFence;
2147	}
2148
2149	pAwait->trigger.pSync = NULL;
2150	/* Provide acceptable values for these unused fields to
2151	 * satisfy SyncInitTrigger's validation logic
2152	 */
2153	pAwait->trigger.value_type = XSyncAbsolute;
2154	XSyncIntToValue(&pAwait->trigger.wait_value, 0);
2155	pAwait->trigger.test_type = 0;
2156
2157	status = SyncInitTrigger(client, &pAwait->trigger,
2158				 *pProtocolFences, RTFence,
2159				 XSyncCAAllTrigger);
2160	if (status != Success)
2161	{
2162	    /*  this should take care of removing any triggers created by
2163	     *  this request that have already been registered on sync objects
2164	     */
2165	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
2166	    return status;
2167	}
2168	/* this is not a mistake -- same function works for both cases */
2169	pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
2170	pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
2171	/* event_threshold is unused for fence syncs */
2172	XSyncIntToValue(&pAwait->event_threshold, 0);
2173	pAwait->pHeader = &pAwaitUnion->header;
2174	pAwaitUnion->header.num_waitconditions++;
2175    }
2176
2177    SyncAwaitEpilogue(client, items, pAwaitUnion);
2178
2179    return client->noClientException;
2180}
2181
2182/*
2183 * ** Given an extension request, call the appropriate request procedure
2184 */
2185static int
2186ProcSyncDispatch(ClientPtr client)
2187{
2188    REQUEST(xReq);
2189
2190    switch (stuff->data)
2191    {
2192      case X_SyncInitialize:
2193	return ProcSyncInitialize(client);
2194      case X_SyncListSystemCounters:
2195	return ProcSyncListSystemCounters(client);
2196      case X_SyncCreateCounter:
2197	return ProcSyncCreateCounter(client);
2198      case X_SyncSetCounter:
2199	return ProcSyncSetCounter(client);
2200      case X_SyncChangeCounter:
2201	return ProcSyncChangeCounter(client);
2202      case X_SyncQueryCounter:
2203	return ProcSyncQueryCounter(client);
2204      case X_SyncDestroyCounter:
2205	return ProcSyncDestroyCounter(client);
2206      case X_SyncAwait:
2207	return ProcSyncAwait(client);
2208      case X_SyncCreateAlarm:
2209	return ProcSyncCreateAlarm(client);
2210      case X_SyncChangeAlarm:
2211	return ProcSyncChangeAlarm(client);
2212      case X_SyncQueryAlarm:
2213	return ProcSyncQueryAlarm(client);
2214      case X_SyncDestroyAlarm:
2215	return ProcSyncDestroyAlarm(client);
2216      case X_SyncSetPriority:
2217	return ProcSyncSetPriority(client);
2218      case X_SyncGetPriority:
2219	return ProcSyncGetPriority(client);
2220      case X_SyncCreateFence:
2221	return ProcSyncCreateFence(client);
2222      case X_SyncTriggerFence:
2223	return ProcSyncTriggerFence(client);
2224      case X_SyncResetFence:
2225	return ProcSyncResetFence(client);
2226      case X_SyncDestroyFence:
2227	return ProcSyncDestroyFence(client);
2228      case X_SyncQueryFence:
2229	return ProcSyncQueryFence(client);
2230      case X_SyncAwaitFence:
2231	return ProcSyncAwaitFence(client);
2232      default:
2233	return BadRequest;
2234    }
2235}
2236
2237/*
2238 * Boring Swapping stuff ...
2239 */
2240
2241static int
2242SProcSyncInitialize(ClientPtr client)
2243{
2244    REQUEST(xSyncInitializeReq);
2245    char   n;
2246
2247    swaps(&stuff->length, n);
2248    REQUEST_SIZE_MATCH (xSyncInitializeReq);
2249
2250    return ProcSyncInitialize(client);
2251}
2252
2253static int
2254SProcSyncListSystemCounters(ClientPtr client)
2255{
2256    REQUEST(xSyncListSystemCountersReq);
2257    char   n;
2258
2259    swaps(&stuff->length, n);
2260    REQUEST_SIZE_MATCH (xSyncListSystemCountersReq);
2261
2262    return ProcSyncListSystemCounters(client);
2263}
2264
2265static int
2266SProcSyncCreateCounter(ClientPtr client)
2267{
2268    REQUEST(xSyncCreateCounterReq);
2269    char   n;
2270
2271    swaps(&stuff->length, n);
2272    REQUEST_SIZE_MATCH (xSyncCreateCounterReq);
2273    swapl(&stuff->cid, n);
2274    swapl(&stuff->initial_value_lo, n);
2275    swapl(&stuff->initial_value_hi, n);
2276
2277    return ProcSyncCreateCounter(client);
2278}
2279
2280static int
2281SProcSyncSetCounter(ClientPtr client)
2282{
2283    REQUEST(xSyncSetCounterReq);
2284    char   n;
2285
2286    swaps(&stuff->length, n);
2287    REQUEST_SIZE_MATCH (xSyncSetCounterReq);
2288    swapl(&stuff->cid, n);
2289    swapl(&stuff->value_lo, n);
2290    swapl(&stuff->value_hi, n);
2291
2292    return ProcSyncSetCounter(client);
2293}
2294
2295static int
2296SProcSyncChangeCounter(ClientPtr client)
2297{
2298    REQUEST(xSyncChangeCounterReq);
2299    char   n;
2300
2301    swaps(&stuff->length, n);
2302    REQUEST_SIZE_MATCH (xSyncChangeCounterReq);
2303    swapl(&stuff->cid, n);
2304    swapl(&stuff->value_lo, n);
2305    swapl(&stuff->value_hi, n);
2306
2307    return ProcSyncChangeCounter(client);
2308}
2309
2310static int
2311SProcSyncQueryCounter(ClientPtr client)
2312{
2313    REQUEST(xSyncQueryCounterReq);
2314    char   n;
2315
2316    swaps(&stuff->length, n);
2317    REQUEST_SIZE_MATCH (xSyncQueryCounterReq);
2318    swapl(&stuff->counter, n);
2319
2320    return ProcSyncQueryCounter(client);
2321}
2322
2323static int
2324SProcSyncDestroyCounter(ClientPtr client)
2325{
2326    REQUEST(xSyncDestroyCounterReq);
2327    char   n;
2328
2329    swaps(&stuff->length, n);
2330    REQUEST_SIZE_MATCH (xSyncDestroyCounterReq);
2331    swapl(&stuff->counter, n);
2332
2333    return ProcSyncDestroyCounter(client);
2334}
2335
2336static int
2337SProcSyncAwait(ClientPtr client)
2338{
2339    REQUEST(xSyncAwaitReq);
2340    char   n;
2341
2342    swaps(&stuff->length, n);
2343    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
2344    SwapRestL(stuff);
2345
2346    return ProcSyncAwait(client);
2347}
2348
2349static int
2350SProcSyncCreateAlarm(ClientPtr client)
2351{
2352    REQUEST(xSyncCreateAlarmReq);
2353    char   n;
2354
2355    swaps(&stuff->length, n);
2356    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
2357    swapl(&stuff->id, n);
2358    swapl(&stuff->valueMask, n);
2359    SwapRestL(stuff);
2360
2361    return ProcSyncCreateAlarm(client);
2362}
2363
2364static int
2365SProcSyncChangeAlarm(ClientPtr client)
2366{
2367    REQUEST(xSyncChangeAlarmReq);
2368    char   n;
2369
2370    swaps(&stuff->length, n);
2371    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
2372    swapl(&stuff->alarm, n);
2373    swapl(&stuff->valueMask, n);
2374    SwapRestL(stuff);
2375    return ProcSyncChangeAlarm(client);
2376}
2377
2378static int
2379SProcSyncQueryAlarm(ClientPtr client)
2380{
2381    REQUEST(xSyncQueryAlarmReq);
2382    char   n;
2383
2384    swaps(&stuff->length, n);
2385    REQUEST_SIZE_MATCH (xSyncQueryAlarmReq);
2386    swapl(&stuff->alarm, n);
2387
2388    return ProcSyncQueryAlarm(client);
2389}
2390
2391static int
2392SProcSyncDestroyAlarm(ClientPtr client)
2393{
2394    REQUEST(xSyncDestroyAlarmReq);
2395    char   n;
2396
2397    swaps(&stuff->length, n);
2398    REQUEST_SIZE_MATCH (xSyncDestroyAlarmReq);
2399    swapl(&stuff->alarm, n);
2400
2401    return ProcSyncDestroyAlarm(client);
2402}
2403
2404static int
2405SProcSyncSetPriority(ClientPtr client)
2406{
2407    REQUEST(xSyncSetPriorityReq);
2408    char   n;
2409
2410    swaps(&stuff->length, n);
2411    REQUEST_SIZE_MATCH (xSyncSetPriorityReq);
2412    swapl(&stuff->id, n);
2413    swapl(&stuff->priority, n);
2414
2415    return ProcSyncSetPriority(client);
2416}
2417
2418static int
2419SProcSyncGetPriority(ClientPtr client)
2420{
2421    REQUEST(xSyncGetPriorityReq);
2422    char   n;
2423
2424    swaps(&stuff->length, n);
2425    REQUEST_SIZE_MATCH (xSyncGetPriorityReq);
2426    swapl(&stuff->id, n);
2427
2428    return ProcSyncGetPriority(client);
2429}
2430
2431static int
2432SProcSyncCreateFence(ClientPtr client)
2433{
2434    REQUEST(xSyncCreateFenceReq);
2435    char n;
2436
2437    swaps(&stuff->length, n);
2438    REQUEST_SIZE_MATCH (xSyncCreateFenceReq);
2439    swapl(&stuff->fid, n);
2440
2441    return ProcSyncCreateFence(client);
2442}
2443
2444static int
2445SProcSyncTriggerFence(ClientPtr client)
2446{
2447    REQUEST(xSyncTriggerFenceReq);
2448    char n;
2449
2450    swaps(&stuff->length, n);
2451    REQUEST_SIZE_MATCH (xSyncTriggerFenceReq);
2452    swapl(&stuff->fid, n);
2453
2454    return ProcSyncTriggerFence(client);
2455}
2456
2457static int
2458SProcSyncResetFence(ClientPtr client)
2459{
2460    REQUEST(xSyncResetFenceReq);
2461    char n;
2462
2463    swaps(&stuff->length, n);
2464    REQUEST_SIZE_MATCH (xSyncResetFenceReq);
2465    swapl(&stuff->fid, n);
2466
2467    return ProcSyncResetFence(client);
2468}
2469
2470static int
2471SProcSyncDestroyFence(ClientPtr client)
2472{
2473    REQUEST(xSyncDestroyFenceReq);
2474    char n;
2475
2476    swaps(&stuff->length, n);
2477    REQUEST_SIZE_MATCH (xSyncDestroyFenceReq);
2478    swapl(&stuff->fid, n);
2479
2480    return ProcSyncDestroyFence(client);
2481}
2482
2483static int
2484SProcSyncQueryFence(ClientPtr client)
2485{
2486    REQUEST(xSyncQueryFenceReq);
2487    char   n;
2488
2489    swaps(&stuff->length, n);
2490    REQUEST_SIZE_MATCH (xSyncQueryFenceReq);
2491    swapl(&stuff->fid, n);
2492
2493    return ProcSyncQueryFence(client);
2494}
2495
2496static int
2497SProcSyncAwaitFence(ClientPtr client)
2498{
2499    REQUEST(xSyncAwaitFenceReq);
2500    char   n;
2501
2502    swaps(&stuff->length, n);
2503    REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
2504    SwapRestL(stuff);
2505
2506    return ProcSyncAwaitFence(client);
2507}
2508
2509static int
2510SProcSyncDispatch(ClientPtr client)
2511{
2512    REQUEST(xReq);
2513
2514    switch (stuff->data)
2515    {
2516      case X_SyncInitialize:
2517	return SProcSyncInitialize(client);
2518      case X_SyncListSystemCounters:
2519	return SProcSyncListSystemCounters(client);
2520      case X_SyncCreateCounter:
2521	return SProcSyncCreateCounter(client);
2522      case X_SyncSetCounter:
2523	return SProcSyncSetCounter(client);
2524      case X_SyncChangeCounter:
2525	return SProcSyncChangeCounter(client);
2526      case X_SyncQueryCounter:
2527	return SProcSyncQueryCounter(client);
2528      case X_SyncDestroyCounter:
2529	return SProcSyncDestroyCounter(client);
2530      case X_SyncAwait:
2531	return SProcSyncAwait(client);
2532      case X_SyncCreateAlarm:
2533	return SProcSyncCreateAlarm(client);
2534      case X_SyncChangeAlarm:
2535	return SProcSyncChangeAlarm(client);
2536      case X_SyncQueryAlarm:
2537	return SProcSyncQueryAlarm(client);
2538      case X_SyncDestroyAlarm:
2539	return SProcSyncDestroyAlarm(client);
2540      case X_SyncSetPriority:
2541	return SProcSyncSetPriority(client);
2542      case X_SyncGetPriority:
2543	return SProcSyncGetPriority(client);
2544      case X_SyncCreateFence:
2545	return SProcSyncCreateFence(client);
2546      case X_SyncTriggerFence:
2547	return SProcSyncTriggerFence(client);
2548      case X_SyncResetFence:
2549	return SProcSyncResetFence(client);
2550      case X_SyncDestroyFence:
2551	return SProcSyncDestroyFence(client);
2552      case X_SyncQueryFence:
2553	return SProcSyncQueryFence(client);
2554      case X_SyncAwaitFence:
2555	return SProcSyncAwaitFence(client);
2556      default:
2557	return BadRequest;
2558    }
2559}
2560
2561/*
2562 * Event Swapping
2563 */
2564
2565static void
2566SCounterNotifyEvent(xSyncCounterNotifyEvent *from, xSyncCounterNotifyEvent *to)
2567{
2568    to->type = from->type;
2569    to->kind = from->kind;
2570    cpswaps(from->sequenceNumber, to->sequenceNumber);
2571    cpswapl(from->counter, to->counter);
2572    cpswapl(from->wait_value_lo, to->wait_value_lo);
2573    cpswapl(from->wait_value_hi, to->wait_value_hi);
2574    cpswapl(from->counter_value_lo, to->counter_value_lo);
2575    cpswapl(from->counter_value_hi, to->counter_value_hi);
2576    cpswapl(from->time, to->time);
2577    cpswaps(from->count, to->count);
2578    to->destroyed = from->destroyed;
2579}
2580
2581
2582static void
2583SAlarmNotifyEvent(xSyncAlarmNotifyEvent *from, xSyncAlarmNotifyEvent *to)
2584{
2585    to->type = from->type;
2586    to->kind = from->kind;
2587    cpswaps(from->sequenceNumber, to->sequenceNumber);
2588    cpswapl(from->alarm, to->alarm);
2589    cpswapl(from->counter_value_lo, to->counter_value_lo);
2590    cpswapl(from->counter_value_hi, to->counter_value_hi);
2591    cpswapl(from->alarm_value_lo, to->alarm_value_lo);
2592    cpswapl(from->alarm_value_hi, to->alarm_value_hi);
2593    cpswapl(from->time, to->time);
2594    to->state = from->state;
2595}
2596
2597/*
2598 * ** Close everything down. ** This is fairly simple for now.
2599 */
2600/* ARGSUSED */
2601static void
2602SyncResetProc(ExtensionEntry *extEntry)
2603{
2604    free(SysCounterList);
2605    SysCounterList = NULL;
2606    RTCounter = 0;
2607}
2608
2609/*
2610 * ** Initialise the extension.
2611 */
2612void
2613SyncExtensionInit(void)
2614{
2615    ExtensionEntry *extEntry;
2616    int 	    s;
2617
2618    for (s = 0; s < screenInfo.numScreens; s++)
2619	miSyncSetup(screenInfo.screens[s]);
2620
2621    if (RTCounter == 0)
2622    {
2623	RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
2624    }
2625    RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm");
2626    RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait");
2627    RTFence = CreateNewResourceType(FreeFence, "SyncFence");
2628    if (RTAwait)
2629	RTAwait |= RC_NEVERRETAIN;
2630    RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient");
2631    if (RTAlarmClient)
2632	RTAlarmClient |= RC_NEVERRETAIN;
2633
2634    if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 ||
2635	RTAlarmClient == 0 ||
2636	(extEntry = AddExtension(SYNC_NAME,
2637				 XSyncNumberEvents, XSyncNumberErrors,
2638				 ProcSyncDispatch, SProcSyncDispatch,
2639				 SyncResetProc,
2640				 StandardMinorOpcode)) == NULL)
2641    {
2642	ErrorF("Sync Extension %d.%d failed to Initialise\n",
2643		SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
2644	return;
2645    }
2646
2647    SyncEventBase = extEntry->eventBase;
2648    SyncErrorBase = extEntry->errorBase;
2649    EventSwapVector[SyncEventBase + XSyncCounterNotify] = (EventSwapPtr) SCounterNotifyEvent;
2650    EventSwapVector[SyncEventBase + XSyncAlarmNotify] = (EventSwapPtr) SAlarmNotifyEvent;
2651
2652    SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter);
2653    SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm);
2654    SetResourceTypeErrorValue(RTFence, SyncErrorBase + XSyncBadFence);
2655
2656    /*
2657     * Although SERVERTIME is implemented by the OS layer, we initialise it
2658     * here because doing it in OsInit() is too early. The resource database
2659     * is not initialised when OsInit() is called. This is just about OK
2660     * because there is always a servertime counter.
2661     */
2662    SyncInitServerTime();
2663    SyncInitIdleTime();
2664
2665#ifdef DEBUG
2666    fprintf(stderr, "Sync Extension %d.%d\n",
2667	    SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
2668#endif
2669}
2670
2671
2672/*
2673 * ***** SERVERTIME implementation - should go in its own file in OS directory?
2674 */
2675
2676
2677
2678static pointer ServertimeCounter;
2679static XSyncValue Now;
2680static XSyncValue *pnext_time;
2681
2682#define GetTime()\
2683{\
2684    unsigned long millis = GetTimeInMillis();\
2685    unsigned long maxis = XSyncValueHigh32(Now);\
2686    if (millis < XSyncValueLow32(Now)) maxis++;\
2687    XSyncIntsToValue(&Now, millis, maxis);\
2688}
2689
2690/*
2691*** Server Block Handler
2692*** code inspired by multibuffer extension (now deprecated)
2693 */
2694/*ARGSUSED*/
2695static void
2696ServertimeBlockHandler(void *env, struct timeval **wt, void *LastSelectMask)
2697{
2698    XSyncValue delay;
2699    unsigned long timeout;
2700
2701    if (pnext_time)
2702    {
2703        GetTime();
2704
2705        if (XSyncValueGreaterOrEqual(Now, *pnext_time))
2706	{
2707            timeout = 0;
2708        }
2709	else
2710	{
2711	    Bool overflow;
2712            XSyncValueSubtract(&delay, *pnext_time, Now, &overflow);
2713	    (void)overflow;
2714            timeout = XSyncValueLow32(delay);
2715        }
2716        AdjustWaitForDelay(wt, timeout); /* os/utils.c */
2717    }
2718}
2719
2720/*
2721*** Wakeup Handler
2722 */
2723/*ARGSUSED*/
2724static void
2725ServertimeWakeupHandler(void *env, int rc, void *LastSelectMask)
2726{
2727    if (pnext_time)
2728    {
2729        GetTime();
2730
2731        if (XSyncValueGreaterOrEqual(Now, *pnext_time))
2732	{
2733            SyncChangeCounter(ServertimeCounter, Now);
2734        }
2735    }
2736}
2737
2738static void
2739ServertimeQueryValue(void *pCounter, CARD64 *pValue_return)
2740{
2741    GetTime();
2742    *pValue_return = Now;
2743}
2744
2745static void
2746ServertimeBracketValues(void *pCounter, CARD64 *pbracket_less,
2747			CARD64 *pbracket_greater)
2748{
2749    if (!pnext_time && pbracket_greater)
2750    {
2751	RegisterBlockAndWakeupHandlers(ServertimeBlockHandler,
2752				       ServertimeWakeupHandler,
2753				       NULL);
2754    }
2755    else if (pnext_time && !pbracket_greater)
2756    {
2757	RemoveBlockAndWakeupHandlers(ServertimeBlockHandler,
2758				     ServertimeWakeupHandler,
2759				     NULL);
2760    }
2761    pnext_time = pbracket_greater;
2762}
2763
2764static void
2765SyncInitServerTime(void)
2766{
2767    CARD64 resolution;
2768
2769    XSyncIntsToValue(&Now, GetTimeInMillis(), 0);
2770    XSyncIntToValue(&resolution, 4);
2771    ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution,
2772			    XSyncCounterNeverDecreases,
2773			    ServertimeQueryValue, ServertimeBracketValues);
2774    pnext_time = NULL;
2775}
2776
2777
2778
2779/*
2780 * IDLETIME implementation
2781 */
2782
2783static SyncCounter *IdleTimeCounter;
2784static XSyncValue *pIdleTimeValueLess;
2785static XSyncValue *pIdleTimeValueGreater;
2786
2787static void
2788IdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return)
2789{
2790    CARD32 idle = GetTimeInMillis() - lastDeviceEventTime.milliseconds;
2791    XSyncIntsToValue (pValue_return, idle, 0);
2792}
2793
2794static void
2795IdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask)
2796{
2797    XSyncValue idle, old_idle;
2798    SyncTriggerList *list = IdleTimeCounter->sync.pTriglist;
2799    SyncTrigger *trig;
2800
2801    if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
2802	return;
2803
2804    old_idle = IdleTimeCounter->value;
2805    IdleTimeQueryValue (NULL, &idle);
2806    IdleTimeCounter->value = idle; /* push, so CheckTrigger works */
2807
2808    if (pIdleTimeValueLess &&
2809        XSyncValueLessOrEqual (idle, *pIdleTimeValueLess))
2810    {
2811	/*
2812	 * We've been idle for less than the threshold value, and someone
2813	 * wants to know about that, but now we need to know whether they
2814	 * want level or edge trigger.  Check the trigger list against the
2815	 * current idle time, and if any succeed, bomb out of select()
2816	 * immediately so we can reschedule.
2817	 */
2818
2819	for (list = IdleTimeCounter->sync.pTriglist; list; list = list->next) {
2820	    trig = list->pTrigger;
2821	    if (trig->CheckTrigger(trig, old_idle)) {
2822		AdjustWaitForDelay(wt, 0);
2823		break;
2824	    }
2825	}
2826	/*
2827	 * We've been called exactly on the idle time, but we have a
2828	 * NegativeTransition trigger which requires a transition from an
2829	 * idle time greater than this.  Schedule a wakeup for the next
2830	 * millisecond so we won't miss a transition.
2831	 */
2832	if (XSyncValueEqual (idle, *pIdleTimeValueLess))
2833	    AdjustWaitForDelay(wt, 1);
2834    }
2835    else if (pIdleTimeValueGreater)
2836    {
2837	/*
2838	 * There's a threshold in the positive direction.  If we've been
2839	 * idle less than it, schedule a wakeup for sometime in the future.
2840	 * If we've been idle more than it, and someone wants to know about
2841	 * that level-triggered, schedule an immediate wakeup.
2842	 */
2843	unsigned long timeout = -1;
2844
2845	if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) {
2846	    XSyncValue value;
2847	    Bool overflow;
2848
2849	    XSyncValueSubtract (&value, *pIdleTimeValueGreater,
2850	                        idle, &overflow);
2851	    timeout = min(timeout, XSyncValueLow32 (value));
2852	} else {
2853	    for (list = IdleTimeCounter->sync.pTriglist; list; list = list->next) {
2854		trig = list->pTrigger;
2855		if (trig->CheckTrigger(trig, old_idle)) {
2856		    timeout = min(timeout, 0);
2857		    break;
2858		}
2859	    }
2860	}
2861
2862	AdjustWaitForDelay (wt, timeout);
2863    }
2864
2865    IdleTimeCounter->value = old_idle; /* pop */
2866}
2867
2868static void
2869IdleTimeWakeupHandler (pointer env, int rc, pointer LastSelectMask)
2870{
2871    XSyncValue idle;
2872
2873    if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
2874	return;
2875
2876    IdleTimeQueryValue (NULL, &idle);
2877
2878    if ((pIdleTimeValueGreater &&
2879         XSyncValueGreaterOrEqual (idle, *pIdleTimeValueGreater)) ||
2880        (pIdleTimeValueLess &&
2881	 XSyncValueLessOrEqual (idle, *pIdleTimeValueLess)))
2882    {
2883	SyncChangeCounter (IdleTimeCounter, idle);
2884    }
2885}
2886
2887static void
2888IdleTimeBracketValues (pointer pCounter, CARD64 *pbracket_less,
2889                       CARD64 *pbracket_greater)
2890{
2891    Bool registered = (pIdleTimeValueLess || pIdleTimeValueGreater);
2892
2893    if (registered && !pbracket_less && !pbracket_greater)
2894    {
2895	RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler,
2896	                             IdleTimeWakeupHandler,
2897	                             NULL);
2898    }
2899    else if (!registered && (pbracket_less || pbracket_greater))
2900    {
2901	RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
2902	                               IdleTimeWakeupHandler,
2903	                               NULL);
2904    }
2905
2906    pIdleTimeValueGreater = pbracket_greater;
2907    pIdleTimeValueLess    = pbracket_less;
2908}
2909
2910static void
2911SyncInitIdleTime (void)
2912{
2913    CARD64 resolution;
2914    XSyncValue idle;
2915
2916    IdleTimeQueryValue (NULL, &idle);
2917    XSyncIntToValue (&resolution, 4);
2918
2919    IdleTimeCounter = SyncCreateSystemCounter ("IDLETIME", idle, resolution,
2920                                               XSyncCounterUnrestricted,
2921                                               IdleTimeQueryValue,
2922                                               IdleTimeBracketValues);
2923
2924    pIdleTimeValueLess = pIdleTimeValueGreater = NULL;
2925}
2926