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