sync.c revision f7df2e56
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
2024202a189Smrg    if (!(pCur = malloc(sizeof(SyncTriggerList))))
203f7df2e56Smrg        return BadAlloc;
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
240f7df2e56SmrgSyncCheckTriggerPositiveComparison(SyncTrigger * pTrigger, CARD64 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
25165b04b38Smrg    return (pCounter == NULL ||
252f7df2e56Smrg            XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value));
25305b261ecSmrg}
25405b261ecSmrg
25505b261ecSmrgstatic Bool
256f7df2e56SmrgSyncCheckTriggerNegativeComparison(SyncTrigger * pTrigger, CARD64 oldval)
25705b261ecSmrg{
25865b04b38Smrg    SyncCounter *pCounter;
25965b04b38Smrg
26065b04b38Smrg    /* Non-counter sync objects should never get here because they
26165b04b38Smrg     * never trigger this comparison. */
26265b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
263f7df2e56Smrg        return FALSE;
26465b04b38Smrg
265f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
26665b04b38Smrg
26765b04b38Smrg    return (pCounter == NULL ||
268f7df2e56Smrg            XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value));
26905b261ecSmrg}
27005b261ecSmrg
27105b261ecSmrgstatic Bool
272f7df2e56SmrgSyncCheckTriggerPositiveTransition(SyncTrigger * pTrigger, CARD64 oldval)
27305b261ecSmrg{
27465b04b38Smrg    SyncCounter *pCounter;
27565b04b38Smrg
27665b04b38Smrg    /* Non-counter sync objects should never get here because they
27765b04b38Smrg     * never trigger this comparison. */
27865b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
279f7df2e56Smrg        return FALSE;
28065b04b38Smrg
281f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
28265b04b38Smrg
28365b04b38Smrg    return (pCounter == NULL ||
284f7df2e56Smrg            (XSyncValueLessThan(oldval, pTrigger->test_value) &&
285f7df2e56Smrg             XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value)));
28605b261ecSmrg}
28705b261ecSmrg
28805b261ecSmrgstatic Bool
289f7df2e56SmrgSyncCheckTriggerNegativeTransition(SyncTrigger * pTrigger, CARD64 oldval)
29005b261ecSmrg{
29165b04b38Smrg    SyncCounter *pCounter;
29265b04b38Smrg
29365b04b38Smrg    /* Non-counter sync objects should never get here because they
29465b04b38Smrg     * never trigger this comparison. */
29565b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
296f7df2e56Smrg        return FALSE;
29765b04b38Smrg
298f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
29965b04b38Smrg
30065b04b38Smrg    return (pCounter == NULL ||
301f7df2e56Smrg            (XSyncValueGreaterThan(oldval, pTrigger->test_value) &&
302f7df2e56Smrg             XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value)));
30365b04b38Smrg}
30465b04b38Smrg
30565b04b38Smrgstatic Bool
306f7df2e56SmrgSyncCheckTriggerFence(SyncTrigger * pTrigger, CARD64 unused)
30765b04b38Smrg{
308f7df2e56Smrg    SyncFence *pFence = (SyncFence *) pTrigger->pSync;
309f7df2e56Smrg
310f7df2e56Smrg    (void) unused;
31165b04b38Smrg
312f7df2e56Smrg    return (pFence == NULL || pFence->funcs.CheckTriggered(pFence));
31305b261ecSmrg}
31405b261ecSmrg
3154202a189Smrgstatic int
316f7df2e56SmrgSyncInitTrigger(ClientPtr client, SyncTrigger * pTrigger, XID syncObject,
317f7df2e56Smrg                RESTYPE resType, Mask changes)
31805b261ecSmrg{
31965b04b38Smrg    SyncObject *pSync = pTrigger->pSync;
32065b04b38Smrg    SyncCounter *pCounter = NULL;
321f7df2e56Smrg    int rc;
322f7df2e56Smrg    Bool newSyncObject = FALSE;
323f7df2e56Smrg
324f7df2e56Smrg    if (changes & XSyncCACounter) {
325f7df2e56Smrg        if (syncObject == None)
326f7df2e56Smrg            pSync = NULL;
327f7df2e56Smrg        else if (Success != (rc = dixLookupResourceByType((void **) &pSync,
328f7df2e56Smrg                                                          syncObject, resType,
329f7df2e56Smrg                                                          client,
330f7df2e56Smrg                                                          DixReadAccess))) {
331f7df2e56Smrg            client->errorValue = syncObject;
332f7df2e56Smrg            return rc;
333f7df2e56Smrg        }
334f7df2e56Smrg        if (pSync != pTrigger->pSync) { /* new counter for trigger */
335f7df2e56Smrg            SyncDeleteTriggerFromSyncObject(pTrigger);
336f7df2e56Smrg            pTrigger->pSync = pSync;
337f7df2e56Smrg            newSyncObject = TRUE;
338f7df2e56Smrg        }
33905b261ecSmrg    }
34005b261ecSmrg
34105b261ecSmrg    /* if system counter, ask it what the current value is */
34205b261ecSmrg
343f7df2e56Smrg    if (pSync && SYNC_COUNTER == pSync->type) {
344f7df2e56Smrg        pCounter = (SyncCounter *) pSync;
345f7df2e56Smrg
346f7df2e56Smrg        if (IsSystemCounter(pCounter)) {
347f7df2e56Smrg            (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter,
348f7df2e56Smrg                                                      &pCounter->value);
349f7df2e56Smrg        }
350f7df2e56Smrg    }
351f7df2e56Smrg
352f7df2e56Smrg    if (changes & XSyncCAValueType) {
353f7df2e56Smrg        if (pTrigger->value_type != XSyncRelative &&
354f7df2e56Smrg            pTrigger->value_type != XSyncAbsolute) {
355f7df2e56Smrg            client->errorValue = pTrigger->value_type;
356f7df2e56Smrg            return BadValue;
357f7df2e56Smrg        }
358f7df2e56Smrg    }
359f7df2e56Smrg
360f7df2e56Smrg    if (changes & XSyncCATestType) {
361f7df2e56Smrg
362f7df2e56Smrg        if (pSync && SYNC_FENCE == pSync->type) {
363f7df2e56Smrg            pTrigger->CheckTrigger = SyncCheckTriggerFence;
364f7df2e56Smrg        }
365f7df2e56Smrg        else {
366f7df2e56Smrg            /* select appropriate CheckTrigger function */
367f7df2e56Smrg
368f7df2e56Smrg            switch (pTrigger->test_type) {
369f7df2e56Smrg            case XSyncPositiveTransition:
370f7df2e56Smrg                pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition;
371f7df2e56Smrg                break;
372f7df2e56Smrg            case XSyncNegativeTransition:
373f7df2e56Smrg                pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition;
374f7df2e56Smrg                break;
375f7df2e56Smrg            case XSyncPositiveComparison:
376f7df2e56Smrg                pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison;
377f7df2e56Smrg                break;
378f7df2e56Smrg            case XSyncNegativeComparison:
379f7df2e56Smrg                pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison;
380f7df2e56Smrg                break;
381f7df2e56Smrg            default:
382f7df2e56Smrg                client->errorValue = pTrigger->test_type;
383f7df2e56Smrg                return BadValue;
384f7df2e56Smrg            }
385f7df2e56Smrg        }
386f7df2e56Smrg    }
387f7df2e56Smrg
388f7df2e56Smrg    if (changes & (XSyncCAValueType | XSyncCAValue)) {
389f7df2e56Smrg        if (pTrigger->value_type == XSyncAbsolute)
390f7df2e56Smrg            pTrigger->test_value = pTrigger->wait_value;
391f7df2e56Smrg        else {                  /* relative */
392f7df2e56Smrg
393f7df2e56Smrg            Bool overflow;
394f7df2e56Smrg
395f7df2e56Smrg            if (pCounter == NULL)
396f7df2e56Smrg                return BadMatch;
397f7df2e56Smrg
398f7df2e56Smrg            XSyncValueAdd(&pTrigger->test_value, pCounter->value,
399f7df2e56Smrg                          pTrigger->wait_value, &overflow);
400f7df2e56Smrg            if (overflow) {
401f7df2e56Smrg                client->errorValue = XSyncValueHigh32(pTrigger->wait_value);
402f7df2e56Smrg                return BadValue;
403f7df2e56Smrg            }
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) {
411f7df2e56Smrg        if ((rc = SyncAddTriggerToSyncObject(pTrigger)) != Success)
412f7df2e56Smrg            return rc;
41305b261ecSmrg    }
414f7df2e56Smrg    else if (pCounter && IsSystemCounter(pCounter)) {
415f7df2e56Smrg        SyncComputeBracketValues(pCounter);
41605b261ecSmrg    }
4174202a189Smrg
41805b261ecSmrg    return Success;
41905b261ecSmrg}
42005b261ecSmrg
42105b261ecSmrg/*  AlarmNotify events happen in response to actions taken on an Alarm or
4224202a189Smrg *  the counter used by the alarm.  AlarmNotify may be sent to multiple
42305b261ecSmrg *  clients.  The alarm maintains a list of clients interested in events.
42405b261ecSmrg */
42505b261ecSmrgstatic void
426f7df2e56SmrgSyncSendAlarmNotifyEvents(SyncAlarm * pAlarm)
42705b261ecSmrg{
42805b261ecSmrg    SyncAlarmClientList *pcl;
42905b261ecSmrg    xSyncAlarmNotifyEvent ane;
43005b261ecSmrg    SyncTrigger *pTrigger = &pAlarm->trigger;
43165b04b38Smrg    SyncCounter *pCounter;
43265b04b38Smrg
43365b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
434f7df2e56Smrg        return;
43565b04b38Smrg
436f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
43705b261ecSmrg
43805b261ecSmrg    UpdateCurrentTime();
43905b261ecSmrg
440f7df2e56Smrg    ane = (xSyncAlarmNotifyEvent) {
441f7df2e56Smrg        .type = SyncEventBase + XSyncAlarmNotify,
442f7df2e56Smrg        .kind = XSyncAlarmNotify,
443f7df2e56Smrg        .alarm = pAlarm->alarm_id,
444f7df2e56Smrg        .alarm_value_hi = XSyncValueHigh32(pTrigger->test_value),
445f7df2e56Smrg        .alarm_value_lo = XSyncValueLow32(pTrigger->test_value),
446f7df2e56Smrg        .time = currentTime.milliseconds,
447f7df2e56Smrg        .state = pAlarm->state
448f7df2e56Smrg    };
449f7df2e56Smrg
450f7df2e56Smrg    if (pTrigger->pSync && SYNC_COUNTER == pTrigger->pSync->type) {
451f7df2e56Smrg        ane.counter_value_hi = XSyncValueHigh32(pCounter->value);
452f7df2e56Smrg        ane.counter_value_lo = XSyncValueLow32(pCounter->value);
45305b261ecSmrg    }
454f7df2e56Smrg    else {
455f7df2e56Smrg        /* XXX what else can we do if there's no counter? */
456f7df2e56Smrg        ane.counter_value_hi = ane.counter_value_lo = 0;
45705b261ecSmrg    }
45805b261ecSmrg
45905b261ecSmrg    /* send to owner */
4604202a189Smrg    if (pAlarm->events)
461f7df2e56Smrg        WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane);
46205b261ecSmrg
46305b261ecSmrg    /* send to other interested clients */
46405b261ecSmrg    for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next)
465f7df2e56Smrg        WriteEventsToClient(pcl->client, 1, (xEvent *) &ane);
46605b261ecSmrg}
46705b261ecSmrg
4684202a189Smrg/*  CounterNotify events only occur in response to an Await.  The events
46905b261ecSmrg *  go only to the Awaiting client.
47005b261ecSmrg */
47105b261ecSmrgstatic void
472f7df2e56SmrgSyncSendCounterNotifyEvents(ClientPtr client, SyncAwait ** ppAwait,
473f7df2e56Smrg                            int num_events)
47405b261ecSmrg{
47505b261ecSmrg    xSyncCounterNotifyEvent *pEvents, *pev;
47605b261ecSmrg    int i;
47705b261ecSmrg
47805b261ecSmrg    if (client->clientGone)
479f7df2e56Smrg        return;
480f7df2e56Smrg    pev = pEvents = calloc(num_events, sizeof(xSyncCounterNotifyEvent));
4814202a189Smrg    if (!pEvents)
482f7df2e56Smrg        return;
48305b261ecSmrg    UpdateCurrentTime();
484f7df2e56Smrg    for (i = 0; i < num_events; i++, ppAwait++, pev++) {
485f7df2e56Smrg        SyncTrigger *pTrigger = &(*ppAwait)->trigger;
486f7df2e56Smrg
487f7df2e56Smrg        pev->type = SyncEventBase + XSyncCounterNotify;
488f7df2e56Smrg        pev->kind = XSyncCounterNotify;
489f7df2e56Smrg        pev->counter = pTrigger->pSync->id;
490f7df2e56Smrg        pev->wait_value_lo = XSyncValueLow32(pTrigger->test_value);
491f7df2e56Smrg        pev->wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
492f7df2e56Smrg        if (SYNC_COUNTER == pTrigger->pSync->type) {
493f7df2e56Smrg            SyncCounter *pCounter = (SyncCounter *) pTrigger->pSync;
494f7df2e56Smrg
495f7df2e56Smrg            pev->counter_value_lo = XSyncValueLow32(pCounter->value);
496f7df2e56Smrg            pev->counter_value_hi = XSyncValueHigh32(pCounter->value);
497f7df2e56Smrg        }
498f7df2e56Smrg        else {
499f7df2e56Smrg            pev->counter_value_lo = 0;
500f7df2e56Smrg            pev->counter_value_hi = 0;
501f7df2e56Smrg        }
502f7df2e56Smrg
503f7df2e56Smrg        pev->time = currentTime.milliseconds;
504f7df2e56Smrg        pev->count = num_events - i - 1;        /* events remaining */
505f7df2e56Smrg        pev->destroyed = pTrigger->pSync->beingDestroyed;
50605b261ecSmrg    }
50705b261ecSmrg    /* swapping will be taken care of by this */
508f7df2e56Smrg    WriteEventsToClient(client, num_events, (xEvent *) pEvents);
5094202a189Smrg    free(pEvents);
51005b261ecSmrg}
51105b261ecSmrg
51205b261ecSmrg/* This function is called when an alarm's counter is destroyed.
51305b261ecSmrg * It is plugged into pTrigger->CounterDestroyed (for alarm triggers).
51405b261ecSmrg */
5154202a189Smrgstatic void
516f7df2e56SmrgSyncAlarmCounterDestroyed(SyncTrigger * pTrigger)
51705b261ecSmrg{
518f7df2e56Smrg    SyncAlarm *pAlarm = (SyncAlarm *) pTrigger;
51905b261ecSmrg
52005b261ecSmrg    pAlarm->state = XSyncAlarmInactive;
52105b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
52265b04b38Smrg    pTrigger->pSync = NULL;
52305b261ecSmrg}
52405b261ecSmrg
5254202a189Smrg/*  This function is called when an alarm "goes off."
52605b261ecSmrg *  It is plugged into pTrigger->TriggerFired (for alarm triggers).
52705b261ecSmrg */
52805b261ecSmrgstatic void
529f7df2e56SmrgSyncAlarmTriggerFired(SyncTrigger * pTrigger)
53005b261ecSmrg{
531f7df2e56Smrg    SyncAlarm *pAlarm = (SyncAlarm *) pTrigger;
53265b04b38Smrg    SyncCounter *pCounter;
53305b261ecSmrg    CARD64 new_test_value;
53405b261ecSmrg
53565b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
536f7df2e56Smrg        return;
53765b04b38Smrg
538f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
53965b04b38Smrg
54005b261ecSmrg    /* no need to check alarm unless it's active */
54105b261ecSmrg    if (pAlarm->state != XSyncAlarmActive)
542f7df2e56Smrg        return;
54305b261ecSmrg
54405b261ecSmrg    /*  " if the counter value is None, or if the delta is 0 and
54505b261ecSmrg     *    the test-type is PositiveComparison or NegativeComparison,
54605b261ecSmrg     *    no change is made to value (test-value) and the alarm
54705b261ecSmrg     *    state is changed to Inactive before the event is generated."
54805b261ecSmrg     */
549f7df2e56Smrg    if (pCounter == NULL || (XSyncValueIsZero(pAlarm->delta)
550f7df2e56Smrg                             && (pAlarm->trigger.test_type ==
551f7df2e56Smrg                                 XSyncPositiveComparison ||
552f7df2e56Smrg                                 pAlarm->trigger.test_type ==
553f7df2e56Smrg                                 XSyncNegativeComparison)))
554f7df2e56Smrg        pAlarm->state = XSyncAlarmInactive;
55505b261ecSmrg
55605b261ecSmrg    new_test_value = pAlarm->trigger.test_value;
55705b261ecSmrg
558f7df2e56Smrg    if (pAlarm->state == XSyncAlarmActive) {
559f7df2e56Smrg        Bool overflow;
560f7df2e56Smrg        CARD64 oldvalue;
561f7df2e56Smrg        SyncTrigger *paTrigger = &pAlarm->trigger;
562f7df2e56Smrg        SyncCounter *paCounter;
563f7df2e56Smrg
564f7df2e56Smrg        if (!SyncCheckWarnIsCounter(paTrigger->pSync,
565f7df2e56Smrg                                    WARN_INVALID_COUNTER_ALARM))
566f7df2e56Smrg            return;
567f7df2e56Smrg
568f7df2e56Smrg        paCounter = (SyncCounter *) pTrigger->pSync;
569f7df2e56Smrg
570f7df2e56Smrg        /* "The alarm is updated by repeatedly adding delta to the
571f7df2e56Smrg         *  value of the trigger and re-initializing it until it
572f7df2e56Smrg         *  becomes FALSE."
573f7df2e56Smrg         */
574f7df2e56Smrg        oldvalue = paTrigger->test_value;
575f7df2e56Smrg
576f7df2e56Smrg        /* XXX really should do something smarter here */
577f7df2e56Smrg
578f7df2e56Smrg        do {
579f7df2e56Smrg            XSyncValueAdd(&paTrigger->test_value, paTrigger->test_value,
580f7df2e56Smrg                          pAlarm->delta, &overflow);
581f7df2e56Smrg        } while (!overflow &&
582f7df2e56Smrg                 (*paTrigger->CheckTrigger) (paTrigger, paCounter->value));
583f7df2e56Smrg
584f7df2e56Smrg        new_test_value = paTrigger->test_value;
585f7df2e56Smrg        paTrigger->test_value = oldvalue;
586f7df2e56Smrg
587f7df2e56Smrg        /* "If this update would cause value to fall outside the range
588f7df2e56Smrg         *  for an INT64...no change is made to value (test-value) and
589f7df2e56Smrg         *  the alarm state is changed to Inactive before the event is
590f7df2e56Smrg         *  generated."
591f7df2e56Smrg         */
592f7df2e56Smrg        if (overflow) {
593f7df2e56Smrg            new_test_value = oldvalue;
594f7df2e56Smrg            pAlarm->state = XSyncAlarmInactive;
595f7df2e56Smrg        }
59605b261ecSmrg    }
59705b261ecSmrg    /*  The AlarmNotify event has to have the "new state of the alarm"
59805b261ecSmrg     *  which we can't be sure of until this point.  However, it has
59905b261ecSmrg     *  to have the "old" trigger test value.  That's the reason for
60005b261ecSmrg     *  all the newvalue/oldvalue shuffling above.  After we send the
60105b261ecSmrg     *  events, give the trigger its new test value.
60205b261ecSmrg     */
60305b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
60405b261ecSmrg    pTrigger->test_value = new_test_value;
60505b261ecSmrg}
60605b261ecSmrg
60705b261ecSmrg/*  This function is called when an Await unblocks, either as a result
60805b261ecSmrg *  of the trigger firing OR the counter being destroyed.
60905b261ecSmrg *  It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed
61005b261ecSmrg *  (for Await triggers).
61105b261ecSmrg */
61205b261ecSmrgstatic void
613f7df2e56SmrgSyncAwaitTriggerFired(SyncTrigger * pTrigger)
61405b261ecSmrg{
615f7df2e56Smrg    SyncAwait *pAwait = (SyncAwait *) pTrigger;
61605b261ecSmrg    int numwaits;
61705b261ecSmrg    SyncAwaitUnion *pAwaitUnion;
61805b261ecSmrg    SyncAwait **ppAwait;
61905b261ecSmrg    int num_events = 0;
62005b261ecSmrg
621f7df2e56Smrg    pAwaitUnion = (SyncAwaitUnion *) pAwait->pHeader;
62205b261ecSmrg    numwaits = pAwaitUnion->header.num_waitconditions;
623f7df2e56Smrg    ppAwait = xallocarray(numwaits, sizeof(SyncAwait *));
62405b261ecSmrg    if (!ppAwait)
625f7df2e56Smrg        goto bail;
62605b261ecSmrg
627f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await;
62805b261ecSmrg
62905b261ecSmrg    /* "When a client is unblocked, all the CounterNotify events for
63005b261ecSmrg     *  the Await request are generated contiguously. If count is 0
63105b261ecSmrg     *  there are no more events to follow for this request. If
63205b261ecSmrg     *  count is n, there are at least n more events to follow."
63305b261ecSmrg     *
63405b261ecSmrg     *  Thus, it is best to find all the counters for which events
63505b261ecSmrg     *  need to be sent first, so that an accurate count field can
63605b261ecSmrg     *  be stored in the events.
63705b261ecSmrg     */
638f7df2e56Smrg    for (; numwaits; numwaits--, pAwait++) {
639f7df2e56Smrg        CARD64 diff;
640f7df2e56Smrg        Bool overflow, diffgreater, diffequal;
641f7df2e56Smrg
642f7df2e56Smrg        /* "A CounterNotify event with the destroyed flag set to TRUE is
643f7df2e56Smrg         *  always generated if the counter for one of the triggers is
644f7df2e56Smrg         *  destroyed."
645f7df2e56Smrg         */
646f7df2e56Smrg        if (pAwait->trigger.pSync->beingDestroyed) {
647f7df2e56Smrg            ppAwait[num_events++] = pAwait;
648f7df2e56Smrg            continue;
649f7df2e56Smrg        }
650f7df2e56Smrg
651f7df2e56Smrg        if (SYNC_COUNTER == pAwait->trigger.pSync->type) {
652f7df2e56Smrg            SyncCounter *pCounter = (SyncCounter *) pAwait->trigger.pSync;
653f7df2e56Smrg
654f7df2e56Smrg            /* "The difference between the counter and the test value is
655f7df2e56Smrg             *  calculated by subtracting the test value from the value of
656f7df2e56Smrg             *  the counter."
657f7df2e56Smrg             */
658f7df2e56Smrg            XSyncValueSubtract(&diff, pCounter->value,
659f7df2e56Smrg                               pAwait->trigger.test_value, &overflow);
660f7df2e56Smrg
661f7df2e56Smrg            /* "If the difference lies outside the range for an INT64, an
662f7df2e56Smrg             *  event is not generated."
663f7df2e56Smrg             */
664f7df2e56Smrg            if (overflow)
665f7df2e56Smrg                continue;
666f7df2e56Smrg            diffgreater = XSyncValueGreaterThan(diff, pAwait->event_threshold);
667f7df2e56Smrg            diffequal = XSyncValueEqual(diff, pAwait->event_threshold);
668f7df2e56Smrg
669f7df2e56Smrg            /* "If the test-type is PositiveTransition or
670f7df2e56Smrg             *  PositiveComparison, a CounterNotify event is generated if
671f7df2e56Smrg             *  the difference is at least event-threshold. If the test-type
672f7df2e56Smrg             *  is NegativeTransition or NegativeComparison, a CounterNotify
673f7df2e56Smrg             *  event is generated if the difference is at most
674f7df2e56Smrg             *  event-threshold."
675f7df2e56Smrg             */
676f7df2e56Smrg
677f7df2e56Smrg            if (((pAwait->trigger.test_type == XSyncPositiveComparison ||
678f7df2e56Smrg                  pAwait->trigger.test_type == XSyncPositiveTransition)
679f7df2e56Smrg                 && (diffgreater || diffequal))
680f7df2e56Smrg                ||
681f7df2e56Smrg                ((pAwait->trigger.test_type == XSyncNegativeComparison ||
682f7df2e56Smrg                  pAwait->trigger.test_type == XSyncNegativeTransition)
683f7df2e56Smrg                 && (!diffgreater)      /* less or equal */
684f7df2e56Smrg                )
685f7df2e56Smrg                ) {
686f7df2e56Smrg                ppAwait[num_events++] = pAwait;
687f7df2e56Smrg            }
688f7df2e56Smrg        }
68905b261ecSmrg    }
69005b261ecSmrg    if (num_events)
691f7df2e56Smrg        SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait,
692f7df2e56Smrg                                    num_events);
6934202a189Smrg    free(ppAwait);
69405b261ecSmrg
695f7df2e56Smrg bail:
69605b261ecSmrg    /* unblock the client */
69705b261ecSmrg    AttendClient(pAwaitUnion->header.client);
69805b261ecSmrg    /* delete the await */
69905b261ecSmrg    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
70005b261ecSmrg}
70105b261ecSmrg
702f7df2e56Smrgstatic CARD64
703f7df2e56SmrgSyncUpdateCounter(SyncCounter *pCounter, CARD64 newval)
704f7df2e56Smrg{
705f7df2e56Smrg    CARD64 oldval = pCounter->value;
706f7df2e56Smrg    pCounter->value = newval;
707f7df2e56Smrg    return oldval;
708f7df2e56Smrg}
70905b261ecSmrg
71005b261ecSmrg/*  This function should always be used to change a counter's value so that
71105b261ecSmrg *  any triggers depending on the counter will be checked.
71205b261ecSmrg */
71305b261ecSmrgvoid
714f7df2e56SmrgSyncChangeCounter(SyncCounter * pCounter, CARD64 newval)
71505b261ecSmrg{
716f7df2e56Smrg    SyncTriggerList *ptl, *pnext;
71705b261ecSmrg    CARD64 oldval;
71805b261ecSmrg
719f7df2e56Smrg    oldval = SyncUpdateCounter(pCounter, newval);
72005b261ecSmrg
72105b261ecSmrg    /* run through triggers to see if any become true */
722f7df2e56Smrg    for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) {
723f7df2e56Smrg        pnext = ptl->next;
724f7df2e56Smrg        if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, oldval))
725f7df2e56Smrg            (*ptl->pTrigger->TriggerFired) (ptl->pTrigger);
72605b261ecSmrg    }
72705b261ecSmrg
728f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
729f7df2e56Smrg        SyncComputeBracketValues(pCounter);
73005b261ecSmrg    }
73105b261ecSmrg}
73205b261ecSmrg
73305b261ecSmrg/* loosely based on dix/events.c/EventSelectForWindow */
73405b261ecSmrgstatic Bool
735f7df2e56SmrgSyncEventSelectForAlarm(SyncAlarm * pAlarm, ClientPtr client, Bool wantevents)
73605b261ecSmrg{
73705b261ecSmrg    SyncAlarmClientList *pClients;
73805b261ecSmrg
739f7df2e56Smrg    if (client == pAlarm->client) {     /* alarm owner */
740f7df2e56Smrg        pAlarm->events = wantevents;
741f7df2e56Smrg        return Success;
74205b261ecSmrg    }
74305b261ecSmrg
74405b261ecSmrg    /* see if the client is already on the list (has events selected) */
74505b261ecSmrg
746f7df2e56Smrg    for (pClients = pAlarm->pEventClients; pClients; pClients = pClients->next) {
747f7df2e56Smrg        if (pClients->client == client) {
748f7df2e56Smrg            /* client's presence on the list indicates desire for
749f7df2e56Smrg             * events.  If the client doesn't want events, remove it
750f7df2e56Smrg             * from the list.  If the client does want events, do
751f7df2e56Smrg             * nothing, since it's already got them.
752f7df2e56Smrg             */
753f7df2e56Smrg            if (!wantevents) {
754f7df2e56Smrg                FreeResource(pClients->delete_id, RT_NONE);
755f7df2e56Smrg            }
756f7df2e56Smrg            return Success;
757f7df2e56Smrg        }
75805b261ecSmrg    }
75905b261ecSmrg
76005b261ecSmrg    /*  if we get here, this client does not currently have
76105b261ecSmrg     *  events selected on the alarm
76205b261ecSmrg     */
76305b261ecSmrg
76405b261ecSmrg    if (!wantevents)
765f7df2e56Smrg        /* client doesn't want events, and we just discovered that it
766f7df2e56Smrg         * doesn't have them, so there's nothing to do.
767f7df2e56Smrg         */
768f7df2e56Smrg        return Success;
76905b261ecSmrg
77005b261ecSmrg    /* add new client to pAlarm->pEventClients */
77105b261ecSmrg
7724202a189Smrg    pClients = malloc(sizeof(SyncAlarmClientList));
77305b261ecSmrg    if (!pClients)
774f7df2e56Smrg        return BadAlloc;
77505b261ecSmrg
7764202a189Smrg    /*  register it as a resource so it will be cleaned up
77705b261ecSmrg     *  if the client dies
77805b261ecSmrg     */
77905b261ecSmrg
78005b261ecSmrg    pClients->delete_id = FakeClientID(client->index);
78105b261ecSmrg
78205b261ecSmrg    /* link it into list after we know all the allocations succeed */
78305b261ecSmrg    pClients->next = pAlarm->pEventClients;
78405b261ecSmrg    pAlarm->pEventClients = pClients;
78505b261ecSmrg    pClients->client = client;
78665b04b38Smrg
78765b04b38Smrg    if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm))
788f7df2e56Smrg        return BadAlloc;
78965b04b38Smrg
79005b261ecSmrg    return Success;
79105b261ecSmrg}
79205b261ecSmrg
79305b261ecSmrg/*
79405b261ecSmrg * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm
79505b261ecSmrg */
7964202a189Smrgstatic int
797f7df2e56SmrgSyncChangeAlarmAttributes(ClientPtr client, SyncAlarm * pAlarm, Mask mask,
798f7df2e56Smrg                          CARD32 *values)
799f7df2e56Smrg{
800f7df2e56Smrg    int status;
801f7df2e56Smrg    XSyncCounter counter;
802f7df2e56Smrg    Mask origmask = mask;
803f7df2e56Smrg
804f7df2e56Smrg    counter = pAlarm->trigger.pSync ? pAlarm->trigger.pSync->id : None;
805f7df2e56Smrg
806f7df2e56Smrg    while (mask) {
807f7df2e56Smrg        int index2 = lowbit(mask);
808f7df2e56Smrg
809f7df2e56Smrg        mask &= ~index2;
810f7df2e56Smrg        switch (index2) {
811f7df2e56Smrg        case XSyncCACounter:
812f7df2e56Smrg            mask &= ~XSyncCACounter;
813f7df2e56Smrg            /* sanity check in SyncInitTrigger */
814f7df2e56Smrg            counter = *values++;
815f7df2e56Smrg            break;
816f7df2e56Smrg
817f7df2e56Smrg        case XSyncCAValueType:
818f7df2e56Smrg            mask &= ~XSyncCAValueType;
819f7df2e56Smrg            /* sanity check in SyncInitTrigger */
820f7df2e56Smrg            pAlarm->trigger.value_type = *values++;
821f7df2e56Smrg            break;
822f7df2e56Smrg
823f7df2e56Smrg        case XSyncCAValue:
824f7df2e56Smrg            mask &= ~XSyncCAValue;
825f7df2e56Smrg            XSyncIntsToValue(&pAlarm->trigger.wait_value, values[1], values[0]);
826f7df2e56Smrg            values += 2;
827f7df2e56Smrg            break;
828f7df2e56Smrg
829f7df2e56Smrg        case XSyncCATestType:
830f7df2e56Smrg            mask &= ~XSyncCATestType;
831f7df2e56Smrg            /* sanity check in SyncInitTrigger */
832f7df2e56Smrg            pAlarm->trigger.test_type = *values++;
833f7df2e56Smrg            break;
834f7df2e56Smrg
835f7df2e56Smrg        case XSyncCADelta:
836f7df2e56Smrg            mask &= ~XSyncCADelta;
837f7df2e56Smrg            XSyncIntsToValue(&pAlarm->delta, values[1], values[0]);
838f7df2e56Smrg            values += 2;
839f7df2e56Smrg            break;
840f7df2e56Smrg
841f7df2e56Smrg        case XSyncCAEvents:
842f7df2e56Smrg            mask &= ~XSyncCAEvents;
843f7df2e56Smrg            if ((*values != xTrue) && (*values != xFalse)) {
844f7df2e56Smrg                client->errorValue = *values;
845f7df2e56Smrg                return BadValue;
846f7df2e56Smrg            }
847f7df2e56Smrg            status = SyncEventSelectForAlarm(pAlarm, client,
848f7df2e56Smrg                                             (Bool) (*values++));
849f7df2e56Smrg            if (status != Success)
850f7df2e56Smrg                return status;
851f7df2e56Smrg            break;
852f7df2e56Smrg
853f7df2e56Smrg        default:
854f7df2e56Smrg            client->errorValue = mask;
855f7df2e56Smrg            return BadValue;
856f7df2e56Smrg        }
85705b261ecSmrg    }
85805b261ecSmrg
85905b261ecSmrg    /* "If the test-type is PositiveComparison or PositiveTransition
86005b261ecSmrg     *  and delta is less than zero, or if the test-type is
86105b261ecSmrg     *  NegativeComparison or NegativeTransition and delta is
86205b261ecSmrg     *  greater than zero, a Match error is generated."
86305b261ecSmrg     */
864f7df2e56Smrg    if (origmask & (XSyncCADelta | XSyncCATestType)) {
865f7df2e56Smrg        CARD64 zero;
866f7df2e56Smrg
867f7df2e56Smrg        XSyncIntToValue(&zero, 0);
868f7df2e56Smrg        if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) ||
869f7df2e56Smrg              (pAlarm->trigger.test_type == XSyncPositiveTransition))
870f7df2e56Smrg             && XSyncValueLessThan(pAlarm->delta, zero))
871f7df2e56Smrg            ||
872f7df2e56Smrg            (((pAlarm->trigger.test_type == XSyncNegativeComparison) ||
873f7df2e56Smrg              (pAlarm->trigger.test_type == XSyncNegativeTransition))
874f7df2e56Smrg             && XSyncValueGreaterThan(pAlarm->delta, zero))
875f7df2e56Smrg            ) {
876f7df2e56Smrg            return BadMatch;
877f7df2e56Smrg        }
87805b261ecSmrg    }
87905b261ecSmrg
88005b261ecSmrg    /* postpone this until now, when we're sure nothing else can go wrong */
88165b04b38Smrg    if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter,
882f7df2e56Smrg                                  origmask & XSyncCAAllTrigger)) != Success)
883f7df2e56Smrg        return status;
88405b261ecSmrg
88505b261ecSmrg    /* XXX spec does not really say to do this - needs clarification */
88605b261ecSmrg    pAlarm->state = XSyncAlarmActive;
88705b261ecSmrg    return Success;
88805b261ecSmrg}
88905b261ecSmrg
89065b04b38Smrgstatic SyncObject *
89165b04b38SmrgSyncCreate(ClientPtr client, XID id, unsigned char type)
89265b04b38Smrg{
89365b04b38Smrg    SyncObject *pSync;
89465b04b38Smrg
89565b04b38Smrg    switch (type) {
89665b04b38Smrg    case SYNC_COUNTER:
897f7df2e56Smrg        pSync = malloc(sizeof(SyncCounter));
898f7df2e56Smrg        break;
89965b04b38Smrg    case SYNC_FENCE:
900f7df2e56Smrg        pSync = (SyncObject *) dixAllocateObjectWithPrivates(SyncFence,
901f7df2e56Smrg                                                             PRIVATE_SYNC_FENCE);
902f7df2e56Smrg        break;
90365b04b38Smrg    default:
904f7df2e56Smrg        return NULL;
90565b04b38Smrg    }
90665b04b38Smrg
90765b04b38Smrg    if (!pSync)
908f7df2e56Smrg        return NULL;
90965b04b38Smrg
91065b04b38Smrg    pSync->client = client;
91165b04b38Smrg    pSync->id = id;
91265b04b38Smrg    pSync->pTriglist = NULL;
91365b04b38Smrg    pSync->beingDestroyed = FALSE;
91465b04b38Smrg    pSync->type = type;
91565b04b38Smrg
91665b04b38Smrg    return pSync;
91765b04b38Smrg}
91865b04b38Smrg
919f7df2e56Smrgint
920f7df2e56SmrgSyncCreateFenceFromFD(ClientPtr client, DrawablePtr pDraw, XID id, int fd, BOOL initially_triggered)
921f7df2e56Smrg{
922f7df2e56Smrg#if HAVE_XSHMFENCE
923f7df2e56Smrg    SyncFence  *pFence;
924f7df2e56Smrg    int         status;
925f7df2e56Smrg
926f7df2e56Smrg    pFence = (SyncFence *) SyncCreate(client, id, SYNC_FENCE);
927f7df2e56Smrg    if (!pFence)
928f7df2e56Smrg        return BadAlloc;
929f7df2e56Smrg
930f7df2e56Smrg    status = miSyncInitFenceFromFD(pDraw, pFence, fd, initially_triggered);
931f7df2e56Smrg    if (status != Success) {
932f7df2e56Smrg        dixFreeObjectWithPrivates(pFence, PRIVATE_SYNC_FENCE);
933f7df2e56Smrg        return status;
934f7df2e56Smrg    }
935f7df2e56Smrg
936f7df2e56Smrg    if (!AddResource(id, RTFence, (void *) pFence))
937f7df2e56Smrg        return BadAlloc;
938f7df2e56Smrg
939f7df2e56Smrg    return Success;
940f7df2e56Smrg#else
941f7df2e56Smrg    return BadImplementation;
942f7df2e56Smrg#endif
943f7df2e56Smrg}
944f7df2e56Smrg
945f7df2e56Smrgint
946f7df2e56SmrgSyncFDFromFence(ClientPtr client, DrawablePtr pDraw, SyncFence *pFence)
947f7df2e56Smrg{
948f7df2e56Smrg#if HAVE_XSHMFENCE
949f7df2e56Smrg    return miSyncFDFromFence(pDraw, pFence);
950f7df2e56Smrg#else
951f7df2e56Smrg    return BadImplementation;
952f7df2e56Smrg#endif
953f7df2e56Smrg}
95405b261ecSmrg
95505b261ecSmrgstatic SyncCounter *
9564202a189SmrgSyncCreateCounter(ClientPtr client, XSyncCounter id, CARD64 initialvalue)
95705b261ecSmrg{
95805b261ecSmrg    SyncCounter *pCounter;
95905b261ecSmrg
960f7df2e56Smrg    if (!(pCounter = (SyncCounter *) SyncCreate(client, id, SYNC_COUNTER)))
961f7df2e56Smrg        return NULL;
96205b261ecSmrg
96365b04b38Smrg    pCounter->value = initialvalue;
96465b04b38Smrg    pCounter->pSysCounterInfo = NULL;
96565b04b38Smrg
966f7df2e56Smrg    if (!AddResource(id, RTCounter, (void *) pCounter))
967f7df2e56Smrg        return NULL;
96805b261ecSmrg
96905b261ecSmrg    return pCounter;
97005b261ecSmrg}
97105b261ecSmrg
9724202a189Smrgstatic int FreeCounter(void *, XID);
97305b261ecSmrg
97405b261ecSmrg/*
97505b261ecSmrg * ***** System Counter utilities
97605b261ecSmrg */
97705b261ecSmrg
978f7df2e56SmrgSyncCounter*
979f7df2e56SmrgSyncCreateSystemCounter(const char *name,
980f7df2e56Smrg                        CARD64 initial,
981f7df2e56Smrg                        CARD64 resolution,
982f7df2e56Smrg                        SyncCounterType counterType,
983f7df2e56Smrg                        SyncSystemCounterQueryValue QueryValue,
984f7df2e56Smrg                        SyncSystemCounterBracketValues BracketValues
985f7df2e56Smrg    )
986f7df2e56Smrg{
987f7df2e56Smrg    SyncCounter *pCounter;
98805b261ecSmrg
98905b261ecSmrg    /* this function may be called before SYNC has been initialized, so we
99005b261ecSmrg     * have to make sure RTCounter is created.
99105b261ecSmrg     */
992f7df2e56Smrg    if (RTCounter == 0) {
993f7df2e56Smrg        RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
994f7df2e56Smrg        if (RTCounter == 0) {
995f7df2e56Smrg            return NULL;
996f7df2e56Smrg        }
997f7df2e56Smrg        xorg_list_init(&SysCounterList);
99805b261ecSmrg    }
99905b261ecSmrg
10004202a189Smrg    pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial);
100105b261ecSmrg
1002f7df2e56Smrg    if (pCounter) {
1003f7df2e56Smrg        SysCounterInfo *psci;
1004f7df2e56Smrg
1005f7df2e56Smrg        psci = malloc(sizeof(SysCounterInfo));
1006f7df2e56Smrg        if (!psci) {
1007f7df2e56Smrg            FreeResource(pCounter->sync.id, RT_NONE);
1008f7df2e56Smrg            return pCounter;
1009f7df2e56Smrg        }
1010f7df2e56Smrg        pCounter->pSysCounterInfo = psci;
1011f7df2e56Smrg        psci->pCounter = pCounter;
1012f7df2e56Smrg        psci->name = strdup(name);
1013f7df2e56Smrg        psci->resolution = resolution;
1014f7df2e56Smrg        psci->counterType = counterType;
1015f7df2e56Smrg        psci->QueryValue = QueryValue;
1016f7df2e56Smrg        psci->BracketValues = BracketValues;
1017f7df2e56Smrg        psci->private = NULL;
1018f7df2e56Smrg        XSyncMaxValue(&psci->bracket_greater);
1019f7df2e56Smrg        XSyncMinValue(&psci->bracket_less);
1020f7df2e56Smrg        xorg_list_add(&psci->entry, &SysCounterList);
102105b261ecSmrg    }
10224202a189Smrg    return pCounter;
102305b261ecSmrg}
102405b261ecSmrg
102505b261ecSmrgvoid
1026f7df2e56SmrgSyncDestroySystemCounter(void *pSysCounter)
102705b261ecSmrg{
1028f7df2e56Smrg    SyncCounter *pCounter = (SyncCounter *) pSysCounter;
1029f7df2e56Smrg
103065b04b38Smrg    FreeResource(pCounter->sync.id, RT_NONE);
103105b261ecSmrg}
103205b261ecSmrg
103305b261ecSmrgstatic void
1034f7df2e56SmrgSyncComputeBracketValues(SyncCounter * pCounter)
103505b261ecSmrg{
103605b261ecSmrg    SyncTriggerList *pCur;
103705b261ecSmrg    SyncTrigger *pTrigger;
103805b261ecSmrg    SysCounterInfo *psci;
103905b261ecSmrg    CARD64 *pnewgtval = NULL;
104005b261ecSmrg    CARD64 *pnewltval = NULL;
104105b261ecSmrg    SyncCounterType ct;
104205b261ecSmrg
104305b261ecSmrg    if (!pCounter)
1044f7df2e56Smrg        return;
104505b261ecSmrg
104605b261ecSmrg    psci = pCounter->pSysCounterInfo;
104705b261ecSmrg    ct = pCounter->pSysCounterInfo->counterType;
104805b261ecSmrg    if (ct == XSyncCounterNeverChanges)
1049f7df2e56Smrg        return;
105005b261ecSmrg
10514202a189Smrg    XSyncMaxValue(&psci->bracket_greater);
10524202a189Smrg    XSyncMinValue(&psci->bracket_less);
105305b261ecSmrg
1054f7df2e56Smrg    for (pCur = pCounter->sync.pTriglist; pCur; pCur = pCur->next) {
1055f7df2e56Smrg        pTrigger = pCur->pTrigger;
1056f7df2e56Smrg
105705b261ecSmrg        if (pTrigger->test_type == XSyncPositiveComparison &&
1058f7df2e56Smrg            ct != XSyncCounterNeverIncreases) {
1059f7df2e56Smrg            if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
1060f7df2e56Smrg                XSyncValueLessThan(pTrigger->test_value,
1061f7df2e56Smrg                                   psci->bracket_greater)) {
1062f7df2e56Smrg                psci->bracket_greater = pTrigger->test_value;
1063f7df2e56Smrg                pnewgtval = &psci->bracket_greater;
1064f7df2e56Smrg            }
1065f7df2e56Smrg            else if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
1066f7df2e56Smrg                     XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less)) {
1067f7df2e56Smrg                    psci->bracket_less = pTrigger->test_value;
1068f7df2e56Smrg                    pnewltval = &psci->bracket_less;
1069f7df2e56Smrg            }
1070f7df2e56Smrg        }
1071f7df2e56Smrg        else if (pTrigger->test_type == XSyncNegativeComparison &&
1072f7df2e56Smrg                 ct != XSyncCounterNeverDecreases) {
1073f7df2e56Smrg            if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
1074f7df2e56Smrg                XSyncValueGreaterThan(pTrigger->test_value,
1075f7df2e56Smrg                                      psci->bracket_less)) {
1076f7df2e56Smrg                psci->bracket_less = pTrigger->test_value;
1077f7df2e56Smrg                pnewltval = &psci->bracket_less;
1078f7df2e56Smrg            }
1079f7df2e56Smrg            else if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
1080f7df2e56Smrg                     XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater)) {
1081f7df2e56Smrg                    psci->bracket_greater = pTrigger->test_value;
1082f7df2e56Smrg                    pnewgtval = &psci->bracket_greater;
1083f7df2e56Smrg            }
1084f7df2e56Smrg        }
1085f7df2e56Smrg        else if (pTrigger->test_type == XSyncNegativeTransition &&
1086f7df2e56Smrg                 ct != XSyncCounterNeverIncreases) {
1087f7df2e56Smrg            if (XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value) &&
1088f7df2e56Smrg                XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less)) {
1089f7df2e56Smrg                    /*
1090f7df2e56Smrg                     * If the value is exactly equal to our threshold, we want one
1091f7df2e56Smrg                     * more event in the negative direction to ensure we pick up
1092f7df2e56Smrg                     * when the value is less than this threshold.
1093f7df2e56Smrg                     */
1094f7df2e56Smrg                    psci->bracket_less = pTrigger->test_value;
1095f7df2e56Smrg                    pnewltval = &psci->bracket_less;
1096f7df2e56Smrg            }
1097f7df2e56Smrg            else if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
1098f7df2e56Smrg                     XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater)) {
1099f7df2e56Smrg                    psci->bracket_greater = pTrigger->test_value;
1100f7df2e56Smrg                    pnewgtval = &psci->bracket_greater;
1101f7df2e56Smrg            }
1102f7df2e56Smrg        }
1103a0d10bb6Smrg        else if (pTrigger->test_type == XSyncPositiveTransition &&
1104f7df2e56Smrg                 ct != XSyncCounterNeverDecreases) {
1105f7df2e56Smrg            if (XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value) &&
1106f7df2e56Smrg                XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater)) {
1107f7df2e56Smrg                    /*
1108f7df2e56Smrg                     * If the value is exactly equal to our threshold, we
1109f7df2e56Smrg                     * want one more event in the positive direction to
1110f7df2e56Smrg                     * ensure we pick up when the value *exceeds* this
1111f7df2e56Smrg                     * threshold.
1112f7df2e56Smrg                     */
1113f7df2e56Smrg                    psci->bracket_greater = pTrigger->test_value;
1114f7df2e56Smrg                    pnewgtval = &psci->bracket_greater;
1115f7df2e56Smrg            }
1116f7df2e56Smrg            else if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
1117f7df2e56Smrg                     XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less)) {
1118f7df2e56Smrg                    psci->bracket_less = pTrigger->test_value;
1119f7df2e56Smrg                    pnewltval = &psci->bracket_less;
1120f7df2e56Smrg            }
1121f7df2e56Smrg        }
1122f7df2e56Smrg    }                           /* end for each trigger */
1123f7df2e56Smrg
1124f7df2e56Smrg    (*psci->BracketValues) ((void *) pCounter, pnewltval, pnewgtval);
1125f7df2e56Smrg
112605b261ecSmrg}
112705b261ecSmrg
112805b261ecSmrg/*
112905b261ecSmrg * *****  Resource delete functions
113005b261ecSmrg */
113105b261ecSmrg
113205b261ecSmrg/* ARGSUSED */
113305b261ecSmrgstatic int
11344202a189SmrgFreeAlarm(void *addr, XID id)
113505b261ecSmrg{
1136f7df2e56Smrg    SyncAlarm *pAlarm = (SyncAlarm *) addr;
113705b261ecSmrg
113805b261ecSmrg    pAlarm->state = XSyncAlarmDestroyed;
113905b261ecSmrg
114005b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
114105b261ecSmrg
114205b261ecSmrg    /* delete event selections */
114305b261ecSmrg
114405b261ecSmrg    while (pAlarm->pEventClients)
1145f7df2e56Smrg        FreeResource(pAlarm->pEventClients->delete_id, RT_NONE);
114605b261ecSmrg
114765b04b38Smrg    SyncDeleteTriggerFromSyncObject(&pAlarm->trigger);
114805b261ecSmrg
11494202a189Smrg    free(pAlarm);
115005b261ecSmrg    return Success;
115105b261ecSmrg}
115205b261ecSmrg
115305b261ecSmrg/*
115405b261ecSmrg * ** Cleanup after the destruction of a Counter
115505b261ecSmrg */
115605b261ecSmrg/* ARGSUSED */
115705b261ecSmrgstatic int
11584202a189SmrgFreeCounter(void *env, XID id)
115905b261ecSmrg{
1160f7df2e56Smrg    SyncCounter *pCounter = (SyncCounter *) env;
116105b261ecSmrg    SyncTriggerList *ptl, *pnext;
116205b261ecSmrg
116365b04b38Smrg    pCounter->sync.beingDestroyed = TRUE;
116405b261ecSmrg    /* tell all the counter's triggers that the counter has been destroyed */
1165f7df2e56Smrg    for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) {
1166f7df2e56Smrg        (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger);
1167f7df2e56Smrg        pnext = ptl->next;
1168f7df2e56Smrg        free(ptl);              /* destroy the trigger list as we go */
1169f7df2e56Smrg    }
1170f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
1171f7df2e56Smrg        xorg_list_del(&pCounter->pSysCounterInfo->entry);
1172f7df2e56Smrg        free(pCounter->pSysCounterInfo->name);
1173f7df2e56Smrg        free(pCounter->pSysCounterInfo->private);
1174f7df2e56Smrg        free(pCounter->pSysCounterInfo);
117505b261ecSmrg    }
11764202a189Smrg    free(pCounter);
117705b261ecSmrg    return Success;
117805b261ecSmrg}
117905b261ecSmrg
118005b261ecSmrg/*
118105b261ecSmrg * ** Cleanup after Await
118205b261ecSmrg */
118305b261ecSmrg/* ARGSUSED */
118405b261ecSmrgstatic int
11854202a189SmrgFreeAwait(void *addr, XID id)
118605b261ecSmrg{
118705b261ecSmrg    SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr;
118805b261ecSmrg    SyncAwait *pAwait;
118905b261ecSmrg    int numwaits;
119005b261ecSmrg
1191f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await; /* first await on list */
119205b261ecSmrg
119305b261ecSmrg    /* remove triggers from counters */
119405b261ecSmrg
119505b261ecSmrg    for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits;
1196f7df2e56Smrg         numwaits--, pAwait++) {
1197f7df2e56Smrg        /* If the counter is being destroyed, FreeCounter will delete
1198f7df2e56Smrg         * the trigger list itself, so don't do it here.
1199f7df2e56Smrg         */
1200f7df2e56Smrg        SyncObject *pSync = pAwait->trigger.pSync;
1201f7df2e56Smrg
1202f7df2e56Smrg        if (pSync && !pSync->beingDestroyed)
1203f7df2e56Smrg            SyncDeleteTriggerFromSyncObject(&pAwait->trigger);
120405b261ecSmrg    }
12054202a189Smrg    free(pAwaitUnion);
120605b261ecSmrg    return Success;
120705b261ecSmrg}
120805b261ecSmrg
120905b261ecSmrg/* loosely based on dix/events.c/OtherClientGone */
121005b261ecSmrgstatic int
12114202a189SmrgFreeAlarmClient(void *value, XID id)
121205b261ecSmrg{
1213f7df2e56Smrg    SyncAlarm *pAlarm = (SyncAlarm *) value;
121405b261ecSmrg    SyncAlarmClientList *pCur, *pPrev;
121505b261ecSmrg
121605b261ecSmrg    for (pPrev = NULL, pCur = pAlarm->pEventClients;
1217f7df2e56Smrg         pCur; pPrev = pCur, pCur = pCur->next) {
1218f7df2e56Smrg        if (pCur->delete_id == id) {
1219f7df2e56Smrg            if (pPrev)
1220f7df2e56Smrg                pPrev->next = pCur->next;
1221f7df2e56Smrg            else
1222f7df2e56Smrg                pAlarm->pEventClients = pCur->next;
1223f7df2e56Smrg            free(pCur);
1224f7df2e56Smrg            return Success;
1225f7df2e56Smrg        }
122605b261ecSmrg    }
122705b261ecSmrg    FatalError("alarm client not on event list");
1228f7df2e56Smrg /*NOTREACHED*/}
122905b261ecSmrg
123005b261ecSmrg/*
123105b261ecSmrg * *****  Proc functions
123205b261ecSmrg */
123305b261ecSmrg
123405b261ecSmrg/*
123505b261ecSmrg * ** Initialize the extension
123605b261ecSmrg */
12374202a189Smrgstatic int
12384202a189SmrgProcSyncInitialize(ClientPtr client)
123905b261ecSmrg{
1240f7df2e56Smrg    xSyncInitializeReply rep = {
1241f7df2e56Smrg        .type = X_Reply,
1242f7df2e56Smrg        .sequenceNumber = client->sequence,
1243f7df2e56Smrg        .length = 0,
1244f7df2e56Smrg        .majorVersion = SERVER_SYNC_MAJOR_VERSION,
1245f7df2e56Smrg        .minorVersion = SERVER_SYNC_MINOR_VERSION,
1246f7df2e56Smrg    };
124705b261ecSmrg
124805b261ecSmrg    REQUEST_SIZE_MATCH(xSyncInitializeReq);
124905b261ecSmrg
1250f7df2e56Smrg    if (client->swapped) {
1251f7df2e56Smrg        swaps(&rep.sequenceNumber);
125205b261ecSmrg    }
1253f7df2e56Smrg    WriteToClient(client, sizeof(rep), &rep);
12544202a189Smrg    return Success;
125505b261ecSmrg}
125605b261ecSmrg
125705b261ecSmrg/*
125805b261ecSmrg * ** Get list of system counters available through the extension
125905b261ecSmrg */
12604202a189Smrgstatic int
12614202a189SmrgProcSyncListSystemCounters(ClientPtr client)
126205b261ecSmrg{
1263f7df2e56Smrg    xSyncListSystemCountersReply rep = {
1264f7df2e56Smrg        .type = X_Reply,
1265f7df2e56Smrg        .sequenceNumber = client->sequence,
1266f7df2e56Smrg        .nCounters = 0,
1267f7df2e56Smrg    };
1268f7df2e56Smrg    SysCounterInfo *psci;
1269f7df2e56Smrg    int len = 0;
127005b261ecSmrg    xSyncSystemCounter *list = NULL, *walklist = NULL;
12714202a189Smrg
127205b261ecSmrg    REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
127305b261ecSmrg
1274f7df2e56Smrg    xorg_list_for_each_entry(psci, &SysCounterList, entry) {
1275f7df2e56Smrg        /* pad to 4 byte boundary */
1276f7df2e56Smrg        len += pad_to_int32(sz_xSyncSystemCounter + strlen(psci->name));
1277f7df2e56Smrg        ++rep.nCounters;
127805b261ecSmrg    }
127905b261ecSmrg
1280f7df2e56Smrg    if (len) {
1281f7df2e56Smrg        walklist = list = malloc(len);
1282f7df2e56Smrg        if (!list)
1283f7df2e56Smrg            return BadAlloc;
128405b261ecSmrg    }
128505b261ecSmrg
12864202a189Smrg    rep.length = bytes_to_int32(len);
128705b261ecSmrg
1288f7df2e56Smrg    if (client->swapped) {
1289f7df2e56Smrg        swaps(&rep.sequenceNumber);
1290f7df2e56Smrg        swapl(&rep.length);
1291f7df2e56Smrg        swapl(&rep.nCounters);
129205b261ecSmrg    }
129305b261ecSmrg
1294f7df2e56Smrg    xorg_list_for_each_entry(psci, &SysCounterList, entry) {
1295f7df2e56Smrg        int namelen;
1296f7df2e56Smrg        char *pname_in_reply;
129705b261ecSmrg
1298f7df2e56Smrg        walklist->counter = psci->pCounter->sync.id;
1299f7df2e56Smrg        walklist->resolution_hi = XSyncValueHigh32(psci->resolution);
1300f7df2e56Smrg        walklist->resolution_lo = XSyncValueLow32(psci->resolution);
1301f7df2e56Smrg        namelen = strlen(psci->name);
1302f7df2e56Smrg        walklist->name_length = namelen;
130305b261ecSmrg
1304f7df2e56Smrg        if (client->swapped) {
1305f7df2e56Smrg            swapl(&walklist->counter);
1306f7df2e56Smrg            swapl(&walklist->resolution_hi);
1307f7df2e56Smrg            swapl(&walklist->resolution_lo);
1308f7df2e56Smrg            swaps(&walklist->name_length);
1309f7df2e56Smrg        }
131005b261ecSmrg
1311f7df2e56Smrg        pname_in_reply = ((char *) walklist) + sz_xSyncSystemCounter;
1312f7df2e56Smrg        strncpy(pname_in_reply, psci->name, namelen);
1313f7df2e56Smrg        walklist = (xSyncSystemCounter *) (((char *) walklist) +
1314f7df2e56Smrg                                           pad_to_int32(sz_xSyncSystemCounter +
1315f7df2e56Smrg                                                        namelen));
131605b261ecSmrg    }
131705b261ecSmrg
1318f7df2e56Smrg    WriteToClient(client, sizeof(rep), &rep);
1319f7df2e56Smrg    if (len) {
1320f7df2e56Smrg        WriteToClient(client, len, list);
1321f7df2e56Smrg        free(list);
132205b261ecSmrg    }
132305b261ecSmrg
13244202a189Smrg    return Success;
132505b261ecSmrg}
132605b261ecSmrg
132705b261ecSmrg/*
132805b261ecSmrg * ** Set client Priority
132905b261ecSmrg */
13304202a189Smrgstatic int
13314202a189SmrgProcSyncSetPriority(ClientPtr client)
133205b261ecSmrg{
133305b261ecSmrg    REQUEST(xSyncSetPriorityReq);
133405b261ecSmrg    ClientPtr priorityclient;
133505b261ecSmrg    int rc;
133605b261ecSmrg
133705b261ecSmrg    REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
133805b261ecSmrg
133905b261ecSmrg    if (stuff->id == None)
1340f7df2e56Smrg        priorityclient = client;
134105b261ecSmrg    else {
1342f7df2e56Smrg        rc = dixLookupClient(&priorityclient, stuff->id, client,
1343f7df2e56Smrg                             DixSetAttrAccess);
1344f7df2e56Smrg        if (rc != Success)
1345f7df2e56Smrg            return rc;
134605b261ecSmrg    }
134705b261ecSmrg
1348f7df2e56Smrg    if (priorityclient->priority != stuff->priority) {
1349f7df2e56Smrg        priorityclient->priority = stuff->priority;
135005b261ecSmrg
1351f7df2e56Smrg        /*  The following will force the server back into WaitForSomething
1352f7df2e56Smrg         *  so that the change in this client's priority is immediately
1353f7df2e56Smrg         *  reflected.
1354f7df2e56Smrg         */
1355f7df2e56Smrg        isItTimeToYield = TRUE;
1356f7df2e56Smrg        dispatchException |= DE_PRIORITYCHANGE;
135705b261ecSmrg    }
135805b261ecSmrg    return Success;
135905b261ecSmrg}
136005b261ecSmrg
136105b261ecSmrg/*
136205b261ecSmrg * ** Get client Priority
136305b261ecSmrg */
13644202a189Smrgstatic int
13654202a189SmrgProcSyncGetPriority(ClientPtr client)
136605b261ecSmrg{
136705b261ecSmrg    REQUEST(xSyncGetPriorityReq);
136805b261ecSmrg    xSyncGetPriorityReply rep;
136905b261ecSmrg    ClientPtr priorityclient;
137005b261ecSmrg    int rc;
137105b261ecSmrg
137205b261ecSmrg    REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
137305b261ecSmrg
137405b261ecSmrg    if (stuff->id == None)
1375f7df2e56Smrg        priorityclient = client;
137605b261ecSmrg    else {
1377f7df2e56Smrg        rc = dixLookupClient(&priorityclient, stuff->id, client,
1378f7df2e56Smrg                             DixGetAttrAccess);
1379f7df2e56Smrg        if (rc != Success)
1380f7df2e56Smrg            return rc;
138105b261ecSmrg    }
138205b261ecSmrg
1383f7df2e56Smrg    rep = (xSyncGetPriorityReply) {
1384f7df2e56Smrg        .type = X_Reply,
1385f7df2e56Smrg        .sequenceNumber = client->sequence,
1386f7df2e56Smrg        .length = 0,
1387f7df2e56Smrg        .priority = priorityclient->priority
1388f7df2e56Smrg    };
138905b261ecSmrg
1390f7df2e56Smrg    if (client->swapped) {
1391f7df2e56Smrg        swaps(&rep.sequenceNumber);
1392f7df2e56Smrg        swapl(&rep.priority);
139305b261ecSmrg    }
139405b261ecSmrg
1395f7df2e56Smrg    WriteToClient(client, sizeof(xSyncGetPriorityReply), &rep);
139605b261ecSmrg
13974202a189Smrg    return Success;
139805b261ecSmrg}
139905b261ecSmrg
140005b261ecSmrg/*
140105b261ecSmrg * ** Create a new counter
140205b261ecSmrg */
14034202a189Smrgstatic int
14044202a189SmrgProcSyncCreateCounter(ClientPtr client)
140505b261ecSmrg{
140605b261ecSmrg    REQUEST(xSyncCreateCounterReq);
1407f7df2e56Smrg    CARD64 initial;
140805b261ecSmrg
140905b261ecSmrg    REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
141005b261ecSmrg
141105b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->cid, client);
141205b261ecSmrg
1413f7df2e56Smrg    XSyncIntsToValue(&initial, stuff->initial_value_lo,
1414f7df2e56Smrg                     stuff->initial_value_hi);
141505b261ecSmrg    if (!SyncCreateCounter(client, stuff->cid, initial))
1416f7df2e56Smrg        return BadAlloc;
141705b261ecSmrg
14184202a189Smrg    return Success;
141905b261ecSmrg}
142005b261ecSmrg
142105b261ecSmrg/*
142205b261ecSmrg * ** Set Counter value
142305b261ecSmrg */
14244202a189Smrgstatic int
14254202a189SmrgProcSyncSetCounter(ClientPtr client)
142605b261ecSmrg{
142705b261ecSmrg    REQUEST(xSyncSetCounterReq);
1428f7df2e56Smrg    SyncCounter *pCounter;
1429f7df2e56Smrg    CARD64 newvalue;
1430f7df2e56Smrg    int rc;
143105b261ecSmrg
143205b261ecSmrg    REQUEST_SIZE_MATCH(xSyncSetCounterReq);
143305b261ecSmrg
1434f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter,
1435f7df2e56Smrg                                 client, DixWriteAccess);
14364202a189Smrg    if (rc != Success)
1437f7df2e56Smrg        return rc;
143805b261ecSmrg
1439f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
1440f7df2e56Smrg        client->errorValue = stuff->cid;
1441f7df2e56Smrg        return BadAccess;
144205b261ecSmrg    }
144305b261ecSmrg
144405b261ecSmrg    XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
144505b261ecSmrg    SyncChangeCounter(pCounter, newvalue);
144605b261ecSmrg    return Success;
144705b261ecSmrg}
144805b261ecSmrg
144905b261ecSmrg/*
145005b261ecSmrg * ** Change Counter value
145105b261ecSmrg */
14524202a189Smrgstatic int
14534202a189SmrgProcSyncChangeCounter(ClientPtr client)
145405b261ecSmrg{
145505b261ecSmrg    REQUEST(xSyncChangeCounterReq);
1456f7df2e56Smrg    SyncCounter *pCounter;
1457f7df2e56Smrg    CARD64 newvalue;
1458f7df2e56Smrg    Bool overflow;
1459f7df2e56Smrg    int rc;
146005b261ecSmrg
146105b261ecSmrg    REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
146205b261ecSmrg
1463f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter,
1464f7df2e56Smrg                                 client, DixWriteAccess);
14654202a189Smrg    if (rc != Success)
1466f7df2e56Smrg        return rc;
146705b261ecSmrg
1468f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
1469f7df2e56Smrg        client->errorValue = stuff->cid;
1470f7df2e56Smrg        return BadAccess;
147105b261ecSmrg    }
147205b261ecSmrg
147305b261ecSmrg    XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
147405b261ecSmrg    XSyncValueAdd(&newvalue, pCounter->value, newvalue, &overflow);
1475f7df2e56Smrg    if (overflow) {
1476f7df2e56Smrg        /* XXX 64 bit value can't fit in 32 bits; do the best we can */
1477f7df2e56Smrg        client->errorValue = stuff->value_hi;
1478f7df2e56Smrg        return BadValue;
147905b261ecSmrg    }
148005b261ecSmrg    SyncChangeCounter(pCounter, newvalue);
148105b261ecSmrg    return Success;
148205b261ecSmrg}
148305b261ecSmrg
148405b261ecSmrg/*
148505b261ecSmrg * ** Destroy a counter
148605b261ecSmrg */
14874202a189Smrgstatic int
14884202a189SmrgProcSyncDestroyCounter(ClientPtr client)
148905b261ecSmrg{
149005b261ecSmrg    REQUEST(xSyncDestroyCounterReq);
1491f7df2e56Smrg    SyncCounter *pCounter;
14924202a189Smrg    int rc;
149305b261ecSmrg
149405b261ecSmrg    REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
149505b261ecSmrg
1496f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pCounter, stuff->counter,
1497f7df2e56Smrg                                 RTCounter, client, DixDestroyAccess);
14984202a189Smrg    if (rc != Success)
1499f7df2e56Smrg        return rc;
15004202a189Smrg
1501f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
1502f7df2e56Smrg        client->errorValue = stuff->counter;
1503f7df2e56Smrg        return BadAccess;
150405b261ecSmrg    }
150565b04b38Smrg    FreeResource(pCounter->sync.id, RT_NONE);
150605b261ecSmrg    return Success;
150705b261ecSmrg}
150805b261ecSmrg
1509f7df2e56Smrgstatic SyncAwaitUnion *
151065b04b38SmrgSyncAwaitPrologue(ClientPtr client, int items)
151165b04b38Smrg{
151265b04b38Smrg    SyncAwaitUnion *pAwaitUnion;
151365b04b38Smrg
151465b04b38Smrg    /*  all the memory for the entire await list is allocated
151565b04b38Smrg     *  here in one chunk
151665b04b38Smrg     */
1517f7df2e56Smrg    pAwaitUnion = xallocarray(items + 1, sizeof(SyncAwaitUnion));
151865b04b38Smrg    if (!pAwaitUnion)
1519f7df2e56Smrg        return NULL;
152065b04b38Smrg
152165b04b38Smrg    /* first item is the header, remainder are real wait conditions */
152265b04b38Smrg
152365b04b38Smrg    pAwaitUnion->header.delete_id = FakeClientID(client->index);
152465b04b38Smrg    pAwaitUnion->header.client = client;
152565b04b38Smrg    pAwaitUnion->header.num_waitconditions = 0;
152665b04b38Smrg
152765b04b38Smrg    if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion))
1528f7df2e56Smrg        return NULL;
152965b04b38Smrg
153065b04b38Smrg    return pAwaitUnion;
153165b04b38Smrg}
153265b04b38Smrg
153365b04b38Smrgstatic void
1534f7df2e56SmrgSyncAwaitEpilogue(ClientPtr client, int items, SyncAwaitUnion * pAwaitUnion)
153565b04b38Smrg{
153665b04b38Smrg    SyncAwait *pAwait;
153765b04b38Smrg    int i;
153865b04b38Smrg
153965b04b38Smrg    IgnoreClient(client);
154065b04b38Smrg
154165b04b38Smrg    /* see if any of the triggers are already true */
154265b04b38Smrg
1543f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await; /* skip over header */
1544f7df2e56Smrg    for (i = 0; i < items; i++, pAwait++) {
1545f7df2e56Smrg        CARD64 value;
1546f7df2e56Smrg
1547f7df2e56Smrg        /*  don't have to worry about NULL counters because the request
1548f7df2e56Smrg         *  errors before we get here out if they occur
1549f7df2e56Smrg         */
1550f7df2e56Smrg        switch (pAwait->trigger.pSync->type) {
1551f7df2e56Smrg        case SYNC_COUNTER:
1552f7df2e56Smrg            value = ((SyncCounter *) pAwait->trigger.pSync)->value;
1553f7df2e56Smrg            break;
1554f7df2e56Smrg        default:
1555f7df2e56Smrg            XSyncIntToValue(&value, 0);
1556f7df2e56Smrg        }
155765b04b38Smrg
1558f7df2e56Smrg        if ((*pAwait->trigger.CheckTrigger) (&pAwait->trigger, value)) {
1559f7df2e56Smrg            (*pAwait->trigger.TriggerFired) (&pAwait->trigger);
1560f7df2e56Smrg            break;              /* once is enough */
1561f7df2e56Smrg        }
156265b04b38Smrg    }
156365b04b38Smrg}
156405b261ecSmrg
156505b261ecSmrg/*
156605b261ecSmrg * ** Await
156705b261ecSmrg */
15684202a189Smrgstatic int
15694202a189SmrgProcSyncAwait(ClientPtr client)
157005b261ecSmrg{
157105b261ecSmrg    REQUEST(xSyncAwaitReq);
1572f7df2e56Smrg    int len, items;
1573f7df2e56Smrg    int i;
157405b261ecSmrg    xSyncWaitCondition *pProtocolWaitConds;
157505b261ecSmrg    SyncAwaitUnion *pAwaitUnion;
1576f7df2e56Smrg    SyncAwait *pAwait;
1577f7df2e56Smrg    int status;
157805b261ecSmrg
157905b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
158005b261ecSmrg
158105b261ecSmrg    len = client->req_len << 2;
158205b261ecSmrg    len -= sz_xSyncAwaitReq;
158305b261ecSmrg    items = len / sz_xSyncWaitCondition;
158405b261ecSmrg
1585f7df2e56Smrg    if (items * sz_xSyncWaitCondition != len) {
1586f7df2e56Smrg        return BadLength;
158705b261ecSmrg    }
1588f7df2e56Smrg    if (items == 0) {
1589f7df2e56Smrg        client->errorValue = items;     /* XXX protocol change */
1590f7df2e56Smrg        return BadValue;
159105b261ecSmrg    }
159205b261ecSmrg
159365b04b38Smrg    if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
1594f7df2e56Smrg        return BadAlloc;
159505b261ecSmrg
159605b261ecSmrg    /* don't need to do any more memory allocation for this request! */
159705b261ecSmrg
1598f7df2e56Smrg    pProtocolWaitConds = (xSyncWaitCondition *) &stuff[1];
1599f7df2e56Smrg
1600f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await; /* skip over header */
1601f7df2e56Smrg    for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++) {
1602f7df2e56Smrg        if (pProtocolWaitConds->counter == None) {      /* XXX protocol change */
1603f7df2e56Smrg            /*  this should take care of removing any triggers created by
1604f7df2e56Smrg             *  this request that have already been registered on sync objects
1605f7df2e56Smrg             */
1606f7df2e56Smrg            FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
1607f7df2e56Smrg            client->errorValue = pProtocolWaitConds->counter;
1608f7df2e56Smrg            return SyncErrorBase + XSyncBadCounter;
1609f7df2e56Smrg        }
1610f7df2e56Smrg
1611f7df2e56Smrg        /* sanity checks are in SyncInitTrigger */
1612f7df2e56Smrg        pAwait->trigger.pSync = NULL;
1613f7df2e56Smrg        pAwait->trigger.value_type = pProtocolWaitConds->value_type;
1614f7df2e56Smrg        XSyncIntsToValue(&pAwait->trigger.wait_value,
1615f7df2e56Smrg                         pProtocolWaitConds->wait_value_lo,
1616f7df2e56Smrg                         pProtocolWaitConds->wait_value_hi);
1617f7df2e56Smrg        pAwait->trigger.test_type = pProtocolWaitConds->test_type;
1618f7df2e56Smrg
1619f7df2e56Smrg        status = SyncInitTrigger(client, &pAwait->trigger,
1620f7df2e56Smrg                                 pProtocolWaitConds->counter, RTCounter,
1621f7df2e56Smrg                                 XSyncCAAllTrigger);
1622f7df2e56Smrg        if (status != Success) {
1623f7df2e56Smrg            /*  this should take care of removing any triggers created by
1624f7df2e56Smrg             *  this request that have already been registered on sync objects
1625f7df2e56Smrg             */
1626f7df2e56Smrg            FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
1627f7df2e56Smrg            return status;
1628f7df2e56Smrg        }
1629f7df2e56Smrg        /* this is not a mistake -- same function works for both cases */
1630f7df2e56Smrg        pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
1631f7df2e56Smrg        pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
1632f7df2e56Smrg        XSyncIntsToValue(&pAwait->event_threshold,
1633f7df2e56Smrg                         pProtocolWaitConds->event_threshold_lo,
1634f7df2e56Smrg                         pProtocolWaitConds->event_threshold_hi);
1635f7df2e56Smrg        pAwait->pHeader = &pAwaitUnion->header;
1636f7df2e56Smrg        pAwaitUnion->header.num_waitconditions++;
163705b261ecSmrg    }
163805b261ecSmrg
163965b04b38Smrg    SyncAwaitEpilogue(client, items, pAwaitUnion);
164005b261ecSmrg
164105b261ecSmrg    return Success;
164205b261ecSmrg}
164305b261ecSmrg
164405b261ecSmrg/*
164505b261ecSmrg * ** Query a counter
164605b261ecSmrg */
16474202a189Smrgstatic int
16484202a189SmrgProcSyncQueryCounter(ClientPtr client)
164905b261ecSmrg{
165005b261ecSmrg    REQUEST(xSyncQueryCounterReq);
165105b261ecSmrg    xSyncQueryCounterReply rep;
1652f7df2e56Smrg    SyncCounter *pCounter;
16534202a189Smrg    int rc;
165405b261ecSmrg
165505b261ecSmrg    REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
165605b261ecSmrg
1657f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pCounter, stuff->counter,
1658f7df2e56Smrg                                 RTCounter, client, DixReadAccess);
16594202a189Smrg    if (rc != Success)
1660f7df2e56Smrg        return rc;
166105b261ecSmrg
166205b261ecSmrg    /* if system counter, ask it what the current value is */
1663f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
1664f7df2e56Smrg        (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter,
1665f7df2e56Smrg                                                  &pCounter->value);
1666f7df2e56Smrg    }
1667f7df2e56Smrg
1668f7df2e56Smrg    rep = (xSyncQueryCounterReply) {
1669f7df2e56Smrg        .type = X_Reply,
1670f7df2e56Smrg        .sequenceNumber = client->sequence,
1671f7df2e56Smrg        .length = 0,
1672f7df2e56Smrg        .value_hi = XSyncValueHigh32(pCounter->value),
1673f7df2e56Smrg        .value_lo = XSyncValueLow32(pCounter->value)
1674f7df2e56Smrg    };
1675f7df2e56Smrg
1676f7df2e56Smrg    if (client->swapped) {
1677f7df2e56Smrg        swaps(&rep.sequenceNumber);
1678f7df2e56Smrg        swapl(&rep.length);
1679f7df2e56Smrg        swapl(&rep.value_hi);
1680f7df2e56Smrg        swapl(&rep.value_lo);
1681f7df2e56Smrg    }
1682f7df2e56Smrg    WriteToClient(client, sizeof(xSyncQueryCounterReply), &rep);
16834202a189Smrg    return Success;
168405b261ecSmrg}
168505b261ecSmrg
168605b261ecSmrg/*
168705b261ecSmrg * ** Create Alarm
168805b261ecSmrg */
16894202a189Smrgstatic int
16904202a189SmrgProcSyncCreateAlarm(ClientPtr client)
169105b261ecSmrg{
169205b261ecSmrg    REQUEST(xSyncCreateAlarmReq);
1693f7df2e56Smrg    SyncAlarm *pAlarm;
1694f7df2e56Smrg    int status;
1695f7df2e56Smrg    unsigned long len, vmask;
1696f7df2e56Smrg    SyncTrigger *pTrigger;
169705b261ecSmrg
169805b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
169905b261ecSmrg
170005b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->id, client);
170105b261ecSmrg
170205b261ecSmrg    vmask = stuff->valueMask;
17034202a189Smrg    len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq));
170405b261ecSmrg    /* the "extra" call to Ones accounts for the presence of 64 bit values */
1705f7df2e56Smrg    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta))))
1706f7df2e56Smrg        return BadLength;
170705b261ecSmrg
1708f7df2e56Smrg    if (!(pAlarm = malloc(sizeof(SyncAlarm)))) {
1709f7df2e56Smrg        return BadAlloc;
171005b261ecSmrg    }
171105b261ecSmrg
171205b261ecSmrg    /* set up defaults */
171305b261ecSmrg
171405b261ecSmrg    pTrigger = &pAlarm->trigger;
171565b04b38Smrg    pTrigger->pSync = NULL;
171605b261ecSmrg    pTrigger->value_type = XSyncAbsolute;
171705b261ecSmrg    XSyncIntToValue(&pTrigger->wait_value, 0L);
171805b261ecSmrg    pTrigger->test_type = XSyncPositiveComparison;
171905b261ecSmrg    pTrigger->TriggerFired = SyncAlarmTriggerFired;
172005b261ecSmrg    pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed;
172165b04b38Smrg    status = SyncInitTrigger(client, pTrigger, None, RTCounter,
1722f7df2e56Smrg                             XSyncCAAllTrigger);
1723f7df2e56Smrg    if (status != Success) {
1724f7df2e56Smrg        free(pAlarm);
1725f7df2e56Smrg        return status;
172605b261ecSmrg    }
172705b261ecSmrg
172805b261ecSmrg    pAlarm->client = client;
172905b261ecSmrg    pAlarm->alarm_id = stuff->id;
173005b261ecSmrg    XSyncIntToValue(&pAlarm->delta, 1L);
173105b261ecSmrg    pAlarm->events = TRUE;
173205b261ecSmrg    pAlarm->state = XSyncAlarmInactive;
173305b261ecSmrg    pAlarm->pEventClients = NULL;
173405b261ecSmrg    status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
1735f7df2e56Smrg                                       (CARD32 *) &stuff[1]);
1736f7df2e56Smrg    if (status != Success) {
1737f7df2e56Smrg        free(pAlarm);
1738f7df2e56Smrg        return status;
173905b261ecSmrg    }
174005b261ecSmrg
174105b261ecSmrg    if (!AddResource(stuff->id, RTAlarm, pAlarm))
1742f7df2e56Smrg        return BadAlloc;
174305b261ecSmrg
174405b261ecSmrg    /*  see if alarm already triggered.  NULL counter will not trigger
174505b261ecSmrg     *  in CreateAlarm and sets alarm state to Inactive.
174605b261ecSmrg     */
174705b261ecSmrg
1748f7df2e56Smrg    if (!pTrigger->pSync) {
1749f7df2e56Smrg        pAlarm->state = XSyncAlarmInactive;     /* XXX protocol change */
175005b261ecSmrg    }
1751f7df2e56Smrg    else {
1752f7df2e56Smrg        SyncCounter *pCounter;
175365b04b38Smrg
1754f7df2e56Smrg        if (!SyncCheckWarnIsCounter(pTrigger->pSync,
1755f7df2e56Smrg                                    WARN_INVALID_COUNTER_ALARM)) {
1756f7df2e56Smrg            FreeResource(stuff->id, RT_NONE);
1757f7df2e56Smrg            return BadAlloc;
1758f7df2e56Smrg        }
175965b04b38Smrg
1760f7df2e56Smrg        pCounter = (SyncCounter *) pTrigger->pSync;
176165b04b38Smrg
1762f7df2e56Smrg        if ((*pTrigger->CheckTrigger) (pTrigger, pCounter->value))
1763f7df2e56Smrg            (*pTrigger->TriggerFired) (pTrigger);
176405b261ecSmrg    }
176505b261ecSmrg
176605b261ecSmrg    return Success;
176705b261ecSmrg}
176805b261ecSmrg
176905b261ecSmrg/*
177005b261ecSmrg * ** Change Alarm
177105b261ecSmrg */
17724202a189Smrgstatic int
17734202a189SmrgProcSyncChangeAlarm(ClientPtr client)
177405b261ecSmrg{
177505b261ecSmrg    REQUEST(xSyncChangeAlarmReq);
1776f7df2e56Smrg    SyncAlarm *pAlarm;
177765b04b38Smrg    SyncCounter *pCounter = NULL;
1778f7df2e56Smrg    long vmask;
1779f7df2e56Smrg    int len, status;
178005b261ecSmrg
178105b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
178205b261ecSmrg
1783f7df2e56Smrg    status = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm,
1784f7df2e56Smrg                                     client, DixWriteAccess);
17854202a189Smrg    if (status != Success)
1786f7df2e56Smrg        return status;
178705b261ecSmrg
178805b261ecSmrg    vmask = stuff->valueMask;
17894202a189Smrg    len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq));
179005b261ecSmrg    /* the "extra" call to Ones accounts for the presence of 64 bit values */
1791f7df2e56Smrg    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta))))
1792f7df2e56Smrg        return BadLength;
179305b261ecSmrg
17944202a189Smrg    if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
1795f7df2e56Smrg                                            (CARD32 *) &stuff[1])) != Success)
1796f7df2e56Smrg        return status;
179705b261ecSmrg
179865b04b38Smrg    if (SyncCheckWarnIsCounter(pAlarm->trigger.pSync,
1799f7df2e56Smrg                               WARN_INVALID_COUNTER_ALARM))
1800f7df2e56Smrg        pCounter = (SyncCounter *) pAlarm->trigger.pSync;
180165b04b38Smrg
180205b261ecSmrg    /*  see if alarm already triggered.  NULL counter WILL trigger
180305b261ecSmrg     *  in ChangeAlarm.
180405b261ecSmrg     */
180505b261ecSmrg
180665b04b38Smrg    if (!pCounter ||
1807f7df2e56Smrg        (*pAlarm->trigger.CheckTrigger) (&pAlarm->trigger, pCounter->value)) {
1808f7df2e56Smrg        (*pAlarm->trigger.TriggerFired) (&pAlarm->trigger);
180905b261ecSmrg    }
181005b261ecSmrg    return Success;
181105b261ecSmrg}
181205b261ecSmrg
18134202a189Smrgstatic int
18144202a189SmrgProcSyncQueryAlarm(ClientPtr client)
181505b261ecSmrg{
181605b261ecSmrg    REQUEST(xSyncQueryAlarmReq);
1817f7df2e56Smrg    SyncAlarm *pAlarm;
181805b261ecSmrg    xSyncQueryAlarmReply rep;
1819f7df2e56Smrg    SyncTrigger *pTrigger;
18204202a189Smrg    int rc;
182105b261ecSmrg
182205b261ecSmrg    REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
182305b261ecSmrg
1824f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm,
1825f7df2e56Smrg                                 client, DixReadAccess);
18264202a189Smrg    if (rc != Success)
1827f7df2e56Smrg        return rc;
182805b261ecSmrg
182905b261ecSmrg    pTrigger = &pAlarm->trigger;
1830f7df2e56Smrg    rep = (xSyncQueryAlarmReply) {
1831f7df2e56Smrg        .type = X_Reply,
1832f7df2e56Smrg        .sequenceNumber = client->sequence,
1833f7df2e56Smrg        .length =
1834f7df2e56Smrg          bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply)),
1835f7df2e56Smrg        .counter = (pTrigger->pSync) ? pTrigger->pSync->id : None,
1836f7df2e56Smrg
1837f7df2e56Smrg#if 0  /* XXX unclear what to do, depends on whether relative value-types
1838f7df2e56Smrg        * are "consumed" immediately and are considered absolute from then
1839f7df2e56Smrg        * on.
1840f7df2e56Smrg        */
1841f7df2e56Smrg        .value_type = pTrigger->value_type,
1842f7df2e56Smrg        .wait_value_hi = XSyncValueHigh32(pTrigger->wait_value),
1843f7df2e56Smrg        .wait_value_lo = XSyncValueLow32(pTrigger->wait_value),
184405b261ecSmrg#else
1845f7df2e56Smrg        .value_type = XSyncAbsolute,
1846f7df2e56Smrg        .wait_value_hi = XSyncValueHigh32(pTrigger->test_value),
1847f7df2e56Smrg        .wait_value_lo = XSyncValueLow32(pTrigger->test_value),
184805b261ecSmrg#endif
184905b261ecSmrg
1850f7df2e56Smrg        .test_type = pTrigger->test_type,
1851f7df2e56Smrg        .delta_hi = XSyncValueHigh32(pAlarm->delta),
1852f7df2e56Smrg        .delta_lo = XSyncValueLow32(pAlarm->delta),
1853f7df2e56Smrg        .events = pAlarm->events,
1854f7df2e56Smrg        .state = pAlarm->state
1855f7df2e56Smrg    };
1856f7df2e56Smrg
1857f7df2e56Smrg    if (client->swapped) {
1858f7df2e56Smrg        swaps(&rep.sequenceNumber);
1859f7df2e56Smrg        swapl(&rep.length);
1860f7df2e56Smrg        swapl(&rep.counter);
1861f7df2e56Smrg        swapl(&rep.wait_value_hi);
1862f7df2e56Smrg        swapl(&rep.wait_value_lo);
1863f7df2e56Smrg        swapl(&rep.test_type);
1864f7df2e56Smrg        swapl(&rep.delta_hi);
1865f7df2e56Smrg        swapl(&rep.delta_lo);
1866f7df2e56Smrg    }
1867f7df2e56Smrg
1868f7df2e56Smrg    WriteToClient(client, sizeof(xSyncQueryAlarmReply), &rep);
18694202a189Smrg    return Success;
187005b261ecSmrg}
187105b261ecSmrg
18724202a189Smrgstatic int
18734202a189SmrgProcSyncDestroyAlarm(ClientPtr client)
187405b261ecSmrg{
18754202a189Smrg    SyncAlarm *pAlarm;
18764202a189Smrg    int rc;
1877f7df2e56Smrg
187805b261ecSmrg    REQUEST(xSyncDestroyAlarmReq);
187905b261ecSmrg
188005b261ecSmrg    REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
188105b261ecSmrg
1882f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm,
1883f7df2e56Smrg                                 client, DixDestroyAccess);
18844202a189Smrg    if (rc != Success)
1885f7df2e56Smrg        return rc;
188605b261ecSmrg
188705b261ecSmrg    FreeResource(stuff->alarm, RT_NONE);
18884202a189Smrg    return Success;
188905b261ecSmrg}
189005b261ecSmrg
189165b04b38Smrgstatic int
189265b04b38SmrgProcSyncCreateFence(ClientPtr client)
189365b04b38Smrg{
189465b04b38Smrg    REQUEST(xSyncCreateFenceReq);
189565b04b38Smrg    DrawablePtr pDraw;
189665b04b38Smrg    SyncFence *pFence;
189765b04b38Smrg    int rc;
189865b04b38Smrg
189965b04b38Smrg    REQUEST_SIZE_MATCH(xSyncCreateFenceReq);
190065b04b38Smrg
190165b04b38Smrg    rc = dixLookupDrawable(&pDraw, stuff->d, client, M_ANY, DixGetAttrAccess);
190265b04b38Smrg    if (rc != Success)
1903f7df2e56Smrg        return rc;
190465b04b38Smrg
190565b04b38Smrg    LEGAL_NEW_RESOURCE(stuff->fid, client);
190665b04b38Smrg
1907f7df2e56Smrg    if (!(pFence = (SyncFence *) SyncCreate(client, stuff->fid, SYNC_FENCE)))
1908f7df2e56Smrg        return BadAlloc;
190965b04b38Smrg
191065b04b38Smrg    miSyncInitFence(pDraw->pScreen, pFence, stuff->initially_triggered);
191165b04b38Smrg
1912f7df2e56Smrg    if (!AddResource(stuff->fid, RTFence, (void *) pFence))
1913f7df2e56Smrg        return BadAlloc;
191465b04b38Smrg
191565b04b38Smrg    return client->noClientException;
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
195665b04b38Smrg    return client->noClientException;
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
197865b04b38Smrg    return client->noClientException;
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);
199665b04b38Smrg    return client->noClientException;
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);
202865b04b38Smrg    return client->noClientException;
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;
2083f7df2e56Smrg        XSyncIntToValue(&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 */
2099f7df2e56Smrg        XSyncIntToValue(&pAwait->event_threshold, 0);
2100f7df2e56Smrg        pAwait->pHeader = &pAwaitUnion->header;
2101f7df2e56Smrg        pAwaitUnion->header.num_waitconditions++;
210265b04b38Smrg    }
210365b04b38Smrg
210465b04b38Smrg    SyncAwaitEpilogue(client, items, pAwaitUnion);
210565b04b38Smrg
210665b04b38Smrg    return client->noClientException;
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
21674202a189Smrgstatic int
21684202a189SmrgSProcSyncInitialize(ClientPtr client)
216905b261ecSmrg{
217005b261ecSmrg    REQUEST(xSyncInitializeReq);
2171f7df2e56Smrg    swaps(&stuff->length);
2172f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncInitializeReq);
217305b261ecSmrg
217405b261ecSmrg    return ProcSyncInitialize(client);
217505b261ecSmrg}
217605b261ecSmrg
21774202a189Smrgstatic int
21784202a189SmrgSProcSyncListSystemCounters(ClientPtr client)
217905b261ecSmrg{
218005b261ecSmrg    REQUEST(xSyncListSystemCountersReq);
2181f7df2e56Smrg    swaps(&stuff->length);
2182f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
218305b261ecSmrg
218405b261ecSmrg    return ProcSyncListSystemCounters(client);
218505b261ecSmrg}
218605b261ecSmrg
21874202a189Smrgstatic int
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
22004202a189Smrgstatic int
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
22134202a189Smrgstatic int
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
22264202a189Smrgstatic int
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
22374202a189Smrgstatic int
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
22484202a189Smrgstatic int
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
22594202a189Smrgstatic int
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
22724202a189Smrgstatic int
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
22844202a189Smrgstatic int
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
22954202a189Smrgstatic int
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
23064202a189Smrgstatic int
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
23184202a189Smrgstatic int
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
232965b04b38Smrgstatic int
233065b04b38SmrgSProcSyncCreateFence(ClientPtr client)
233165b04b38Smrg{
233265b04b38Smrg    REQUEST(xSyncCreateFenceReq);
2333f7df2e56Smrg    swaps(&stuff->length);
2334f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncCreateFenceReq);
2335f7df2e56Smrg    swapl(&stuff->fid);
233665b04b38Smrg
233765b04b38Smrg    return ProcSyncCreateFence(client);
233865b04b38Smrg}
233965b04b38Smrg
234065b04b38Smrgstatic int
234165b04b38SmrgSProcSyncTriggerFence(ClientPtr client)
234265b04b38Smrg{
234365b04b38Smrg    REQUEST(xSyncTriggerFenceReq);
2344f7df2e56Smrg    swaps(&stuff->length);
2345f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncTriggerFenceReq);
2346f7df2e56Smrg    swapl(&stuff->fid);
234765b04b38Smrg
234865b04b38Smrg    return ProcSyncTriggerFence(client);
234965b04b38Smrg}
235065b04b38Smrg
235165b04b38Smrgstatic int
235265b04b38SmrgSProcSyncResetFence(ClientPtr client)
235365b04b38Smrg{
235465b04b38Smrg    REQUEST(xSyncResetFenceReq);
2355f7df2e56Smrg    swaps(&stuff->length);
2356f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncResetFenceReq);
2357f7df2e56Smrg    swapl(&stuff->fid);
235865b04b38Smrg
235965b04b38Smrg    return ProcSyncResetFence(client);
236065b04b38Smrg}
236165b04b38Smrg
236265b04b38Smrgstatic int
236365b04b38SmrgSProcSyncDestroyFence(ClientPtr client)
236465b04b38Smrg{
236565b04b38Smrg    REQUEST(xSyncDestroyFenceReq);
2366f7df2e56Smrg    swaps(&stuff->length);
2367f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncDestroyFenceReq);
2368f7df2e56Smrg    swapl(&stuff->fid);
236965b04b38Smrg
237065b04b38Smrg    return ProcSyncDestroyFence(client);
237165b04b38Smrg}
237265b04b38Smrg
237365b04b38Smrgstatic int
237465b04b38SmrgSProcSyncQueryFence(ClientPtr client)
237565b04b38Smrg{
237665b04b38Smrg    REQUEST(xSyncQueryFenceReq);
2377f7df2e56Smrg    swaps(&stuff->length);
2378f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncQueryFenceReq);
2379f7df2e56Smrg    swapl(&stuff->fid);
238065b04b38Smrg
238165b04b38Smrg    return ProcSyncQueryFence(client);
238265b04b38Smrg}
238365b04b38Smrg
238465b04b38Smrgstatic int
238565b04b38SmrgSProcSyncAwaitFence(ClientPtr client)
238665b04b38Smrg{
238765b04b38Smrg    REQUEST(xSyncAwaitFenceReq);
2388f7df2e56Smrg    swaps(&stuff->length);
238965b04b38Smrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
239065b04b38Smrg    SwapRestL(stuff);
239165b04b38Smrg
239265b04b38Smrg    return ProcSyncAwaitFence(client);
239365b04b38Smrg}
239405b261ecSmrg
23954202a189Smrgstatic int
23964202a189SmrgSProcSyncDispatch(ClientPtr client)
239705b261ecSmrg{
239805b261ecSmrg    REQUEST(xReq);
239905b261ecSmrg
2400f7df2e56Smrg    switch (stuff->data) {
2401f7df2e56Smrg    case X_SyncInitialize:
2402f7df2e56Smrg        return SProcSyncInitialize(client);
2403f7df2e56Smrg    case X_SyncListSystemCounters:
2404f7df2e56Smrg        return SProcSyncListSystemCounters(client);
2405f7df2e56Smrg    case X_SyncCreateCounter:
2406f7df2e56Smrg        return SProcSyncCreateCounter(client);
2407f7df2e56Smrg    case X_SyncSetCounter:
2408f7df2e56Smrg        return SProcSyncSetCounter(client);
2409f7df2e56Smrg    case X_SyncChangeCounter:
2410f7df2e56Smrg        return SProcSyncChangeCounter(client);
2411f7df2e56Smrg    case X_SyncQueryCounter:
2412f7df2e56Smrg        return SProcSyncQueryCounter(client);
2413f7df2e56Smrg    case X_SyncDestroyCounter:
2414f7df2e56Smrg        return SProcSyncDestroyCounter(client);
2415f7df2e56Smrg    case X_SyncAwait:
2416f7df2e56Smrg        return SProcSyncAwait(client);
2417f7df2e56Smrg    case X_SyncCreateAlarm:
2418f7df2e56Smrg        return SProcSyncCreateAlarm(client);
2419f7df2e56Smrg    case X_SyncChangeAlarm:
2420f7df2e56Smrg        return SProcSyncChangeAlarm(client);
2421f7df2e56Smrg    case X_SyncQueryAlarm:
2422f7df2e56Smrg        return SProcSyncQueryAlarm(client);
2423f7df2e56Smrg    case X_SyncDestroyAlarm:
2424f7df2e56Smrg        return SProcSyncDestroyAlarm(client);
2425f7df2e56Smrg    case X_SyncSetPriority:
2426f7df2e56Smrg        return SProcSyncSetPriority(client);
2427f7df2e56Smrg    case X_SyncGetPriority:
2428f7df2e56Smrg        return SProcSyncGetPriority(client);
2429f7df2e56Smrg    case X_SyncCreateFence:
2430f7df2e56Smrg        return SProcSyncCreateFence(client);
2431f7df2e56Smrg    case X_SyncTriggerFence:
2432f7df2e56Smrg        return SProcSyncTriggerFence(client);
2433f7df2e56Smrg    case X_SyncResetFence:
2434f7df2e56Smrg        return SProcSyncResetFence(client);
2435f7df2e56Smrg    case X_SyncDestroyFence:
2436f7df2e56Smrg        return SProcSyncDestroyFence(client);
2437f7df2e56Smrg    case X_SyncQueryFence:
2438f7df2e56Smrg        return SProcSyncQueryFence(client);
2439f7df2e56Smrg    case X_SyncAwaitFence:
2440f7df2e56Smrg        return SProcSyncAwaitFence(client);
2441f7df2e56Smrg    default:
2442f7df2e56Smrg        return BadRequest;
244305b261ecSmrg    }
244405b261ecSmrg}
244505b261ecSmrg
244605b261ecSmrg/*
244705b261ecSmrg * Event Swapping
244805b261ecSmrg */
244905b261ecSmrg
24504202a189Smrgstatic void
2451f7df2e56SmrgSCounterNotifyEvent(xSyncCounterNotifyEvent * from,
2452f7df2e56Smrg                    xSyncCounterNotifyEvent * to)
245305b261ecSmrg{
245405b261ecSmrg    to->type = from->type;
245505b261ecSmrg    to->kind = from->kind;
245605b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
245705b261ecSmrg    cpswapl(from->counter, to->counter);
245805b261ecSmrg    cpswapl(from->wait_value_lo, to->wait_value_lo);
245905b261ecSmrg    cpswapl(from->wait_value_hi, to->wait_value_hi);
246005b261ecSmrg    cpswapl(from->counter_value_lo, to->counter_value_lo);
246105b261ecSmrg    cpswapl(from->counter_value_hi, to->counter_value_hi);
246205b261ecSmrg    cpswapl(from->time, to->time);
246305b261ecSmrg    cpswaps(from->count, to->count);
246405b261ecSmrg    to->destroyed = from->destroyed;
246505b261ecSmrg}
246605b261ecSmrg
24674202a189Smrgstatic void
2468f7df2e56SmrgSAlarmNotifyEvent(xSyncAlarmNotifyEvent * from, xSyncAlarmNotifyEvent * to)
246905b261ecSmrg{
247005b261ecSmrg    to->type = from->type;
247105b261ecSmrg    to->kind = from->kind;
247205b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
247305b261ecSmrg    cpswapl(from->alarm, to->alarm);
247405b261ecSmrg    cpswapl(from->counter_value_lo, to->counter_value_lo);
247505b261ecSmrg    cpswapl(from->counter_value_hi, to->counter_value_hi);
247605b261ecSmrg    cpswapl(from->alarm_value_lo, to->alarm_value_lo);
247705b261ecSmrg    cpswapl(from->alarm_value_hi, to->alarm_value_hi);
247805b261ecSmrg    cpswapl(from->time, to->time);
247905b261ecSmrg    to->state = from->state;
248005b261ecSmrg}
248105b261ecSmrg
248205b261ecSmrg/*
248305b261ecSmrg * ** Close everything down. ** This is fairly simple for now.
248405b261ecSmrg */
248505b261ecSmrg/* ARGSUSED */
24864202a189Smrgstatic void
2487f7df2e56SmrgSyncResetProc(ExtensionEntry * extEntry)
248805b261ecSmrg{
248905b261ecSmrg    RTCounter = 0;
249005b261ecSmrg}
249105b261ecSmrg
249205b261ecSmrg/*
249305b261ecSmrg * ** Initialise the extension.
249405b261ecSmrg */
24954202a189Smrgvoid
24964202a189SmrgSyncExtensionInit(void)
249705b261ecSmrg{
249805b261ecSmrg    ExtensionEntry *extEntry;
2499f7df2e56Smrg    int s;
250065b04b38Smrg
250165b04b38Smrg    for (s = 0; s < screenInfo.numScreens; s++)
2502f7df2e56Smrg        miSyncSetup(screenInfo.screens[s]);
250305b261ecSmrg
2504f7df2e56Smrg    if (RTCounter == 0) {
2505f7df2e56Smrg        RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
2506f7df2e56Smrg        xorg_list_init(&SysCounterList);
250705b261ecSmrg    }
25084202a189Smrg    RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm");
25094202a189Smrg    RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait");
251065b04b38Smrg    RTFence = CreateNewResourceType(FreeFence, "SyncFence");
25114202a189Smrg    if (RTAwait)
2512f7df2e56Smrg        RTAwait |= RC_NEVERRETAIN;
25134202a189Smrg    RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient");
25144202a189Smrg    if (RTAlarmClient)
2515f7df2e56Smrg        RTAlarmClient |= RC_NEVERRETAIN;
251605b261ecSmrg
251705b261ecSmrg    if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 ||
2518f7df2e56Smrg        RTAlarmClient == 0 ||
2519f7df2e56Smrg        (extEntry = AddExtension(SYNC_NAME,
2520f7df2e56Smrg                                 XSyncNumberEvents, XSyncNumberErrors,
2521f7df2e56Smrg                                 ProcSyncDispatch, SProcSyncDispatch,
2522f7df2e56Smrg                                 SyncResetProc, StandardMinorOpcode)) == NULL) {
2523f7df2e56Smrg        ErrorF("Sync Extension %d.%d failed to Initialise\n",
2524f7df2e56Smrg               SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
2525f7df2e56Smrg        return;
252605b261ecSmrg    }
252705b261ecSmrg
252805b261ecSmrg    SyncEventBase = extEntry->eventBase;
252905b261ecSmrg    SyncErrorBase = extEntry->errorBase;
2530f7df2e56Smrg    EventSwapVector[SyncEventBase + XSyncCounterNotify] =
2531f7df2e56Smrg        (EventSwapPtr) SCounterNotifyEvent;
2532f7df2e56Smrg    EventSwapVector[SyncEventBase + XSyncAlarmNotify] =
2533f7df2e56Smrg        (EventSwapPtr) SAlarmNotifyEvent;
253405b261ecSmrg
25354202a189Smrg    SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter);
25364202a189Smrg    SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm);
253765b04b38Smrg    SetResourceTypeErrorValue(RTFence, SyncErrorBase + XSyncBadFence);
25384202a189Smrg
253905b261ecSmrg    /*
254005b261ecSmrg     * Although SERVERTIME is implemented by the OS layer, we initialise it
254105b261ecSmrg     * here because doing it in OsInit() is too early. The resource database
254205b261ecSmrg     * is not initialised when OsInit() is called. This is just about OK
254305b261ecSmrg     * because there is always a servertime counter.
254405b261ecSmrg     */
254505b261ecSmrg    SyncInitServerTime();
254605b261ecSmrg    SyncInitIdleTime();
254705b261ecSmrg
254805b261ecSmrg#ifdef DEBUG
254905b261ecSmrg    fprintf(stderr, "Sync Extension %d.%d\n",
2550f7df2e56Smrg            SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
255105b261ecSmrg#endif
255205b261ecSmrg}
255305b261ecSmrg
255405b261ecSmrg/*
255505b261ecSmrg * ***** SERVERTIME implementation - should go in its own file in OS directory?
255605b261ecSmrg */
255705b261ecSmrg
2558f7df2e56Smrgstatic void *ServertimeCounter;
255905b261ecSmrgstatic XSyncValue Now;
256005b261ecSmrgstatic XSyncValue *pnext_time;
256105b261ecSmrg
256205b261ecSmrg#define GetTime()\
256305b261ecSmrg{\
256405b261ecSmrg    unsigned long millis = GetTimeInMillis();\
256505b261ecSmrg    unsigned long maxis = XSyncValueHigh32(Now);\
256605b261ecSmrg    if (millis < XSyncValueLow32(Now)) maxis++;\
256705b261ecSmrg    XSyncIntsToValue(&Now, millis, maxis);\
256805b261ecSmrg}
256905b261ecSmrg
257005b261ecSmrg/*
257105b261ecSmrg*** Server Block Handler
25724202a189Smrg*** code inspired by multibuffer extension (now deprecated)
257305b261ecSmrg */
2574f7df2e56Smrg /*ARGSUSED*/ static void
25754202a189SmrgServertimeBlockHandler(void *env, struct timeval **wt, void *LastSelectMask)
257605b261ecSmrg{
257705b261ecSmrg    XSyncValue delay;
257805b261ecSmrg    unsigned long timeout;
257905b261ecSmrg
2580f7df2e56Smrg    if (pnext_time) {
258105b261ecSmrg        GetTime();
258205b261ecSmrg
2583f7df2e56Smrg        if (XSyncValueGreaterOrEqual(Now, *pnext_time)) {
258405b261ecSmrg            timeout = 0;
25854202a189Smrg        }
2586f7df2e56Smrg        else {
2587f7df2e56Smrg            Bool overflow;
2588f7df2e56Smrg
258905b261ecSmrg            XSyncValueSubtract(&delay, *pnext_time, Now, &overflow);
2590f7df2e56Smrg            (void) overflow;
259105b261ecSmrg            timeout = XSyncValueLow32(delay);
259205b261ecSmrg        }
2593f7df2e56Smrg        AdjustWaitForDelay(wt, timeout);        /* os/utils.c */
259405b261ecSmrg    }
259505b261ecSmrg}
259605b261ecSmrg
259705b261ecSmrg/*
259805b261ecSmrg*** Wakeup Handler
259905b261ecSmrg */
2600f7df2e56Smrg /*ARGSUSED*/ static void
26014202a189SmrgServertimeWakeupHandler(void *env, int rc, void *LastSelectMask)
260205b261ecSmrg{
2603f7df2e56Smrg    if (pnext_time) {
260405b261ecSmrg        GetTime();
260505b261ecSmrg
2606f7df2e56Smrg        if (XSyncValueGreaterOrEqual(Now, *pnext_time)) {
260705b261ecSmrg            SyncChangeCounter(ServertimeCounter, Now);
260805b261ecSmrg        }
260905b261ecSmrg    }
261005b261ecSmrg}
261105b261ecSmrg
261205b261ecSmrgstatic void
2613f7df2e56SmrgServertimeQueryValue(void *pCounter, CARD64 * pValue_return)
261405b261ecSmrg{
261505b261ecSmrg    GetTime();
261605b261ecSmrg    *pValue_return = Now;
261705b261ecSmrg}
261805b261ecSmrg
261905b261ecSmrgstatic void
2620f7df2e56SmrgServertimeBracketValues(void *pCounter, CARD64 * pbracket_less,
2621f7df2e56Smrg                        CARD64 * pbracket_greater)
262205b261ecSmrg{
2623f7df2e56Smrg    if (!pnext_time && pbracket_greater) {
2624f7df2e56Smrg        RegisterBlockAndWakeupHandlers(ServertimeBlockHandler,
2625f7df2e56Smrg                                       ServertimeWakeupHandler, NULL);
262605b261ecSmrg    }
2627f7df2e56Smrg    else if (pnext_time && !pbracket_greater) {
2628f7df2e56Smrg        RemoveBlockAndWakeupHandlers(ServertimeBlockHandler,
2629f7df2e56Smrg                                     ServertimeWakeupHandler, NULL);
263005b261ecSmrg    }
263105b261ecSmrg    pnext_time = pbracket_greater;
263205b261ecSmrg}
263305b261ecSmrg
263405b261ecSmrgstatic void
263505b261ecSmrgSyncInitServerTime(void)
263605b261ecSmrg{
263705b261ecSmrg    CARD64 resolution;
263805b261ecSmrg
263905b261ecSmrg    XSyncIntsToValue(&Now, GetTimeInMillis(), 0);
264005b261ecSmrg    XSyncIntToValue(&resolution, 4);
264105b261ecSmrg    ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution,
2642f7df2e56Smrg                                                XSyncCounterNeverDecreases,
2643f7df2e56Smrg                                                ServertimeQueryValue,
2644f7df2e56Smrg                                                ServertimeBracketValues);
264505b261ecSmrg    pnext_time = NULL;
264605b261ecSmrg}
264705b261ecSmrg
264805b261ecSmrg/*
264905b261ecSmrg * IDLETIME implementation
265005b261ecSmrg */
265105b261ecSmrg
2652f7df2e56Smrgtypedef struct {
2653f7df2e56Smrg    XSyncValue *value_less;
2654f7df2e56Smrg    XSyncValue *value_greater;
2655f7df2e56Smrg    int deviceid;
2656f7df2e56Smrg} IdleCounterPriv;
265705b261ecSmrg
265805b261ecSmrgstatic void
2659f7df2e56SmrgIdleTimeQueryValue(void *pCounter, CARD64 * pValue_return)
266005b261ecSmrg{
2661f7df2e56Smrg    int deviceid;
2662f7df2e56Smrg    CARD32 idle;
2663f7df2e56Smrg
2664f7df2e56Smrg    if (pCounter) {
2665f7df2e56Smrg        SyncCounter *counter = pCounter;
2666f7df2e56Smrg        IdleCounterPriv *priv = SysCounterGetPrivate(counter);
2667f7df2e56Smrg        deviceid = priv->deviceid;
2668f7df2e56Smrg    }
2669f7df2e56Smrg    else
2670f7df2e56Smrg        deviceid = XIAllDevices;
2671f7df2e56Smrg    idle = GetTimeInMillis() - LastEventTime(deviceid).milliseconds;
2672f7df2e56Smrg    XSyncIntsToValue(pValue_return, idle, 0);
267305b261ecSmrg}
267405b261ecSmrg
267505b261ecSmrgstatic void
2676f7df2e56SmrgIdleTimeBlockHandler(void *pCounter, struct timeval **wt, void *LastSelectMask)
267705b261ecSmrg{
2678f7df2e56Smrg    SyncCounter *counter = pCounter;
2679f7df2e56Smrg    IdleCounterPriv *priv = SysCounterGetPrivate(counter);
2680f7df2e56Smrg    XSyncValue *less = priv->value_less,
2681f7df2e56Smrg               *greater = priv->value_greater;
268245801275Sjmcneill    XSyncValue idle, old_idle;
2683f7df2e56Smrg    SyncTriggerList *list = counter->sync.pTriglist;
268445801275Sjmcneill    SyncTrigger *trig;
268505b261ecSmrg
2686f7df2e56Smrg    if (!less && !greater)
2687f7df2e56Smrg        return;
2688f7df2e56Smrg
2689f7df2e56Smrg    old_idle = counter->value;
2690f7df2e56Smrg    IdleTimeQueryValue(counter, &idle);
2691f7df2e56Smrg    counter->value = idle;      /* push, so CheckTrigger works */
2692f7df2e56Smrg
2693f7df2e56Smrg    /**
2694f7df2e56Smrg     * There's an indefinite amount of time between ProcessInputEvents()
2695f7df2e56Smrg     * where the idle time is reset and the time we actually get here. idle
2696f7df2e56Smrg     * may be past the lower bracket if we dawdled with the events, so
2697f7df2e56Smrg     * check for whether we did reset and bomb out of select immediately.
2698f7df2e56Smrg     */
2699f7df2e56Smrg    if (less && XSyncValueGreaterThan(idle, *less) &&
2700f7df2e56Smrg        LastEventTimeWasReset(priv->deviceid)) {
2701f7df2e56Smrg        AdjustWaitForDelay(wt, 0);
2702f7df2e56Smrg    } else if (less && XSyncValueLessOrEqual(idle, *less)) {
2703f7df2e56Smrg        /*
2704f7df2e56Smrg         * We've been idle for less than the threshold value, and someone
2705f7df2e56Smrg         * wants to know about that, but now we need to know whether they
2706f7df2e56Smrg         * want level or edge trigger.  Check the trigger list against the
2707f7df2e56Smrg         * current idle time, and if any succeed, bomb out of select()
2708f7df2e56Smrg         * immediately so we can reschedule.
2709f7df2e56Smrg         */
2710f7df2e56Smrg
2711f7df2e56Smrg        for (list = counter->sync.pTriglist; list; list = list->next) {
2712f7df2e56Smrg            trig = list->pTrigger;
2713f7df2e56Smrg            if (trig->CheckTrigger(trig, old_idle)) {
2714f7df2e56Smrg                AdjustWaitForDelay(wt, 0);
2715f7df2e56Smrg                break;
2716f7df2e56Smrg            }
2717f7df2e56Smrg        }
2718f7df2e56Smrg        /*
2719f7df2e56Smrg         * We've been called exactly on the idle time, but we have a
2720f7df2e56Smrg         * NegativeTransition trigger which requires a transition from an
2721f7df2e56Smrg         * idle time greater than this.  Schedule a wakeup for the next
2722f7df2e56Smrg         * millisecond so we won't miss a transition.
2723f7df2e56Smrg         */
2724f7df2e56Smrg        if (XSyncValueEqual(idle, *less))
2725f7df2e56Smrg            AdjustWaitForDelay(wt, 1);
2726f7df2e56Smrg    }
2727f7df2e56Smrg    else if (greater) {
2728f7df2e56Smrg        /*
2729f7df2e56Smrg         * There's a threshold in the positive direction.  If we've been
2730f7df2e56Smrg         * idle less than it, schedule a wakeup for sometime in the future.
2731f7df2e56Smrg         * If we've been idle more than it, and someone wants to know about
2732f7df2e56Smrg         * that level-triggered, schedule an immediate wakeup.
2733f7df2e56Smrg         */
2734f7df2e56Smrg
2735f7df2e56Smrg        if (XSyncValueLessThan(idle, *greater)) {
2736f7df2e56Smrg            XSyncValue value;
2737f7df2e56Smrg            Bool overflow;
2738f7df2e56Smrg
2739f7df2e56Smrg            XSyncValueSubtract(&value, *greater, idle, &overflow);
2740f7df2e56Smrg            AdjustWaitForDelay(wt, XSyncValueLow32(value));
2741f7df2e56Smrg        }
2742f7df2e56Smrg        else {
2743f7df2e56Smrg            for (list = counter->sync.pTriglist; list;
2744f7df2e56Smrg                 list = list->next) {
2745f7df2e56Smrg                trig = list->pTrigger;
2746f7df2e56Smrg                if (trig->CheckTrigger(trig, old_idle)) {
2747f7df2e56Smrg                    AdjustWaitForDelay(wt, 0);
2748f7df2e56Smrg                    break;
2749f7df2e56Smrg                }
2750f7df2e56Smrg            }
2751f7df2e56Smrg        }
2752f7df2e56Smrg    }
2753f7df2e56Smrg
2754f7df2e56Smrg    counter->value = old_idle;  /* pop */
2755f7df2e56Smrg}
2756f7df2e56Smrg
2757f7df2e56Smrgstatic void
2758f7df2e56SmrgIdleTimeCheckBrackets(SyncCounter *counter, XSyncValue idle, XSyncValue *less, XSyncValue *greater)
2759f7df2e56Smrg{
2760f7df2e56Smrg    if ((greater && XSyncValueGreaterOrEqual(idle, *greater)) ||
2761f7df2e56Smrg        (less && XSyncValueLessOrEqual(idle, *less))) {
2762f7df2e56Smrg        SyncChangeCounter(counter, idle);
2763f7df2e56Smrg    }
2764f7df2e56Smrg    else
2765f7df2e56Smrg        SyncUpdateCounter(counter, idle);
276605b261ecSmrg}
276705b261ecSmrg
276805b261ecSmrgstatic void
2769f7df2e56SmrgIdleTimeWakeupHandler(void *pCounter, int rc, void *LastSelectMask)
277005b261ecSmrg{
2771f7df2e56Smrg    SyncCounter *counter = pCounter;
2772f7df2e56Smrg    IdleCounterPriv *priv = SysCounterGetPrivate(counter);
2773f7df2e56Smrg    XSyncValue *less = priv->value_less,
2774f7df2e56Smrg               *greater = priv->value_greater;
277505b261ecSmrg    XSyncValue idle;
277605b261ecSmrg
2777f7df2e56Smrg    if (!less && !greater)
2778f7df2e56Smrg        return;
277905b261ecSmrg
2780f7df2e56Smrg    IdleTimeQueryValue(pCounter, &idle);
278105b261ecSmrg
2782f7df2e56Smrg    /*
2783f7df2e56Smrg      There is no guarantee for the WakeupHandler to be called within a specific
2784f7df2e56Smrg      timeframe. Idletime may go to 0, but by the time we get here, it may be
2785f7df2e56Smrg      non-zero and alarms for a pos. transition on 0 won't get triggered.
2786f7df2e56Smrg      https://bugs.freedesktop.org/show_bug.cgi?id=70476
2787f7df2e56Smrg      */
2788f7df2e56Smrg    if (LastEventTimeWasReset(priv->deviceid)) {
2789f7df2e56Smrg        LastEventTimeToggleResetFlag(priv->deviceid, FALSE);
2790f7df2e56Smrg        if (!XSyncValueIsZero(idle)) {
2791f7df2e56Smrg            XSyncValue zero;
2792f7df2e56Smrg            XSyncIntsToValue(&zero, 0, 0);
2793f7df2e56Smrg            IdleTimeCheckBrackets(counter, zero, less, greater);
2794f7df2e56Smrg            less = priv->value_less;
2795f7df2e56Smrg            greater = priv->value_greater;
2796f7df2e56Smrg        }
279705b261ecSmrg    }
2798f7df2e56Smrg
2799f7df2e56Smrg    IdleTimeCheckBrackets(counter, idle, less, greater);
280005b261ecSmrg}
280105b261ecSmrg
280205b261ecSmrgstatic void
2803f7df2e56SmrgIdleTimeBracketValues(void *pCounter, CARD64 * pbracket_less,
2804f7df2e56Smrg                      CARD64 * pbracket_greater)
280505b261ecSmrg{
2806f7df2e56Smrg    SyncCounter *counter = pCounter;
2807f7df2e56Smrg    IdleCounterPriv *priv = SysCounterGetPrivate(counter);
2808f7df2e56Smrg    XSyncValue *less = priv->value_less,
2809f7df2e56Smrg               *greater = priv->value_greater;
2810f7df2e56Smrg    Bool registered = (less || greater);
281105b261ecSmrg
2812f7df2e56Smrg    if (registered && !pbracket_less && !pbracket_greater) {
2813f7df2e56Smrg        RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler,
2814f7df2e56Smrg                                     IdleTimeWakeupHandler, pCounter);
281505b261ecSmrg    }
2816f7df2e56Smrg    else if (!registered && (pbracket_less || pbracket_greater)) {
2817f7df2e56Smrg        /* Reset flag must be zero so we don't force a idle timer reset on
2818f7df2e56Smrg           the first wakeup */
2819f7df2e56Smrg        LastEventTimeToggleResetAll(FALSE);
2820f7df2e56Smrg        RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
2821f7df2e56Smrg                                       IdleTimeWakeupHandler, pCounter);
282205b261ecSmrg    }
282305b261ecSmrg
2824f7df2e56Smrg    priv->value_greater = pbracket_greater;
2825f7df2e56Smrg    priv->value_less = pbracket_less;
282605b261ecSmrg}
282705b261ecSmrg
2828f7df2e56Smrgstatic SyncCounter*
2829f7df2e56Smrginit_system_idle_counter(const char *name, int deviceid)
283005b261ecSmrg{
283105b261ecSmrg    CARD64 resolution;
283205b261ecSmrg    XSyncValue idle;
2833f7df2e56Smrg    SyncCounter *idle_time_counter;
2834f7df2e56Smrg
2835f7df2e56Smrg    IdleTimeQueryValue(NULL, &idle);
2836f7df2e56Smrg    XSyncIntToValue(&resolution, 4);
283705b261ecSmrg
2838f7df2e56Smrg    idle_time_counter = SyncCreateSystemCounter(name, idle, resolution,
2839f7df2e56Smrg                                                XSyncCounterUnrestricted,
2840f7df2e56Smrg                                                IdleTimeQueryValue,
2841f7df2e56Smrg                                                IdleTimeBracketValues);
284205b261ecSmrg
2843f7df2e56Smrg    if (idle_time_counter != NULL) {
2844f7df2e56Smrg        IdleCounterPriv *priv = malloc(sizeof(IdleCounterPriv));
284505b261ecSmrg
2846f7df2e56Smrg        priv->value_less = priv->value_greater = NULL;
2847f7df2e56Smrg        priv->deviceid = deviceid;
2848f7df2e56Smrg
2849f7df2e56Smrg        idle_time_counter->pSysCounterInfo->private = priv;
2850f7df2e56Smrg    }
2851f7df2e56Smrg
2852f7df2e56Smrg    return idle_time_counter;
2853f7df2e56Smrg}
2854f7df2e56Smrg
2855f7df2e56Smrgstatic void
2856f7df2e56SmrgSyncInitIdleTime(void)
2857f7df2e56Smrg{
2858f7df2e56Smrg    init_system_idle_counter("IDLETIME", XIAllDevices);
2859f7df2e56Smrg}
2860f7df2e56Smrg
2861f7df2e56SmrgSyncCounter*
2862f7df2e56SmrgSyncInitDeviceIdleTime(DeviceIntPtr dev)
2863f7df2e56Smrg{
2864f7df2e56Smrg    char timer_name[64];
2865f7df2e56Smrg    sprintf(timer_name, "DEVICEIDLETIME %d", dev->id);
2866f7df2e56Smrg
2867f7df2e56Smrg    return init_system_idle_counter(timer_name, dev->id);
2868f7df2e56Smrg}
2869f7df2e56Smrg
2870f7df2e56Smrgvoid SyncRemoveDeviceIdleTime(SyncCounter *counter)
2871f7df2e56Smrg{
2872f7df2e56Smrg    /* FreeAllResources() frees all system counters before the devices are
2873f7df2e56Smrg       shut down, check if there are any left before freeing the device's
2874f7df2e56Smrg       counter */
2875f7df2e56Smrg    if (counter && !xorg_list_is_empty(&SysCounterList))
2876f7df2e56Smrg        xorg_list_del(&counter->pSysCounterInfo->entry);
287705b261ecSmrg}
2878