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