105b261ecSmrg/*
205b261ecSmrg
305b261ecSmrgCopyright 1991, 1993, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included
1205b261ecSmrgin all copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1505b261ecSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1605b261ecSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1705b261ecSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
1805b261ecSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1905b261ecSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2005b261ecSmrgOTHER DEALINGS IN THE SOFTWARE.
2105b261ecSmrg
2205b261ecSmrgExcept as contained in this notice, the name of The Open Group shall
2305b261ecSmrgnot be used in advertising or otherwise to promote the sale, use or
2405b261ecSmrgother dealings in this Software without prior written authorization
2505b261ecSmrgfrom The Open Group.
2605b261ecSmrg
2705b261ecSmrgCopyright 1991, 1993 by Digital Equipment Corporation, Maynard, Massachusetts,
2805b261ecSmrgand Olivetti Research Limited, Cambridge, England.
2905b261ecSmrg
3005b261ecSmrg                        All Rights Reserved
3105b261ecSmrg
3205b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3305b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3405b261ecSmrgprovided that the above copyright notice appear in all copies and that
3505b261ecSmrgboth that copyright notice and this permission notice appear in
364202a189Smrgsupporting documentation, and that the names of Digital or Olivetti
3705b261ecSmrgnot be used in advertising or publicity pertaining to distribution of the
3805b261ecSmrgsoftware without specific, written prior permission.  Digital and Olivetti
3905b261ecSmrgmake no representations about the suitability of this software
4005b261ecSmrgfor any purpose.  It is provided "as is" without express or implied warranty.
4105b261ecSmrg
4205b261ecSmrgDIGITAL AND OLIVETTI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
4305b261ecSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
4405b261ecSmrgFITNESS, IN NO EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR
4505b261ecSmrgCONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
4605b261ecSmrgUSE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
4705b261ecSmrgOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
4805b261ecSmrgPERFORMANCE OF THIS SOFTWARE.
4905b261ecSmrg
5005b261ecSmrg*/
5105b261ecSmrg
5205b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5305b261ecSmrg#include <dix-config.h>
5405b261ecSmrg#endif
5505b261ecSmrg
5605b261ecSmrg#include <string.h>
5705b261ecSmrg
5805b261ecSmrg#include <X11/X.h>
5905b261ecSmrg#include <X11/Xproto.h>
6005b261ecSmrg#include <X11/Xmd.h>
6165b04b38Smrg#include "scrnintstr.h"
6205b261ecSmrg#include "os.h"
6305b261ecSmrg#include "extnsionst.h"
6405b261ecSmrg#include "dixstruct.h"
6565b04b38Smrg#include "pixmapstr.h"
6605b261ecSmrg#include "resource.h"
6705b261ecSmrg#include "opaque.h"
684202a189Smrg#include <X11/extensions/syncproto.h>
694202a189Smrg#include "syncsrv.h"
7065b04b38Smrg#include "syncsdk.h"
711b684552Smrg#include "protocol-versions.h"
72f7df2e56Smrg#include "inputstr.h"
7305b261ecSmrg
7405b261ecSmrg#include <stdio.h>
75637ac9abSmrg#if !defined(WIN32)
7605b261ecSmrg#include <sys/time.h>
7705b261ecSmrg#endif
7805b261ecSmrg
79f7df2e56Smrg#include "extinit.h"
8005b261ecSmrg
8105b261ecSmrg/*
8205b261ecSmrg * Local Global Variables
8305b261ecSmrg */
84f7df2e56Smrgstatic int SyncEventBase;
85f7df2e56Smrgstatic int SyncErrorBase;
86f7df2e56Smrgstatic RESTYPE RTCounter = 0;
87f7df2e56Smrgstatic RESTYPE RTAwait;
88f7df2e56Smrgstatic RESTYPE RTAlarm;
89f7df2e56Smrgstatic RESTYPE RTAlarmClient;
90f7df2e56Smrgstatic RESTYPE RTFence;
91f7df2e56Smrgstatic struct xorg_list SysCounterList;
9265b04b38Smrgstatic int SyncNumInvalidCounterWarnings = 0;
93f7df2e56Smrg
9465b04b38Smrg#define MAX_INVALID_COUNTER_WARNINGS	   5
9565b04b38Smrg
9665b04b38Smrgstatic const char *WARN_INVALID_COUNTER_COMPARE =
97f7df2e56Smrg    "Warning: Non-counter XSync object using Counter-only\n"
98f7df2e56Smrg    "         comparison.  Result will never be true.\n";
9965b04b38Smrg
10065b04b38Smrgstatic const char *WARN_INVALID_COUNTER_ALARM =
101f7df2e56Smrg    "Warning: Non-counter XSync object used in alarm.  This is\n"
102f7df2e56Smrg    "         the result of a programming error in the X server.\n";
10305b261ecSmrg
10405b261ecSmrg#define IsSystemCounter(pCounter) \
10565b04b38Smrg    (pCounter && (pCounter->sync.client == NULL))
10605b261ecSmrg
10705b261ecSmrg/* these are all the alarm attributes that pertain to the alarm's trigger */
10805b261ecSmrg#define XSyncCAAllTrigger \
10905b261ecSmrg    (XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType)
11005b261ecSmrg
1114202a189Smrgstatic void SyncComputeBracketValues(SyncCounter *);
11205b261ecSmrg
1134202a189Smrgstatic void SyncInitServerTime(void);
11405b261ecSmrg
1154202a189Smrgstatic void SyncInitIdleTime(void);
11605b261ecSmrg
117f7df2e56Smrgstatic inline void*
118f7df2e56SmrgSysCounterGetPrivate(SyncCounter *counter)
119f7df2e56Smrg{
120f7df2e56Smrg    BUG_WARN(!IsSystemCounter(counter));
121f7df2e56Smrg
122f7df2e56Smrg    return counter->pSysCounterInfo ? counter->pSysCounterInfo->private : NULL;
123f7df2e56Smrg}
124f7df2e56Smrg
12565b04b38Smrgstatic Bool
126f7df2e56SmrgSyncCheckWarnIsCounter(const SyncObject * pSync, const char *warning)
12765b04b38Smrg{
128f7df2e56Smrg    if (pSync && (SYNC_COUNTER != pSync->type)) {
129f7df2e56Smrg        if (SyncNumInvalidCounterWarnings++ < MAX_INVALID_COUNTER_WARNINGS) {
130f7df2e56Smrg            ErrorF("%s", warning);
131f7df2e56Smrg            ErrorF("         Counter type: %d\n", pSync->type);
132f7df2e56Smrg        }
13365b04b38Smrg
134f7df2e56Smrg        return FALSE;
13565b04b38Smrg    }
13665b04b38Smrg
13765b04b38Smrg    return TRUE;
13865b04b38Smrg}
13905b261ecSmrg
14005b261ecSmrg/*  Each counter maintains a simple linked list of triggers that are
14105b261ecSmrg *  interested in the counter.  The two functions below are used to
14205b261ecSmrg *  delete and add triggers on this list.
14305b261ecSmrg */
144f7df2e56Smrgvoid
145f7df2e56SmrgSyncDeleteTriggerFromSyncObject(SyncTrigger * pTrigger)
14605b261ecSmrg{
14705b261ecSmrg    SyncTriggerList *pCur;
14805b261ecSmrg    SyncTriggerList *pPrev;
14965b04b38Smrg    SyncCounter *pCounter;
15005b261ecSmrg
15165b04b38Smrg    /* pSync needs to be stored in pTrigger before calling here. */
15205b261ecSmrg
15365b04b38Smrg    if (!pTrigger->pSync)
154f7df2e56Smrg        return;
15505b261ecSmrg
15605b261ecSmrg    pPrev = NULL;
15765b04b38Smrg    pCur = pTrigger->pSync->pTriglist;
15805b261ecSmrg
159f7df2e56Smrg    while (pCur) {
160f7df2e56Smrg        if (pCur->pTrigger == pTrigger) {
161f7df2e56Smrg            if (pPrev)
162f7df2e56Smrg                pPrev->next = pCur->next;
163f7df2e56Smrg            else
164f7df2e56Smrg                pTrigger->pSync->pTriglist = pCur->next;
165f7df2e56Smrg
166f7df2e56Smrg            free(pCur);
167f7df2e56Smrg            break;
168f7df2e56Smrg        }
1694202a189Smrg
170f7df2e56Smrg        pPrev = pCur;
171f7df2e56Smrg        pCur = pCur->next;
17205b261ecSmrg    }
1734202a189Smrg
174f7df2e56Smrg    if (SYNC_COUNTER == pTrigger->pSync->type) {
175f7df2e56Smrg        pCounter = (SyncCounter *) pTrigger->pSync;
17665b04b38Smrg
177f7df2e56Smrg        if (IsSystemCounter(pCounter))
178f7df2e56Smrg            SyncComputeBracketValues(pCounter);
17965b04b38Smrg    }
180f7df2e56Smrg    else if (SYNC_FENCE == pTrigger->pSync->type) {
181f7df2e56Smrg        SyncFence *pFence = (SyncFence *) pTrigger->pSync;
18205b261ecSmrg
183f7df2e56Smrg        pFence->funcs.DeleteTrigger(pTrigger);
184f7df2e56Smrg    }
185f7df2e56Smrg}
18605b261ecSmrg
187f7df2e56Smrgint
188f7df2e56SmrgSyncAddTriggerToSyncObject(SyncTrigger * pTrigger)
18905b261ecSmrg{
19005b261ecSmrg    SyncTriggerList *pCur;
19165b04b38Smrg    SyncCounter *pCounter;
19205b261ecSmrg
19365b04b38Smrg    if (!pTrigger->pSync)
194f7df2e56Smrg        return Success;
19505b261ecSmrg
19605b261ecSmrg    /* don't do anything if it's already there */
197f7df2e56Smrg    for (pCur = pTrigger->pSync->pTriglist; pCur; pCur = pCur->next) {
198f7df2e56Smrg        if (pCur->pTrigger == pTrigger)
199f7df2e56Smrg            return Success;
20005b261ecSmrg    }
20105b261ecSmrg
202d566a54bSmrg    /* Failure is not an option, it's succeed or burst! */
203d566a54bSmrg    pCur = XNFalloc(sizeof(SyncTriggerList));
20405b261ecSmrg
20505b261ecSmrg    pCur->pTrigger = pTrigger;
20665b04b38Smrg    pCur->next = pTrigger->pSync->pTriglist;
20765b04b38Smrg    pTrigger->pSync->pTriglist = pCur;
20805b261ecSmrg
209f7df2e56Smrg    if (SYNC_COUNTER == pTrigger->pSync->type) {
210f7df2e56Smrg        pCounter = (SyncCounter *) pTrigger->pSync;
21165b04b38Smrg
212f7df2e56Smrg        if (IsSystemCounter(pCounter))
213f7df2e56Smrg            SyncComputeBracketValues(pCounter);
214f7df2e56Smrg    }
215f7df2e56Smrg    else if (SYNC_FENCE == pTrigger->pSync->type) {
216f7df2e56Smrg        SyncFence *pFence = (SyncFence *) pTrigger->pSync;
217f7df2e56Smrg
218f7df2e56Smrg        pFence->funcs.AddTrigger(pTrigger);
21965b04b38Smrg    }
22005b261ecSmrg
22105b261ecSmrg    return Success;
22205b261ecSmrg}
22305b261ecSmrg
22465b04b38Smrg/*  Below are five possible functions that can be plugged into
22565b04b38Smrg *  pTrigger->CheckTrigger for counter sync objects, corresponding to
22665b04b38Smrg *  the four possible test-types, and the one possible function that
22765b04b38Smrg *  can be plugged into pTrigger->CheckTrigger for fence sync objects.
22865b04b38Smrg *  These functions are called after the sync object's state changes
22965b04b38Smrg *  but are also passed the old state so they can inspect both the old
23065b04b38Smrg *  and new values.  (PositiveTransition and NegativeTransition need to
23165b04b38Smrg *  see both pieces of information.)  These functions return the truth
23265b04b38Smrg *  value of the trigger.
23305b261ecSmrg *
23465b04b38Smrg *  All of them include the condition pTrigger->pSync == NULL.
23565b04b38Smrg *  This is because the spec says that a trigger with a sync value
23605b261ecSmrg *  of None is always TRUE.
23705b261ecSmrg */
23805b261ecSmrg
23905b261ecSmrgstatic Bool
2407e31ba66SmrgSyncCheckTriggerPositiveComparison(SyncTrigger * pTrigger, int64_t oldval)
24105b261ecSmrg{
24265b04b38Smrg    SyncCounter *pCounter;
24365b04b38Smrg
24465b04b38Smrg    /* Non-counter sync objects should never get here because they
24565b04b38Smrg     * never trigger this comparison. */
24665b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
247f7df2e56Smrg        return FALSE;
24865b04b38Smrg
249f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
25065b04b38Smrg
2517e31ba66Smrg    return pCounter == NULL || pCounter->value >= pTrigger->test_value;
25205b261ecSmrg}
25305b261ecSmrg
25405b261ecSmrgstatic Bool
2557e31ba66SmrgSyncCheckTriggerNegativeComparison(SyncTrigger * pTrigger, int64_t oldval)
25605b261ecSmrg{
25765b04b38Smrg    SyncCounter *pCounter;
25865b04b38Smrg
25965b04b38Smrg    /* Non-counter sync objects should never get here because they
26065b04b38Smrg     * never trigger this comparison. */
26165b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
262f7df2e56Smrg        return FALSE;
26365b04b38Smrg
264f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
26565b04b38Smrg
2667e31ba66Smrg    return pCounter == NULL || pCounter->value <= pTrigger->test_value;
26705b261ecSmrg}
26805b261ecSmrg
26905b261ecSmrgstatic Bool
2707e31ba66SmrgSyncCheckTriggerPositiveTransition(SyncTrigger * pTrigger, int64_t oldval)
27105b261ecSmrg{
27265b04b38Smrg    SyncCounter *pCounter;
27365b04b38Smrg
27465b04b38Smrg    /* Non-counter sync objects should never get here because they
27565b04b38Smrg     * never trigger this comparison. */
27665b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
277f7df2e56Smrg        return FALSE;
27865b04b38Smrg
279f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
28065b04b38Smrg
28165b04b38Smrg    return (pCounter == NULL ||
2827e31ba66Smrg            (oldval < pTrigger->test_value &&
2837e31ba66Smrg             pCounter->value >= pTrigger->test_value));
28405b261ecSmrg}
28505b261ecSmrg
28605b261ecSmrgstatic Bool
2877e31ba66SmrgSyncCheckTriggerNegativeTransition(SyncTrigger * pTrigger, int64_t oldval)
28805b261ecSmrg{
28965b04b38Smrg    SyncCounter *pCounter;
29065b04b38Smrg
29165b04b38Smrg    /* Non-counter sync objects should never get here because they
29265b04b38Smrg     * never trigger this comparison. */
29365b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
294f7df2e56Smrg        return FALSE;
29565b04b38Smrg
296f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
29765b04b38Smrg
29865b04b38Smrg    return (pCounter == NULL ||
2997e31ba66Smrg            (oldval > pTrigger->test_value &&
3007e31ba66Smrg             pCounter->value <= pTrigger->test_value));
30165b04b38Smrg}
30265b04b38Smrg
30365b04b38Smrgstatic Bool
3047e31ba66SmrgSyncCheckTriggerFence(SyncTrigger * pTrigger, int64_t unused)
30565b04b38Smrg{
306f7df2e56Smrg    SyncFence *pFence = (SyncFence *) pTrigger->pSync;
307f7df2e56Smrg
308f7df2e56Smrg    (void) unused;
30965b04b38Smrg
310f7df2e56Smrg    return (pFence == NULL || pFence->funcs.CheckTriggered(pFence));
31105b261ecSmrg}
31205b261ecSmrg
3134202a189Smrgstatic int
314f7df2e56SmrgSyncInitTrigger(ClientPtr client, SyncTrigger * pTrigger, XID syncObject,
315f7df2e56Smrg                RESTYPE resType, Mask changes)
31605b261ecSmrg{
31765b04b38Smrg    SyncObject *pSync = pTrigger->pSync;
31865b04b38Smrg    SyncCounter *pCounter = NULL;
319f7df2e56Smrg    int rc;
320f7df2e56Smrg    Bool newSyncObject = FALSE;
321f7df2e56Smrg
322f7df2e56Smrg    if (changes & XSyncCACounter) {
323f7df2e56Smrg        if (syncObject == None)
324f7df2e56Smrg            pSync = NULL;
325f7df2e56Smrg        else if (Success != (rc = dixLookupResourceByType((void **) &pSync,
326f7df2e56Smrg                                                          syncObject, resType,
327f7df2e56Smrg                                                          client,
328f7df2e56Smrg                                                          DixReadAccess))) {
329f7df2e56Smrg            client->errorValue = syncObject;
330f7df2e56Smrg            return rc;
331f7df2e56Smrg        }
33205b261ecSmrg    }
33305b261ecSmrg
33405b261ecSmrg    /* if system counter, ask it what the current value is */
33505b261ecSmrg
336f7df2e56Smrg    if (pSync && SYNC_COUNTER == pSync->type) {
337f7df2e56Smrg        pCounter = (SyncCounter *) pSync;
338f7df2e56Smrg
339f7df2e56Smrg        if (IsSystemCounter(pCounter)) {
340f7df2e56Smrg            (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter,
341f7df2e56Smrg                                                      &pCounter->value);
342f7df2e56Smrg        }
343f7df2e56Smrg    }
344f7df2e56Smrg
345f7df2e56Smrg    if (changes & XSyncCAValueType) {
346f7df2e56Smrg        if (pTrigger->value_type != XSyncRelative &&
347f7df2e56Smrg            pTrigger->value_type != XSyncAbsolute) {
348f7df2e56Smrg            client->errorValue = pTrigger->value_type;
349f7df2e56Smrg            return BadValue;
350f7df2e56Smrg        }
351f7df2e56Smrg    }
352f7df2e56Smrg
353d566a54bSmrg    if (changes & (XSyncCAValueType | XSyncCAValue)) {
354d566a54bSmrg        if (pTrigger->value_type == XSyncAbsolute)
355d566a54bSmrg            pTrigger->test_value = pTrigger->wait_value;
356d566a54bSmrg        else {                  /* relative */
357d566a54bSmrg            Bool overflow;
358d566a54bSmrg
359d566a54bSmrg            if (pCounter == NULL)
360d566a54bSmrg                return BadMatch;
361d566a54bSmrg
362d566a54bSmrg            overflow = checked_int64_add(&pTrigger->test_value,
363d566a54bSmrg                                         pCounter->value, pTrigger->wait_value);
364d566a54bSmrg            if (overflow) {
365d566a54bSmrg                client->errorValue = pTrigger->wait_value >> 32;
366d566a54bSmrg                return BadValue;
367d566a54bSmrg            }
368d566a54bSmrg        }
369d566a54bSmrg    }
370d566a54bSmrg
371f7df2e56Smrg    if (changes & XSyncCATestType) {
372f7df2e56Smrg
373f7df2e56Smrg        if (pSync && SYNC_FENCE == pSync->type) {
374f7df2e56Smrg            pTrigger->CheckTrigger = SyncCheckTriggerFence;
375f7df2e56Smrg        }
376f7df2e56Smrg        else {
377f7df2e56Smrg            /* select appropriate CheckTrigger function */
378f7df2e56Smrg
379f7df2e56Smrg            switch (pTrigger->test_type) {
380f7df2e56Smrg            case XSyncPositiveTransition:
381f7df2e56Smrg                pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition;
382f7df2e56Smrg                break;
383f7df2e56Smrg            case XSyncNegativeTransition:
384f7df2e56Smrg                pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition;
385f7df2e56Smrg                break;
386f7df2e56Smrg            case XSyncPositiveComparison:
387f7df2e56Smrg                pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison;
388f7df2e56Smrg                break;
389f7df2e56Smrg            case XSyncNegativeComparison:
390f7df2e56Smrg                pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison;
391f7df2e56Smrg                break;
392f7df2e56Smrg            default:
393f7df2e56Smrg                client->errorValue = pTrigger->test_type;
394f7df2e56Smrg                return BadValue;
395f7df2e56Smrg            }
396f7df2e56Smrg        }
397f7df2e56Smrg    }
398f7df2e56Smrg
399d566a54bSmrg    if (changes & XSyncCACounter) {
400d566a54bSmrg        if (pSync != pTrigger->pSync) { /* new counter for trigger */
401d566a54bSmrg            SyncDeleteTriggerFromSyncObject(pTrigger);
402d566a54bSmrg            pTrigger->pSync = pSync;
403d566a54bSmrg            newSyncObject = TRUE;
404f7df2e56Smrg        }
40505b261ecSmrg    }
40605b261ecSmrg
40705b261ecSmrg    /*  we wait until we're sure there are no errors before registering
40805b261ecSmrg     *  a new counter on a trigger
40905b261ecSmrg     */
410f7df2e56Smrg    if (newSyncObject) {
411d566a54bSmrg        SyncAddTriggerToSyncObject(pTrigger);
41205b261ecSmrg    }
413f7df2e56Smrg    else if (pCounter && IsSystemCounter(pCounter)) {
414f7df2e56Smrg        SyncComputeBracketValues(pCounter);
41505b261ecSmrg    }
4164202a189Smrg
41705b261ecSmrg    return Success;
41805b261ecSmrg}
41905b261ecSmrg
42005b261ecSmrg/*  AlarmNotify events happen in response to actions taken on an Alarm or
4214202a189Smrg *  the counter used by the alarm.  AlarmNotify may be sent to multiple
42205b261ecSmrg *  clients.  The alarm maintains a list of clients interested in events.
42305b261ecSmrg */
42405b261ecSmrgstatic void
425f7df2e56SmrgSyncSendAlarmNotifyEvents(SyncAlarm * pAlarm)
42605b261ecSmrg{
42705b261ecSmrg    SyncAlarmClientList *pcl;
42805b261ecSmrg    xSyncAlarmNotifyEvent ane;
42905b261ecSmrg    SyncTrigger *pTrigger = &pAlarm->trigger;
43065b04b38Smrg    SyncCounter *pCounter;
43165b04b38Smrg
43265b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
433f7df2e56Smrg        return;
43465b04b38Smrg
435f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
43605b261ecSmrg
43705b261ecSmrg    UpdateCurrentTime();
43805b261ecSmrg
439f7df2e56Smrg    ane = (xSyncAlarmNotifyEvent) {
440f7df2e56Smrg        .type = SyncEventBase + XSyncAlarmNotify,
441f7df2e56Smrg        .kind = XSyncAlarmNotify,
442f7df2e56Smrg        .alarm = pAlarm->alarm_id,
4437e31ba66Smrg        .alarm_value_hi = pTrigger->test_value >> 32,
4447e31ba66Smrg        .alarm_value_lo = pTrigger->test_value,
445f7df2e56Smrg        .time = currentTime.milliseconds,
446f7df2e56Smrg        .state = pAlarm->state
447f7df2e56Smrg    };
448f7df2e56Smrg
449f7df2e56Smrg    if (pTrigger->pSync && SYNC_COUNTER == pTrigger->pSync->type) {
4507e31ba66Smrg        ane.counter_value_hi = pCounter->value >> 32;
4517e31ba66Smrg        ane.counter_value_lo = pCounter->value;
45205b261ecSmrg    }
453f7df2e56Smrg    else {
454f7df2e56Smrg        /* XXX what else can we do if there's no counter? */
455f7df2e56Smrg        ane.counter_value_hi = ane.counter_value_lo = 0;
45605b261ecSmrg    }
45705b261ecSmrg
45805b261ecSmrg    /* send to owner */
4594202a189Smrg    if (pAlarm->events)
460f7df2e56Smrg        WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane);
46105b261ecSmrg
46205b261ecSmrg    /* send to other interested clients */
46305b261ecSmrg    for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next)
464f7df2e56Smrg        WriteEventsToClient(pcl->client, 1, (xEvent *) &ane);
46505b261ecSmrg}
46605b261ecSmrg
4674202a189Smrg/*  CounterNotify events only occur in response to an Await.  The events
46805b261ecSmrg *  go only to the Awaiting client.
46905b261ecSmrg */
47005b261ecSmrgstatic void
471f7df2e56SmrgSyncSendCounterNotifyEvents(ClientPtr client, SyncAwait ** ppAwait,
472f7df2e56Smrg                            int num_events)
47305b261ecSmrg{
47405b261ecSmrg    xSyncCounterNotifyEvent *pEvents, *pev;
47505b261ecSmrg    int i;
47605b261ecSmrg
47705b261ecSmrg    if (client->clientGone)
478f7df2e56Smrg        return;
479f7df2e56Smrg    pev = pEvents = calloc(num_events, sizeof(xSyncCounterNotifyEvent));
4804202a189Smrg    if (!pEvents)
481f7df2e56Smrg        return;
48205b261ecSmrg    UpdateCurrentTime();
483f7df2e56Smrg    for (i = 0; i < num_events; i++, ppAwait++, pev++) {
484f7df2e56Smrg        SyncTrigger *pTrigger = &(*ppAwait)->trigger;
485f7df2e56Smrg
486f7df2e56Smrg        pev->type = SyncEventBase + XSyncCounterNotify;
487f7df2e56Smrg        pev->kind = XSyncCounterNotify;
488f7df2e56Smrg        pev->counter = pTrigger->pSync->id;
4897e31ba66Smrg        pev->wait_value_lo = pTrigger->test_value;
4907e31ba66Smrg        pev->wait_value_hi = pTrigger->test_value >> 32;
491f7df2e56Smrg        if (SYNC_COUNTER == pTrigger->pSync->type) {
492f7df2e56Smrg            SyncCounter *pCounter = (SyncCounter *) pTrigger->pSync;
493f7df2e56Smrg
4947e31ba66Smrg            pev->counter_value_lo = pCounter->value;
4957e31ba66Smrg            pev->counter_value_hi = pCounter->value >> 32;
496f7df2e56Smrg        }
497f7df2e56Smrg        else {
498f7df2e56Smrg            pev->counter_value_lo = 0;
499f7df2e56Smrg            pev->counter_value_hi = 0;
500f7df2e56Smrg        }
501f7df2e56Smrg
502f7df2e56Smrg        pev->time = currentTime.milliseconds;
503f7df2e56Smrg        pev->count = num_events - i - 1;        /* events remaining */
504f7df2e56Smrg        pev->destroyed = pTrigger->pSync->beingDestroyed;
50505b261ecSmrg    }
50605b261ecSmrg    /* swapping will be taken care of by this */
507f7df2e56Smrg    WriteEventsToClient(client, num_events, (xEvent *) pEvents);
5084202a189Smrg    free(pEvents);
50905b261ecSmrg}
51005b261ecSmrg
51105b261ecSmrg/* This function is called when an alarm's counter is destroyed.
51205b261ecSmrg * It is plugged into pTrigger->CounterDestroyed (for alarm triggers).
51305b261ecSmrg */
5144202a189Smrgstatic void
515f7df2e56SmrgSyncAlarmCounterDestroyed(SyncTrigger * pTrigger)
51605b261ecSmrg{
517f7df2e56Smrg    SyncAlarm *pAlarm = (SyncAlarm *) pTrigger;
51805b261ecSmrg
51905b261ecSmrg    pAlarm->state = XSyncAlarmInactive;
52005b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
52165b04b38Smrg    pTrigger->pSync = NULL;
52205b261ecSmrg}
52305b261ecSmrg
5244202a189Smrg/*  This function is called when an alarm "goes off."
52505b261ecSmrg *  It is plugged into pTrigger->TriggerFired (for alarm triggers).
52605b261ecSmrg */
52705b261ecSmrgstatic void
528f7df2e56SmrgSyncAlarmTriggerFired(SyncTrigger * pTrigger)
52905b261ecSmrg{
530f7df2e56Smrg    SyncAlarm *pAlarm = (SyncAlarm *) pTrigger;
53165b04b38Smrg    SyncCounter *pCounter;
5327e31ba66Smrg    int64_t new_test_value;
53305b261ecSmrg
53465b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
535f7df2e56Smrg        return;
53665b04b38Smrg
537f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
53865b04b38Smrg
53905b261ecSmrg    /* no need to check alarm unless it's active */
54005b261ecSmrg    if (pAlarm->state != XSyncAlarmActive)
541f7df2e56Smrg        return;
54205b261ecSmrg
54305b261ecSmrg    /*  " if the counter value is None, or if the delta is 0 and
54405b261ecSmrg     *    the test-type is PositiveComparison or NegativeComparison,
54505b261ecSmrg     *    no change is made to value (test-value) and the alarm
54605b261ecSmrg     *    state is changed to Inactive before the event is generated."
54705b261ecSmrg     */
5487e31ba66Smrg    if (pCounter == NULL || (pAlarm->delta == 0
549f7df2e56Smrg                             && (pAlarm->trigger.test_type ==
550f7df2e56Smrg                                 XSyncPositiveComparison ||
551f7df2e56Smrg                                 pAlarm->trigger.test_type ==
552f7df2e56Smrg                                 XSyncNegativeComparison)))
553f7df2e56Smrg        pAlarm->state = XSyncAlarmInactive;
55405b261ecSmrg
55505b261ecSmrg    new_test_value = pAlarm->trigger.test_value;
55605b261ecSmrg
557f7df2e56Smrg    if (pAlarm->state == XSyncAlarmActive) {
558f7df2e56Smrg        Bool overflow;
5597e31ba66Smrg        int64_t oldvalue;
560f7df2e56Smrg        SyncTrigger *paTrigger = &pAlarm->trigger;
561f7df2e56Smrg        SyncCounter *paCounter;
562f7df2e56Smrg
563f7df2e56Smrg        if (!SyncCheckWarnIsCounter(paTrigger->pSync,
564f7df2e56Smrg                                    WARN_INVALID_COUNTER_ALARM))
565f7df2e56Smrg            return;
566f7df2e56Smrg
567f7df2e56Smrg        paCounter = (SyncCounter *) pTrigger->pSync;
568f7df2e56Smrg
569f7df2e56Smrg        /* "The alarm is updated by repeatedly adding delta to the
570f7df2e56Smrg         *  value of the trigger and re-initializing it until it
571f7df2e56Smrg         *  becomes FALSE."
572f7df2e56Smrg         */
573f7df2e56Smrg        oldvalue = paTrigger->test_value;
574f7df2e56Smrg
575f7df2e56Smrg        /* XXX really should do something smarter here */
576f7df2e56Smrg
577f7df2e56Smrg        do {
5787e31ba66Smrg            overflow = checked_int64_add(&paTrigger->test_value,
5797e31ba66Smrg                                         paTrigger->test_value, pAlarm->delta);
580f7df2e56Smrg        } while (!overflow &&
581f7df2e56Smrg                 (*paTrigger->CheckTrigger) (paTrigger, paCounter->value));
582f7df2e56Smrg
583f7df2e56Smrg        new_test_value = paTrigger->test_value;
584f7df2e56Smrg        paTrigger->test_value = oldvalue;
585f7df2e56Smrg
586f7df2e56Smrg        /* "If this update would cause value to fall outside the range
587f7df2e56Smrg         *  for an INT64...no change is made to value (test-value) and
588f7df2e56Smrg         *  the alarm state is changed to Inactive before the event is
589f7df2e56Smrg         *  generated."
590f7df2e56Smrg         */
591f7df2e56Smrg        if (overflow) {
592f7df2e56Smrg            new_test_value = oldvalue;
593f7df2e56Smrg            pAlarm->state = XSyncAlarmInactive;
594f7df2e56Smrg        }
59505b261ecSmrg    }
59605b261ecSmrg    /*  The AlarmNotify event has to have the "new state of the alarm"
59705b261ecSmrg     *  which we can't be sure of until this point.  However, it has
59805b261ecSmrg     *  to have the "old" trigger test value.  That's the reason for
59905b261ecSmrg     *  all the newvalue/oldvalue shuffling above.  After we send the
60005b261ecSmrg     *  events, give the trigger its new test value.
60105b261ecSmrg     */
60205b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
60305b261ecSmrg    pTrigger->test_value = new_test_value;
60405b261ecSmrg}
60505b261ecSmrg
60605b261ecSmrg/*  This function is called when an Await unblocks, either as a result
60705b261ecSmrg *  of the trigger firing OR the counter being destroyed.
60805b261ecSmrg *  It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed
60905b261ecSmrg *  (for Await triggers).
61005b261ecSmrg */
61105b261ecSmrgstatic void
612f7df2e56SmrgSyncAwaitTriggerFired(SyncTrigger * pTrigger)
61305b261ecSmrg{
614f7df2e56Smrg    SyncAwait *pAwait = (SyncAwait *) pTrigger;
61505b261ecSmrg    int numwaits;
61605b261ecSmrg    SyncAwaitUnion *pAwaitUnion;
61705b261ecSmrg    SyncAwait **ppAwait;
61805b261ecSmrg    int num_events = 0;
61905b261ecSmrg
620f7df2e56Smrg    pAwaitUnion = (SyncAwaitUnion *) pAwait->pHeader;
62105b261ecSmrg    numwaits = pAwaitUnion->header.num_waitconditions;
622f7df2e56Smrg    ppAwait = xallocarray(numwaits, sizeof(SyncAwait *));
62305b261ecSmrg    if (!ppAwait)
624f7df2e56Smrg        goto bail;
62505b261ecSmrg
626f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await;
62705b261ecSmrg
62805b261ecSmrg    /* "When a client is unblocked, all the CounterNotify events for
62905b261ecSmrg     *  the Await request are generated contiguously. If count is 0
63005b261ecSmrg     *  there are no more events to follow for this request. If
63105b261ecSmrg     *  count is n, there are at least n more events to follow."
63205b261ecSmrg     *
63305b261ecSmrg     *  Thus, it is best to find all the counters for which events
63405b261ecSmrg     *  need to be sent first, so that an accurate count field can
63505b261ecSmrg     *  be stored in the events.
63605b261ecSmrg     */
637f7df2e56Smrg    for (; numwaits; numwaits--, pAwait++) {
6387e31ba66Smrg        int64_t diff;
639f7df2e56Smrg        Bool overflow, diffgreater, diffequal;
640f7df2e56Smrg
641f7df2e56Smrg        /* "A CounterNotify event with the destroyed flag set to TRUE is
642f7df2e56Smrg         *  always generated if the counter for one of the triggers is
643f7df2e56Smrg         *  destroyed."
644f7df2e56Smrg         */
645f7df2e56Smrg        if (pAwait->trigger.pSync->beingDestroyed) {
646f7df2e56Smrg            ppAwait[num_events++] = pAwait;
647f7df2e56Smrg            continue;
648f7df2e56Smrg        }
649f7df2e56Smrg
650f7df2e56Smrg        if (SYNC_COUNTER == pAwait->trigger.pSync->type) {
651f7df2e56Smrg            SyncCounter *pCounter = (SyncCounter *) pAwait->trigger.pSync;
652f7df2e56Smrg
653f7df2e56Smrg            /* "The difference between the counter and the test value is
654f7df2e56Smrg             *  calculated by subtracting the test value from the value of
655f7df2e56Smrg             *  the counter."
656f7df2e56Smrg             */
6577e31ba66Smrg            overflow = checked_int64_subtract(&diff, pCounter->value,
6587e31ba66Smrg                                              pAwait->trigger.test_value);
659f7df2e56Smrg
660f7df2e56Smrg            /* "If the difference lies outside the range for an INT64, an
661f7df2e56Smrg             *  event is not generated."
662f7df2e56Smrg             */
663f7df2e56Smrg            if (overflow)
664f7df2e56Smrg                continue;
6657e31ba66Smrg            diffgreater = diff > pAwait->event_threshold;
6667e31ba66Smrg            diffequal = diff == pAwait->event_threshold;
667f7df2e56Smrg
668f7df2e56Smrg            /* "If the test-type is PositiveTransition or
669f7df2e56Smrg             *  PositiveComparison, a CounterNotify event is generated if
670f7df2e56Smrg             *  the difference is at least event-threshold. If the test-type
671f7df2e56Smrg             *  is NegativeTransition or NegativeComparison, a CounterNotify
672f7df2e56Smrg             *  event is generated if the difference is at most
673f7df2e56Smrg             *  event-threshold."
674f7df2e56Smrg             */
675f7df2e56Smrg
676f7df2e56Smrg            if (((pAwait->trigger.test_type == XSyncPositiveComparison ||
677f7df2e56Smrg                  pAwait->trigger.test_type == XSyncPositiveTransition)
678f7df2e56Smrg                 && (diffgreater || diffequal))
679f7df2e56Smrg                ||
680f7df2e56Smrg                ((pAwait->trigger.test_type == XSyncNegativeComparison ||
681f7df2e56Smrg                  pAwait->trigger.test_type == XSyncNegativeTransition)
682f7df2e56Smrg                 && (!diffgreater)      /* less or equal */
683f7df2e56Smrg                )
684f7df2e56Smrg                ) {
685f7df2e56Smrg                ppAwait[num_events++] = pAwait;
686f7df2e56Smrg            }
687f7df2e56Smrg        }
68805b261ecSmrg    }
68905b261ecSmrg    if (num_events)
690f7df2e56Smrg        SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait,
691f7df2e56Smrg                                    num_events);
6924202a189Smrg    free(ppAwait);
69305b261ecSmrg
694f7df2e56Smrg bail:
69505b261ecSmrg    /* unblock the client */
69605b261ecSmrg    AttendClient(pAwaitUnion->header.client);
69705b261ecSmrg    /* delete the await */
69805b261ecSmrg    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
69905b261ecSmrg}
70005b261ecSmrg
7017e31ba66Smrgstatic int64_t
7027e31ba66SmrgSyncUpdateCounter(SyncCounter *pCounter, int64_t newval)
703f7df2e56Smrg{
7047e31ba66Smrg    int64_t oldval = pCounter->value;
705f7df2e56Smrg    pCounter->value = newval;
706f7df2e56Smrg    return oldval;
707f7df2e56Smrg}
70805b261ecSmrg
70905b261ecSmrg/*  This function should always be used to change a counter's value so that
71005b261ecSmrg *  any triggers depending on the counter will be checked.
71105b261ecSmrg */
71205b261ecSmrgvoid
7137e31ba66SmrgSyncChangeCounter(SyncCounter * pCounter, int64_t newval)
71405b261ecSmrg{
715f7df2e56Smrg    SyncTriggerList *ptl, *pnext;
7167e31ba66Smrg    int64_t oldval;
71705b261ecSmrg
718f7df2e56Smrg    oldval = SyncUpdateCounter(pCounter, newval);
71905b261ecSmrg
72005b261ecSmrg    /* run through triggers to see if any become true */
721f7df2e56Smrg    for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) {
722f7df2e56Smrg        pnext = ptl->next;
723f7df2e56Smrg        if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, oldval))
724f7df2e56Smrg            (*ptl->pTrigger->TriggerFired) (ptl->pTrigger);
72505b261ecSmrg    }
72605b261ecSmrg
727f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
728f7df2e56Smrg        SyncComputeBracketValues(pCounter);
72905b261ecSmrg    }
73005b261ecSmrg}
73105b261ecSmrg
73205b261ecSmrg/* loosely based on dix/events.c/EventSelectForWindow */
73305b261ecSmrgstatic Bool
734f7df2e56SmrgSyncEventSelectForAlarm(SyncAlarm * pAlarm, ClientPtr client, Bool wantevents)
73505b261ecSmrg{
73605b261ecSmrg    SyncAlarmClientList *pClients;
73705b261ecSmrg
738f7df2e56Smrg    if (client == pAlarm->client) {     /* alarm owner */
739f7df2e56Smrg        pAlarm->events = wantevents;
740f7df2e56Smrg        return Success;
74105b261ecSmrg    }
74205b261ecSmrg
74305b261ecSmrg    /* see if the client is already on the list (has events selected) */
74405b261ecSmrg
745f7df2e56Smrg    for (pClients = pAlarm->pEventClients; pClients; pClients = pClients->next) {
746f7df2e56Smrg        if (pClients->client == client) {
747f7df2e56Smrg            /* client's presence on the list indicates desire for
748f7df2e56Smrg             * events.  If the client doesn't want events, remove it
749f7df2e56Smrg             * from the list.  If the client does want events, do
750f7df2e56Smrg             * nothing, since it's already got them.
751f7df2e56Smrg             */
752f7df2e56Smrg            if (!wantevents) {
753f7df2e56Smrg                FreeResource(pClients->delete_id, RT_NONE);
754f7df2e56Smrg            }
755f7df2e56Smrg            return Success;
756f7df2e56Smrg        }
75705b261ecSmrg    }
75805b261ecSmrg
75905b261ecSmrg    /*  if we get here, this client does not currently have
76005b261ecSmrg     *  events selected on the alarm
76105b261ecSmrg     */
76205b261ecSmrg
76305b261ecSmrg    if (!wantevents)
764f7df2e56Smrg        /* client doesn't want events, and we just discovered that it
765f7df2e56Smrg         * doesn't have them, so there's nothing to do.
766f7df2e56Smrg         */
767f7df2e56Smrg        return Success;
76805b261ecSmrg
76905b261ecSmrg    /* add new client to pAlarm->pEventClients */
77005b261ecSmrg
7714202a189Smrg    pClients = malloc(sizeof(SyncAlarmClientList));
77205b261ecSmrg    if (!pClients)
773f7df2e56Smrg        return BadAlloc;
77405b261ecSmrg
7754202a189Smrg    /*  register it as a resource so it will be cleaned up
77605b261ecSmrg     *  if the client dies
77705b261ecSmrg     */
77805b261ecSmrg
77905b261ecSmrg    pClients->delete_id = FakeClientID(client->index);
78005b261ecSmrg
78105b261ecSmrg    /* link it into list after we know all the allocations succeed */
78205b261ecSmrg    pClients->next = pAlarm->pEventClients;
78305b261ecSmrg    pAlarm->pEventClients = pClients;
78405b261ecSmrg    pClients->client = client;
78565b04b38Smrg
78665b04b38Smrg    if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm))
787f7df2e56Smrg        return BadAlloc;
78865b04b38Smrg
78905b261ecSmrg    return Success;
79005b261ecSmrg}
79105b261ecSmrg
79205b261ecSmrg/*
79305b261ecSmrg * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm
79405b261ecSmrg */
7954202a189Smrgstatic int
796f7df2e56SmrgSyncChangeAlarmAttributes(ClientPtr client, SyncAlarm * pAlarm, Mask mask,
797f7df2e56Smrg                          CARD32 *values)
798f7df2e56Smrg{
799f7df2e56Smrg    int status;
800f7df2e56Smrg    XSyncCounter counter;
801f7df2e56Smrg    Mask origmask = mask;
802d566a54bSmrg    SyncTrigger trigger;
803d566a54bSmrg    Bool select_events_changed = FALSE;
804d566a54bSmrg    Bool select_events_value = FALSE;
805d566a54bSmrg    int64_t delta;
806f7df2e56Smrg
807d566a54bSmrg    trigger = pAlarm->trigger;
808d566a54bSmrg    delta = pAlarm->delta;
809d566a54bSmrg    counter = trigger.pSync ? trigger.pSync->id : None;
810f7df2e56Smrg
811f7df2e56Smrg    while (mask) {
812f7df2e56Smrg        int index2 = lowbit(mask);
813f7df2e56Smrg
814f7df2e56Smrg        mask &= ~index2;
815f7df2e56Smrg        switch (index2) {
816f7df2e56Smrg        case XSyncCACounter:
817f7df2e56Smrg            mask &= ~XSyncCACounter;
818f7df2e56Smrg            /* sanity check in SyncInitTrigger */
819f7df2e56Smrg            counter = *values++;
820f7df2e56Smrg            break;
821f7df2e56Smrg
822f7df2e56Smrg        case XSyncCAValueType:
823f7df2e56Smrg            mask &= ~XSyncCAValueType;
824f7df2e56Smrg            /* sanity check in SyncInitTrigger */
825d566a54bSmrg            trigger.value_type = *values++;
826f7df2e56Smrg            break;
827f7df2e56Smrg
828f7df2e56Smrg        case XSyncCAValue:
829f7df2e56Smrg            mask &= ~XSyncCAValue;
830d566a54bSmrg            trigger.wait_value = ((int64_t)values[0] << 32) | values[1];
831f7df2e56Smrg            values += 2;
832f7df2e56Smrg            break;
833f7df2e56Smrg
834f7df2e56Smrg        case XSyncCATestType:
835f7df2e56Smrg            mask &= ~XSyncCATestType;
836f7df2e56Smrg            /* sanity check in SyncInitTrigger */
837d566a54bSmrg            trigger.test_type = *values++;
838f7df2e56Smrg            break;
839f7df2e56Smrg
840f7df2e56Smrg        case XSyncCADelta:
841f7df2e56Smrg            mask &= ~XSyncCADelta;
842d566a54bSmrg            delta = ((int64_t)values[0] << 32) | values[1];
843f7df2e56Smrg            values += 2;
844f7df2e56Smrg            break;
845f7df2e56Smrg
846f7df2e56Smrg        case XSyncCAEvents:
847f7df2e56Smrg            mask &= ~XSyncCAEvents;
848f7df2e56Smrg            if ((*values != xTrue) && (*values != xFalse)) {
849f7df2e56Smrg                client->errorValue = *values;
850f7df2e56Smrg                return BadValue;
851f7df2e56Smrg            }
852d566a54bSmrg            select_events_value = (Bool) (*values++);
853d566a54bSmrg            select_events_changed = TRUE;
854f7df2e56Smrg            break;
855f7df2e56Smrg
856f7df2e56Smrg        default:
857f7df2e56Smrg            client->errorValue = mask;
858f7df2e56Smrg            return BadValue;
859f7df2e56Smrg        }
86005b261ecSmrg    }
86105b261ecSmrg
862d566a54bSmrg    if (select_events_changed) {
863d566a54bSmrg        status = SyncEventSelectForAlarm(pAlarm, client, select_events_value);
864d566a54bSmrg        if (status != Success)
865d566a54bSmrg            return status;
866d566a54bSmrg    }
867d566a54bSmrg
86805b261ecSmrg    /* "If the test-type is PositiveComparison or PositiveTransition
86905b261ecSmrg     *  and delta is less than zero, or if the test-type is
87005b261ecSmrg     *  NegativeComparison or NegativeTransition and delta is
87105b261ecSmrg     *  greater than zero, a Match error is generated."
87205b261ecSmrg     */
873f7df2e56Smrg    if (origmask & (XSyncCADelta | XSyncCATestType)) {
874d566a54bSmrg        if ((((trigger.test_type == XSyncPositiveComparison) ||
875d566a54bSmrg              (trigger.test_type == XSyncPositiveTransition))
876d566a54bSmrg             && delta < 0)
877f7df2e56Smrg            ||
878d566a54bSmrg            (((trigger.test_type == XSyncNegativeComparison) ||
879d566a54bSmrg              (trigger.test_type == XSyncNegativeTransition))
880d566a54bSmrg             && delta > 0)
881f7df2e56Smrg            ) {
882f7df2e56Smrg            return BadMatch;
883f7df2e56Smrg        }
88405b261ecSmrg    }
88505b261ecSmrg
88605b261ecSmrg    /* postpone this until now, when we're sure nothing else can go wrong */
887d566a54bSmrg    pAlarm->delta = delta;
888d566a54bSmrg    pAlarm->trigger = trigger;
88965b04b38Smrg    if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter,
890f7df2e56Smrg                                  origmask & XSyncCAAllTrigger)) != Success)
891f7df2e56Smrg        return status;
89205b261ecSmrg
89305b261ecSmrg    /* XXX spec does not really say to do this - needs clarification */
89405b261ecSmrg    pAlarm->state = XSyncAlarmActive;
89505b261ecSmrg    return Success;
89605b261ecSmrg}
89705b261ecSmrg
8984e185dc0SmrgSyncObject *
89965b04b38SmrgSyncCreate(ClientPtr client, XID id, unsigned char type)
90065b04b38Smrg{
90165b04b38Smrg    SyncObject *pSync;
9024e185dc0Smrg    RESTYPE resType;
90365b04b38Smrg
90465b04b38Smrg    switch (type) {
90565b04b38Smrg    case SYNC_COUNTER:
906f7df2e56Smrg        pSync = malloc(sizeof(SyncCounter));
9074e185dc0Smrg        resType = RTCounter;
908f7df2e56Smrg        break;
90965b04b38Smrg    case SYNC_FENCE:
910f7df2e56Smrg        pSync = (SyncObject *) dixAllocateObjectWithPrivates(SyncFence,
911f7df2e56Smrg                                                             PRIVATE_SYNC_FENCE);
9124e185dc0Smrg        resType = RTFence;
913f7df2e56Smrg        break;
91465b04b38Smrg    default:
915f7df2e56Smrg        return NULL;
91665b04b38Smrg    }
91765b04b38Smrg
91865b04b38Smrg    if (!pSync)
919f7df2e56Smrg        return NULL;
92065b04b38Smrg
9214e185dc0Smrg    pSync->initialized = FALSE;
9224e185dc0Smrg
9234e185dc0Smrg    if (!AddResource(id, resType, (void *) pSync))
9244e185dc0Smrg        return NULL;
9254e185dc0Smrg
92665b04b38Smrg    pSync->client = client;
92765b04b38Smrg    pSync->id = id;
92865b04b38Smrg    pSync->pTriglist = NULL;
92965b04b38Smrg    pSync->beingDestroyed = FALSE;
93065b04b38Smrg    pSync->type = type;
93165b04b38Smrg
93265b04b38Smrg    return pSync;
93365b04b38Smrg}
93465b04b38Smrg
935f7df2e56Smrgint
936f7df2e56SmrgSyncCreateFenceFromFD(ClientPtr client, DrawablePtr pDraw, XID id, int fd, BOOL initially_triggered)
937f7df2e56Smrg{
9387e31ba66Smrg#ifdef HAVE_XSHMFENCE
939f7df2e56Smrg    SyncFence  *pFence;
940f7df2e56Smrg    int         status;
941f7df2e56Smrg
942f7df2e56Smrg    pFence = (SyncFence *) SyncCreate(client, id, SYNC_FENCE);
943f7df2e56Smrg    if (!pFence)
944f7df2e56Smrg        return BadAlloc;
945f7df2e56Smrg
946f7df2e56Smrg    status = miSyncInitFenceFromFD(pDraw, pFence, fd, initially_triggered);
947f7df2e56Smrg    if (status != Success) {
9484e185dc0Smrg        FreeResource(pFence->sync.id, RT_NONE);
949f7df2e56Smrg        return status;
950f7df2e56Smrg    }
951f7df2e56Smrg
952f7df2e56Smrg    return Success;
953f7df2e56Smrg#else
954f7df2e56Smrg    return BadImplementation;
955f7df2e56Smrg#endif
956f7df2e56Smrg}
957f7df2e56Smrg
958f7df2e56Smrgint
959f7df2e56SmrgSyncFDFromFence(ClientPtr client, DrawablePtr pDraw, SyncFence *pFence)
960f7df2e56Smrg{
9617e31ba66Smrg#ifdef HAVE_XSHMFENCE
962f7df2e56Smrg    return miSyncFDFromFence(pDraw, pFence);
963f7df2e56Smrg#else
964f7df2e56Smrg    return BadImplementation;
965f7df2e56Smrg#endif
966f7df2e56Smrg}
96705b261ecSmrg
96805b261ecSmrgstatic SyncCounter *
9697e31ba66SmrgSyncCreateCounter(ClientPtr client, XSyncCounter id, int64_t initialvalue)
97005b261ecSmrg{
97105b261ecSmrg    SyncCounter *pCounter;
97205b261ecSmrg
973f7df2e56Smrg    if (!(pCounter = (SyncCounter *) SyncCreate(client, id, SYNC_COUNTER)))
974f7df2e56Smrg        return NULL;
97505b261ecSmrg
97665b04b38Smrg    pCounter->value = initialvalue;
97765b04b38Smrg    pCounter->pSysCounterInfo = NULL;
97865b04b38Smrg
9794e185dc0Smrg    pCounter->sync.initialized = TRUE;
98005b261ecSmrg
98105b261ecSmrg    return pCounter;
98205b261ecSmrg}
98305b261ecSmrg
9844202a189Smrgstatic int FreeCounter(void *, XID);
98505b261ecSmrg
98605b261ecSmrg/*
98705b261ecSmrg * ***** System Counter utilities
98805b261ecSmrg */
98905b261ecSmrg
990f7df2e56SmrgSyncCounter*
991f7df2e56SmrgSyncCreateSystemCounter(const char *name,
9927e31ba66Smrg                        int64_t initial,
9937e31ba66Smrg                        int64_t resolution,
994f7df2e56Smrg                        SyncCounterType counterType,
995f7df2e56Smrg                        SyncSystemCounterQueryValue QueryValue,
996f7df2e56Smrg                        SyncSystemCounterBracketValues BracketValues
997f7df2e56Smrg    )
998f7df2e56Smrg{
9997e31ba66Smrg    SyncCounter *pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial);
100005b261ecSmrg
1001f7df2e56Smrg    if (pCounter) {
1002f7df2e56Smrg        SysCounterInfo *psci;
1003f7df2e56Smrg
1004f7df2e56Smrg        psci = malloc(sizeof(SysCounterInfo));
1005f7df2e56Smrg        if (!psci) {
1006f7df2e56Smrg            FreeResource(pCounter->sync.id, RT_NONE);
1007f7df2e56Smrg            return pCounter;
1008f7df2e56Smrg        }
1009f7df2e56Smrg        pCounter->pSysCounterInfo = psci;
1010f7df2e56Smrg        psci->pCounter = pCounter;
1011f7df2e56Smrg        psci->name = strdup(name);
1012f7df2e56Smrg        psci->resolution = resolution;
1013f7df2e56Smrg        psci->counterType = counterType;
1014f7df2e56Smrg        psci->QueryValue = QueryValue;
1015f7df2e56Smrg        psci->BracketValues = BracketValues;
1016f7df2e56Smrg        psci->private = NULL;
10177e31ba66Smrg        psci->bracket_greater = LLONG_MAX;
10187e31ba66Smrg        psci->bracket_less = LLONG_MIN;
1019f7df2e56Smrg        xorg_list_add(&psci->entry, &SysCounterList);
102005b261ecSmrg    }
10214202a189Smrg    return pCounter;
102205b261ecSmrg}
102305b261ecSmrg
102405b261ecSmrgvoid
1025f7df2e56SmrgSyncDestroySystemCounter(void *pSysCounter)
102605b261ecSmrg{
1027f7df2e56Smrg    SyncCounter *pCounter = (SyncCounter *) pSysCounter;
1028f7df2e56Smrg
102965b04b38Smrg    FreeResource(pCounter->sync.id, RT_NONE);
103005b261ecSmrg}
103105b261ecSmrg
103205b261ecSmrgstatic void
1033f7df2e56SmrgSyncComputeBracketValues(SyncCounter * pCounter)
103405b261ecSmrg{
103505b261ecSmrg    SyncTriggerList *pCur;
103605b261ecSmrg    SyncTrigger *pTrigger;
103705b261ecSmrg    SysCounterInfo *psci;
10387e31ba66Smrg    int64_t *pnewgtval = NULL;
10397e31ba66Smrg    int64_t *pnewltval = NULL;
104005b261ecSmrg    SyncCounterType ct;
104105b261ecSmrg
104205b261ecSmrg    if (!pCounter)
1043f7df2e56Smrg        return;
104405b261ecSmrg
104505b261ecSmrg    psci = pCounter->pSysCounterInfo;
104605b261ecSmrg    ct = pCounter->pSysCounterInfo->counterType;
104705b261ecSmrg    if (ct == XSyncCounterNeverChanges)
1048f7df2e56Smrg        return;
104905b261ecSmrg
10507e31ba66Smrg    psci->bracket_greater = LLONG_MAX;
10517e31ba66Smrg    psci->bracket_less = LLONG_MIN;
105205b261ecSmrg
1053f7df2e56Smrg    for (pCur = pCounter->sync.pTriglist; pCur; pCur = pCur->next) {
1054f7df2e56Smrg        pTrigger = pCur->pTrigger;
1055f7df2e56Smrg
105605b261ecSmrg        if (pTrigger->test_type == XSyncPositiveComparison &&
1057f7df2e56Smrg            ct != XSyncCounterNeverIncreases) {
10587e31ba66Smrg            if (pCounter->value < pTrigger->test_value &&
10597e31ba66Smrg                pTrigger->test_value < psci->bracket_greater) {
1060f7df2e56Smrg                psci->bracket_greater = pTrigger->test_value;
1061f7df2e56Smrg                pnewgtval = &psci->bracket_greater;
1062f7df2e56Smrg            }
10637e31ba66Smrg            else if (pCounter->value > pTrigger->test_value &&
10647e31ba66Smrg                     pTrigger->test_value > psci->bracket_less) {
1065f7df2e56Smrg                    psci->bracket_less = pTrigger->test_value;
1066f7df2e56Smrg                    pnewltval = &psci->bracket_less;
1067f7df2e56Smrg            }
1068f7df2e56Smrg        }
1069f7df2e56Smrg        else if (pTrigger->test_type == XSyncNegativeComparison &&
1070f7df2e56Smrg                 ct != XSyncCounterNeverDecreases) {
10717e31ba66Smrg            if (pCounter->value > pTrigger->test_value &&
10727e31ba66Smrg                pTrigger->test_value > psci->bracket_less) {
1073f7df2e56Smrg                psci->bracket_less = pTrigger->test_value;
1074f7df2e56Smrg                pnewltval = &psci->bracket_less;
1075f7df2e56Smrg            }
10767e31ba66Smrg            else if (pCounter->value < pTrigger->test_value &&
10777e31ba66Smrg                     pTrigger->test_value < psci->bracket_greater) {
1078f7df2e56Smrg                    psci->bracket_greater = pTrigger->test_value;
1079f7df2e56Smrg                    pnewgtval = &psci->bracket_greater;
1080f7df2e56Smrg            }
1081f7df2e56Smrg        }
1082f7df2e56Smrg        else if (pTrigger->test_type == XSyncNegativeTransition &&
1083f7df2e56Smrg                 ct != XSyncCounterNeverIncreases) {
10847e31ba66Smrg            if (pCounter->value >= pTrigger->test_value &&
10857e31ba66Smrg                pTrigger->test_value > psci->bracket_less) {
1086f7df2e56Smrg                    /*
1087f7df2e56Smrg                     * If the value is exactly equal to our threshold, we want one
1088f7df2e56Smrg                     * more event in the negative direction to ensure we pick up
1089f7df2e56Smrg                     * when the value is less than this threshold.
1090f7df2e56Smrg                     */
1091f7df2e56Smrg                    psci->bracket_less = pTrigger->test_value;
1092f7df2e56Smrg                    pnewltval = &psci->bracket_less;
1093f7df2e56Smrg            }
10947e31ba66Smrg            else if (pCounter->value < pTrigger->test_value &&
10957e31ba66Smrg                     pTrigger->test_value < psci->bracket_greater) {
1096f7df2e56Smrg                    psci->bracket_greater = pTrigger->test_value;
1097f7df2e56Smrg                    pnewgtval = &psci->bracket_greater;
1098f7df2e56Smrg            }
1099f7df2e56Smrg        }
1100a0d10bb6Smrg        else if (pTrigger->test_type == XSyncPositiveTransition &&
1101f7df2e56Smrg                 ct != XSyncCounterNeverDecreases) {
11027e31ba66Smrg            if (pCounter->value <= pTrigger->test_value &&
11037e31ba66Smrg                pTrigger->test_value < psci->bracket_greater) {
1104f7df2e56Smrg                    /*
1105f7df2e56Smrg                     * If the value is exactly equal to our threshold, we
1106f7df2e56Smrg                     * want one more event in the positive direction to
1107f7df2e56Smrg                     * ensure we pick up when the value *exceeds* this
1108f7df2e56Smrg                     * threshold.
1109f7df2e56Smrg                     */
1110f7df2e56Smrg                    psci->bracket_greater = pTrigger->test_value;
1111f7df2e56Smrg                    pnewgtval = &psci->bracket_greater;
1112f7df2e56Smrg            }
11137e31ba66Smrg            else if (pCounter->value > pTrigger->test_value &&
11147e31ba66Smrg                     pTrigger->test_value > psci->bracket_less) {
1115f7df2e56Smrg                    psci->bracket_less = pTrigger->test_value;
1116f7df2e56Smrg                    pnewltval = &psci->bracket_less;
1117f7df2e56Smrg            }
1118f7df2e56Smrg        }
1119f7df2e56Smrg    }                           /* end for each trigger */
1120f7df2e56Smrg
1121f7df2e56Smrg    (*psci->BracketValues) ((void *) pCounter, pnewltval, pnewgtval);
1122f7df2e56Smrg
112305b261ecSmrg}
112405b261ecSmrg
112505b261ecSmrg/*
112605b261ecSmrg * *****  Resource delete functions
112705b261ecSmrg */
112805b261ecSmrg
112905b261ecSmrg/* ARGSUSED */
113005b261ecSmrgstatic int
11314202a189SmrgFreeAlarm(void *addr, XID id)
113205b261ecSmrg{
1133f7df2e56Smrg    SyncAlarm *pAlarm = (SyncAlarm *) addr;
113405b261ecSmrg
113505b261ecSmrg    pAlarm->state = XSyncAlarmDestroyed;
113605b261ecSmrg
113705b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
113805b261ecSmrg
113905b261ecSmrg    /* delete event selections */
114005b261ecSmrg
114105b261ecSmrg    while (pAlarm->pEventClients)
1142f7df2e56Smrg        FreeResource(pAlarm->pEventClients->delete_id, RT_NONE);
114305b261ecSmrg
114465b04b38Smrg    SyncDeleteTriggerFromSyncObject(&pAlarm->trigger);
114505b261ecSmrg
11464202a189Smrg    free(pAlarm);
114705b261ecSmrg    return Success;
114805b261ecSmrg}
114905b261ecSmrg
115005b261ecSmrg/*
115105b261ecSmrg * ** Cleanup after the destruction of a Counter
115205b261ecSmrg */
115305b261ecSmrg/* ARGSUSED */
115405b261ecSmrgstatic int
11554202a189SmrgFreeCounter(void *env, XID id)
115605b261ecSmrg{
1157f7df2e56Smrg    SyncCounter *pCounter = (SyncCounter *) env;
115805b261ecSmrg
115965b04b38Smrg    pCounter->sync.beingDestroyed = TRUE;
11604e185dc0Smrg
11614e185dc0Smrg    if (pCounter->sync.initialized) {
11624e185dc0Smrg        SyncTriggerList *ptl, *pnext;
11634e185dc0Smrg
11644e185dc0Smrg        /* tell all the counter's triggers that counter has been destroyed */
11654e185dc0Smrg        for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) {
11664e185dc0Smrg            (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger);
11674e185dc0Smrg            pnext = ptl->next;
11684e185dc0Smrg            free(ptl); /* destroy the trigger list as we go */
11694e185dc0Smrg        }
11704e185dc0Smrg        if (IsSystemCounter(pCounter)) {
11714e185dc0Smrg            xorg_list_del(&pCounter->pSysCounterInfo->entry);
11724e185dc0Smrg            free(pCounter->pSysCounterInfo->name);
11734e185dc0Smrg            free(pCounter->pSysCounterInfo->private);
11744e185dc0Smrg            free(pCounter->pSysCounterInfo);
11754e185dc0Smrg        }
117605b261ecSmrg    }
11774e185dc0Smrg
11784202a189Smrg    free(pCounter);
117905b261ecSmrg    return Success;
118005b261ecSmrg}
118105b261ecSmrg
118205b261ecSmrg/*
118305b261ecSmrg * ** Cleanup after Await
118405b261ecSmrg */
118505b261ecSmrg/* ARGSUSED */
118605b261ecSmrgstatic int
11874202a189SmrgFreeAwait(void *addr, XID id)
118805b261ecSmrg{
118905b261ecSmrg    SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr;
119005b261ecSmrg    SyncAwait *pAwait;
119105b261ecSmrg    int numwaits;
119205b261ecSmrg
1193f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await; /* first await on list */
119405b261ecSmrg
119505b261ecSmrg    /* remove triggers from counters */
119605b261ecSmrg
119705b261ecSmrg    for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits;
1198f7df2e56Smrg         numwaits--, pAwait++) {
1199f7df2e56Smrg        /* If the counter is being destroyed, FreeCounter will delete
1200f7df2e56Smrg         * the trigger list itself, so don't do it here.
1201f7df2e56Smrg         */
1202f7df2e56Smrg        SyncObject *pSync = pAwait->trigger.pSync;
1203f7df2e56Smrg
1204f7df2e56Smrg        if (pSync && !pSync->beingDestroyed)
1205f7df2e56Smrg            SyncDeleteTriggerFromSyncObject(&pAwait->trigger);
120605b261ecSmrg    }
12074202a189Smrg    free(pAwaitUnion);
120805b261ecSmrg    return Success;
120905b261ecSmrg}
121005b261ecSmrg
121105b261ecSmrg/* loosely based on dix/events.c/OtherClientGone */
121205b261ecSmrgstatic int
12134202a189SmrgFreeAlarmClient(void *value, XID id)
121405b261ecSmrg{
1215f7df2e56Smrg    SyncAlarm *pAlarm = (SyncAlarm *) value;
121605b261ecSmrg    SyncAlarmClientList *pCur, *pPrev;
121705b261ecSmrg
121805b261ecSmrg    for (pPrev = NULL, pCur = pAlarm->pEventClients;
1219f7df2e56Smrg         pCur; pPrev = pCur, pCur = pCur->next) {
1220f7df2e56Smrg        if (pCur->delete_id == id) {
1221f7df2e56Smrg            if (pPrev)
1222f7df2e56Smrg                pPrev->next = pCur->next;
1223f7df2e56Smrg            else
1224f7df2e56Smrg                pAlarm->pEventClients = pCur->next;
1225f7df2e56Smrg            free(pCur);
1226f7df2e56Smrg            return Success;
1227f7df2e56Smrg        }
122805b261ecSmrg    }
122905b261ecSmrg    FatalError("alarm client not on event list");
1230f7df2e56Smrg /*NOTREACHED*/}
123105b261ecSmrg
123205b261ecSmrg/*
123305b261ecSmrg * *****  Proc functions
123405b261ecSmrg */
123505b261ecSmrg
123605b261ecSmrg/*
123705b261ecSmrg * ** Initialize the extension
123805b261ecSmrg */
12394202a189Smrgstatic int
12404202a189SmrgProcSyncInitialize(ClientPtr client)
124105b261ecSmrg{
1242f7df2e56Smrg    xSyncInitializeReply rep = {
1243f7df2e56Smrg        .type = X_Reply,
1244f7df2e56Smrg        .sequenceNumber = client->sequence,
1245f7df2e56Smrg        .length = 0,
1246f7df2e56Smrg        .majorVersion = SERVER_SYNC_MAJOR_VERSION,
1247f7df2e56Smrg        .minorVersion = SERVER_SYNC_MINOR_VERSION,
1248f7df2e56Smrg    };
124905b261ecSmrg
125005b261ecSmrg    REQUEST_SIZE_MATCH(xSyncInitializeReq);
125105b261ecSmrg
1252f7df2e56Smrg    if (client->swapped) {
1253f7df2e56Smrg        swaps(&rep.sequenceNumber);
125405b261ecSmrg    }
1255f7df2e56Smrg    WriteToClient(client, sizeof(rep), &rep);
12564202a189Smrg    return Success;
125705b261ecSmrg}
125805b261ecSmrg
125905b261ecSmrg/*
126005b261ecSmrg * ** Get list of system counters available through the extension
126105b261ecSmrg */
12624202a189Smrgstatic int
12634202a189SmrgProcSyncListSystemCounters(ClientPtr client)
126405b261ecSmrg{
1265f7df2e56Smrg    xSyncListSystemCountersReply rep = {
1266f7df2e56Smrg        .type = X_Reply,
1267f7df2e56Smrg        .sequenceNumber = client->sequence,
1268f7df2e56Smrg        .nCounters = 0,
1269f7df2e56Smrg    };
1270f7df2e56Smrg    SysCounterInfo *psci;
1271f7df2e56Smrg    int len = 0;
127205b261ecSmrg    xSyncSystemCounter *list = NULL, *walklist = NULL;
12734202a189Smrg
127405b261ecSmrg    REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
127505b261ecSmrg
1276f7df2e56Smrg    xorg_list_for_each_entry(psci, &SysCounterList, entry) {
1277f7df2e56Smrg        /* pad to 4 byte boundary */
1278f7df2e56Smrg        len += pad_to_int32(sz_xSyncSystemCounter + strlen(psci->name));
1279f7df2e56Smrg        ++rep.nCounters;
128005b261ecSmrg    }
128105b261ecSmrg
1282f7df2e56Smrg    if (len) {
1283f7df2e56Smrg        walklist = list = malloc(len);
1284f7df2e56Smrg        if (!list)
1285f7df2e56Smrg            return BadAlloc;
128605b261ecSmrg    }
128705b261ecSmrg
12884202a189Smrg    rep.length = bytes_to_int32(len);
128905b261ecSmrg
1290f7df2e56Smrg    if (client->swapped) {
1291f7df2e56Smrg        swaps(&rep.sequenceNumber);
1292f7df2e56Smrg        swapl(&rep.length);
1293f7df2e56Smrg        swapl(&rep.nCounters);
129405b261ecSmrg    }
129505b261ecSmrg
1296f7df2e56Smrg    xorg_list_for_each_entry(psci, &SysCounterList, entry) {
1297f7df2e56Smrg        int namelen;
1298f7df2e56Smrg        char *pname_in_reply;
129905b261ecSmrg
1300f7df2e56Smrg        walklist->counter = psci->pCounter->sync.id;
13017e31ba66Smrg        walklist->resolution_hi = psci->resolution >> 32;
13027e31ba66Smrg        walklist->resolution_lo = psci->resolution;
1303f7df2e56Smrg        namelen = strlen(psci->name);
1304f7df2e56Smrg        walklist->name_length = namelen;
130505b261ecSmrg
1306f7df2e56Smrg        if (client->swapped) {
1307f7df2e56Smrg            swapl(&walklist->counter);
1308f7df2e56Smrg            swapl(&walklist->resolution_hi);
1309f7df2e56Smrg            swapl(&walklist->resolution_lo);
1310f7df2e56Smrg            swaps(&walklist->name_length);
1311f7df2e56Smrg        }
131205b261ecSmrg
1313f7df2e56Smrg        pname_in_reply = ((char *) walklist) + sz_xSyncSystemCounter;
1314f7df2e56Smrg        strncpy(pname_in_reply, psci->name, namelen);
1315f7df2e56Smrg        walklist = (xSyncSystemCounter *) (((char *) walklist) +
1316f7df2e56Smrg                                           pad_to_int32(sz_xSyncSystemCounter +
1317f7df2e56Smrg                                                        namelen));
131805b261ecSmrg    }
131905b261ecSmrg
1320f7df2e56Smrg    WriteToClient(client, sizeof(rep), &rep);
1321f7df2e56Smrg    if (len) {
1322f7df2e56Smrg        WriteToClient(client, len, list);
1323f7df2e56Smrg        free(list);
132405b261ecSmrg    }
132505b261ecSmrg
13264202a189Smrg    return Success;
132705b261ecSmrg}
132805b261ecSmrg
132905b261ecSmrg/*
133005b261ecSmrg * ** Set client Priority
133105b261ecSmrg */
13324202a189Smrgstatic int
13334202a189SmrgProcSyncSetPriority(ClientPtr client)
133405b261ecSmrg{
133505b261ecSmrg    REQUEST(xSyncSetPriorityReq);
133605b261ecSmrg    ClientPtr priorityclient;
133705b261ecSmrg    int rc;
133805b261ecSmrg
133905b261ecSmrg    REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
134005b261ecSmrg
134105b261ecSmrg    if (stuff->id == None)
1342f7df2e56Smrg        priorityclient = client;
134305b261ecSmrg    else {
1344f7df2e56Smrg        rc = dixLookupClient(&priorityclient, stuff->id, client,
1345f7df2e56Smrg                             DixSetAttrAccess);
1346f7df2e56Smrg        if (rc != Success)
1347f7df2e56Smrg            return rc;
134805b261ecSmrg    }
134905b261ecSmrg
1350f7df2e56Smrg    if (priorityclient->priority != stuff->priority) {
1351f7df2e56Smrg        priorityclient->priority = stuff->priority;
135205b261ecSmrg
1353f7df2e56Smrg        /*  The following will force the server back into WaitForSomething
1354f7df2e56Smrg         *  so that the change in this client's priority is immediately
1355f7df2e56Smrg         *  reflected.
1356f7df2e56Smrg         */
1357f7df2e56Smrg        isItTimeToYield = TRUE;
1358f7df2e56Smrg        dispatchException |= DE_PRIORITYCHANGE;
135905b261ecSmrg    }
136005b261ecSmrg    return Success;
136105b261ecSmrg}
136205b261ecSmrg
136305b261ecSmrg/*
136405b261ecSmrg * ** Get client Priority
136505b261ecSmrg */
13664202a189Smrgstatic int
13674202a189SmrgProcSyncGetPriority(ClientPtr client)
136805b261ecSmrg{
136905b261ecSmrg    REQUEST(xSyncGetPriorityReq);
137005b261ecSmrg    xSyncGetPriorityReply rep;
137105b261ecSmrg    ClientPtr priorityclient;
137205b261ecSmrg    int rc;
137305b261ecSmrg
137405b261ecSmrg    REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
137505b261ecSmrg
137605b261ecSmrg    if (stuff->id == None)
1377f7df2e56Smrg        priorityclient = client;
137805b261ecSmrg    else {
1379f7df2e56Smrg        rc = dixLookupClient(&priorityclient, stuff->id, client,
1380f7df2e56Smrg                             DixGetAttrAccess);
1381f7df2e56Smrg        if (rc != Success)
1382f7df2e56Smrg            return rc;
138305b261ecSmrg    }
138405b261ecSmrg
1385f7df2e56Smrg    rep = (xSyncGetPriorityReply) {
1386f7df2e56Smrg        .type = X_Reply,
1387f7df2e56Smrg        .sequenceNumber = client->sequence,
1388f7df2e56Smrg        .length = 0,
1389f7df2e56Smrg        .priority = priorityclient->priority
1390f7df2e56Smrg    };
139105b261ecSmrg
1392f7df2e56Smrg    if (client->swapped) {
1393f7df2e56Smrg        swaps(&rep.sequenceNumber);
1394f7df2e56Smrg        swapl(&rep.priority);
139505b261ecSmrg    }
139605b261ecSmrg
1397f7df2e56Smrg    WriteToClient(client, sizeof(xSyncGetPriorityReply), &rep);
139805b261ecSmrg
13994202a189Smrg    return Success;
140005b261ecSmrg}
140105b261ecSmrg
140205b261ecSmrg/*
140305b261ecSmrg * ** Create a new counter
140405b261ecSmrg */
14054202a189Smrgstatic int
14064202a189SmrgProcSyncCreateCounter(ClientPtr client)
140705b261ecSmrg{
140805b261ecSmrg    REQUEST(xSyncCreateCounterReq);
14097e31ba66Smrg    int64_t initial;
141005b261ecSmrg
141105b261ecSmrg    REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
141205b261ecSmrg
141305b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->cid, client);
141405b261ecSmrg
14157e31ba66Smrg    initial = ((int64_t)stuff->initial_value_hi << 32) | stuff->initial_value_lo;
14167e31ba66Smrg
141705b261ecSmrg    if (!SyncCreateCounter(client, stuff->cid, initial))
1418f7df2e56Smrg        return BadAlloc;
141905b261ecSmrg
14204202a189Smrg    return Success;
142105b261ecSmrg}
142205b261ecSmrg
142305b261ecSmrg/*
142405b261ecSmrg * ** Set Counter value
142505b261ecSmrg */
14264202a189Smrgstatic int
14274202a189SmrgProcSyncSetCounter(ClientPtr client)
142805b261ecSmrg{
142905b261ecSmrg    REQUEST(xSyncSetCounterReq);
1430f7df2e56Smrg    SyncCounter *pCounter;
14317e31ba66Smrg    int64_t newvalue;
1432f7df2e56Smrg    int rc;
143305b261ecSmrg
143405b261ecSmrg    REQUEST_SIZE_MATCH(xSyncSetCounterReq);
143505b261ecSmrg
1436f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter,
1437f7df2e56Smrg                                 client, DixWriteAccess);
14384202a189Smrg    if (rc != Success)
1439f7df2e56Smrg        return rc;
144005b261ecSmrg
1441f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
1442f7df2e56Smrg        client->errorValue = stuff->cid;
1443f7df2e56Smrg        return BadAccess;
144405b261ecSmrg    }
144505b261ecSmrg
14467e31ba66Smrg    newvalue = ((int64_t)stuff->value_hi << 32) | stuff->value_lo;
144705b261ecSmrg    SyncChangeCounter(pCounter, newvalue);
144805b261ecSmrg    return Success;
144905b261ecSmrg}
145005b261ecSmrg
145105b261ecSmrg/*
145205b261ecSmrg * ** Change Counter value
145305b261ecSmrg */
14544202a189Smrgstatic int
14554202a189SmrgProcSyncChangeCounter(ClientPtr client)
145605b261ecSmrg{
145705b261ecSmrg    REQUEST(xSyncChangeCounterReq);
1458f7df2e56Smrg    SyncCounter *pCounter;
14597e31ba66Smrg    int64_t newvalue;
1460f7df2e56Smrg    Bool overflow;
1461f7df2e56Smrg    int rc;
146205b261ecSmrg
146305b261ecSmrg    REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
146405b261ecSmrg
1465f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter,
1466f7df2e56Smrg                                 client, DixWriteAccess);
14674202a189Smrg    if (rc != Success)
1468f7df2e56Smrg        return rc;
146905b261ecSmrg
1470f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
1471f7df2e56Smrg        client->errorValue = stuff->cid;
1472f7df2e56Smrg        return BadAccess;
147305b261ecSmrg    }
147405b261ecSmrg
14757e31ba66Smrg    newvalue = (int64_t)stuff->value_hi << 32 | stuff->value_lo;
14767e31ba66Smrg    overflow = checked_int64_add(&newvalue, newvalue, pCounter->value);
1477f7df2e56Smrg    if (overflow) {
1478f7df2e56Smrg        /* XXX 64 bit value can't fit in 32 bits; do the best we can */
1479f7df2e56Smrg        client->errorValue = stuff->value_hi;
1480f7df2e56Smrg        return BadValue;
148105b261ecSmrg    }
148205b261ecSmrg    SyncChangeCounter(pCounter, newvalue);
148305b261ecSmrg    return Success;
148405b261ecSmrg}
148505b261ecSmrg
148605b261ecSmrg/*
148705b261ecSmrg * ** Destroy a counter
148805b261ecSmrg */
14894202a189Smrgstatic int
14904202a189SmrgProcSyncDestroyCounter(ClientPtr client)
149105b261ecSmrg{
149205b261ecSmrg    REQUEST(xSyncDestroyCounterReq);
1493f7df2e56Smrg    SyncCounter *pCounter;
14944202a189Smrg    int rc;
149505b261ecSmrg
149605b261ecSmrg    REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
149705b261ecSmrg
1498f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pCounter, stuff->counter,
1499f7df2e56Smrg                                 RTCounter, client, DixDestroyAccess);
15004202a189Smrg    if (rc != Success)
1501f7df2e56Smrg        return rc;
15024202a189Smrg
1503f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
1504f7df2e56Smrg        client->errorValue = stuff->counter;
1505f7df2e56Smrg        return BadAccess;
150605b261ecSmrg    }
150765b04b38Smrg    FreeResource(pCounter->sync.id, RT_NONE);
150805b261ecSmrg    return Success;
150905b261ecSmrg}
151005b261ecSmrg
1511f7df2e56Smrgstatic SyncAwaitUnion *
151265b04b38SmrgSyncAwaitPrologue(ClientPtr client, int items)
151365b04b38Smrg{
151465b04b38Smrg    SyncAwaitUnion *pAwaitUnion;
151565b04b38Smrg
151665b04b38Smrg    /*  all the memory for the entire await list is allocated
151765b04b38Smrg     *  here in one chunk
151865b04b38Smrg     */
1519f7df2e56Smrg    pAwaitUnion = xallocarray(items + 1, sizeof(SyncAwaitUnion));
152065b04b38Smrg    if (!pAwaitUnion)
1521f7df2e56Smrg        return NULL;
152265b04b38Smrg
152365b04b38Smrg    /* first item is the header, remainder are real wait conditions */
152465b04b38Smrg
152565b04b38Smrg    pAwaitUnion->header.delete_id = FakeClientID(client->index);
152665b04b38Smrg    pAwaitUnion->header.client = client;
152765b04b38Smrg    pAwaitUnion->header.num_waitconditions = 0;
152865b04b38Smrg
152965b04b38Smrg    if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion))
1530f7df2e56Smrg        return NULL;
153165b04b38Smrg
153265b04b38Smrg    return pAwaitUnion;
153365b04b38Smrg}
153465b04b38Smrg
153565b04b38Smrgstatic void
1536f7df2e56SmrgSyncAwaitEpilogue(ClientPtr client, int items, SyncAwaitUnion * pAwaitUnion)
153765b04b38Smrg{
153865b04b38Smrg    SyncAwait *pAwait;
153965b04b38Smrg    int i;
154065b04b38Smrg
154165b04b38Smrg    IgnoreClient(client);
154265b04b38Smrg
154365b04b38Smrg    /* see if any of the triggers are already true */
154465b04b38Smrg
1545f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await; /* skip over header */
1546f7df2e56Smrg    for (i = 0; i < items; i++, pAwait++) {
15477e31ba66Smrg        int64_t value;
1548f7df2e56Smrg
1549f7df2e56Smrg        /*  don't have to worry about NULL counters because the request
1550f7df2e56Smrg         *  errors before we get here out if they occur
1551f7df2e56Smrg         */
1552f7df2e56Smrg        switch (pAwait->trigger.pSync->type) {
1553f7df2e56Smrg        case SYNC_COUNTER:
1554f7df2e56Smrg            value = ((SyncCounter *) pAwait->trigger.pSync)->value;
1555f7df2e56Smrg            break;
1556f7df2e56Smrg        default:
15577e31ba66Smrg            value = 0;
1558f7df2e56Smrg        }
155965b04b38Smrg
1560f7df2e56Smrg        if ((*pAwait->trigger.CheckTrigger) (&pAwait->trigger, value)) {
1561f7df2e56Smrg            (*pAwait->trigger.TriggerFired) (&pAwait->trigger);
1562f7df2e56Smrg            break;              /* once is enough */
1563f7df2e56Smrg        }
156465b04b38Smrg    }
156565b04b38Smrg}
156605b261ecSmrg
156705b261ecSmrg/*
156805b261ecSmrg * ** Await
156905b261ecSmrg */
15704202a189Smrgstatic int
15714202a189SmrgProcSyncAwait(ClientPtr client)
157205b261ecSmrg{
157305b261ecSmrg    REQUEST(xSyncAwaitReq);
1574f7df2e56Smrg    int len, items;
1575f7df2e56Smrg    int i;
157605b261ecSmrg    xSyncWaitCondition *pProtocolWaitConds;
157705b261ecSmrg    SyncAwaitUnion *pAwaitUnion;
1578f7df2e56Smrg    SyncAwait *pAwait;
1579f7df2e56Smrg    int status;
158005b261ecSmrg
158105b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
158205b261ecSmrg
158305b261ecSmrg    len = client->req_len << 2;
158405b261ecSmrg    len -= sz_xSyncAwaitReq;
158505b261ecSmrg    items = len / sz_xSyncWaitCondition;
158605b261ecSmrg
1587f7df2e56Smrg    if (items * sz_xSyncWaitCondition != len) {
1588f7df2e56Smrg        return BadLength;
158905b261ecSmrg    }
1590f7df2e56Smrg    if (items == 0) {
1591f7df2e56Smrg        client->errorValue = items;     /* XXX protocol change */
1592f7df2e56Smrg        return BadValue;
159305b261ecSmrg    }
159405b261ecSmrg
159565b04b38Smrg    if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
1596f7df2e56Smrg        return BadAlloc;
159705b261ecSmrg
159805b261ecSmrg    /* don't need to do any more memory allocation for this request! */
159905b261ecSmrg
1600f7df2e56Smrg    pProtocolWaitConds = (xSyncWaitCondition *) &stuff[1];
1601f7df2e56Smrg
1602f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await; /* skip over header */
1603f7df2e56Smrg    for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++) {
1604f7df2e56Smrg        if (pProtocolWaitConds->counter == None) {      /* XXX protocol change */
1605f7df2e56Smrg            /*  this should take care of removing any triggers created by
1606f7df2e56Smrg             *  this request that have already been registered on sync objects
1607f7df2e56Smrg             */
1608f7df2e56Smrg            FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
1609f7df2e56Smrg            client->errorValue = pProtocolWaitConds->counter;
1610f7df2e56Smrg            return SyncErrorBase + XSyncBadCounter;
1611f7df2e56Smrg        }
1612f7df2e56Smrg
1613f7df2e56Smrg        /* sanity checks are in SyncInitTrigger */
1614f7df2e56Smrg        pAwait->trigger.pSync = NULL;
1615f7df2e56Smrg        pAwait->trigger.value_type = pProtocolWaitConds->value_type;
16167e31ba66Smrg        pAwait->trigger.wait_value =
16177e31ba66Smrg            ((int64_t)pProtocolWaitConds->wait_value_hi << 32) |
16187e31ba66Smrg            pProtocolWaitConds->wait_value_lo;
1619f7df2e56Smrg        pAwait->trigger.test_type = pProtocolWaitConds->test_type;
1620f7df2e56Smrg
1621f7df2e56Smrg        status = SyncInitTrigger(client, &pAwait->trigger,
1622f7df2e56Smrg                                 pProtocolWaitConds->counter, RTCounter,
1623f7df2e56Smrg                                 XSyncCAAllTrigger);
1624f7df2e56Smrg        if (status != Success) {
1625f7df2e56Smrg            /*  this should take care of removing any triggers created by
1626f7df2e56Smrg             *  this request that have already been registered on sync objects
1627f7df2e56Smrg             */
1628f7df2e56Smrg            FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
1629f7df2e56Smrg            return status;
1630f7df2e56Smrg        }
1631f7df2e56Smrg        /* this is not a mistake -- same function works for both cases */
1632f7df2e56Smrg        pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
1633f7df2e56Smrg        pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
16347e31ba66Smrg        pAwait->event_threshold =
16357e31ba66Smrg            ((int64_t) pProtocolWaitConds->event_threshold_hi << 32) |
16367e31ba66Smrg            pProtocolWaitConds->event_threshold_lo;
16377e31ba66Smrg
1638f7df2e56Smrg        pAwait->pHeader = &pAwaitUnion->header;
1639f7df2e56Smrg        pAwaitUnion->header.num_waitconditions++;
164005b261ecSmrg    }
164105b261ecSmrg
164265b04b38Smrg    SyncAwaitEpilogue(client, items, pAwaitUnion);
164305b261ecSmrg
164405b261ecSmrg    return Success;
164505b261ecSmrg}
164605b261ecSmrg
164705b261ecSmrg/*
164805b261ecSmrg * ** Query a counter
164905b261ecSmrg */
16504202a189Smrgstatic int
16514202a189SmrgProcSyncQueryCounter(ClientPtr client)
165205b261ecSmrg{
165305b261ecSmrg    REQUEST(xSyncQueryCounterReq);
165405b261ecSmrg    xSyncQueryCounterReply rep;
1655f7df2e56Smrg    SyncCounter *pCounter;
16564202a189Smrg    int rc;
165705b261ecSmrg
165805b261ecSmrg    REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
165905b261ecSmrg
1660f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pCounter, stuff->counter,
1661f7df2e56Smrg                                 RTCounter, client, DixReadAccess);
16624202a189Smrg    if (rc != Success)
1663f7df2e56Smrg        return rc;
166405b261ecSmrg
166505b261ecSmrg    /* if system counter, ask it what the current value is */
1666f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
1667f7df2e56Smrg        (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter,
1668f7df2e56Smrg                                                  &pCounter->value);
1669f7df2e56Smrg    }
1670f7df2e56Smrg
1671f7df2e56Smrg    rep = (xSyncQueryCounterReply) {
1672f7df2e56Smrg        .type = X_Reply,
1673f7df2e56Smrg        .sequenceNumber = client->sequence,
1674f7df2e56Smrg        .length = 0,
16757e31ba66Smrg        .value_hi = pCounter->value >> 32,
16767e31ba66Smrg        .value_lo = pCounter->value
1677f7df2e56Smrg    };
1678f7df2e56Smrg
1679f7df2e56Smrg    if (client->swapped) {
1680f7df2e56Smrg        swaps(&rep.sequenceNumber);
1681f7df2e56Smrg        swapl(&rep.length);
1682f7df2e56Smrg        swapl(&rep.value_hi);
1683f7df2e56Smrg        swapl(&rep.value_lo);
1684f7df2e56Smrg    }
1685f7df2e56Smrg    WriteToClient(client, sizeof(xSyncQueryCounterReply), &rep);
16864202a189Smrg    return Success;
168705b261ecSmrg}
168805b261ecSmrg
168905b261ecSmrg/*
169005b261ecSmrg * ** Create Alarm
169105b261ecSmrg */
16924202a189Smrgstatic int
16934202a189SmrgProcSyncCreateAlarm(ClientPtr client)
169405b261ecSmrg{
169505b261ecSmrg    REQUEST(xSyncCreateAlarmReq);
1696f7df2e56Smrg    SyncAlarm *pAlarm;
1697f7df2e56Smrg    int status;
1698f7df2e56Smrg    unsigned long len, vmask;
1699f7df2e56Smrg    SyncTrigger *pTrigger;
170005b261ecSmrg
170105b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
170205b261ecSmrg
170305b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->id, client);
170405b261ecSmrg
170505b261ecSmrg    vmask = stuff->valueMask;
17064202a189Smrg    len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq));
170705b261ecSmrg    /* the "extra" call to Ones accounts for the presence of 64 bit values */
1708f7df2e56Smrg    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta))))
1709f7df2e56Smrg        return BadLength;
171005b261ecSmrg
1711f7df2e56Smrg    if (!(pAlarm = malloc(sizeof(SyncAlarm)))) {
1712f7df2e56Smrg        return BadAlloc;
171305b261ecSmrg    }
171405b261ecSmrg
171505b261ecSmrg    /* set up defaults */
171605b261ecSmrg
171705b261ecSmrg    pTrigger = &pAlarm->trigger;
171865b04b38Smrg    pTrigger->pSync = NULL;
171905b261ecSmrg    pTrigger->value_type = XSyncAbsolute;
17207e31ba66Smrg    pTrigger->wait_value = 0;
172105b261ecSmrg    pTrigger->test_type = XSyncPositiveComparison;
172205b261ecSmrg    pTrigger->TriggerFired = SyncAlarmTriggerFired;
172305b261ecSmrg    pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed;
172465b04b38Smrg    status = SyncInitTrigger(client, pTrigger, None, RTCounter,
1725f7df2e56Smrg                             XSyncCAAllTrigger);
1726f7df2e56Smrg    if (status != Success) {
1727f7df2e56Smrg        free(pAlarm);
1728f7df2e56Smrg        return status;
172905b261ecSmrg    }
173005b261ecSmrg
173105b261ecSmrg    pAlarm->client = client;
173205b261ecSmrg    pAlarm->alarm_id = stuff->id;
17337e31ba66Smrg    pAlarm->delta = 1;
173405b261ecSmrg    pAlarm->events = TRUE;
173505b261ecSmrg    pAlarm->state = XSyncAlarmInactive;
173605b261ecSmrg    pAlarm->pEventClients = NULL;
173705b261ecSmrg    status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
1738f7df2e56Smrg                                       (CARD32 *) &stuff[1]);
1739f7df2e56Smrg    if (status != Success) {
1740f7df2e56Smrg        free(pAlarm);
1741f7df2e56Smrg        return status;
174205b261ecSmrg    }
174305b261ecSmrg
174405b261ecSmrg    if (!AddResource(stuff->id, RTAlarm, pAlarm))
1745f7df2e56Smrg        return BadAlloc;
174605b261ecSmrg
174705b261ecSmrg    /*  see if alarm already triggered.  NULL counter will not trigger
174805b261ecSmrg     *  in CreateAlarm and sets alarm state to Inactive.
174905b261ecSmrg     */
175005b261ecSmrg
1751f7df2e56Smrg    if (!pTrigger->pSync) {
1752f7df2e56Smrg        pAlarm->state = XSyncAlarmInactive;     /* XXX protocol change */
175305b261ecSmrg    }
1754f7df2e56Smrg    else {
1755f7df2e56Smrg        SyncCounter *pCounter;
175665b04b38Smrg
1757f7df2e56Smrg        if (!SyncCheckWarnIsCounter(pTrigger->pSync,
1758f7df2e56Smrg                                    WARN_INVALID_COUNTER_ALARM)) {
1759f7df2e56Smrg            FreeResource(stuff->id, RT_NONE);
1760f7df2e56Smrg            return BadAlloc;
1761f7df2e56Smrg        }
176265b04b38Smrg
1763f7df2e56Smrg        pCounter = (SyncCounter *) pTrigger->pSync;
176465b04b38Smrg
1765f7df2e56Smrg        if ((*pTrigger->CheckTrigger) (pTrigger, pCounter->value))
1766f7df2e56Smrg            (*pTrigger->TriggerFired) (pTrigger);
176705b261ecSmrg    }
176805b261ecSmrg
176905b261ecSmrg    return Success;
177005b261ecSmrg}
177105b261ecSmrg
177205b261ecSmrg/*
177305b261ecSmrg * ** Change Alarm
177405b261ecSmrg */
17754202a189Smrgstatic int
17764202a189SmrgProcSyncChangeAlarm(ClientPtr client)
177705b261ecSmrg{
177805b261ecSmrg    REQUEST(xSyncChangeAlarmReq);
1779f7df2e56Smrg    SyncAlarm *pAlarm;
178065b04b38Smrg    SyncCounter *pCounter = NULL;
1781f7df2e56Smrg    long vmask;
1782f7df2e56Smrg    int len, status;
178305b261ecSmrg
178405b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
178505b261ecSmrg
1786f7df2e56Smrg    status = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm,
1787f7df2e56Smrg                                     client, DixWriteAccess);
17884202a189Smrg    if (status != Success)
1789f7df2e56Smrg        return status;
179005b261ecSmrg
179105b261ecSmrg    vmask = stuff->valueMask;
17924202a189Smrg    len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq));
179305b261ecSmrg    /* the "extra" call to Ones accounts for the presence of 64 bit values */
1794f7df2e56Smrg    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta))))
1795f7df2e56Smrg        return BadLength;
179605b261ecSmrg
17974202a189Smrg    if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
1798f7df2e56Smrg                                            (CARD32 *) &stuff[1])) != Success)
1799f7df2e56Smrg        return status;
180005b261ecSmrg
180165b04b38Smrg    if (SyncCheckWarnIsCounter(pAlarm->trigger.pSync,
1802f7df2e56Smrg                               WARN_INVALID_COUNTER_ALARM))
1803f7df2e56Smrg        pCounter = (SyncCounter *) pAlarm->trigger.pSync;
180465b04b38Smrg
180505b261ecSmrg    /*  see if alarm already triggered.  NULL counter WILL trigger
180605b261ecSmrg     *  in ChangeAlarm.
180705b261ecSmrg     */
180805b261ecSmrg
180965b04b38Smrg    if (!pCounter ||
1810f7df2e56Smrg        (*pAlarm->trigger.CheckTrigger) (&pAlarm->trigger, pCounter->value)) {
1811f7df2e56Smrg        (*pAlarm->trigger.TriggerFired) (&pAlarm->trigger);
181205b261ecSmrg    }
181305b261ecSmrg    return Success;
181405b261ecSmrg}
181505b261ecSmrg
18164202a189Smrgstatic int
18174202a189SmrgProcSyncQueryAlarm(ClientPtr client)
181805b261ecSmrg{
181905b261ecSmrg    REQUEST(xSyncQueryAlarmReq);
1820f7df2e56Smrg    SyncAlarm *pAlarm;
182105b261ecSmrg    xSyncQueryAlarmReply rep;
1822f7df2e56Smrg    SyncTrigger *pTrigger;
18234202a189Smrg    int rc;
182405b261ecSmrg
182505b261ecSmrg    REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
182605b261ecSmrg
1827f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm,
1828f7df2e56Smrg                                 client, DixReadAccess);
18294202a189Smrg    if (rc != Success)
1830f7df2e56Smrg        return rc;
183105b261ecSmrg
183205b261ecSmrg    pTrigger = &pAlarm->trigger;
1833f7df2e56Smrg    rep = (xSyncQueryAlarmReply) {
1834f7df2e56Smrg        .type = X_Reply,
1835f7df2e56Smrg        .sequenceNumber = client->sequence,
1836f7df2e56Smrg        .length =
1837f7df2e56Smrg          bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply)),
1838f7df2e56Smrg        .counter = (pTrigger->pSync) ? pTrigger->pSync->id : None,
1839f7df2e56Smrg
1840f7df2e56Smrg#if 0  /* XXX unclear what to do, depends on whether relative value-types
1841f7df2e56Smrg        * are "consumed" immediately and are considered absolute from then
1842f7df2e56Smrg        * on.
1843f7df2e56Smrg        */
1844f7df2e56Smrg        .value_type = pTrigger->value_type,
18457e31ba66Smrg        .wait_value_hi = pTrigger->wait_value >> 32,
18467e31ba66Smrg        .wait_value_lo = pTrigger->wait_value,
184705b261ecSmrg#else
1848f7df2e56Smrg        .value_type = XSyncAbsolute,
18497e31ba66Smrg        .wait_value_hi = pTrigger->test_value >> 32,
18507e31ba66Smrg        .wait_value_lo = pTrigger->test_value,
185105b261ecSmrg#endif
185205b261ecSmrg
1853f7df2e56Smrg        .test_type = pTrigger->test_type,
18547e31ba66Smrg        .delta_hi = pAlarm->delta >> 32,
18557e31ba66Smrg        .delta_lo = pAlarm->delta,
1856f7df2e56Smrg        .events = pAlarm->events,
1857f7df2e56Smrg        .state = pAlarm->state
1858f7df2e56Smrg    };
1859f7df2e56Smrg
1860f7df2e56Smrg    if (client->swapped) {
1861f7df2e56Smrg        swaps(&rep.sequenceNumber);
1862f7df2e56Smrg        swapl(&rep.length);
1863f7df2e56Smrg        swapl(&rep.counter);
1864f7df2e56Smrg        swapl(&rep.wait_value_hi);
1865f7df2e56Smrg        swapl(&rep.wait_value_lo);
1866f7df2e56Smrg        swapl(&rep.test_type);
1867f7df2e56Smrg        swapl(&rep.delta_hi);
1868f7df2e56Smrg        swapl(&rep.delta_lo);
1869f7df2e56Smrg    }
1870f7df2e56Smrg
1871f7df2e56Smrg    WriteToClient(client, sizeof(xSyncQueryAlarmReply), &rep);
18724202a189Smrg    return Success;
187305b261ecSmrg}
187405b261ecSmrg
18754202a189Smrgstatic int
18764202a189SmrgProcSyncDestroyAlarm(ClientPtr client)
187705b261ecSmrg{
18784202a189Smrg    SyncAlarm *pAlarm;
18794202a189Smrg    int rc;
1880f7df2e56Smrg
188105b261ecSmrg    REQUEST(xSyncDestroyAlarmReq);
188205b261ecSmrg
188305b261ecSmrg    REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
188405b261ecSmrg
1885f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm,
1886f7df2e56Smrg                                 client, DixDestroyAccess);
18874202a189Smrg    if (rc != Success)
1888f7df2e56Smrg        return rc;
188905b261ecSmrg
189005b261ecSmrg    FreeResource(stuff->alarm, RT_NONE);
18914202a189Smrg    return Success;
189205b261ecSmrg}
189305b261ecSmrg
189465b04b38Smrgstatic int
189565b04b38SmrgProcSyncCreateFence(ClientPtr client)
189665b04b38Smrg{
189765b04b38Smrg    REQUEST(xSyncCreateFenceReq);
189865b04b38Smrg    DrawablePtr pDraw;
189965b04b38Smrg    SyncFence *pFence;
190065b04b38Smrg    int rc;
190165b04b38Smrg
190265b04b38Smrg    REQUEST_SIZE_MATCH(xSyncCreateFenceReq);
190365b04b38Smrg
190465b04b38Smrg    rc = dixLookupDrawable(&pDraw, stuff->d, client, M_ANY, DixGetAttrAccess);
190565b04b38Smrg    if (rc != Success)
1906f7df2e56Smrg        return rc;
190765b04b38Smrg
190865b04b38Smrg    LEGAL_NEW_RESOURCE(stuff->fid, client);
190965b04b38Smrg
1910f7df2e56Smrg    if (!(pFence = (SyncFence *) SyncCreate(client, stuff->fid, SYNC_FENCE)))
1911f7df2e56Smrg        return BadAlloc;
191265b04b38Smrg
191365b04b38Smrg    miSyncInitFence(pDraw->pScreen, pFence, stuff->initially_triggered);
191465b04b38Smrg
19157e31ba66Smrg    return Success;
191665b04b38Smrg}
191765b04b38Smrg
191865b04b38Smrgstatic int
191965b04b38SmrgFreeFence(void *obj, XID id)
192065b04b38Smrg{
192165b04b38Smrg    SyncFence *pFence = (SyncFence *) obj;
192265b04b38Smrg
192365b04b38Smrg    miSyncDestroyFence(pFence);
192465b04b38Smrg
192565b04b38Smrg    return Success;
192665b04b38Smrg}
192765b04b38Smrg
1928f7df2e56Smrgint
1929f7df2e56SmrgSyncVerifyFence(SyncFence ** ppSyncFence, XID fid, ClientPtr client, Mask mode)
193065b04b38Smrg{
1931f7df2e56Smrg    int rc = dixLookupResourceByType((void **) ppSyncFence, fid, RTFence,
1932f7df2e56Smrg                                     client, mode);
193365b04b38Smrg
193465b04b38Smrg    if (rc != Success)
1935f7df2e56Smrg        client->errorValue = fid;
193665b04b38Smrg
193765b04b38Smrg    return rc;
193865b04b38Smrg}
193965b04b38Smrg
194065b04b38Smrgstatic int
194165b04b38SmrgProcSyncTriggerFence(ClientPtr client)
194265b04b38Smrg{
194365b04b38Smrg    REQUEST(xSyncTriggerFenceReq);
194465b04b38Smrg    SyncFence *pFence;
194565b04b38Smrg    int rc;
194665b04b38Smrg
194765b04b38Smrg    REQUEST_SIZE_MATCH(xSyncTriggerFenceReq);
194865b04b38Smrg
1949f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence,
1950f7df2e56Smrg                                 client, DixWriteAccess);
195165b04b38Smrg    if (rc != Success)
1952f7df2e56Smrg        return rc;
195365b04b38Smrg
195465b04b38Smrg    miSyncTriggerFence(pFence);
195565b04b38Smrg
19567e31ba66Smrg    return Success;
195765b04b38Smrg}
195865b04b38Smrg
195965b04b38Smrgstatic int
196065b04b38SmrgProcSyncResetFence(ClientPtr client)
196165b04b38Smrg{
196265b04b38Smrg    REQUEST(xSyncResetFenceReq);
196365b04b38Smrg    SyncFence *pFence;
196465b04b38Smrg    int rc;
196565b04b38Smrg
196665b04b38Smrg    REQUEST_SIZE_MATCH(xSyncResetFenceReq);
196765b04b38Smrg
1968f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence,
1969f7df2e56Smrg                                 client, DixWriteAccess);
197065b04b38Smrg    if (rc != Success)
1971f7df2e56Smrg        return rc;
197265b04b38Smrg
197365b04b38Smrg    if (pFence->funcs.CheckTriggered(pFence) != TRUE)
1974f7df2e56Smrg        return BadMatch;
197565b04b38Smrg
197665b04b38Smrg    pFence->funcs.Reset(pFence);
197765b04b38Smrg
19787e31ba66Smrg    return Success;
197965b04b38Smrg}
198065b04b38Smrg
198165b04b38Smrgstatic int
198265b04b38SmrgProcSyncDestroyFence(ClientPtr client)
198365b04b38Smrg{
198465b04b38Smrg    REQUEST(xSyncDestroyFenceReq);
198565b04b38Smrg    SyncFence *pFence;
198665b04b38Smrg    int rc;
198765b04b38Smrg
198865b04b38Smrg    REQUEST_SIZE_MATCH(xSyncDestroyFenceReq);
198965b04b38Smrg
1990f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence,
1991f7df2e56Smrg                                 client, DixDestroyAccess);
199265b04b38Smrg    if (rc != Success)
1993f7df2e56Smrg        return rc;
199465b04b38Smrg
199565b04b38Smrg    FreeResource(stuff->fid, RT_NONE);
19967e31ba66Smrg    return Success;
199765b04b38Smrg}
199865b04b38Smrg
199965b04b38Smrgstatic int
200065b04b38SmrgProcSyncQueryFence(ClientPtr client)
200165b04b38Smrg{
200265b04b38Smrg    REQUEST(xSyncQueryFenceReq);
200365b04b38Smrg    xSyncQueryFenceReply rep;
200465b04b38Smrg    SyncFence *pFence;
200565b04b38Smrg    int rc;
200665b04b38Smrg
200765b04b38Smrg    REQUEST_SIZE_MATCH(xSyncQueryFenceReq);
200865b04b38Smrg
2009f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pFence, stuff->fid,
2010f7df2e56Smrg                                 RTFence, client, DixReadAccess);
201165b04b38Smrg    if (rc != Success)
2012f7df2e56Smrg        return rc;
201365b04b38Smrg
2014f7df2e56Smrg    rep = (xSyncQueryFenceReply) {
2015f7df2e56Smrg        .type = X_Reply,
2016f7df2e56Smrg        .sequenceNumber = client->sequence,
2017f7df2e56Smrg        .length = 0,
201865b04b38Smrg
2019f7df2e56Smrg        .triggered = pFence->funcs.CheckTriggered(pFence)
2020f7df2e56Smrg    };
202165b04b38Smrg
2022f7df2e56Smrg    if (client->swapped) {
2023f7df2e56Smrg        swaps(&rep.sequenceNumber);
2024f7df2e56Smrg        swapl(&rep.length);
202565b04b38Smrg    }
202665b04b38Smrg
2027f7df2e56Smrg    WriteToClient(client, sizeof(xSyncQueryFenceReply), &rep);
20287e31ba66Smrg    return Success;
202965b04b38Smrg}
203065b04b38Smrg
203165b04b38Smrgstatic int
203265b04b38SmrgProcSyncAwaitFence(ClientPtr client)
203365b04b38Smrg{
203465b04b38Smrg    REQUEST(xSyncAwaitFenceReq);
203565b04b38Smrg    SyncAwaitUnion *pAwaitUnion;
203665b04b38Smrg    SyncAwait *pAwait;
2037f7df2e56Smrg
203865b04b38Smrg    /* Use CARD32 rather than XSyncFence because XIDs are hard-coded to
203965b04b38Smrg     * CARD32 in protocol definitions */
204065b04b38Smrg    CARD32 *pProtocolFences;
204165b04b38Smrg    int status;
204265b04b38Smrg    int len;
204365b04b38Smrg    int items;
204465b04b38Smrg    int i;
204565b04b38Smrg
204665b04b38Smrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
204765b04b38Smrg
204865b04b38Smrg    len = client->req_len << 2;
204965b04b38Smrg    len -= sz_xSyncAwaitFenceReq;
205065b04b38Smrg    items = len / sizeof(CARD32);
205165b04b38Smrg
2052f7df2e56Smrg    if (items * sizeof(CARD32) != len) {
2053f7df2e56Smrg        return BadLength;
205465b04b38Smrg    }
2055f7df2e56Smrg    if (items == 0) {
2056f7df2e56Smrg        client->errorValue = items;
2057f7df2e56Smrg        return BadValue;
205865b04b38Smrg    }
205965b04b38Smrg
206065b04b38Smrg    if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
2061f7df2e56Smrg        return BadAlloc;
206265b04b38Smrg
206365b04b38Smrg    /* don't need to do any more memory allocation for this request! */
206465b04b38Smrg
2065f7df2e56Smrg    pProtocolFences = (CARD32 *) &stuff[1];
2066f7df2e56Smrg
2067f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await; /* skip over header */
2068f7df2e56Smrg    for (i = 0; i < items; i++, pProtocolFences++, pAwait++) {
2069f7df2e56Smrg        if (*pProtocolFences == None) {
2070f7df2e56Smrg            /*  this should take care of removing any triggers created by
2071f7df2e56Smrg             *  this request that have already been registered on sync objects
2072f7df2e56Smrg             */
2073f7df2e56Smrg            FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
2074f7df2e56Smrg            client->errorValue = *pProtocolFences;
2075f7df2e56Smrg            return SyncErrorBase + XSyncBadFence;
2076f7df2e56Smrg        }
2077f7df2e56Smrg
2078f7df2e56Smrg        pAwait->trigger.pSync = NULL;
2079f7df2e56Smrg        /* Provide acceptable values for these unused fields to
2080f7df2e56Smrg         * satisfy SyncInitTrigger's validation logic
2081f7df2e56Smrg         */
2082f7df2e56Smrg        pAwait->trigger.value_type = XSyncAbsolute;
20837e31ba66Smrg        pAwait->trigger.wait_value = 0;
2084f7df2e56Smrg        pAwait->trigger.test_type = 0;
2085f7df2e56Smrg
2086f7df2e56Smrg        status = SyncInitTrigger(client, &pAwait->trigger,
2087f7df2e56Smrg                                 *pProtocolFences, RTFence, XSyncCAAllTrigger);
2088f7df2e56Smrg        if (status != Success) {
2089f7df2e56Smrg            /*  this should take care of removing any triggers created by
2090f7df2e56Smrg             *  this request that have already been registered on sync objects
2091f7df2e56Smrg             */
2092f7df2e56Smrg            FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
2093f7df2e56Smrg            return status;
2094f7df2e56Smrg        }
2095f7df2e56Smrg        /* this is not a mistake -- same function works for both cases */
2096f7df2e56Smrg        pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
2097f7df2e56Smrg        pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
2098f7df2e56Smrg        /* event_threshold is unused for fence syncs */
20997e31ba66Smrg        pAwait->event_threshold = 0;
2100f7df2e56Smrg        pAwait->pHeader = &pAwaitUnion->header;
2101f7df2e56Smrg        pAwaitUnion->header.num_waitconditions++;
210265b04b38Smrg    }
210365b04b38Smrg
210465b04b38Smrg    SyncAwaitEpilogue(client, items, pAwaitUnion);
210565b04b38Smrg
21067e31ba66Smrg    return Success;
210765b04b38Smrg}
210865b04b38Smrg
210905b261ecSmrg/*
211005b261ecSmrg * ** Given an extension request, call the appropriate request procedure
211105b261ecSmrg */
21124202a189Smrgstatic int
21134202a189SmrgProcSyncDispatch(ClientPtr client)
211405b261ecSmrg{
211505b261ecSmrg    REQUEST(xReq);
211605b261ecSmrg
2117f7df2e56Smrg    switch (stuff->data) {
2118f7df2e56Smrg    case X_SyncInitialize:
2119f7df2e56Smrg        return ProcSyncInitialize(client);
2120f7df2e56Smrg    case X_SyncListSystemCounters:
2121f7df2e56Smrg        return ProcSyncListSystemCounters(client);
2122f7df2e56Smrg    case X_SyncCreateCounter:
2123f7df2e56Smrg        return ProcSyncCreateCounter(client);
2124f7df2e56Smrg    case X_SyncSetCounter:
2125f7df2e56Smrg        return ProcSyncSetCounter(client);
2126f7df2e56Smrg    case X_SyncChangeCounter:
2127f7df2e56Smrg        return ProcSyncChangeCounter(client);
2128f7df2e56Smrg    case X_SyncQueryCounter:
2129f7df2e56Smrg        return ProcSyncQueryCounter(client);
2130f7df2e56Smrg    case X_SyncDestroyCounter:
2131f7df2e56Smrg        return ProcSyncDestroyCounter(client);
2132f7df2e56Smrg    case X_SyncAwait:
2133f7df2e56Smrg        return ProcSyncAwait(client);
2134f7df2e56Smrg    case X_SyncCreateAlarm:
2135f7df2e56Smrg        return ProcSyncCreateAlarm(client);
2136f7df2e56Smrg    case X_SyncChangeAlarm:
2137f7df2e56Smrg        return ProcSyncChangeAlarm(client);
2138f7df2e56Smrg    case X_SyncQueryAlarm:
2139f7df2e56Smrg        return ProcSyncQueryAlarm(client);
2140f7df2e56Smrg    case X_SyncDestroyAlarm:
2141f7df2e56Smrg        return ProcSyncDestroyAlarm(client);
2142f7df2e56Smrg    case X_SyncSetPriority:
2143f7df2e56Smrg        return ProcSyncSetPriority(client);
2144f7df2e56Smrg    case X_SyncGetPriority:
2145f7df2e56Smrg        return ProcSyncGetPriority(client);
2146f7df2e56Smrg    case X_SyncCreateFence:
2147f7df2e56Smrg        return ProcSyncCreateFence(client);
2148f7df2e56Smrg    case X_SyncTriggerFence:
2149f7df2e56Smrg        return ProcSyncTriggerFence(client);
2150f7df2e56Smrg    case X_SyncResetFence:
2151f7df2e56Smrg        return ProcSyncResetFence(client);
2152f7df2e56Smrg    case X_SyncDestroyFence:
2153f7df2e56Smrg        return ProcSyncDestroyFence(client);
2154f7df2e56Smrg    case X_SyncQueryFence:
2155f7df2e56Smrg        return ProcSyncQueryFence(client);
2156f7df2e56Smrg    case X_SyncAwaitFence:
2157f7df2e56Smrg        return ProcSyncAwaitFence(client);
2158f7df2e56Smrg    default:
2159f7df2e56Smrg        return BadRequest;
216005b261ecSmrg    }
216105b261ecSmrg}
216205b261ecSmrg
216305b261ecSmrg/*
216405b261ecSmrg * Boring Swapping stuff ...
216505b261ecSmrg */
216605b261ecSmrg
21677e31ba66Smrgstatic int _X_COLD
21684202a189SmrgSProcSyncInitialize(ClientPtr client)
216905b261ecSmrg{
217005b261ecSmrg    REQUEST(xSyncInitializeReq);
2171f7df2e56Smrg    swaps(&stuff->length);
2172f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncInitializeReq);
217305b261ecSmrg
217405b261ecSmrg    return ProcSyncInitialize(client);
217505b261ecSmrg}
217605b261ecSmrg
21777e31ba66Smrgstatic int _X_COLD
21784202a189SmrgSProcSyncListSystemCounters(ClientPtr client)
217905b261ecSmrg{
218005b261ecSmrg    REQUEST(xSyncListSystemCountersReq);
2181f7df2e56Smrg    swaps(&stuff->length);
2182f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
218305b261ecSmrg
218405b261ecSmrg    return ProcSyncListSystemCounters(client);
218505b261ecSmrg}
218605b261ecSmrg
21877e31ba66Smrgstatic int _X_COLD
21884202a189SmrgSProcSyncCreateCounter(ClientPtr client)
218905b261ecSmrg{
219005b261ecSmrg    REQUEST(xSyncCreateCounterReq);
2191f7df2e56Smrg    swaps(&stuff->length);
2192f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
2193f7df2e56Smrg    swapl(&stuff->cid);
2194f7df2e56Smrg    swapl(&stuff->initial_value_lo);
2195f7df2e56Smrg    swapl(&stuff->initial_value_hi);
219605b261ecSmrg
219705b261ecSmrg    return ProcSyncCreateCounter(client);
219805b261ecSmrg}
219905b261ecSmrg
22007e31ba66Smrgstatic int _X_COLD
22014202a189SmrgSProcSyncSetCounter(ClientPtr client)
220205b261ecSmrg{
220305b261ecSmrg    REQUEST(xSyncSetCounterReq);
2204f7df2e56Smrg    swaps(&stuff->length);
2205f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncSetCounterReq);
2206f7df2e56Smrg    swapl(&stuff->cid);
2207f7df2e56Smrg    swapl(&stuff->value_lo);
2208f7df2e56Smrg    swapl(&stuff->value_hi);
220905b261ecSmrg
221005b261ecSmrg    return ProcSyncSetCounter(client);
221105b261ecSmrg}
221205b261ecSmrg
22137e31ba66Smrgstatic int _X_COLD
22144202a189SmrgSProcSyncChangeCounter(ClientPtr client)
221505b261ecSmrg{
221605b261ecSmrg    REQUEST(xSyncChangeCounterReq);
2217f7df2e56Smrg    swaps(&stuff->length);
2218f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
2219f7df2e56Smrg    swapl(&stuff->cid);
2220f7df2e56Smrg    swapl(&stuff->value_lo);
2221f7df2e56Smrg    swapl(&stuff->value_hi);
222205b261ecSmrg
222305b261ecSmrg    return ProcSyncChangeCounter(client);
222405b261ecSmrg}
222505b261ecSmrg
22267e31ba66Smrgstatic int _X_COLD
22274202a189SmrgSProcSyncQueryCounter(ClientPtr client)
222805b261ecSmrg{
222905b261ecSmrg    REQUEST(xSyncQueryCounterReq);
2230f7df2e56Smrg    swaps(&stuff->length);
2231f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
2232f7df2e56Smrg    swapl(&stuff->counter);
223305b261ecSmrg
223405b261ecSmrg    return ProcSyncQueryCounter(client);
223505b261ecSmrg}
223605b261ecSmrg
22377e31ba66Smrgstatic int _X_COLD
22384202a189SmrgSProcSyncDestroyCounter(ClientPtr client)
223905b261ecSmrg{
224005b261ecSmrg    REQUEST(xSyncDestroyCounterReq);
2241f7df2e56Smrg    swaps(&stuff->length);
2242f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
2243f7df2e56Smrg    swapl(&stuff->counter);
224405b261ecSmrg
224505b261ecSmrg    return ProcSyncDestroyCounter(client);
224605b261ecSmrg}
224705b261ecSmrg
22487e31ba66Smrgstatic int _X_COLD
22494202a189SmrgSProcSyncAwait(ClientPtr client)
225005b261ecSmrg{
225105b261ecSmrg    REQUEST(xSyncAwaitReq);
2252f7df2e56Smrg    swaps(&stuff->length);
225305b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
225405b261ecSmrg    SwapRestL(stuff);
225505b261ecSmrg
225605b261ecSmrg    return ProcSyncAwait(client);
225705b261ecSmrg}
225805b261ecSmrg
22597e31ba66Smrgstatic int _X_COLD
22604202a189SmrgSProcSyncCreateAlarm(ClientPtr client)
226105b261ecSmrg{
226205b261ecSmrg    REQUEST(xSyncCreateAlarmReq);
2263f7df2e56Smrg    swaps(&stuff->length);
226405b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
2265f7df2e56Smrg    swapl(&stuff->id);
2266f7df2e56Smrg    swapl(&stuff->valueMask);
226705b261ecSmrg    SwapRestL(stuff);
226805b261ecSmrg
226905b261ecSmrg    return ProcSyncCreateAlarm(client);
227005b261ecSmrg}
227105b261ecSmrg
22727e31ba66Smrgstatic int _X_COLD
22734202a189SmrgSProcSyncChangeAlarm(ClientPtr client)
227405b261ecSmrg{
227505b261ecSmrg    REQUEST(xSyncChangeAlarmReq);
2276f7df2e56Smrg    swaps(&stuff->length);
227705b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
2278f7df2e56Smrg    swapl(&stuff->alarm);
2279f7df2e56Smrg    swapl(&stuff->valueMask);
228005b261ecSmrg    SwapRestL(stuff);
228105b261ecSmrg    return ProcSyncChangeAlarm(client);
228205b261ecSmrg}
228305b261ecSmrg
22847e31ba66Smrgstatic int _X_COLD
22854202a189SmrgSProcSyncQueryAlarm(ClientPtr client)
228605b261ecSmrg{
228705b261ecSmrg    REQUEST(xSyncQueryAlarmReq);
2288f7df2e56Smrg    swaps(&stuff->length);
2289f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
2290f7df2e56Smrg    swapl(&stuff->alarm);
229105b261ecSmrg
229205b261ecSmrg    return ProcSyncQueryAlarm(client);
229305b261ecSmrg}
229405b261ecSmrg
22957e31ba66Smrgstatic int _X_COLD
22964202a189SmrgSProcSyncDestroyAlarm(ClientPtr client)
229705b261ecSmrg{
229805b261ecSmrg    REQUEST(xSyncDestroyAlarmReq);
2299f7df2e56Smrg    swaps(&stuff->length);
2300f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
2301f7df2e56Smrg    swapl(&stuff->alarm);
230205b261ecSmrg
230305b261ecSmrg    return ProcSyncDestroyAlarm(client);
230405b261ecSmrg}
230505b261ecSmrg
23067e31ba66Smrgstatic int _X_COLD
23074202a189SmrgSProcSyncSetPriority(ClientPtr client)
230805b261ecSmrg{
230905b261ecSmrg    REQUEST(xSyncSetPriorityReq);
2310f7df2e56Smrg    swaps(&stuff->length);
2311f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
2312f7df2e56Smrg    swapl(&stuff->id);
2313f7df2e56Smrg    swapl(&stuff->priority);
231405b261ecSmrg
231505b261ecSmrg    return ProcSyncSetPriority(client);
231605b261ecSmrg}
231705b261ecSmrg
23187e31ba66Smrgstatic int _X_COLD
23194202a189SmrgSProcSyncGetPriority(ClientPtr client)
232005b261ecSmrg{
232105b261ecSmrg    REQUEST(xSyncGetPriorityReq);
2322f7df2e56Smrg    swaps(&stuff->length);
2323f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
2324f7df2e56Smrg    swapl(&stuff->id);
232505b261ecSmrg
232605b261ecSmrg    return ProcSyncGetPriority(client);
232705b261ecSmrg}
232805b261ecSmrg
23297e31ba66Smrgstatic int _X_COLD
233065b04b38SmrgSProcSyncCreateFence(ClientPtr client)
233165b04b38Smrg{
233265b04b38Smrg    REQUEST(xSyncCreateFenceReq);
2333f7df2e56Smrg    swaps(&stuff->length);
2334f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncCreateFenceReq);
2335875c6e4fSmrg    swapl(&stuff->d);
2336f7df2e56Smrg    swapl(&stuff->fid);
233765b04b38Smrg
233865b04b38Smrg    return ProcSyncCreateFence(client);
233965b04b38Smrg}
234065b04b38Smrg
23417e31ba66Smrgstatic int _X_COLD
234265b04b38SmrgSProcSyncTriggerFence(ClientPtr client)
234365b04b38Smrg{
234465b04b38Smrg    REQUEST(xSyncTriggerFenceReq);
2345f7df2e56Smrg    swaps(&stuff->length);
2346f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncTriggerFenceReq);
2347f7df2e56Smrg    swapl(&stuff->fid);
234865b04b38Smrg
234965b04b38Smrg    return ProcSyncTriggerFence(client);
235065b04b38Smrg}
235165b04b38Smrg
23527e31ba66Smrgstatic int _X_COLD
235365b04b38SmrgSProcSyncResetFence(ClientPtr client)
235465b04b38Smrg{
235565b04b38Smrg    REQUEST(xSyncResetFenceReq);
2356f7df2e56Smrg    swaps(&stuff->length);
2357f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncResetFenceReq);
2358f7df2e56Smrg    swapl(&stuff->fid);
235965b04b38Smrg
236065b04b38Smrg    return ProcSyncResetFence(client);
236165b04b38Smrg}
236265b04b38Smrg
23637e31ba66Smrgstatic int _X_COLD
236465b04b38SmrgSProcSyncDestroyFence(ClientPtr client)
236565b04b38Smrg{
236665b04b38Smrg    REQUEST(xSyncDestroyFenceReq);
2367f7df2e56Smrg    swaps(&stuff->length);
2368f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncDestroyFenceReq);
2369f7df2e56Smrg    swapl(&stuff->fid);
237065b04b38Smrg
237165b04b38Smrg    return ProcSyncDestroyFence(client);
237265b04b38Smrg}
237365b04b38Smrg
23747e31ba66Smrgstatic int _X_COLD
237565b04b38SmrgSProcSyncQueryFence(ClientPtr client)
237665b04b38Smrg{
237765b04b38Smrg    REQUEST(xSyncQueryFenceReq);
2378f7df2e56Smrg    swaps(&stuff->length);
2379f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncQueryFenceReq);
2380f7df2e56Smrg    swapl(&stuff->fid);
238165b04b38Smrg
238265b04b38Smrg    return ProcSyncQueryFence(client);
238365b04b38Smrg}
238465b04b38Smrg
23857e31ba66Smrgstatic int _X_COLD
238665b04b38SmrgSProcSyncAwaitFence(ClientPtr client)
238765b04b38Smrg{
238865b04b38Smrg    REQUEST(xSyncAwaitFenceReq);
2389f7df2e56Smrg    swaps(&stuff->length);
239065b04b38Smrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
239165b04b38Smrg    SwapRestL(stuff);
239265b04b38Smrg
239365b04b38Smrg    return ProcSyncAwaitFence(client);
239465b04b38Smrg}
239505b261ecSmrg
23967e31ba66Smrgstatic int _X_COLD
23974202a189SmrgSProcSyncDispatch(ClientPtr client)
239805b261ecSmrg{
239905b261ecSmrg    REQUEST(xReq);
240005b261ecSmrg
2401f7df2e56Smrg    switch (stuff->data) {
2402f7df2e56Smrg    case X_SyncInitialize:
2403f7df2e56Smrg        return SProcSyncInitialize(client);
2404f7df2e56Smrg    case X_SyncListSystemCounters:
2405f7df2e56Smrg        return SProcSyncListSystemCounters(client);
2406f7df2e56Smrg    case X_SyncCreateCounter:
2407f7df2e56Smrg        return SProcSyncCreateCounter(client);
2408f7df2e56Smrg    case X_SyncSetCounter:
2409f7df2e56Smrg        return SProcSyncSetCounter(client);
2410f7df2e56Smrg    case X_SyncChangeCounter:
2411f7df2e56Smrg        return SProcSyncChangeCounter(client);
2412f7df2e56Smrg    case X_SyncQueryCounter:
2413f7df2e56Smrg        return SProcSyncQueryCounter(client);
2414f7df2e56Smrg    case X_SyncDestroyCounter:
2415f7df2e56Smrg        return SProcSyncDestroyCounter(client);
2416f7df2e56Smrg    case X_SyncAwait:
2417f7df2e56Smrg        return SProcSyncAwait(client);
2418f7df2e56Smrg    case X_SyncCreateAlarm:
2419f7df2e56Smrg        return SProcSyncCreateAlarm(client);
2420f7df2e56Smrg    case X_SyncChangeAlarm:
2421f7df2e56Smrg        return SProcSyncChangeAlarm(client);
2422f7df2e56Smrg    case X_SyncQueryAlarm:
2423f7df2e56Smrg        return SProcSyncQueryAlarm(client);
2424f7df2e56Smrg    case X_SyncDestroyAlarm:
2425f7df2e56Smrg        return SProcSyncDestroyAlarm(client);
2426f7df2e56Smrg    case X_SyncSetPriority:
2427f7df2e56Smrg        return SProcSyncSetPriority(client);
2428f7df2e56Smrg    case X_SyncGetPriority:
2429f7df2e56Smrg        return SProcSyncGetPriority(client);
2430f7df2e56Smrg    case X_SyncCreateFence:
2431f7df2e56Smrg        return SProcSyncCreateFence(client);
2432f7df2e56Smrg    case X_SyncTriggerFence:
2433f7df2e56Smrg        return SProcSyncTriggerFence(client);
2434f7df2e56Smrg    case X_SyncResetFence:
2435f7df2e56Smrg        return SProcSyncResetFence(client);
2436f7df2e56Smrg    case X_SyncDestroyFence:
2437f7df2e56Smrg        return SProcSyncDestroyFence(client);
2438f7df2e56Smrg    case X_SyncQueryFence:
2439f7df2e56Smrg        return SProcSyncQueryFence(client);
2440f7df2e56Smrg    case X_SyncAwaitFence:
2441f7df2e56Smrg        return SProcSyncAwaitFence(client);
2442f7df2e56Smrg    default:
2443f7df2e56Smrg        return BadRequest;
244405b261ecSmrg    }
244505b261ecSmrg}
244605b261ecSmrg
244705b261ecSmrg/*
244805b261ecSmrg * Event Swapping
244905b261ecSmrg */
245005b261ecSmrg
24517e31ba66Smrgstatic void _X_COLD
2452f7df2e56SmrgSCounterNotifyEvent(xSyncCounterNotifyEvent * from,
2453f7df2e56Smrg                    xSyncCounterNotifyEvent * to)
245405b261ecSmrg{
245505b261ecSmrg    to->type = from->type;
245605b261ecSmrg    to->kind = from->kind;
245705b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
245805b261ecSmrg    cpswapl(from->counter, to->counter);
245905b261ecSmrg    cpswapl(from->wait_value_lo, to->wait_value_lo);
246005b261ecSmrg    cpswapl(from->wait_value_hi, to->wait_value_hi);
246105b261ecSmrg    cpswapl(from->counter_value_lo, to->counter_value_lo);
246205b261ecSmrg    cpswapl(from->counter_value_hi, to->counter_value_hi);
246305b261ecSmrg    cpswapl(from->time, to->time);
246405b261ecSmrg    cpswaps(from->count, to->count);
246505b261ecSmrg    to->destroyed = from->destroyed;
246605b261ecSmrg}
246705b261ecSmrg
24687e31ba66Smrgstatic void _X_COLD
2469f7df2e56SmrgSAlarmNotifyEvent(xSyncAlarmNotifyEvent * from, xSyncAlarmNotifyEvent * to)
247005b261ecSmrg{
247105b261ecSmrg    to->type = from->type;
247205b261ecSmrg    to->kind = from->kind;
247305b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
247405b261ecSmrg    cpswapl(from->alarm, to->alarm);
247505b261ecSmrg    cpswapl(from->counter_value_lo, to->counter_value_lo);
247605b261ecSmrg    cpswapl(from->counter_value_hi, to->counter_value_hi);
247705b261ecSmrg    cpswapl(from->alarm_value_lo, to->alarm_value_lo);
247805b261ecSmrg    cpswapl(from->alarm_value_hi, to->alarm_value_hi);
247905b261ecSmrg    cpswapl(from->time, to->time);
248005b261ecSmrg    to->state = from->state;
248105b261ecSmrg}
248205b261ecSmrg
248305b261ecSmrg/*
248405b261ecSmrg * ** Close everything down. ** This is fairly simple for now.
248505b261ecSmrg */
248605b261ecSmrg/* ARGSUSED */
24874202a189Smrgstatic void
2488f7df2e56SmrgSyncResetProc(ExtensionEntry * extEntry)
248905b261ecSmrg{
249005b261ecSmrg    RTCounter = 0;
249105b261ecSmrg}
249205b261ecSmrg
249305b261ecSmrg/*
249405b261ecSmrg * ** Initialise the extension.
249505b261ecSmrg */
24964202a189Smrgvoid
24974202a189SmrgSyncExtensionInit(void)
249805b261ecSmrg{
249905b261ecSmrg    ExtensionEntry *extEntry;
2500f7df2e56Smrg    int s;
250165b04b38Smrg
250265b04b38Smrg    for (s = 0; s < screenInfo.numScreens; s++)
2503f7df2e56Smrg        miSyncSetup(screenInfo.screens[s]);
250405b261ecSmrg
25057e31ba66Smrg    RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
25067e31ba66Smrg    xorg_list_init(&SysCounterList);
25074202a189Smrg    RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm");
25084202a189Smrg    RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait");
250965b04b38Smrg    RTFence = CreateNewResourceType(FreeFence, "SyncFence");
25104202a189Smrg    if (RTAwait)
2511f7df2e56Smrg        RTAwait |= RC_NEVERRETAIN;
25124202a189Smrg    RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient");
25134202a189Smrg    if (RTAlarmClient)
2514f7df2e56Smrg        RTAlarmClient |= RC_NEVERRETAIN;
251505b261ecSmrg
251605b261ecSmrg    if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 ||
2517f7df2e56Smrg        RTAlarmClient == 0 ||
2518f7df2e56Smrg        (extEntry = AddExtension(SYNC_NAME,
2519f7df2e56Smrg                                 XSyncNumberEvents, XSyncNumberErrors,
2520f7df2e56Smrg                                 ProcSyncDispatch, SProcSyncDispatch,
2521f7df2e56Smrg                                 SyncResetProc, StandardMinorOpcode)) == NULL) {
2522f7df2e56Smrg        ErrorF("Sync Extension %d.%d failed to Initialise\n",
2523f7df2e56Smrg               SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
2524f7df2e56Smrg        return;
252505b261ecSmrg    }
252605b261ecSmrg
252705b261ecSmrg    SyncEventBase = extEntry->eventBase;
252805b261ecSmrg    SyncErrorBase = extEntry->errorBase;
2529f7df2e56Smrg    EventSwapVector[SyncEventBase + XSyncCounterNotify] =
2530f7df2e56Smrg        (EventSwapPtr) SCounterNotifyEvent;
2531f7df2e56Smrg    EventSwapVector[SyncEventBase + XSyncAlarmNotify] =
2532f7df2e56Smrg        (EventSwapPtr) SAlarmNotifyEvent;
253305b261ecSmrg
25344202a189Smrg    SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter);
25354202a189Smrg    SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm);
253665b04b38Smrg    SetResourceTypeErrorValue(RTFence, SyncErrorBase + XSyncBadFence);
25374202a189Smrg
253805b261ecSmrg    /*
253905b261ecSmrg     * Although SERVERTIME is implemented by the OS layer, we initialise it
254005b261ecSmrg     * here because doing it in OsInit() is too early. The resource database
254105b261ecSmrg     * is not initialised when OsInit() is called. This is just about OK
254205b261ecSmrg     * because there is always a servertime counter.
254305b261ecSmrg     */
254405b261ecSmrg    SyncInitServerTime();
254505b261ecSmrg    SyncInitIdleTime();
254605b261ecSmrg
254705b261ecSmrg#ifdef DEBUG
254805b261ecSmrg    fprintf(stderr, "Sync Extension %d.%d\n",
2549f7df2e56Smrg            SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
255005b261ecSmrg#endif
255105b261ecSmrg}
255205b261ecSmrg
255305b261ecSmrg/*
255405b261ecSmrg * ***** SERVERTIME implementation - should go in its own file in OS directory?
255505b261ecSmrg */
255605b261ecSmrg
2557f7df2e56Smrgstatic void *ServertimeCounter;
25587e31ba66Smrgstatic int64_t Now;
25597e31ba66Smrgstatic int64_t *pnext_time;
25607e31ba66Smrg
25617e31ba66Smrgstatic void GetTime(void)
25627e31ba66Smrg{
25637e31ba66Smrg    unsigned long millis = GetTimeInMillis();
25647e31ba66Smrg    unsigned long maxis = Now >> 32;
25657e31ba66Smrg
25667e31ba66Smrg    if (millis < (Now & 0xffffffff))
25677e31ba66Smrg        maxis++;
256805b261ecSmrg
25697e31ba66Smrg    Now = ((int64_t)maxis << 32) | millis;
257005b261ecSmrg}
257105b261ecSmrg
257205b261ecSmrg/*
257305b261ecSmrg*** Server Block Handler
25744202a189Smrg*** code inspired by multibuffer extension (now deprecated)
257505b261ecSmrg */
25767e31ba66Smrg/*ARGSUSED*/ static void
25777e31ba66SmrgServertimeBlockHandler(void *env, void *wt)
257805b261ecSmrg{
257905b261ecSmrg    unsigned long timeout;
258005b261ecSmrg
2581f7df2e56Smrg    if (pnext_time) {
258205b261ecSmrg        GetTime();
258305b261ecSmrg
25847e31ba66Smrg        if (Now >= *pnext_time) {
258505b261ecSmrg            timeout = 0;
25864202a189Smrg        }
2587f7df2e56Smrg        else {
25887e31ba66Smrg            timeout = *pnext_time - Now;
258905b261ecSmrg        }
2590f7df2e56Smrg        AdjustWaitForDelay(wt, timeout);        /* os/utils.c */
259105b261ecSmrg    }
259205b261ecSmrg}
259305b261ecSmrg
259405b261ecSmrg/*
259505b261ecSmrg*** Wakeup Handler
259605b261ecSmrg */
25977e31ba66Smrg/*ARGSUSED*/ static void
25987e31ba66SmrgServertimeWakeupHandler(void *env, int rc)
259905b261ecSmrg{
2600f7df2e56Smrg    if (pnext_time) {
260105b261ecSmrg        GetTime();
260205b261ecSmrg
26037e31ba66Smrg        if (Now >= *pnext_time) {
260405b261ecSmrg            SyncChangeCounter(ServertimeCounter, Now);
260505b261ecSmrg        }
260605b261ecSmrg    }
260705b261ecSmrg}
260805b261ecSmrg
260905b261ecSmrgstatic void
26107e31ba66SmrgServertimeQueryValue(void *pCounter, int64_t *pValue_return)
261105b261ecSmrg{
261205b261ecSmrg    GetTime();
261305b261ecSmrg    *pValue_return = Now;
261405b261ecSmrg}
261505b261ecSmrg
261605b261ecSmrgstatic void
26177e31ba66SmrgServertimeBracketValues(void *pCounter, int64_t *pbracket_less,
26187e31ba66Smrg                        int64_t *pbracket_greater)
261905b261ecSmrg{
2620f7df2e56Smrg    if (!pnext_time && pbracket_greater) {
2621f7df2e56Smrg        RegisterBlockAndWakeupHandlers(ServertimeBlockHandler,
2622f7df2e56Smrg                                       ServertimeWakeupHandler, NULL);
262305b261ecSmrg    }
2624f7df2e56Smrg    else if (pnext_time && !pbracket_greater) {
2625f7df2e56Smrg        RemoveBlockAndWakeupHandlers(ServertimeBlockHandler,
2626f7df2e56Smrg                                     ServertimeWakeupHandler, NULL);
262705b261ecSmrg    }
262805b261ecSmrg    pnext_time = pbracket_greater;
262905b261ecSmrg}
263005b261ecSmrg
263105b261ecSmrgstatic void
263205b261ecSmrgSyncInitServerTime(void)
263305b261ecSmrg{
26347e31ba66Smrg    int64_t resolution = 4;
263505b261ecSmrg
26367e31ba66Smrg    Now = GetTimeInMillis();
263705b261ecSmrg    ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution,
2638f7df2e56Smrg                                                XSyncCounterNeverDecreases,
2639f7df2e56Smrg                                                ServertimeQueryValue,
2640f7df2e56Smrg                                                ServertimeBracketValues);
264105b261ecSmrg    pnext_time = NULL;
264205b261ecSmrg}
264305b261ecSmrg
264405b261ecSmrg/*
264505b261ecSmrg * IDLETIME implementation
264605b261ecSmrg */
264705b261ecSmrg
2648f7df2e56Smrgtypedef struct {
26497e31ba66Smrg    int64_t *value_less;
26507e31ba66Smrg    int64_t *value_greater;
2651f7df2e56Smrg    int deviceid;
2652f7df2e56Smrg} IdleCounterPriv;
265305b261ecSmrg
265405b261ecSmrgstatic void
26557e31ba66SmrgIdleTimeQueryValue(void *pCounter, int64_t *pValue_return)
265605b261ecSmrg{
2657f7df2e56Smrg    int deviceid;
2658f7df2e56Smrg    CARD32 idle;
2659f7df2e56Smrg
2660f7df2e56Smrg    if (pCounter) {
2661f7df2e56Smrg        SyncCounter *counter = pCounter;
2662f7df2e56Smrg        IdleCounterPriv *priv = SysCounterGetPrivate(counter);
2663f7df2e56Smrg        deviceid = priv->deviceid;
2664f7df2e56Smrg    }
2665f7df2e56Smrg    else
2666f7df2e56Smrg        deviceid = XIAllDevices;
2667f7df2e56Smrg    idle = GetTimeInMillis() - LastEventTime(deviceid).milliseconds;
26687e31ba66Smrg    *pValue_return = idle;
266905b261ecSmrg}
267005b261ecSmrg
267105b261ecSmrgstatic void
26727e31ba66SmrgIdleTimeBlockHandler(void *pCounter, void *wt)
267305b261ecSmrg{
2674f7df2e56Smrg    SyncCounter *counter = pCounter;
2675f7df2e56Smrg    IdleCounterPriv *priv = SysCounterGetPrivate(counter);
26767e31ba66Smrg    int64_t *less = priv->value_less;
26777e31ba66Smrg    int64_t *greater = priv->value_greater;
26787e31ba66Smrg    int64_t idle, old_idle;
2679f7df2e56Smrg    SyncTriggerList *list = counter->sync.pTriglist;
268045801275Sjmcneill    SyncTrigger *trig;
268105b261ecSmrg
2682f7df2e56Smrg    if (!less && !greater)
2683f7df2e56Smrg        return;
2684f7df2e56Smrg
2685f7df2e56Smrg    old_idle = counter->value;
2686f7df2e56Smrg    IdleTimeQueryValue(counter, &idle);
2687f7df2e56Smrg    counter->value = idle;      /* push, so CheckTrigger works */
2688f7df2e56Smrg
2689f7df2e56Smrg    /**
2690f7df2e56Smrg     * There's an indefinite amount of time between ProcessInputEvents()
2691f7df2e56Smrg     * where the idle time is reset and the time we actually get here. idle
2692f7df2e56Smrg     * may be past the lower bracket if we dawdled with the events, so
2693f7df2e56Smrg     * check for whether we did reset and bomb out of select immediately.
2694f7df2e56Smrg     */
26957e31ba66Smrg    if (less && idle > *less &&
2696f7df2e56Smrg        LastEventTimeWasReset(priv->deviceid)) {
2697f7df2e56Smrg        AdjustWaitForDelay(wt, 0);
26987e31ba66Smrg    } else if (less && idle <= *less) {
2699f7df2e56Smrg        /*
2700f7df2e56Smrg         * We've been idle for less than the threshold value, and someone
2701f7df2e56Smrg         * wants to know about that, but now we need to know whether they
2702f7df2e56Smrg         * want level or edge trigger.  Check the trigger list against the
2703f7df2e56Smrg         * current idle time, and if any succeed, bomb out of select()
2704f7df2e56Smrg         * immediately so we can reschedule.
2705f7df2e56Smrg         */
2706f7df2e56Smrg
2707f7df2e56Smrg        for (list = counter->sync.pTriglist; list; list = list->next) {
2708f7df2e56Smrg            trig = list->pTrigger;
2709f7df2e56Smrg            if (trig->CheckTrigger(trig, old_idle)) {
2710f7df2e56Smrg                AdjustWaitForDelay(wt, 0);
2711f7df2e56Smrg                break;
2712f7df2e56Smrg            }
2713f7df2e56Smrg        }
2714f7df2e56Smrg        /*
2715f7df2e56Smrg         * We've been called exactly on the idle time, but we have a
2716f7df2e56Smrg         * NegativeTransition trigger which requires a transition from an
2717f7df2e56Smrg         * idle time greater than this.  Schedule a wakeup for the next
2718f7df2e56Smrg         * millisecond so we won't miss a transition.
2719f7df2e56Smrg         */
27207e31ba66Smrg        if (idle == *less)
2721f7df2e56Smrg            AdjustWaitForDelay(wt, 1);
2722f7df2e56Smrg    }
2723f7df2e56Smrg    else if (greater) {
2724f7df2e56Smrg        /*
2725f7df2e56Smrg         * There's a threshold in the positive direction.  If we've been
2726f7df2e56Smrg         * idle less than it, schedule a wakeup for sometime in the future.
2727f7df2e56Smrg         * If we've been idle more than it, and someone wants to know about
2728f7df2e56Smrg         * that level-triggered, schedule an immediate wakeup.
2729f7df2e56Smrg         */
2730f7df2e56Smrg
27317e31ba66Smrg        if (idle < *greater) {
27327e31ba66Smrg            AdjustWaitForDelay(wt, *greater - idle);
2733f7df2e56Smrg        }
2734f7df2e56Smrg        else {
2735f7df2e56Smrg            for (list = counter->sync.pTriglist; list;
2736f7df2e56Smrg                 list = list->next) {
2737f7df2e56Smrg                trig = list->pTrigger;
2738f7df2e56Smrg                if (trig->CheckTrigger(trig, old_idle)) {
2739f7df2e56Smrg                    AdjustWaitForDelay(wt, 0);
2740f7df2e56Smrg                    break;
2741f7df2e56Smrg                }
2742f7df2e56Smrg            }
2743f7df2e56Smrg        }
2744f7df2e56Smrg    }
2745f7df2e56Smrg
2746f7df2e56Smrg    counter->value = old_idle;  /* pop */
2747f7df2e56Smrg}
2748f7df2e56Smrg
2749f7df2e56Smrgstatic void
27507e31ba66SmrgIdleTimeCheckBrackets(SyncCounter *counter, int64_t idle,
27517e31ba66Smrg                      int64_t *less, int64_t *greater)
2752f7df2e56Smrg{
27537e31ba66Smrg    if ((greater && idle >= *greater) ||
27547e31ba66Smrg        (less && idle <= *less)) {
2755f7df2e56Smrg        SyncChangeCounter(counter, idle);
2756f7df2e56Smrg    }
2757f7df2e56Smrg    else
2758f7df2e56Smrg        SyncUpdateCounter(counter, idle);
275905b261ecSmrg}
276005b261ecSmrg
276105b261ecSmrgstatic void
27627e31ba66SmrgIdleTimeWakeupHandler(void *pCounter, int rc)
276305b261ecSmrg{
2764f7df2e56Smrg    SyncCounter *counter = pCounter;
2765f7df2e56Smrg    IdleCounterPriv *priv = SysCounterGetPrivate(counter);
27667e31ba66Smrg    int64_t *less = priv->value_less;
27677e31ba66Smrg    int64_t *greater = priv->value_greater;
27687e31ba66Smrg    int64_t idle;
276905b261ecSmrg
2770f7df2e56Smrg    if (!less && !greater)
2771f7df2e56Smrg        return;
277205b261ecSmrg
2773f7df2e56Smrg    IdleTimeQueryValue(pCounter, &idle);
277405b261ecSmrg
2775f7df2e56Smrg    /*
2776f7df2e56Smrg      There is no guarantee for the WakeupHandler to be called within a specific
2777f7df2e56Smrg      timeframe. Idletime may go to 0, but by the time we get here, it may be
2778f7df2e56Smrg      non-zero and alarms for a pos. transition on 0 won't get triggered.
2779f7df2e56Smrg      https://bugs.freedesktop.org/show_bug.cgi?id=70476
2780f7df2e56Smrg      */
2781f7df2e56Smrg    if (LastEventTimeWasReset(priv->deviceid)) {
2782f7df2e56Smrg        LastEventTimeToggleResetFlag(priv->deviceid, FALSE);
27837e31ba66Smrg        if (idle != 0) {
27847e31ba66Smrg            IdleTimeCheckBrackets(counter, 0, less, greater);
2785f7df2e56Smrg            less = priv->value_less;
2786f7df2e56Smrg            greater = priv->value_greater;
2787f7df2e56Smrg        }
278805b261ecSmrg    }
2789f7df2e56Smrg
2790f7df2e56Smrg    IdleTimeCheckBrackets(counter, idle, less, greater);
279105b261ecSmrg}
279205b261ecSmrg
279305b261ecSmrgstatic void
27947e31ba66SmrgIdleTimeBracketValues(void *pCounter, int64_t *pbracket_less,
27957e31ba66Smrg                      int64_t *pbracket_greater)
279605b261ecSmrg{
2797f7df2e56Smrg    SyncCounter *counter = pCounter;
2798f7df2e56Smrg    IdleCounterPriv *priv = SysCounterGetPrivate(counter);
27997e31ba66Smrg    int64_t *less = priv->value_less;
28007e31ba66Smrg    int64_t *greater = priv->value_greater;
2801f7df2e56Smrg    Bool registered = (less || greater);
280205b261ecSmrg
2803f7df2e56Smrg    if (registered && !pbracket_less && !pbracket_greater) {
2804f7df2e56Smrg        RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler,
2805f7df2e56Smrg                                     IdleTimeWakeupHandler, pCounter);
280605b261ecSmrg    }
2807f7df2e56Smrg    else if (!registered && (pbracket_less || pbracket_greater)) {
2808f7df2e56Smrg        /* Reset flag must be zero so we don't force a idle timer reset on
2809f7df2e56Smrg           the first wakeup */
2810f7df2e56Smrg        LastEventTimeToggleResetAll(FALSE);
2811f7df2e56Smrg        RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
2812f7df2e56Smrg                                       IdleTimeWakeupHandler, pCounter);
281305b261ecSmrg    }
281405b261ecSmrg
2815f7df2e56Smrg    priv->value_greater = pbracket_greater;
2816f7df2e56Smrg    priv->value_less = pbracket_less;
281705b261ecSmrg}
281805b261ecSmrg
2819f7df2e56Smrgstatic SyncCounter*
2820f7df2e56Smrginit_system_idle_counter(const char *name, int deviceid)
282105b261ecSmrg{
28227e31ba66Smrg    int64_t resolution = 4;
28237e31ba66Smrg    int64_t idle;
2824f7df2e56Smrg    SyncCounter *idle_time_counter;
2825f7df2e56Smrg
2826f7df2e56Smrg    IdleTimeQueryValue(NULL, &idle);
282705b261ecSmrg
2828f7df2e56Smrg    idle_time_counter = SyncCreateSystemCounter(name, idle, resolution,
2829f7df2e56Smrg                                                XSyncCounterUnrestricted,
2830f7df2e56Smrg                                                IdleTimeQueryValue,
2831f7df2e56Smrg                                                IdleTimeBracketValues);
283205b261ecSmrg
2833f7df2e56Smrg    if (idle_time_counter != NULL) {
2834f7df2e56Smrg        IdleCounterPriv *priv = malloc(sizeof(IdleCounterPriv));
283505b261ecSmrg
2836f7df2e56Smrg        priv->value_less = priv->value_greater = NULL;
2837f7df2e56Smrg        priv->deviceid = deviceid;
2838f7df2e56Smrg
2839f7df2e56Smrg        idle_time_counter->pSysCounterInfo->private = priv;
2840f7df2e56Smrg    }
2841f7df2e56Smrg
2842f7df2e56Smrg    return idle_time_counter;
2843f7df2e56Smrg}
2844f7df2e56Smrg
2845f7df2e56Smrgstatic void
2846f7df2e56SmrgSyncInitIdleTime(void)
2847f7df2e56Smrg{
2848f7df2e56Smrg    init_system_idle_counter("IDLETIME", XIAllDevices);
2849f7df2e56Smrg}
2850f7df2e56Smrg
2851f7df2e56SmrgSyncCounter*
2852f7df2e56SmrgSyncInitDeviceIdleTime(DeviceIntPtr dev)
2853f7df2e56Smrg{
2854f7df2e56Smrg    char timer_name[64];
2855f7df2e56Smrg    sprintf(timer_name, "DEVICEIDLETIME %d", dev->id);
2856f7df2e56Smrg
2857f7df2e56Smrg    return init_system_idle_counter(timer_name, dev->id);
2858f7df2e56Smrg}
2859f7df2e56Smrg
2860f7df2e56Smrgvoid SyncRemoveDeviceIdleTime(SyncCounter *counter)
2861f7df2e56Smrg{
2862f7df2e56Smrg    /* FreeAllResources() frees all system counters before the devices are
2863f7df2e56Smrg       shut down, check if there are any left before freeing the device's
2864f7df2e56Smrg       counter */
2865f7df2e56Smrg    if (counter && !xorg_list_is_empty(&SysCounterList))
2866f7df2e56Smrg        xorg_list_del(&counter->pSysCounterInfo->entry);
286705b261ecSmrg}
2868