sync.c revision 875c6e4f
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
2407e31ba66SmrgSyncCheckTriggerPositiveComparison(SyncTrigger * pTrigger, int64_t oldval)
24105b261ecSmrg{
24265b04b38Smrg    SyncCounter *pCounter;
24365b04b38Smrg
24465b04b38Smrg    /* Non-counter sync objects should never get here because they
24565b04b38Smrg     * never trigger this comparison. */
24665b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
247f7df2e56Smrg        return FALSE;
24865b04b38Smrg
249f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
25065b04b38Smrg
2517e31ba66Smrg    return pCounter == NULL || pCounter->value >= pTrigger->test_value;
25205b261ecSmrg}
25305b261ecSmrg
25405b261ecSmrgstatic Bool
2557e31ba66SmrgSyncCheckTriggerNegativeComparison(SyncTrigger * pTrigger, int64_t oldval)
25605b261ecSmrg{
25765b04b38Smrg    SyncCounter *pCounter;
25865b04b38Smrg
25965b04b38Smrg    /* Non-counter sync objects should never get here because they
26065b04b38Smrg     * never trigger this comparison. */
26165b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
262f7df2e56Smrg        return FALSE;
26365b04b38Smrg
264f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
26565b04b38Smrg
2667e31ba66Smrg    return pCounter == NULL || pCounter->value <= pTrigger->test_value;
26705b261ecSmrg}
26805b261ecSmrg
26905b261ecSmrgstatic Bool
2707e31ba66SmrgSyncCheckTriggerPositiveTransition(SyncTrigger * pTrigger, int64_t oldval)
27105b261ecSmrg{
27265b04b38Smrg    SyncCounter *pCounter;
27365b04b38Smrg
27465b04b38Smrg    /* Non-counter sync objects should never get here because they
27565b04b38Smrg     * never trigger this comparison. */
27665b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
277f7df2e56Smrg        return FALSE;
27865b04b38Smrg
279f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
28065b04b38Smrg
28165b04b38Smrg    return (pCounter == NULL ||
2827e31ba66Smrg            (oldval < pTrigger->test_value &&
2837e31ba66Smrg             pCounter->value >= pTrigger->test_value));
28405b261ecSmrg}
28505b261ecSmrg
28605b261ecSmrgstatic Bool
2877e31ba66SmrgSyncCheckTriggerNegativeTransition(SyncTrigger * pTrigger, int64_t oldval)
28805b261ecSmrg{
28965b04b38Smrg    SyncCounter *pCounter;
29065b04b38Smrg
29165b04b38Smrg    /* Non-counter sync objects should never get here because they
29265b04b38Smrg     * never trigger this comparison. */
29365b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
294f7df2e56Smrg        return FALSE;
29565b04b38Smrg
296f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
29765b04b38Smrg
29865b04b38Smrg    return (pCounter == NULL ||
2997e31ba66Smrg            (oldval > pTrigger->test_value &&
3007e31ba66Smrg             pCounter->value <= pTrigger->test_value));
30165b04b38Smrg}
30265b04b38Smrg
30365b04b38Smrgstatic Bool
3047e31ba66SmrgSyncCheckTriggerFence(SyncTrigger * pTrigger, int64_t unused)
30565b04b38Smrg{
306f7df2e56Smrg    SyncFence *pFence = (SyncFence *) pTrigger->pSync;
307f7df2e56Smrg
308f7df2e56Smrg    (void) unused;
30965b04b38Smrg
310f7df2e56Smrg    return (pFence == NULL || pFence->funcs.CheckTriggered(pFence));
31105b261ecSmrg}
31205b261ecSmrg
3134202a189Smrgstatic int
314f7df2e56SmrgSyncInitTrigger(ClientPtr client, SyncTrigger * pTrigger, XID syncObject,
315f7df2e56Smrg                RESTYPE resType, Mask changes)
31605b261ecSmrg{
31765b04b38Smrg    SyncObject *pSync = pTrigger->pSync;
31865b04b38Smrg    SyncCounter *pCounter = NULL;
319f7df2e56Smrg    int rc;
320f7df2e56Smrg    Bool newSyncObject = FALSE;
321f7df2e56Smrg
322f7df2e56Smrg    if (changes & XSyncCACounter) {
323f7df2e56Smrg        if (syncObject == None)
324f7df2e56Smrg            pSync = NULL;
325f7df2e56Smrg        else if (Success != (rc = dixLookupResourceByType((void **) &pSync,
326f7df2e56Smrg                                                          syncObject, resType,
327f7df2e56Smrg                                                          client,
328f7df2e56Smrg                                                          DixReadAccess))) {
329f7df2e56Smrg            client->errorValue = syncObject;
330f7df2e56Smrg            return rc;
331f7df2e56Smrg        }
332f7df2e56Smrg        if (pSync != pTrigger->pSync) { /* new counter for trigger */
333f7df2e56Smrg            SyncDeleteTriggerFromSyncObject(pTrigger);
334f7df2e56Smrg            pTrigger->pSync = pSync;
335f7df2e56Smrg            newSyncObject = TRUE;
336f7df2e56Smrg        }
33705b261ecSmrg    }
33805b261ecSmrg
33905b261ecSmrg    /* if system counter, ask it what the current value is */
34005b261ecSmrg
341f7df2e56Smrg    if (pSync && SYNC_COUNTER == pSync->type) {
342f7df2e56Smrg        pCounter = (SyncCounter *) pSync;
343f7df2e56Smrg
344f7df2e56Smrg        if (IsSystemCounter(pCounter)) {
345f7df2e56Smrg            (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter,
346f7df2e56Smrg                                                      &pCounter->value);
347f7df2e56Smrg        }
348f7df2e56Smrg    }
349f7df2e56Smrg
350f7df2e56Smrg    if (changes & XSyncCAValueType) {
351f7df2e56Smrg        if (pTrigger->value_type != XSyncRelative &&
352f7df2e56Smrg            pTrigger->value_type != XSyncAbsolute) {
353f7df2e56Smrg            client->errorValue = pTrigger->value_type;
354f7df2e56Smrg            return BadValue;
355f7df2e56Smrg        }
356f7df2e56Smrg    }
357f7df2e56Smrg
358f7df2e56Smrg    if (changes & XSyncCATestType) {
359f7df2e56Smrg
360f7df2e56Smrg        if (pSync && SYNC_FENCE == pSync->type) {
361f7df2e56Smrg            pTrigger->CheckTrigger = SyncCheckTriggerFence;
362f7df2e56Smrg        }
363f7df2e56Smrg        else {
364f7df2e56Smrg            /* select appropriate CheckTrigger function */
365f7df2e56Smrg
366f7df2e56Smrg            switch (pTrigger->test_type) {
367f7df2e56Smrg            case XSyncPositiveTransition:
368f7df2e56Smrg                pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition;
369f7df2e56Smrg                break;
370f7df2e56Smrg            case XSyncNegativeTransition:
371f7df2e56Smrg                pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition;
372f7df2e56Smrg                break;
373f7df2e56Smrg            case XSyncPositiveComparison:
374f7df2e56Smrg                pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison;
375f7df2e56Smrg                break;
376f7df2e56Smrg            case XSyncNegativeComparison:
377f7df2e56Smrg                pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison;
378f7df2e56Smrg                break;
379f7df2e56Smrg            default:
380f7df2e56Smrg                client->errorValue = pTrigger->test_type;
381f7df2e56Smrg                return BadValue;
382f7df2e56Smrg            }
383f7df2e56Smrg        }
384f7df2e56Smrg    }
385f7df2e56Smrg
386f7df2e56Smrg    if (changes & (XSyncCAValueType | XSyncCAValue)) {
387f7df2e56Smrg        if (pTrigger->value_type == XSyncAbsolute)
388f7df2e56Smrg            pTrigger->test_value = pTrigger->wait_value;
389f7df2e56Smrg        else {                  /* relative */
390f7df2e56Smrg            Bool overflow;
391f7df2e56Smrg
392f7df2e56Smrg            if (pCounter == NULL)
393f7df2e56Smrg                return BadMatch;
394f7df2e56Smrg
3957e31ba66Smrg            overflow = checked_int64_add(&pTrigger->test_value,
3967e31ba66Smrg                                         pCounter->value, pTrigger->wait_value);
397f7df2e56Smrg            if (overflow) {
3987e31ba66Smrg                client->errorValue = pTrigger->wait_value >> 32;
399f7df2e56Smrg                return BadValue;
400f7df2e56Smrg            }
401f7df2e56Smrg        }
40205b261ecSmrg    }
40305b261ecSmrg
40405b261ecSmrg    /*  we wait until we're sure there are no errors before registering
40505b261ecSmrg     *  a new counter on a trigger
40605b261ecSmrg     */
407f7df2e56Smrg    if (newSyncObject) {
408f7df2e56Smrg        if ((rc = SyncAddTriggerToSyncObject(pTrigger)) != Success)
409f7df2e56Smrg            return rc;
41005b261ecSmrg    }
411f7df2e56Smrg    else if (pCounter && IsSystemCounter(pCounter)) {
412f7df2e56Smrg        SyncComputeBracketValues(pCounter);
41305b261ecSmrg    }
4144202a189Smrg
41505b261ecSmrg    return Success;
41605b261ecSmrg}
41705b261ecSmrg
41805b261ecSmrg/*  AlarmNotify events happen in response to actions taken on an Alarm or
4194202a189Smrg *  the counter used by the alarm.  AlarmNotify may be sent to multiple
42005b261ecSmrg *  clients.  The alarm maintains a list of clients interested in events.
42105b261ecSmrg */
42205b261ecSmrgstatic void
423f7df2e56SmrgSyncSendAlarmNotifyEvents(SyncAlarm * pAlarm)
42405b261ecSmrg{
42505b261ecSmrg    SyncAlarmClientList *pcl;
42605b261ecSmrg    xSyncAlarmNotifyEvent ane;
42705b261ecSmrg    SyncTrigger *pTrigger = &pAlarm->trigger;
42865b04b38Smrg    SyncCounter *pCounter;
42965b04b38Smrg
43065b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
431f7df2e56Smrg        return;
43265b04b38Smrg
433f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
43405b261ecSmrg
43505b261ecSmrg    UpdateCurrentTime();
43605b261ecSmrg
437f7df2e56Smrg    ane = (xSyncAlarmNotifyEvent) {
438f7df2e56Smrg        .type = SyncEventBase + XSyncAlarmNotify,
439f7df2e56Smrg        .kind = XSyncAlarmNotify,
440f7df2e56Smrg        .alarm = pAlarm->alarm_id,
4417e31ba66Smrg        .alarm_value_hi = pTrigger->test_value >> 32,
4427e31ba66Smrg        .alarm_value_lo = pTrigger->test_value,
443f7df2e56Smrg        .time = currentTime.milliseconds,
444f7df2e56Smrg        .state = pAlarm->state
445f7df2e56Smrg    };
446f7df2e56Smrg
447f7df2e56Smrg    if (pTrigger->pSync && SYNC_COUNTER == pTrigger->pSync->type) {
4487e31ba66Smrg        ane.counter_value_hi = pCounter->value >> 32;
4497e31ba66Smrg        ane.counter_value_lo = pCounter->value;
45005b261ecSmrg    }
451f7df2e56Smrg    else {
452f7df2e56Smrg        /* XXX what else can we do if there's no counter? */
453f7df2e56Smrg        ane.counter_value_hi = ane.counter_value_lo = 0;
45405b261ecSmrg    }
45505b261ecSmrg
45605b261ecSmrg    /* send to owner */
4574202a189Smrg    if (pAlarm->events)
458f7df2e56Smrg        WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane);
45905b261ecSmrg
46005b261ecSmrg    /* send to other interested clients */
46105b261ecSmrg    for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next)
462f7df2e56Smrg        WriteEventsToClient(pcl->client, 1, (xEvent *) &ane);
46305b261ecSmrg}
46405b261ecSmrg
4654202a189Smrg/*  CounterNotify events only occur in response to an Await.  The events
46605b261ecSmrg *  go only to the Awaiting client.
46705b261ecSmrg */
46805b261ecSmrgstatic void
469f7df2e56SmrgSyncSendCounterNotifyEvents(ClientPtr client, SyncAwait ** ppAwait,
470f7df2e56Smrg                            int num_events)
47105b261ecSmrg{
47205b261ecSmrg    xSyncCounterNotifyEvent *pEvents, *pev;
47305b261ecSmrg    int i;
47405b261ecSmrg
47505b261ecSmrg    if (client->clientGone)
476f7df2e56Smrg        return;
477f7df2e56Smrg    pev = pEvents = calloc(num_events, sizeof(xSyncCounterNotifyEvent));
4784202a189Smrg    if (!pEvents)
479f7df2e56Smrg        return;
48005b261ecSmrg    UpdateCurrentTime();
481f7df2e56Smrg    for (i = 0; i < num_events; i++, ppAwait++, pev++) {
482f7df2e56Smrg        SyncTrigger *pTrigger = &(*ppAwait)->trigger;
483f7df2e56Smrg
484f7df2e56Smrg        pev->type = SyncEventBase + XSyncCounterNotify;
485f7df2e56Smrg        pev->kind = XSyncCounterNotify;
486f7df2e56Smrg        pev->counter = pTrigger->pSync->id;
4877e31ba66Smrg        pev->wait_value_lo = pTrigger->test_value;
4887e31ba66Smrg        pev->wait_value_hi = pTrigger->test_value >> 32;
489f7df2e56Smrg        if (SYNC_COUNTER == pTrigger->pSync->type) {
490f7df2e56Smrg            SyncCounter *pCounter = (SyncCounter *) pTrigger->pSync;
491f7df2e56Smrg
4927e31ba66Smrg            pev->counter_value_lo = pCounter->value;
4937e31ba66Smrg            pev->counter_value_hi = pCounter->value >> 32;
494f7df2e56Smrg        }
495f7df2e56Smrg        else {
496f7df2e56Smrg            pev->counter_value_lo = 0;
497f7df2e56Smrg            pev->counter_value_hi = 0;
498f7df2e56Smrg        }
499f7df2e56Smrg
500f7df2e56Smrg        pev->time = currentTime.milliseconds;
501f7df2e56Smrg        pev->count = num_events - i - 1;        /* events remaining */
502f7df2e56Smrg        pev->destroyed = pTrigger->pSync->beingDestroyed;
50305b261ecSmrg    }
50405b261ecSmrg    /* swapping will be taken care of by this */
505f7df2e56Smrg    WriteEventsToClient(client, num_events, (xEvent *) pEvents);
5064202a189Smrg    free(pEvents);
50705b261ecSmrg}
50805b261ecSmrg
50905b261ecSmrg/* This function is called when an alarm's counter is destroyed.
51005b261ecSmrg * It is plugged into pTrigger->CounterDestroyed (for alarm triggers).
51105b261ecSmrg */
5124202a189Smrgstatic void
513f7df2e56SmrgSyncAlarmCounterDestroyed(SyncTrigger * pTrigger)
51405b261ecSmrg{
515f7df2e56Smrg    SyncAlarm *pAlarm = (SyncAlarm *) pTrigger;
51605b261ecSmrg
51705b261ecSmrg    pAlarm->state = XSyncAlarmInactive;
51805b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
51965b04b38Smrg    pTrigger->pSync = NULL;
52005b261ecSmrg}
52105b261ecSmrg
5224202a189Smrg/*  This function is called when an alarm "goes off."
52305b261ecSmrg *  It is plugged into pTrigger->TriggerFired (for alarm triggers).
52405b261ecSmrg */
52505b261ecSmrgstatic void
526f7df2e56SmrgSyncAlarmTriggerFired(SyncTrigger * pTrigger)
52705b261ecSmrg{
528f7df2e56Smrg    SyncAlarm *pAlarm = (SyncAlarm *) pTrigger;
52965b04b38Smrg    SyncCounter *pCounter;
5307e31ba66Smrg    int64_t new_test_value;
53105b261ecSmrg
53265b04b38Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
533f7df2e56Smrg        return;
53465b04b38Smrg
535f7df2e56Smrg    pCounter = (SyncCounter *) pTrigger->pSync;
53665b04b38Smrg
53705b261ecSmrg    /* no need to check alarm unless it's active */
53805b261ecSmrg    if (pAlarm->state != XSyncAlarmActive)
539f7df2e56Smrg        return;
54005b261ecSmrg
54105b261ecSmrg    /*  " if the counter value is None, or if the delta is 0 and
54205b261ecSmrg     *    the test-type is PositiveComparison or NegativeComparison,
54305b261ecSmrg     *    no change is made to value (test-value) and the alarm
54405b261ecSmrg     *    state is changed to Inactive before the event is generated."
54505b261ecSmrg     */
5467e31ba66Smrg    if (pCounter == NULL || (pAlarm->delta == 0
547f7df2e56Smrg                             && (pAlarm->trigger.test_type ==
548f7df2e56Smrg                                 XSyncPositiveComparison ||
549f7df2e56Smrg                                 pAlarm->trigger.test_type ==
550f7df2e56Smrg                                 XSyncNegativeComparison)))
551f7df2e56Smrg        pAlarm->state = XSyncAlarmInactive;
55205b261ecSmrg
55305b261ecSmrg    new_test_value = pAlarm->trigger.test_value;
55405b261ecSmrg
555f7df2e56Smrg    if (pAlarm->state == XSyncAlarmActive) {
556f7df2e56Smrg        Bool overflow;
5577e31ba66Smrg        int64_t oldvalue;
558f7df2e56Smrg        SyncTrigger *paTrigger = &pAlarm->trigger;
559f7df2e56Smrg        SyncCounter *paCounter;
560f7df2e56Smrg
561f7df2e56Smrg        if (!SyncCheckWarnIsCounter(paTrigger->pSync,
562f7df2e56Smrg                                    WARN_INVALID_COUNTER_ALARM))
563f7df2e56Smrg            return;
564f7df2e56Smrg
565f7df2e56Smrg        paCounter = (SyncCounter *) pTrigger->pSync;
566f7df2e56Smrg
567f7df2e56Smrg        /* "The alarm is updated by repeatedly adding delta to the
568f7df2e56Smrg         *  value of the trigger and re-initializing it until it
569f7df2e56Smrg         *  becomes FALSE."
570f7df2e56Smrg         */
571f7df2e56Smrg        oldvalue = paTrigger->test_value;
572f7df2e56Smrg
573f7df2e56Smrg        /* XXX really should do something smarter here */
574f7df2e56Smrg
575f7df2e56Smrg        do {
5767e31ba66Smrg            overflow = checked_int64_add(&paTrigger->test_value,
5777e31ba66Smrg                                         paTrigger->test_value, pAlarm->delta);
578f7df2e56Smrg        } while (!overflow &&
579f7df2e56Smrg                 (*paTrigger->CheckTrigger) (paTrigger, paCounter->value));
580f7df2e56Smrg
581f7df2e56Smrg        new_test_value = paTrigger->test_value;
582f7df2e56Smrg        paTrigger->test_value = oldvalue;
583f7df2e56Smrg
584f7df2e56Smrg        /* "If this update would cause value to fall outside the range
585f7df2e56Smrg         *  for an INT64...no change is made to value (test-value) and
586f7df2e56Smrg         *  the alarm state is changed to Inactive before the event is
587f7df2e56Smrg         *  generated."
588f7df2e56Smrg         */
589f7df2e56Smrg        if (overflow) {
590f7df2e56Smrg            new_test_value = oldvalue;
591f7df2e56Smrg            pAlarm->state = XSyncAlarmInactive;
592f7df2e56Smrg        }
59305b261ecSmrg    }
59405b261ecSmrg    /*  The AlarmNotify event has to have the "new state of the alarm"
59505b261ecSmrg     *  which we can't be sure of until this point.  However, it has
59605b261ecSmrg     *  to have the "old" trigger test value.  That's the reason for
59705b261ecSmrg     *  all the newvalue/oldvalue shuffling above.  After we send the
59805b261ecSmrg     *  events, give the trigger its new test value.
59905b261ecSmrg     */
60005b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
60105b261ecSmrg    pTrigger->test_value = new_test_value;
60205b261ecSmrg}
60305b261ecSmrg
60405b261ecSmrg/*  This function is called when an Await unblocks, either as a result
60505b261ecSmrg *  of the trigger firing OR the counter being destroyed.
60605b261ecSmrg *  It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed
60705b261ecSmrg *  (for Await triggers).
60805b261ecSmrg */
60905b261ecSmrgstatic void
610f7df2e56SmrgSyncAwaitTriggerFired(SyncTrigger * pTrigger)
61105b261ecSmrg{
612f7df2e56Smrg    SyncAwait *pAwait = (SyncAwait *) pTrigger;
61305b261ecSmrg    int numwaits;
61405b261ecSmrg    SyncAwaitUnion *pAwaitUnion;
61505b261ecSmrg    SyncAwait **ppAwait;
61605b261ecSmrg    int num_events = 0;
61705b261ecSmrg
618f7df2e56Smrg    pAwaitUnion = (SyncAwaitUnion *) pAwait->pHeader;
61905b261ecSmrg    numwaits = pAwaitUnion->header.num_waitconditions;
620f7df2e56Smrg    ppAwait = xallocarray(numwaits, sizeof(SyncAwait *));
62105b261ecSmrg    if (!ppAwait)
622f7df2e56Smrg        goto bail;
62305b261ecSmrg
624f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await;
62505b261ecSmrg
62605b261ecSmrg    /* "When a client is unblocked, all the CounterNotify events for
62705b261ecSmrg     *  the Await request are generated contiguously. If count is 0
62805b261ecSmrg     *  there are no more events to follow for this request. If
62905b261ecSmrg     *  count is n, there are at least n more events to follow."
63005b261ecSmrg     *
63105b261ecSmrg     *  Thus, it is best to find all the counters for which events
63205b261ecSmrg     *  need to be sent first, so that an accurate count field can
63305b261ecSmrg     *  be stored in the events.
63405b261ecSmrg     */
635f7df2e56Smrg    for (; numwaits; numwaits--, pAwait++) {
6367e31ba66Smrg        int64_t diff;
637f7df2e56Smrg        Bool overflow, diffgreater, diffequal;
638f7df2e56Smrg
639f7df2e56Smrg        /* "A CounterNotify event with the destroyed flag set to TRUE is
640f7df2e56Smrg         *  always generated if the counter for one of the triggers is
641f7df2e56Smrg         *  destroyed."
642f7df2e56Smrg         */
643f7df2e56Smrg        if (pAwait->trigger.pSync->beingDestroyed) {
644f7df2e56Smrg            ppAwait[num_events++] = pAwait;
645f7df2e56Smrg            continue;
646f7df2e56Smrg        }
647f7df2e56Smrg
648f7df2e56Smrg        if (SYNC_COUNTER == pAwait->trigger.pSync->type) {
649f7df2e56Smrg            SyncCounter *pCounter = (SyncCounter *) pAwait->trigger.pSync;
650f7df2e56Smrg
651f7df2e56Smrg            /* "The difference between the counter and the test value is
652f7df2e56Smrg             *  calculated by subtracting the test value from the value of
653f7df2e56Smrg             *  the counter."
654f7df2e56Smrg             */
6557e31ba66Smrg            overflow = checked_int64_subtract(&diff, pCounter->value,
6567e31ba66Smrg                                              pAwait->trigger.test_value);
657f7df2e56Smrg
658f7df2e56Smrg            /* "If the difference lies outside the range for an INT64, an
659f7df2e56Smrg             *  event is not generated."
660f7df2e56Smrg             */
661f7df2e56Smrg            if (overflow)
662f7df2e56Smrg                continue;
6637e31ba66Smrg            diffgreater = diff > pAwait->event_threshold;
6647e31ba66Smrg            diffequal = diff == pAwait->event_threshold;
665f7df2e56Smrg
666f7df2e56Smrg            /* "If the test-type is PositiveTransition or
667f7df2e56Smrg             *  PositiveComparison, a CounterNotify event is generated if
668f7df2e56Smrg             *  the difference is at least event-threshold. If the test-type
669f7df2e56Smrg             *  is NegativeTransition or NegativeComparison, a CounterNotify
670f7df2e56Smrg             *  event is generated if the difference is at most
671f7df2e56Smrg             *  event-threshold."
672f7df2e56Smrg             */
673f7df2e56Smrg
674f7df2e56Smrg            if (((pAwait->trigger.test_type == XSyncPositiveComparison ||
675f7df2e56Smrg                  pAwait->trigger.test_type == XSyncPositiveTransition)
676f7df2e56Smrg                 && (diffgreater || diffequal))
677f7df2e56Smrg                ||
678f7df2e56Smrg                ((pAwait->trigger.test_type == XSyncNegativeComparison ||
679f7df2e56Smrg                  pAwait->trigger.test_type == XSyncNegativeTransition)
680f7df2e56Smrg                 && (!diffgreater)      /* less or equal */
681f7df2e56Smrg                )
682f7df2e56Smrg                ) {
683f7df2e56Smrg                ppAwait[num_events++] = pAwait;
684f7df2e56Smrg            }
685f7df2e56Smrg        }
68605b261ecSmrg    }
68705b261ecSmrg    if (num_events)
688f7df2e56Smrg        SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait,
689f7df2e56Smrg                                    num_events);
6904202a189Smrg    free(ppAwait);
69105b261ecSmrg
692f7df2e56Smrg bail:
69305b261ecSmrg    /* unblock the client */
69405b261ecSmrg    AttendClient(pAwaitUnion->header.client);
69505b261ecSmrg    /* delete the await */
69605b261ecSmrg    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
69705b261ecSmrg}
69805b261ecSmrg
6997e31ba66Smrgstatic int64_t
7007e31ba66SmrgSyncUpdateCounter(SyncCounter *pCounter, int64_t newval)
701f7df2e56Smrg{
7027e31ba66Smrg    int64_t oldval = pCounter->value;
703f7df2e56Smrg    pCounter->value = newval;
704f7df2e56Smrg    return oldval;
705f7df2e56Smrg}
70605b261ecSmrg
70705b261ecSmrg/*  This function should always be used to change a counter's value so that
70805b261ecSmrg *  any triggers depending on the counter will be checked.
70905b261ecSmrg */
71005b261ecSmrgvoid
7117e31ba66SmrgSyncChangeCounter(SyncCounter * pCounter, int64_t newval)
71205b261ecSmrg{
713f7df2e56Smrg    SyncTriggerList *ptl, *pnext;
7147e31ba66Smrg    int64_t oldval;
71505b261ecSmrg
716f7df2e56Smrg    oldval = SyncUpdateCounter(pCounter, newval);
71705b261ecSmrg
71805b261ecSmrg    /* run through triggers to see if any become true */
719f7df2e56Smrg    for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) {
720f7df2e56Smrg        pnext = ptl->next;
721f7df2e56Smrg        if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, oldval))
722f7df2e56Smrg            (*ptl->pTrigger->TriggerFired) (ptl->pTrigger);
72305b261ecSmrg    }
72405b261ecSmrg
725f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
726f7df2e56Smrg        SyncComputeBracketValues(pCounter);
72705b261ecSmrg    }
72805b261ecSmrg}
72905b261ecSmrg
73005b261ecSmrg/* loosely based on dix/events.c/EventSelectForWindow */
73105b261ecSmrgstatic Bool
732f7df2e56SmrgSyncEventSelectForAlarm(SyncAlarm * pAlarm, ClientPtr client, Bool wantevents)
73305b261ecSmrg{
73405b261ecSmrg    SyncAlarmClientList *pClients;
73505b261ecSmrg
736f7df2e56Smrg    if (client == pAlarm->client) {     /* alarm owner */
737f7df2e56Smrg        pAlarm->events = wantevents;
738f7df2e56Smrg        return Success;
73905b261ecSmrg    }
74005b261ecSmrg
74105b261ecSmrg    /* see if the client is already on the list (has events selected) */
74205b261ecSmrg
743f7df2e56Smrg    for (pClients = pAlarm->pEventClients; pClients; pClients = pClients->next) {
744f7df2e56Smrg        if (pClients->client == client) {
745f7df2e56Smrg            /* client's presence on the list indicates desire for
746f7df2e56Smrg             * events.  If the client doesn't want events, remove it
747f7df2e56Smrg             * from the list.  If the client does want events, do
748f7df2e56Smrg             * nothing, since it's already got them.
749f7df2e56Smrg             */
750f7df2e56Smrg            if (!wantevents) {
751f7df2e56Smrg                FreeResource(pClients->delete_id, RT_NONE);
752f7df2e56Smrg            }
753f7df2e56Smrg            return Success;
754f7df2e56Smrg        }
75505b261ecSmrg    }
75605b261ecSmrg
75705b261ecSmrg    /*  if we get here, this client does not currently have
75805b261ecSmrg     *  events selected on the alarm
75905b261ecSmrg     */
76005b261ecSmrg
76105b261ecSmrg    if (!wantevents)
762f7df2e56Smrg        /* client doesn't want events, and we just discovered that it
763f7df2e56Smrg         * doesn't have them, so there's nothing to do.
764f7df2e56Smrg         */
765f7df2e56Smrg        return Success;
76605b261ecSmrg
76705b261ecSmrg    /* add new client to pAlarm->pEventClients */
76805b261ecSmrg
7694202a189Smrg    pClients = malloc(sizeof(SyncAlarmClientList));
77005b261ecSmrg    if (!pClients)
771f7df2e56Smrg        return BadAlloc;
77205b261ecSmrg
7734202a189Smrg    /*  register it as a resource so it will be cleaned up
77405b261ecSmrg     *  if the client dies
77505b261ecSmrg     */
77605b261ecSmrg
77705b261ecSmrg    pClients->delete_id = FakeClientID(client->index);
77805b261ecSmrg
77905b261ecSmrg    /* link it into list after we know all the allocations succeed */
78005b261ecSmrg    pClients->next = pAlarm->pEventClients;
78105b261ecSmrg    pAlarm->pEventClients = pClients;
78205b261ecSmrg    pClients->client = client;
78365b04b38Smrg
78465b04b38Smrg    if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm))
785f7df2e56Smrg        return BadAlloc;
78665b04b38Smrg
78705b261ecSmrg    return Success;
78805b261ecSmrg}
78905b261ecSmrg
79005b261ecSmrg/*
79105b261ecSmrg * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm
79205b261ecSmrg */
7934202a189Smrgstatic int
794f7df2e56SmrgSyncChangeAlarmAttributes(ClientPtr client, SyncAlarm * pAlarm, Mask mask,
795f7df2e56Smrg                          CARD32 *values)
796f7df2e56Smrg{
797f7df2e56Smrg    int status;
798f7df2e56Smrg    XSyncCounter counter;
799f7df2e56Smrg    Mask origmask = mask;
800f7df2e56Smrg
801f7df2e56Smrg    counter = pAlarm->trigger.pSync ? pAlarm->trigger.pSync->id : None;
802f7df2e56Smrg
803f7df2e56Smrg    while (mask) {
804f7df2e56Smrg        int index2 = lowbit(mask);
805f7df2e56Smrg
806f7df2e56Smrg        mask &= ~index2;
807f7df2e56Smrg        switch (index2) {
808f7df2e56Smrg        case XSyncCACounter:
809f7df2e56Smrg            mask &= ~XSyncCACounter;
810f7df2e56Smrg            /* sanity check in SyncInitTrigger */
811f7df2e56Smrg            counter = *values++;
812f7df2e56Smrg            break;
813f7df2e56Smrg
814f7df2e56Smrg        case XSyncCAValueType:
815f7df2e56Smrg            mask &= ~XSyncCAValueType;
816f7df2e56Smrg            /* sanity check in SyncInitTrigger */
817f7df2e56Smrg            pAlarm->trigger.value_type = *values++;
818f7df2e56Smrg            break;
819f7df2e56Smrg
820f7df2e56Smrg        case XSyncCAValue:
821f7df2e56Smrg            mask &= ~XSyncCAValue;
8227e31ba66Smrg            pAlarm->trigger.wait_value = ((int64_t)values[0] << 32) | values[1];
823f7df2e56Smrg            values += 2;
824f7df2e56Smrg            break;
825f7df2e56Smrg
826f7df2e56Smrg        case XSyncCATestType:
827f7df2e56Smrg            mask &= ~XSyncCATestType;
828f7df2e56Smrg            /* sanity check in SyncInitTrigger */
829f7df2e56Smrg            pAlarm->trigger.test_type = *values++;
830f7df2e56Smrg            break;
831f7df2e56Smrg
832f7df2e56Smrg        case XSyncCADelta:
833f7df2e56Smrg            mask &= ~XSyncCADelta;
8347e31ba66Smrg            pAlarm->delta = ((int64_t)values[0] << 32) | values[1];
835f7df2e56Smrg            values += 2;
836f7df2e56Smrg            break;
837f7df2e56Smrg
838f7df2e56Smrg        case XSyncCAEvents:
839f7df2e56Smrg            mask &= ~XSyncCAEvents;
840f7df2e56Smrg            if ((*values != xTrue) && (*values != xFalse)) {
841f7df2e56Smrg                client->errorValue = *values;
842f7df2e56Smrg                return BadValue;
843f7df2e56Smrg            }
844f7df2e56Smrg            status = SyncEventSelectForAlarm(pAlarm, client,
845f7df2e56Smrg                                             (Bool) (*values++));
846f7df2e56Smrg            if (status != Success)
847f7df2e56Smrg                return status;
848f7df2e56Smrg            break;
849f7df2e56Smrg
850f7df2e56Smrg        default:
851f7df2e56Smrg            client->errorValue = mask;
852f7df2e56Smrg            return BadValue;
853f7df2e56Smrg        }
85405b261ecSmrg    }
85505b261ecSmrg
85605b261ecSmrg    /* "If the test-type is PositiveComparison or PositiveTransition
85705b261ecSmrg     *  and delta is less than zero, or if the test-type is
85805b261ecSmrg     *  NegativeComparison or NegativeTransition and delta is
85905b261ecSmrg     *  greater than zero, a Match error is generated."
86005b261ecSmrg     */
861f7df2e56Smrg    if (origmask & (XSyncCADelta | XSyncCATestType)) {
862f7df2e56Smrg        if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) ||
863f7df2e56Smrg              (pAlarm->trigger.test_type == XSyncPositiveTransition))
8647e31ba66Smrg             && pAlarm->delta < 0)
865f7df2e56Smrg            ||
866f7df2e56Smrg            (((pAlarm->trigger.test_type == XSyncNegativeComparison) ||
867f7df2e56Smrg              (pAlarm->trigger.test_type == XSyncNegativeTransition))
8687e31ba66Smrg             && pAlarm->delta > 0)
869f7df2e56Smrg            ) {
870f7df2e56Smrg            return BadMatch;
871f7df2e56Smrg        }
87205b261ecSmrg    }
87305b261ecSmrg
87405b261ecSmrg    /* postpone this until now, when we're sure nothing else can go wrong */
87565b04b38Smrg    if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter,
876f7df2e56Smrg                                  origmask & XSyncCAAllTrigger)) != Success)
877f7df2e56Smrg        return status;
87805b261ecSmrg
87905b261ecSmrg    /* XXX spec does not really say to do this - needs clarification */
88005b261ecSmrg    pAlarm->state = XSyncAlarmActive;
88105b261ecSmrg    return Success;
88205b261ecSmrg}
88305b261ecSmrg
8844e185dc0SmrgSyncObject *
88565b04b38SmrgSyncCreate(ClientPtr client, XID id, unsigned char type)
88665b04b38Smrg{
88765b04b38Smrg    SyncObject *pSync;
8884e185dc0Smrg    RESTYPE resType;
88965b04b38Smrg
89065b04b38Smrg    switch (type) {
89165b04b38Smrg    case SYNC_COUNTER:
892f7df2e56Smrg        pSync = malloc(sizeof(SyncCounter));
8934e185dc0Smrg        resType = RTCounter;
894f7df2e56Smrg        break;
89565b04b38Smrg    case SYNC_FENCE:
896f7df2e56Smrg        pSync = (SyncObject *) dixAllocateObjectWithPrivates(SyncFence,
897f7df2e56Smrg                                                             PRIVATE_SYNC_FENCE);
8984e185dc0Smrg        resType = RTFence;
899f7df2e56Smrg        break;
90065b04b38Smrg    default:
901f7df2e56Smrg        return NULL;
90265b04b38Smrg    }
90365b04b38Smrg
90465b04b38Smrg    if (!pSync)
905f7df2e56Smrg        return NULL;
90665b04b38Smrg
9074e185dc0Smrg    pSync->initialized = FALSE;
9084e185dc0Smrg
9094e185dc0Smrg    if (!AddResource(id, resType, (void *) pSync))
9104e185dc0Smrg        return NULL;
9114e185dc0Smrg
91265b04b38Smrg    pSync->client = client;
91365b04b38Smrg    pSync->id = id;
91465b04b38Smrg    pSync->pTriglist = NULL;
91565b04b38Smrg    pSync->beingDestroyed = FALSE;
91665b04b38Smrg    pSync->type = type;
91765b04b38Smrg
91865b04b38Smrg    return pSync;
91965b04b38Smrg}
92065b04b38Smrg
921f7df2e56Smrgint
922f7df2e56SmrgSyncCreateFenceFromFD(ClientPtr client, DrawablePtr pDraw, XID id, int fd, BOOL initially_triggered)
923f7df2e56Smrg{
9247e31ba66Smrg#ifdef HAVE_XSHMFENCE
925f7df2e56Smrg    SyncFence  *pFence;
926f7df2e56Smrg    int         status;
927f7df2e56Smrg
928f7df2e56Smrg    pFence = (SyncFence *) SyncCreate(client, id, SYNC_FENCE);
929f7df2e56Smrg    if (!pFence)
930f7df2e56Smrg        return BadAlloc;
931f7df2e56Smrg
932f7df2e56Smrg    status = miSyncInitFenceFromFD(pDraw, pFence, fd, initially_triggered);
933f7df2e56Smrg    if (status != Success) {
9344e185dc0Smrg        FreeResource(pFence->sync.id, RT_NONE);
935f7df2e56Smrg        return status;
936f7df2e56Smrg    }
937f7df2e56Smrg
938f7df2e56Smrg    return Success;
939f7df2e56Smrg#else
940f7df2e56Smrg    return BadImplementation;
941f7df2e56Smrg#endif
942f7df2e56Smrg}
943f7df2e56Smrg
944f7df2e56Smrgint
945f7df2e56SmrgSyncFDFromFence(ClientPtr client, DrawablePtr pDraw, SyncFence *pFence)
946f7df2e56Smrg{
9477e31ba66Smrg#ifdef HAVE_XSHMFENCE
948f7df2e56Smrg    return miSyncFDFromFence(pDraw, pFence);
949f7df2e56Smrg#else
950f7df2e56Smrg    return BadImplementation;
951f7df2e56Smrg#endif
952f7df2e56Smrg}
95305b261ecSmrg
95405b261ecSmrgstatic SyncCounter *
9557e31ba66SmrgSyncCreateCounter(ClientPtr client, XSyncCounter id, int64_t initialvalue)
95605b261ecSmrg{
95705b261ecSmrg    SyncCounter *pCounter;
95805b261ecSmrg
959f7df2e56Smrg    if (!(pCounter = (SyncCounter *) SyncCreate(client, id, SYNC_COUNTER)))
960f7df2e56Smrg        return NULL;
96105b261ecSmrg
96265b04b38Smrg    pCounter->value = initialvalue;
96365b04b38Smrg    pCounter->pSysCounterInfo = NULL;
96465b04b38Smrg
9654e185dc0Smrg    pCounter->sync.initialized = TRUE;
96605b261ecSmrg
96705b261ecSmrg    return pCounter;
96805b261ecSmrg}
96905b261ecSmrg
9704202a189Smrgstatic int FreeCounter(void *, XID);
97105b261ecSmrg
97205b261ecSmrg/*
97305b261ecSmrg * ***** System Counter utilities
97405b261ecSmrg */
97505b261ecSmrg
976f7df2e56SmrgSyncCounter*
977f7df2e56SmrgSyncCreateSystemCounter(const char *name,
9787e31ba66Smrg                        int64_t initial,
9797e31ba66Smrg                        int64_t resolution,
980f7df2e56Smrg                        SyncCounterType counterType,
981f7df2e56Smrg                        SyncSystemCounterQueryValue QueryValue,
982f7df2e56Smrg                        SyncSystemCounterBracketValues BracketValues
983f7df2e56Smrg    )
984f7df2e56Smrg{
9857e31ba66Smrg    SyncCounter *pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial);
98605b261ecSmrg
987f7df2e56Smrg    if (pCounter) {
988f7df2e56Smrg        SysCounterInfo *psci;
989f7df2e56Smrg
990f7df2e56Smrg        psci = malloc(sizeof(SysCounterInfo));
991f7df2e56Smrg        if (!psci) {
992f7df2e56Smrg            FreeResource(pCounter->sync.id, RT_NONE);
993f7df2e56Smrg            return pCounter;
994f7df2e56Smrg        }
995f7df2e56Smrg        pCounter->pSysCounterInfo = psci;
996f7df2e56Smrg        psci->pCounter = pCounter;
997f7df2e56Smrg        psci->name = strdup(name);
998f7df2e56Smrg        psci->resolution = resolution;
999f7df2e56Smrg        psci->counterType = counterType;
1000f7df2e56Smrg        psci->QueryValue = QueryValue;
1001f7df2e56Smrg        psci->BracketValues = BracketValues;
1002f7df2e56Smrg        psci->private = NULL;
10037e31ba66Smrg        psci->bracket_greater = LLONG_MAX;
10047e31ba66Smrg        psci->bracket_less = LLONG_MIN;
1005f7df2e56Smrg        xorg_list_add(&psci->entry, &SysCounterList);
100605b261ecSmrg    }
10074202a189Smrg    return pCounter;
100805b261ecSmrg}
100905b261ecSmrg
101005b261ecSmrgvoid
1011f7df2e56SmrgSyncDestroySystemCounter(void *pSysCounter)
101205b261ecSmrg{
1013f7df2e56Smrg    SyncCounter *pCounter = (SyncCounter *) pSysCounter;
1014f7df2e56Smrg
101565b04b38Smrg    FreeResource(pCounter->sync.id, RT_NONE);
101605b261ecSmrg}
101705b261ecSmrg
101805b261ecSmrgstatic void
1019f7df2e56SmrgSyncComputeBracketValues(SyncCounter * pCounter)
102005b261ecSmrg{
102105b261ecSmrg    SyncTriggerList *pCur;
102205b261ecSmrg    SyncTrigger *pTrigger;
102305b261ecSmrg    SysCounterInfo *psci;
10247e31ba66Smrg    int64_t *pnewgtval = NULL;
10257e31ba66Smrg    int64_t *pnewltval = NULL;
102605b261ecSmrg    SyncCounterType ct;
102705b261ecSmrg
102805b261ecSmrg    if (!pCounter)
1029f7df2e56Smrg        return;
103005b261ecSmrg
103105b261ecSmrg    psci = pCounter->pSysCounterInfo;
103205b261ecSmrg    ct = pCounter->pSysCounterInfo->counterType;
103305b261ecSmrg    if (ct == XSyncCounterNeverChanges)
1034f7df2e56Smrg        return;
103505b261ecSmrg
10367e31ba66Smrg    psci->bracket_greater = LLONG_MAX;
10377e31ba66Smrg    psci->bracket_less = LLONG_MIN;
103805b261ecSmrg
1039f7df2e56Smrg    for (pCur = pCounter->sync.pTriglist; pCur; pCur = pCur->next) {
1040f7df2e56Smrg        pTrigger = pCur->pTrigger;
1041f7df2e56Smrg
104205b261ecSmrg        if (pTrigger->test_type == XSyncPositiveComparison &&
1043f7df2e56Smrg            ct != XSyncCounterNeverIncreases) {
10447e31ba66Smrg            if (pCounter->value < pTrigger->test_value &&
10457e31ba66Smrg                pTrigger->test_value < psci->bracket_greater) {
1046f7df2e56Smrg                psci->bracket_greater = pTrigger->test_value;
1047f7df2e56Smrg                pnewgtval = &psci->bracket_greater;
1048f7df2e56Smrg            }
10497e31ba66Smrg            else if (pCounter->value > pTrigger->test_value &&
10507e31ba66Smrg                     pTrigger->test_value > psci->bracket_less) {
1051f7df2e56Smrg                    psci->bracket_less = pTrigger->test_value;
1052f7df2e56Smrg                    pnewltval = &psci->bracket_less;
1053f7df2e56Smrg            }
1054f7df2e56Smrg        }
1055f7df2e56Smrg        else if (pTrigger->test_type == XSyncNegativeComparison &&
1056f7df2e56Smrg                 ct != XSyncCounterNeverDecreases) {
10577e31ba66Smrg            if (pCounter->value > pTrigger->test_value &&
10587e31ba66Smrg                pTrigger->test_value > psci->bracket_less) {
1059f7df2e56Smrg                psci->bracket_less = pTrigger->test_value;
1060f7df2e56Smrg                pnewltval = &psci->bracket_less;
1061f7df2e56Smrg            }
10627e31ba66Smrg            else if (pCounter->value < pTrigger->test_value &&
10637e31ba66Smrg                     pTrigger->test_value < psci->bracket_greater) {
1064f7df2e56Smrg                    psci->bracket_greater = pTrigger->test_value;
1065f7df2e56Smrg                    pnewgtval = &psci->bracket_greater;
1066f7df2e56Smrg            }
1067f7df2e56Smrg        }
1068f7df2e56Smrg        else if (pTrigger->test_type == XSyncNegativeTransition &&
1069f7df2e56Smrg                 ct != XSyncCounterNeverIncreases) {
10707e31ba66Smrg            if (pCounter->value >= pTrigger->test_value &&
10717e31ba66Smrg                pTrigger->test_value > psci->bracket_less) {
1072f7df2e56Smrg                    /*
1073f7df2e56Smrg                     * If the value is exactly equal to our threshold, we want one
1074f7df2e56Smrg                     * more event in the negative direction to ensure we pick up
1075f7df2e56Smrg                     * when the value is less than this threshold.
1076f7df2e56Smrg                     */
1077f7df2e56Smrg                    psci->bracket_less = pTrigger->test_value;
1078f7df2e56Smrg                    pnewltval = &psci->bracket_less;
1079f7df2e56Smrg            }
10807e31ba66Smrg            else if (pCounter->value < pTrigger->test_value &&
10817e31ba66Smrg                     pTrigger->test_value < psci->bracket_greater) {
1082f7df2e56Smrg                    psci->bracket_greater = pTrigger->test_value;
1083f7df2e56Smrg                    pnewgtval = &psci->bracket_greater;
1084f7df2e56Smrg            }
1085f7df2e56Smrg        }
1086a0d10bb6Smrg        else if (pTrigger->test_type == XSyncPositiveTransition &&
1087f7df2e56Smrg                 ct != XSyncCounterNeverDecreases) {
10887e31ba66Smrg            if (pCounter->value <= pTrigger->test_value &&
10897e31ba66Smrg                pTrigger->test_value < psci->bracket_greater) {
1090f7df2e56Smrg                    /*
1091f7df2e56Smrg                     * If the value is exactly equal to our threshold, we
1092f7df2e56Smrg                     * want one more event in the positive direction to
1093f7df2e56Smrg                     * ensure we pick up when the value *exceeds* this
1094f7df2e56Smrg                     * threshold.
1095f7df2e56Smrg                     */
1096f7df2e56Smrg                    psci->bracket_greater = pTrigger->test_value;
1097f7df2e56Smrg                    pnewgtval = &psci->bracket_greater;
1098f7df2e56Smrg            }
10997e31ba66Smrg            else if (pCounter->value > pTrigger->test_value &&
11007e31ba66Smrg                     pTrigger->test_value > psci->bracket_less) {
1101f7df2e56Smrg                    psci->bracket_less = pTrigger->test_value;
1102f7df2e56Smrg                    pnewltval = &psci->bracket_less;
1103f7df2e56Smrg            }
1104f7df2e56Smrg        }
1105f7df2e56Smrg    }                           /* end for each trigger */
1106f7df2e56Smrg
1107f7df2e56Smrg    (*psci->BracketValues) ((void *) pCounter, pnewltval, pnewgtval);
1108f7df2e56Smrg
110905b261ecSmrg}
111005b261ecSmrg
111105b261ecSmrg/*
111205b261ecSmrg * *****  Resource delete functions
111305b261ecSmrg */
111405b261ecSmrg
111505b261ecSmrg/* ARGSUSED */
111605b261ecSmrgstatic int
11174202a189SmrgFreeAlarm(void *addr, XID id)
111805b261ecSmrg{
1119f7df2e56Smrg    SyncAlarm *pAlarm = (SyncAlarm *) addr;
112005b261ecSmrg
112105b261ecSmrg    pAlarm->state = XSyncAlarmDestroyed;
112205b261ecSmrg
112305b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
112405b261ecSmrg
112505b261ecSmrg    /* delete event selections */
112605b261ecSmrg
112705b261ecSmrg    while (pAlarm->pEventClients)
1128f7df2e56Smrg        FreeResource(pAlarm->pEventClients->delete_id, RT_NONE);
112905b261ecSmrg
113065b04b38Smrg    SyncDeleteTriggerFromSyncObject(&pAlarm->trigger);
113105b261ecSmrg
11324202a189Smrg    free(pAlarm);
113305b261ecSmrg    return Success;
113405b261ecSmrg}
113505b261ecSmrg
113605b261ecSmrg/*
113705b261ecSmrg * ** Cleanup after the destruction of a Counter
113805b261ecSmrg */
113905b261ecSmrg/* ARGSUSED */
114005b261ecSmrgstatic int
11414202a189SmrgFreeCounter(void *env, XID id)
114205b261ecSmrg{
1143f7df2e56Smrg    SyncCounter *pCounter = (SyncCounter *) env;
114405b261ecSmrg
114565b04b38Smrg    pCounter->sync.beingDestroyed = TRUE;
11464e185dc0Smrg
11474e185dc0Smrg    if (pCounter->sync.initialized) {
11484e185dc0Smrg        SyncTriggerList *ptl, *pnext;
11494e185dc0Smrg
11504e185dc0Smrg        /* tell all the counter's triggers that counter has been destroyed */
11514e185dc0Smrg        for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) {
11524e185dc0Smrg            (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger);
11534e185dc0Smrg            pnext = ptl->next;
11544e185dc0Smrg            free(ptl); /* destroy the trigger list as we go */
11554e185dc0Smrg        }
11564e185dc0Smrg        if (IsSystemCounter(pCounter)) {
11574e185dc0Smrg            xorg_list_del(&pCounter->pSysCounterInfo->entry);
11584e185dc0Smrg            free(pCounter->pSysCounterInfo->name);
11594e185dc0Smrg            free(pCounter->pSysCounterInfo->private);
11604e185dc0Smrg            free(pCounter->pSysCounterInfo);
11614e185dc0Smrg        }
116205b261ecSmrg    }
11634e185dc0Smrg
11644202a189Smrg    free(pCounter);
116505b261ecSmrg    return Success;
116605b261ecSmrg}
116705b261ecSmrg
116805b261ecSmrg/*
116905b261ecSmrg * ** Cleanup after Await
117005b261ecSmrg */
117105b261ecSmrg/* ARGSUSED */
117205b261ecSmrgstatic int
11734202a189SmrgFreeAwait(void *addr, XID id)
117405b261ecSmrg{
117505b261ecSmrg    SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr;
117605b261ecSmrg    SyncAwait *pAwait;
117705b261ecSmrg    int numwaits;
117805b261ecSmrg
1179f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await; /* first await on list */
118005b261ecSmrg
118105b261ecSmrg    /* remove triggers from counters */
118205b261ecSmrg
118305b261ecSmrg    for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits;
1184f7df2e56Smrg         numwaits--, pAwait++) {
1185f7df2e56Smrg        /* If the counter is being destroyed, FreeCounter will delete
1186f7df2e56Smrg         * the trigger list itself, so don't do it here.
1187f7df2e56Smrg         */
1188f7df2e56Smrg        SyncObject *pSync = pAwait->trigger.pSync;
1189f7df2e56Smrg
1190f7df2e56Smrg        if (pSync && !pSync->beingDestroyed)
1191f7df2e56Smrg            SyncDeleteTriggerFromSyncObject(&pAwait->trigger);
119205b261ecSmrg    }
11934202a189Smrg    free(pAwaitUnion);
119405b261ecSmrg    return Success;
119505b261ecSmrg}
119605b261ecSmrg
119705b261ecSmrg/* loosely based on dix/events.c/OtherClientGone */
119805b261ecSmrgstatic int
11994202a189SmrgFreeAlarmClient(void *value, XID id)
120005b261ecSmrg{
1201f7df2e56Smrg    SyncAlarm *pAlarm = (SyncAlarm *) value;
120205b261ecSmrg    SyncAlarmClientList *pCur, *pPrev;
120305b261ecSmrg
120405b261ecSmrg    for (pPrev = NULL, pCur = pAlarm->pEventClients;
1205f7df2e56Smrg         pCur; pPrev = pCur, pCur = pCur->next) {
1206f7df2e56Smrg        if (pCur->delete_id == id) {
1207f7df2e56Smrg            if (pPrev)
1208f7df2e56Smrg                pPrev->next = pCur->next;
1209f7df2e56Smrg            else
1210f7df2e56Smrg                pAlarm->pEventClients = pCur->next;
1211f7df2e56Smrg            free(pCur);
1212f7df2e56Smrg            return Success;
1213f7df2e56Smrg        }
121405b261ecSmrg    }
121505b261ecSmrg    FatalError("alarm client not on event list");
1216f7df2e56Smrg /*NOTREACHED*/}
121705b261ecSmrg
121805b261ecSmrg/*
121905b261ecSmrg * *****  Proc functions
122005b261ecSmrg */
122105b261ecSmrg
122205b261ecSmrg/*
122305b261ecSmrg * ** Initialize the extension
122405b261ecSmrg */
12254202a189Smrgstatic int
12264202a189SmrgProcSyncInitialize(ClientPtr client)
122705b261ecSmrg{
1228f7df2e56Smrg    xSyncInitializeReply rep = {
1229f7df2e56Smrg        .type = X_Reply,
1230f7df2e56Smrg        .sequenceNumber = client->sequence,
1231f7df2e56Smrg        .length = 0,
1232f7df2e56Smrg        .majorVersion = SERVER_SYNC_MAJOR_VERSION,
1233f7df2e56Smrg        .minorVersion = SERVER_SYNC_MINOR_VERSION,
1234f7df2e56Smrg    };
123505b261ecSmrg
123605b261ecSmrg    REQUEST_SIZE_MATCH(xSyncInitializeReq);
123705b261ecSmrg
1238f7df2e56Smrg    if (client->swapped) {
1239f7df2e56Smrg        swaps(&rep.sequenceNumber);
124005b261ecSmrg    }
1241f7df2e56Smrg    WriteToClient(client, sizeof(rep), &rep);
12424202a189Smrg    return Success;
124305b261ecSmrg}
124405b261ecSmrg
124505b261ecSmrg/*
124605b261ecSmrg * ** Get list of system counters available through the extension
124705b261ecSmrg */
12484202a189Smrgstatic int
12494202a189SmrgProcSyncListSystemCounters(ClientPtr client)
125005b261ecSmrg{
1251f7df2e56Smrg    xSyncListSystemCountersReply rep = {
1252f7df2e56Smrg        .type = X_Reply,
1253f7df2e56Smrg        .sequenceNumber = client->sequence,
1254f7df2e56Smrg        .nCounters = 0,
1255f7df2e56Smrg    };
1256f7df2e56Smrg    SysCounterInfo *psci;
1257f7df2e56Smrg    int len = 0;
125805b261ecSmrg    xSyncSystemCounter *list = NULL, *walklist = NULL;
12594202a189Smrg
126005b261ecSmrg    REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
126105b261ecSmrg
1262f7df2e56Smrg    xorg_list_for_each_entry(psci, &SysCounterList, entry) {
1263f7df2e56Smrg        /* pad to 4 byte boundary */
1264f7df2e56Smrg        len += pad_to_int32(sz_xSyncSystemCounter + strlen(psci->name));
1265f7df2e56Smrg        ++rep.nCounters;
126605b261ecSmrg    }
126705b261ecSmrg
1268f7df2e56Smrg    if (len) {
1269f7df2e56Smrg        walklist = list = malloc(len);
1270f7df2e56Smrg        if (!list)
1271f7df2e56Smrg            return BadAlloc;
127205b261ecSmrg    }
127305b261ecSmrg
12744202a189Smrg    rep.length = bytes_to_int32(len);
127505b261ecSmrg
1276f7df2e56Smrg    if (client->swapped) {
1277f7df2e56Smrg        swaps(&rep.sequenceNumber);
1278f7df2e56Smrg        swapl(&rep.length);
1279f7df2e56Smrg        swapl(&rep.nCounters);
128005b261ecSmrg    }
128105b261ecSmrg
1282f7df2e56Smrg    xorg_list_for_each_entry(psci, &SysCounterList, entry) {
1283f7df2e56Smrg        int namelen;
1284f7df2e56Smrg        char *pname_in_reply;
128505b261ecSmrg
1286f7df2e56Smrg        walklist->counter = psci->pCounter->sync.id;
12877e31ba66Smrg        walklist->resolution_hi = psci->resolution >> 32;
12887e31ba66Smrg        walklist->resolution_lo = psci->resolution;
1289f7df2e56Smrg        namelen = strlen(psci->name);
1290f7df2e56Smrg        walklist->name_length = namelen;
129105b261ecSmrg
1292f7df2e56Smrg        if (client->swapped) {
1293f7df2e56Smrg            swapl(&walklist->counter);
1294f7df2e56Smrg            swapl(&walklist->resolution_hi);
1295f7df2e56Smrg            swapl(&walklist->resolution_lo);
1296f7df2e56Smrg            swaps(&walklist->name_length);
1297f7df2e56Smrg        }
129805b261ecSmrg
1299f7df2e56Smrg        pname_in_reply = ((char *) walklist) + sz_xSyncSystemCounter;
1300f7df2e56Smrg        strncpy(pname_in_reply, psci->name, namelen);
1301f7df2e56Smrg        walklist = (xSyncSystemCounter *) (((char *) walklist) +
1302f7df2e56Smrg                                           pad_to_int32(sz_xSyncSystemCounter +
1303f7df2e56Smrg                                                        namelen));
130405b261ecSmrg    }
130505b261ecSmrg
1306f7df2e56Smrg    WriteToClient(client, sizeof(rep), &rep);
1307f7df2e56Smrg    if (len) {
1308f7df2e56Smrg        WriteToClient(client, len, list);
1309f7df2e56Smrg        free(list);
131005b261ecSmrg    }
131105b261ecSmrg
13124202a189Smrg    return Success;
131305b261ecSmrg}
131405b261ecSmrg
131505b261ecSmrg/*
131605b261ecSmrg * ** Set client Priority
131705b261ecSmrg */
13184202a189Smrgstatic int
13194202a189SmrgProcSyncSetPriority(ClientPtr client)
132005b261ecSmrg{
132105b261ecSmrg    REQUEST(xSyncSetPriorityReq);
132205b261ecSmrg    ClientPtr priorityclient;
132305b261ecSmrg    int rc;
132405b261ecSmrg
132505b261ecSmrg    REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
132605b261ecSmrg
132705b261ecSmrg    if (stuff->id == None)
1328f7df2e56Smrg        priorityclient = client;
132905b261ecSmrg    else {
1330f7df2e56Smrg        rc = dixLookupClient(&priorityclient, stuff->id, client,
1331f7df2e56Smrg                             DixSetAttrAccess);
1332f7df2e56Smrg        if (rc != Success)
1333f7df2e56Smrg            return rc;
133405b261ecSmrg    }
133505b261ecSmrg
1336f7df2e56Smrg    if (priorityclient->priority != stuff->priority) {
1337f7df2e56Smrg        priorityclient->priority = stuff->priority;
133805b261ecSmrg
1339f7df2e56Smrg        /*  The following will force the server back into WaitForSomething
1340f7df2e56Smrg         *  so that the change in this client's priority is immediately
1341f7df2e56Smrg         *  reflected.
1342f7df2e56Smrg         */
1343f7df2e56Smrg        isItTimeToYield = TRUE;
1344f7df2e56Smrg        dispatchException |= DE_PRIORITYCHANGE;
134505b261ecSmrg    }
134605b261ecSmrg    return Success;
134705b261ecSmrg}
134805b261ecSmrg
134905b261ecSmrg/*
135005b261ecSmrg * ** Get client Priority
135105b261ecSmrg */
13524202a189Smrgstatic int
13534202a189SmrgProcSyncGetPriority(ClientPtr client)
135405b261ecSmrg{
135505b261ecSmrg    REQUEST(xSyncGetPriorityReq);
135605b261ecSmrg    xSyncGetPriorityReply rep;
135705b261ecSmrg    ClientPtr priorityclient;
135805b261ecSmrg    int rc;
135905b261ecSmrg
136005b261ecSmrg    REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
136105b261ecSmrg
136205b261ecSmrg    if (stuff->id == None)
1363f7df2e56Smrg        priorityclient = client;
136405b261ecSmrg    else {
1365f7df2e56Smrg        rc = dixLookupClient(&priorityclient, stuff->id, client,
1366f7df2e56Smrg                             DixGetAttrAccess);
1367f7df2e56Smrg        if (rc != Success)
1368f7df2e56Smrg            return rc;
136905b261ecSmrg    }
137005b261ecSmrg
1371f7df2e56Smrg    rep = (xSyncGetPriorityReply) {
1372f7df2e56Smrg        .type = X_Reply,
1373f7df2e56Smrg        .sequenceNumber = client->sequence,
1374f7df2e56Smrg        .length = 0,
1375f7df2e56Smrg        .priority = priorityclient->priority
1376f7df2e56Smrg    };
137705b261ecSmrg
1378f7df2e56Smrg    if (client->swapped) {
1379f7df2e56Smrg        swaps(&rep.sequenceNumber);
1380f7df2e56Smrg        swapl(&rep.priority);
138105b261ecSmrg    }
138205b261ecSmrg
1383f7df2e56Smrg    WriteToClient(client, sizeof(xSyncGetPriorityReply), &rep);
138405b261ecSmrg
13854202a189Smrg    return Success;
138605b261ecSmrg}
138705b261ecSmrg
138805b261ecSmrg/*
138905b261ecSmrg * ** Create a new counter
139005b261ecSmrg */
13914202a189Smrgstatic int
13924202a189SmrgProcSyncCreateCounter(ClientPtr client)
139305b261ecSmrg{
139405b261ecSmrg    REQUEST(xSyncCreateCounterReq);
13957e31ba66Smrg    int64_t initial;
139605b261ecSmrg
139705b261ecSmrg    REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
139805b261ecSmrg
139905b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->cid, client);
140005b261ecSmrg
14017e31ba66Smrg    initial = ((int64_t)stuff->initial_value_hi << 32) | stuff->initial_value_lo;
14027e31ba66Smrg
140305b261ecSmrg    if (!SyncCreateCounter(client, stuff->cid, initial))
1404f7df2e56Smrg        return BadAlloc;
140505b261ecSmrg
14064202a189Smrg    return Success;
140705b261ecSmrg}
140805b261ecSmrg
140905b261ecSmrg/*
141005b261ecSmrg * ** Set Counter value
141105b261ecSmrg */
14124202a189Smrgstatic int
14134202a189SmrgProcSyncSetCounter(ClientPtr client)
141405b261ecSmrg{
141505b261ecSmrg    REQUEST(xSyncSetCounterReq);
1416f7df2e56Smrg    SyncCounter *pCounter;
14177e31ba66Smrg    int64_t newvalue;
1418f7df2e56Smrg    int rc;
141905b261ecSmrg
142005b261ecSmrg    REQUEST_SIZE_MATCH(xSyncSetCounterReq);
142105b261ecSmrg
1422f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter,
1423f7df2e56Smrg                                 client, DixWriteAccess);
14244202a189Smrg    if (rc != Success)
1425f7df2e56Smrg        return rc;
142605b261ecSmrg
1427f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
1428f7df2e56Smrg        client->errorValue = stuff->cid;
1429f7df2e56Smrg        return BadAccess;
143005b261ecSmrg    }
143105b261ecSmrg
14327e31ba66Smrg    newvalue = ((int64_t)stuff->value_hi << 32) | stuff->value_lo;
143305b261ecSmrg    SyncChangeCounter(pCounter, newvalue);
143405b261ecSmrg    return Success;
143505b261ecSmrg}
143605b261ecSmrg
143705b261ecSmrg/*
143805b261ecSmrg * ** Change Counter value
143905b261ecSmrg */
14404202a189Smrgstatic int
14414202a189SmrgProcSyncChangeCounter(ClientPtr client)
144205b261ecSmrg{
144305b261ecSmrg    REQUEST(xSyncChangeCounterReq);
1444f7df2e56Smrg    SyncCounter *pCounter;
14457e31ba66Smrg    int64_t newvalue;
1446f7df2e56Smrg    Bool overflow;
1447f7df2e56Smrg    int rc;
144805b261ecSmrg
144905b261ecSmrg    REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
145005b261ecSmrg
1451f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter,
1452f7df2e56Smrg                                 client, DixWriteAccess);
14534202a189Smrg    if (rc != Success)
1454f7df2e56Smrg        return rc;
145505b261ecSmrg
1456f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
1457f7df2e56Smrg        client->errorValue = stuff->cid;
1458f7df2e56Smrg        return BadAccess;
145905b261ecSmrg    }
146005b261ecSmrg
14617e31ba66Smrg    newvalue = (int64_t)stuff->value_hi << 32 | stuff->value_lo;
14627e31ba66Smrg    overflow = checked_int64_add(&newvalue, newvalue, pCounter->value);
1463f7df2e56Smrg    if (overflow) {
1464f7df2e56Smrg        /* XXX 64 bit value can't fit in 32 bits; do the best we can */
1465f7df2e56Smrg        client->errorValue = stuff->value_hi;
1466f7df2e56Smrg        return BadValue;
146705b261ecSmrg    }
146805b261ecSmrg    SyncChangeCounter(pCounter, newvalue);
146905b261ecSmrg    return Success;
147005b261ecSmrg}
147105b261ecSmrg
147205b261ecSmrg/*
147305b261ecSmrg * ** Destroy a counter
147405b261ecSmrg */
14754202a189Smrgstatic int
14764202a189SmrgProcSyncDestroyCounter(ClientPtr client)
147705b261ecSmrg{
147805b261ecSmrg    REQUEST(xSyncDestroyCounterReq);
1479f7df2e56Smrg    SyncCounter *pCounter;
14804202a189Smrg    int rc;
148105b261ecSmrg
148205b261ecSmrg    REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
148305b261ecSmrg
1484f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pCounter, stuff->counter,
1485f7df2e56Smrg                                 RTCounter, client, DixDestroyAccess);
14864202a189Smrg    if (rc != Success)
1487f7df2e56Smrg        return rc;
14884202a189Smrg
1489f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
1490f7df2e56Smrg        client->errorValue = stuff->counter;
1491f7df2e56Smrg        return BadAccess;
149205b261ecSmrg    }
149365b04b38Smrg    FreeResource(pCounter->sync.id, RT_NONE);
149405b261ecSmrg    return Success;
149505b261ecSmrg}
149605b261ecSmrg
1497f7df2e56Smrgstatic SyncAwaitUnion *
149865b04b38SmrgSyncAwaitPrologue(ClientPtr client, int items)
149965b04b38Smrg{
150065b04b38Smrg    SyncAwaitUnion *pAwaitUnion;
150165b04b38Smrg
150265b04b38Smrg    /*  all the memory for the entire await list is allocated
150365b04b38Smrg     *  here in one chunk
150465b04b38Smrg     */
1505f7df2e56Smrg    pAwaitUnion = xallocarray(items + 1, sizeof(SyncAwaitUnion));
150665b04b38Smrg    if (!pAwaitUnion)
1507f7df2e56Smrg        return NULL;
150865b04b38Smrg
150965b04b38Smrg    /* first item is the header, remainder are real wait conditions */
151065b04b38Smrg
151165b04b38Smrg    pAwaitUnion->header.delete_id = FakeClientID(client->index);
151265b04b38Smrg    pAwaitUnion->header.client = client;
151365b04b38Smrg    pAwaitUnion->header.num_waitconditions = 0;
151465b04b38Smrg
151565b04b38Smrg    if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion))
1516f7df2e56Smrg        return NULL;
151765b04b38Smrg
151865b04b38Smrg    return pAwaitUnion;
151965b04b38Smrg}
152065b04b38Smrg
152165b04b38Smrgstatic void
1522f7df2e56SmrgSyncAwaitEpilogue(ClientPtr client, int items, SyncAwaitUnion * pAwaitUnion)
152365b04b38Smrg{
152465b04b38Smrg    SyncAwait *pAwait;
152565b04b38Smrg    int i;
152665b04b38Smrg
152765b04b38Smrg    IgnoreClient(client);
152865b04b38Smrg
152965b04b38Smrg    /* see if any of the triggers are already true */
153065b04b38Smrg
1531f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await; /* skip over header */
1532f7df2e56Smrg    for (i = 0; i < items; i++, pAwait++) {
15337e31ba66Smrg        int64_t value;
1534f7df2e56Smrg
1535f7df2e56Smrg        /*  don't have to worry about NULL counters because the request
1536f7df2e56Smrg         *  errors before we get here out if they occur
1537f7df2e56Smrg         */
1538f7df2e56Smrg        switch (pAwait->trigger.pSync->type) {
1539f7df2e56Smrg        case SYNC_COUNTER:
1540f7df2e56Smrg            value = ((SyncCounter *) pAwait->trigger.pSync)->value;
1541f7df2e56Smrg            break;
1542f7df2e56Smrg        default:
15437e31ba66Smrg            value = 0;
1544f7df2e56Smrg        }
154565b04b38Smrg
1546f7df2e56Smrg        if ((*pAwait->trigger.CheckTrigger) (&pAwait->trigger, value)) {
1547f7df2e56Smrg            (*pAwait->trigger.TriggerFired) (&pAwait->trigger);
1548f7df2e56Smrg            break;              /* once is enough */
1549f7df2e56Smrg        }
155065b04b38Smrg    }
155165b04b38Smrg}
155205b261ecSmrg
155305b261ecSmrg/*
155405b261ecSmrg * ** Await
155505b261ecSmrg */
15564202a189Smrgstatic int
15574202a189SmrgProcSyncAwait(ClientPtr client)
155805b261ecSmrg{
155905b261ecSmrg    REQUEST(xSyncAwaitReq);
1560f7df2e56Smrg    int len, items;
1561f7df2e56Smrg    int i;
156205b261ecSmrg    xSyncWaitCondition *pProtocolWaitConds;
156305b261ecSmrg    SyncAwaitUnion *pAwaitUnion;
1564f7df2e56Smrg    SyncAwait *pAwait;
1565f7df2e56Smrg    int status;
156605b261ecSmrg
156705b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
156805b261ecSmrg
156905b261ecSmrg    len = client->req_len << 2;
157005b261ecSmrg    len -= sz_xSyncAwaitReq;
157105b261ecSmrg    items = len / sz_xSyncWaitCondition;
157205b261ecSmrg
1573f7df2e56Smrg    if (items * sz_xSyncWaitCondition != len) {
1574f7df2e56Smrg        return BadLength;
157505b261ecSmrg    }
1576f7df2e56Smrg    if (items == 0) {
1577f7df2e56Smrg        client->errorValue = items;     /* XXX protocol change */
1578f7df2e56Smrg        return BadValue;
157905b261ecSmrg    }
158005b261ecSmrg
158165b04b38Smrg    if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
1582f7df2e56Smrg        return BadAlloc;
158305b261ecSmrg
158405b261ecSmrg    /* don't need to do any more memory allocation for this request! */
158505b261ecSmrg
1586f7df2e56Smrg    pProtocolWaitConds = (xSyncWaitCondition *) &stuff[1];
1587f7df2e56Smrg
1588f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await; /* skip over header */
1589f7df2e56Smrg    for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++) {
1590f7df2e56Smrg        if (pProtocolWaitConds->counter == None) {      /* XXX protocol change */
1591f7df2e56Smrg            /*  this should take care of removing any triggers created by
1592f7df2e56Smrg             *  this request that have already been registered on sync objects
1593f7df2e56Smrg             */
1594f7df2e56Smrg            FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
1595f7df2e56Smrg            client->errorValue = pProtocolWaitConds->counter;
1596f7df2e56Smrg            return SyncErrorBase + XSyncBadCounter;
1597f7df2e56Smrg        }
1598f7df2e56Smrg
1599f7df2e56Smrg        /* sanity checks are in SyncInitTrigger */
1600f7df2e56Smrg        pAwait->trigger.pSync = NULL;
1601f7df2e56Smrg        pAwait->trigger.value_type = pProtocolWaitConds->value_type;
16027e31ba66Smrg        pAwait->trigger.wait_value =
16037e31ba66Smrg            ((int64_t)pProtocolWaitConds->wait_value_hi << 32) |
16047e31ba66Smrg            pProtocolWaitConds->wait_value_lo;
1605f7df2e56Smrg        pAwait->trigger.test_type = pProtocolWaitConds->test_type;
1606f7df2e56Smrg
1607f7df2e56Smrg        status = SyncInitTrigger(client, &pAwait->trigger,
1608f7df2e56Smrg                                 pProtocolWaitConds->counter, RTCounter,
1609f7df2e56Smrg                                 XSyncCAAllTrigger);
1610f7df2e56Smrg        if (status != Success) {
1611f7df2e56Smrg            /*  this should take care of removing any triggers created by
1612f7df2e56Smrg             *  this request that have already been registered on sync objects
1613f7df2e56Smrg             */
1614f7df2e56Smrg            FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
1615f7df2e56Smrg            return status;
1616f7df2e56Smrg        }
1617f7df2e56Smrg        /* this is not a mistake -- same function works for both cases */
1618f7df2e56Smrg        pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
1619f7df2e56Smrg        pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
16207e31ba66Smrg        pAwait->event_threshold =
16217e31ba66Smrg            ((int64_t) pProtocolWaitConds->event_threshold_hi << 32) |
16227e31ba66Smrg            pProtocolWaitConds->event_threshold_lo;
16237e31ba66Smrg
1624f7df2e56Smrg        pAwait->pHeader = &pAwaitUnion->header;
1625f7df2e56Smrg        pAwaitUnion->header.num_waitconditions++;
162605b261ecSmrg    }
162705b261ecSmrg
162865b04b38Smrg    SyncAwaitEpilogue(client, items, pAwaitUnion);
162905b261ecSmrg
163005b261ecSmrg    return Success;
163105b261ecSmrg}
163205b261ecSmrg
163305b261ecSmrg/*
163405b261ecSmrg * ** Query a counter
163505b261ecSmrg */
16364202a189Smrgstatic int
16374202a189SmrgProcSyncQueryCounter(ClientPtr client)
163805b261ecSmrg{
163905b261ecSmrg    REQUEST(xSyncQueryCounterReq);
164005b261ecSmrg    xSyncQueryCounterReply rep;
1641f7df2e56Smrg    SyncCounter *pCounter;
16424202a189Smrg    int rc;
164305b261ecSmrg
164405b261ecSmrg    REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
164505b261ecSmrg
1646f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pCounter, stuff->counter,
1647f7df2e56Smrg                                 RTCounter, client, DixReadAccess);
16484202a189Smrg    if (rc != Success)
1649f7df2e56Smrg        return rc;
165005b261ecSmrg
165105b261ecSmrg    /* if system counter, ask it what the current value is */
1652f7df2e56Smrg    if (IsSystemCounter(pCounter)) {
1653f7df2e56Smrg        (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter,
1654f7df2e56Smrg                                                  &pCounter->value);
1655f7df2e56Smrg    }
1656f7df2e56Smrg
1657f7df2e56Smrg    rep = (xSyncQueryCounterReply) {
1658f7df2e56Smrg        .type = X_Reply,
1659f7df2e56Smrg        .sequenceNumber = client->sequence,
1660f7df2e56Smrg        .length = 0,
16617e31ba66Smrg        .value_hi = pCounter->value >> 32,
16627e31ba66Smrg        .value_lo = pCounter->value
1663f7df2e56Smrg    };
1664f7df2e56Smrg
1665f7df2e56Smrg    if (client->swapped) {
1666f7df2e56Smrg        swaps(&rep.sequenceNumber);
1667f7df2e56Smrg        swapl(&rep.length);
1668f7df2e56Smrg        swapl(&rep.value_hi);
1669f7df2e56Smrg        swapl(&rep.value_lo);
1670f7df2e56Smrg    }
1671f7df2e56Smrg    WriteToClient(client, sizeof(xSyncQueryCounterReply), &rep);
16724202a189Smrg    return Success;
167305b261ecSmrg}
167405b261ecSmrg
167505b261ecSmrg/*
167605b261ecSmrg * ** Create Alarm
167705b261ecSmrg */
16784202a189Smrgstatic int
16794202a189SmrgProcSyncCreateAlarm(ClientPtr client)
168005b261ecSmrg{
168105b261ecSmrg    REQUEST(xSyncCreateAlarmReq);
1682f7df2e56Smrg    SyncAlarm *pAlarm;
1683f7df2e56Smrg    int status;
1684f7df2e56Smrg    unsigned long len, vmask;
1685f7df2e56Smrg    SyncTrigger *pTrigger;
168605b261ecSmrg
168705b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
168805b261ecSmrg
168905b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->id, client);
169005b261ecSmrg
169105b261ecSmrg    vmask = stuff->valueMask;
16924202a189Smrg    len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq));
169305b261ecSmrg    /* the "extra" call to Ones accounts for the presence of 64 bit values */
1694f7df2e56Smrg    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta))))
1695f7df2e56Smrg        return BadLength;
169605b261ecSmrg
1697f7df2e56Smrg    if (!(pAlarm = malloc(sizeof(SyncAlarm)))) {
1698f7df2e56Smrg        return BadAlloc;
169905b261ecSmrg    }
170005b261ecSmrg
170105b261ecSmrg    /* set up defaults */
170205b261ecSmrg
170305b261ecSmrg    pTrigger = &pAlarm->trigger;
170465b04b38Smrg    pTrigger->pSync = NULL;
170505b261ecSmrg    pTrigger->value_type = XSyncAbsolute;
17067e31ba66Smrg    pTrigger->wait_value = 0;
170705b261ecSmrg    pTrigger->test_type = XSyncPositiveComparison;
170805b261ecSmrg    pTrigger->TriggerFired = SyncAlarmTriggerFired;
170905b261ecSmrg    pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed;
171065b04b38Smrg    status = SyncInitTrigger(client, pTrigger, None, RTCounter,
1711f7df2e56Smrg                             XSyncCAAllTrigger);
1712f7df2e56Smrg    if (status != Success) {
1713f7df2e56Smrg        free(pAlarm);
1714f7df2e56Smrg        return status;
171505b261ecSmrg    }
171605b261ecSmrg
171705b261ecSmrg    pAlarm->client = client;
171805b261ecSmrg    pAlarm->alarm_id = stuff->id;
17197e31ba66Smrg    pAlarm->delta = 1;
172005b261ecSmrg    pAlarm->events = TRUE;
172105b261ecSmrg    pAlarm->state = XSyncAlarmInactive;
172205b261ecSmrg    pAlarm->pEventClients = NULL;
172305b261ecSmrg    status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
1724f7df2e56Smrg                                       (CARD32 *) &stuff[1]);
1725f7df2e56Smrg    if (status != Success) {
1726f7df2e56Smrg        free(pAlarm);
1727f7df2e56Smrg        return status;
172805b261ecSmrg    }
172905b261ecSmrg
173005b261ecSmrg    if (!AddResource(stuff->id, RTAlarm, pAlarm))
1731f7df2e56Smrg        return BadAlloc;
173205b261ecSmrg
173305b261ecSmrg    /*  see if alarm already triggered.  NULL counter will not trigger
173405b261ecSmrg     *  in CreateAlarm and sets alarm state to Inactive.
173505b261ecSmrg     */
173605b261ecSmrg
1737f7df2e56Smrg    if (!pTrigger->pSync) {
1738f7df2e56Smrg        pAlarm->state = XSyncAlarmInactive;     /* XXX protocol change */
173905b261ecSmrg    }
1740f7df2e56Smrg    else {
1741f7df2e56Smrg        SyncCounter *pCounter;
174265b04b38Smrg
1743f7df2e56Smrg        if (!SyncCheckWarnIsCounter(pTrigger->pSync,
1744f7df2e56Smrg                                    WARN_INVALID_COUNTER_ALARM)) {
1745f7df2e56Smrg            FreeResource(stuff->id, RT_NONE);
1746f7df2e56Smrg            return BadAlloc;
1747f7df2e56Smrg        }
174865b04b38Smrg
1749f7df2e56Smrg        pCounter = (SyncCounter *) pTrigger->pSync;
175065b04b38Smrg
1751f7df2e56Smrg        if ((*pTrigger->CheckTrigger) (pTrigger, pCounter->value))
1752f7df2e56Smrg            (*pTrigger->TriggerFired) (pTrigger);
175305b261ecSmrg    }
175405b261ecSmrg
175505b261ecSmrg    return Success;
175605b261ecSmrg}
175705b261ecSmrg
175805b261ecSmrg/*
175905b261ecSmrg * ** Change Alarm
176005b261ecSmrg */
17614202a189Smrgstatic int
17624202a189SmrgProcSyncChangeAlarm(ClientPtr client)
176305b261ecSmrg{
176405b261ecSmrg    REQUEST(xSyncChangeAlarmReq);
1765f7df2e56Smrg    SyncAlarm *pAlarm;
176665b04b38Smrg    SyncCounter *pCounter = NULL;
1767f7df2e56Smrg    long vmask;
1768f7df2e56Smrg    int len, status;
176905b261ecSmrg
177005b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
177105b261ecSmrg
1772f7df2e56Smrg    status = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm,
1773f7df2e56Smrg                                     client, DixWriteAccess);
17744202a189Smrg    if (status != Success)
1775f7df2e56Smrg        return status;
177605b261ecSmrg
177705b261ecSmrg    vmask = stuff->valueMask;
17784202a189Smrg    len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq));
177905b261ecSmrg    /* the "extra" call to Ones accounts for the presence of 64 bit values */
1780f7df2e56Smrg    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta))))
1781f7df2e56Smrg        return BadLength;
178205b261ecSmrg
17834202a189Smrg    if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
1784f7df2e56Smrg                                            (CARD32 *) &stuff[1])) != Success)
1785f7df2e56Smrg        return status;
178605b261ecSmrg
178765b04b38Smrg    if (SyncCheckWarnIsCounter(pAlarm->trigger.pSync,
1788f7df2e56Smrg                               WARN_INVALID_COUNTER_ALARM))
1789f7df2e56Smrg        pCounter = (SyncCounter *) pAlarm->trigger.pSync;
179065b04b38Smrg
179105b261ecSmrg    /*  see if alarm already triggered.  NULL counter WILL trigger
179205b261ecSmrg     *  in ChangeAlarm.
179305b261ecSmrg     */
179405b261ecSmrg
179565b04b38Smrg    if (!pCounter ||
1796f7df2e56Smrg        (*pAlarm->trigger.CheckTrigger) (&pAlarm->trigger, pCounter->value)) {
1797f7df2e56Smrg        (*pAlarm->trigger.TriggerFired) (&pAlarm->trigger);
179805b261ecSmrg    }
179905b261ecSmrg    return Success;
180005b261ecSmrg}
180105b261ecSmrg
18024202a189Smrgstatic int
18034202a189SmrgProcSyncQueryAlarm(ClientPtr client)
180405b261ecSmrg{
180505b261ecSmrg    REQUEST(xSyncQueryAlarmReq);
1806f7df2e56Smrg    SyncAlarm *pAlarm;
180705b261ecSmrg    xSyncQueryAlarmReply rep;
1808f7df2e56Smrg    SyncTrigger *pTrigger;
18094202a189Smrg    int rc;
181005b261ecSmrg
181105b261ecSmrg    REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
181205b261ecSmrg
1813f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm,
1814f7df2e56Smrg                                 client, DixReadAccess);
18154202a189Smrg    if (rc != Success)
1816f7df2e56Smrg        return rc;
181705b261ecSmrg
181805b261ecSmrg    pTrigger = &pAlarm->trigger;
1819f7df2e56Smrg    rep = (xSyncQueryAlarmReply) {
1820f7df2e56Smrg        .type = X_Reply,
1821f7df2e56Smrg        .sequenceNumber = client->sequence,
1822f7df2e56Smrg        .length =
1823f7df2e56Smrg          bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply)),
1824f7df2e56Smrg        .counter = (pTrigger->pSync) ? pTrigger->pSync->id : None,
1825f7df2e56Smrg
1826f7df2e56Smrg#if 0  /* XXX unclear what to do, depends on whether relative value-types
1827f7df2e56Smrg        * are "consumed" immediately and are considered absolute from then
1828f7df2e56Smrg        * on.
1829f7df2e56Smrg        */
1830f7df2e56Smrg        .value_type = pTrigger->value_type,
18317e31ba66Smrg        .wait_value_hi = pTrigger->wait_value >> 32,
18327e31ba66Smrg        .wait_value_lo = pTrigger->wait_value,
183305b261ecSmrg#else
1834f7df2e56Smrg        .value_type = XSyncAbsolute,
18357e31ba66Smrg        .wait_value_hi = pTrigger->test_value >> 32,
18367e31ba66Smrg        .wait_value_lo = pTrigger->test_value,
183705b261ecSmrg#endif
183805b261ecSmrg
1839f7df2e56Smrg        .test_type = pTrigger->test_type,
18407e31ba66Smrg        .delta_hi = pAlarm->delta >> 32,
18417e31ba66Smrg        .delta_lo = pAlarm->delta,
1842f7df2e56Smrg        .events = pAlarm->events,
1843f7df2e56Smrg        .state = pAlarm->state
1844f7df2e56Smrg    };
1845f7df2e56Smrg
1846f7df2e56Smrg    if (client->swapped) {
1847f7df2e56Smrg        swaps(&rep.sequenceNumber);
1848f7df2e56Smrg        swapl(&rep.length);
1849f7df2e56Smrg        swapl(&rep.counter);
1850f7df2e56Smrg        swapl(&rep.wait_value_hi);
1851f7df2e56Smrg        swapl(&rep.wait_value_lo);
1852f7df2e56Smrg        swapl(&rep.test_type);
1853f7df2e56Smrg        swapl(&rep.delta_hi);
1854f7df2e56Smrg        swapl(&rep.delta_lo);
1855f7df2e56Smrg    }
1856f7df2e56Smrg
1857f7df2e56Smrg    WriteToClient(client, sizeof(xSyncQueryAlarmReply), &rep);
18584202a189Smrg    return Success;
185905b261ecSmrg}
186005b261ecSmrg
18614202a189Smrgstatic int
18624202a189SmrgProcSyncDestroyAlarm(ClientPtr client)
186305b261ecSmrg{
18644202a189Smrg    SyncAlarm *pAlarm;
18654202a189Smrg    int rc;
1866f7df2e56Smrg
186705b261ecSmrg    REQUEST(xSyncDestroyAlarmReq);
186805b261ecSmrg
186905b261ecSmrg    REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
187005b261ecSmrg
1871f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm,
1872f7df2e56Smrg                                 client, DixDestroyAccess);
18734202a189Smrg    if (rc != Success)
1874f7df2e56Smrg        return rc;
187505b261ecSmrg
187605b261ecSmrg    FreeResource(stuff->alarm, RT_NONE);
18774202a189Smrg    return Success;
187805b261ecSmrg}
187905b261ecSmrg
188065b04b38Smrgstatic int
188165b04b38SmrgProcSyncCreateFence(ClientPtr client)
188265b04b38Smrg{
188365b04b38Smrg    REQUEST(xSyncCreateFenceReq);
188465b04b38Smrg    DrawablePtr pDraw;
188565b04b38Smrg    SyncFence *pFence;
188665b04b38Smrg    int rc;
188765b04b38Smrg
188865b04b38Smrg    REQUEST_SIZE_MATCH(xSyncCreateFenceReq);
188965b04b38Smrg
189065b04b38Smrg    rc = dixLookupDrawable(&pDraw, stuff->d, client, M_ANY, DixGetAttrAccess);
189165b04b38Smrg    if (rc != Success)
1892f7df2e56Smrg        return rc;
189365b04b38Smrg
189465b04b38Smrg    LEGAL_NEW_RESOURCE(stuff->fid, client);
189565b04b38Smrg
1896f7df2e56Smrg    if (!(pFence = (SyncFence *) SyncCreate(client, stuff->fid, SYNC_FENCE)))
1897f7df2e56Smrg        return BadAlloc;
189865b04b38Smrg
189965b04b38Smrg    miSyncInitFence(pDraw->pScreen, pFence, stuff->initially_triggered);
190065b04b38Smrg
19017e31ba66Smrg    return Success;
190265b04b38Smrg}
190365b04b38Smrg
190465b04b38Smrgstatic int
190565b04b38SmrgFreeFence(void *obj, XID id)
190665b04b38Smrg{
190765b04b38Smrg    SyncFence *pFence = (SyncFence *) obj;
190865b04b38Smrg
190965b04b38Smrg    miSyncDestroyFence(pFence);
191065b04b38Smrg
191165b04b38Smrg    return Success;
191265b04b38Smrg}
191365b04b38Smrg
1914f7df2e56Smrgint
1915f7df2e56SmrgSyncVerifyFence(SyncFence ** ppSyncFence, XID fid, ClientPtr client, Mask mode)
191665b04b38Smrg{
1917f7df2e56Smrg    int rc = dixLookupResourceByType((void **) ppSyncFence, fid, RTFence,
1918f7df2e56Smrg                                     client, mode);
191965b04b38Smrg
192065b04b38Smrg    if (rc != Success)
1921f7df2e56Smrg        client->errorValue = fid;
192265b04b38Smrg
192365b04b38Smrg    return rc;
192465b04b38Smrg}
192565b04b38Smrg
192665b04b38Smrgstatic int
192765b04b38SmrgProcSyncTriggerFence(ClientPtr client)
192865b04b38Smrg{
192965b04b38Smrg    REQUEST(xSyncTriggerFenceReq);
193065b04b38Smrg    SyncFence *pFence;
193165b04b38Smrg    int rc;
193265b04b38Smrg
193365b04b38Smrg    REQUEST_SIZE_MATCH(xSyncTriggerFenceReq);
193465b04b38Smrg
1935f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence,
1936f7df2e56Smrg                                 client, DixWriteAccess);
193765b04b38Smrg    if (rc != Success)
1938f7df2e56Smrg        return rc;
193965b04b38Smrg
194065b04b38Smrg    miSyncTriggerFence(pFence);
194165b04b38Smrg
19427e31ba66Smrg    return Success;
194365b04b38Smrg}
194465b04b38Smrg
194565b04b38Smrgstatic int
194665b04b38SmrgProcSyncResetFence(ClientPtr client)
194765b04b38Smrg{
194865b04b38Smrg    REQUEST(xSyncResetFenceReq);
194965b04b38Smrg    SyncFence *pFence;
195065b04b38Smrg    int rc;
195165b04b38Smrg
195265b04b38Smrg    REQUEST_SIZE_MATCH(xSyncResetFenceReq);
195365b04b38Smrg
1954f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence,
1955f7df2e56Smrg                                 client, DixWriteAccess);
195665b04b38Smrg    if (rc != Success)
1957f7df2e56Smrg        return rc;
195865b04b38Smrg
195965b04b38Smrg    if (pFence->funcs.CheckTriggered(pFence) != TRUE)
1960f7df2e56Smrg        return BadMatch;
196165b04b38Smrg
196265b04b38Smrg    pFence->funcs.Reset(pFence);
196365b04b38Smrg
19647e31ba66Smrg    return Success;
196565b04b38Smrg}
196665b04b38Smrg
196765b04b38Smrgstatic int
196865b04b38SmrgProcSyncDestroyFence(ClientPtr client)
196965b04b38Smrg{
197065b04b38Smrg    REQUEST(xSyncDestroyFenceReq);
197165b04b38Smrg    SyncFence *pFence;
197265b04b38Smrg    int rc;
197365b04b38Smrg
197465b04b38Smrg    REQUEST_SIZE_MATCH(xSyncDestroyFenceReq);
197565b04b38Smrg
1976f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence,
1977f7df2e56Smrg                                 client, DixDestroyAccess);
197865b04b38Smrg    if (rc != Success)
1979f7df2e56Smrg        return rc;
198065b04b38Smrg
198165b04b38Smrg    FreeResource(stuff->fid, RT_NONE);
19827e31ba66Smrg    return Success;
198365b04b38Smrg}
198465b04b38Smrg
198565b04b38Smrgstatic int
198665b04b38SmrgProcSyncQueryFence(ClientPtr client)
198765b04b38Smrg{
198865b04b38Smrg    REQUEST(xSyncQueryFenceReq);
198965b04b38Smrg    xSyncQueryFenceReply rep;
199065b04b38Smrg    SyncFence *pFence;
199165b04b38Smrg    int rc;
199265b04b38Smrg
199365b04b38Smrg    REQUEST_SIZE_MATCH(xSyncQueryFenceReq);
199465b04b38Smrg
1995f7df2e56Smrg    rc = dixLookupResourceByType((void **) &pFence, stuff->fid,
1996f7df2e56Smrg                                 RTFence, client, DixReadAccess);
199765b04b38Smrg    if (rc != Success)
1998f7df2e56Smrg        return rc;
199965b04b38Smrg
2000f7df2e56Smrg    rep = (xSyncQueryFenceReply) {
2001f7df2e56Smrg        .type = X_Reply,
2002f7df2e56Smrg        .sequenceNumber = client->sequence,
2003f7df2e56Smrg        .length = 0,
200465b04b38Smrg
2005f7df2e56Smrg        .triggered = pFence->funcs.CheckTriggered(pFence)
2006f7df2e56Smrg    };
200765b04b38Smrg
2008f7df2e56Smrg    if (client->swapped) {
2009f7df2e56Smrg        swaps(&rep.sequenceNumber);
2010f7df2e56Smrg        swapl(&rep.length);
201165b04b38Smrg    }
201265b04b38Smrg
2013f7df2e56Smrg    WriteToClient(client, sizeof(xSyncQueryFenceReply), &rep);
20147e31ba66Smrg    return Success;
201565b04b38Smrg}
201665b04b38Smrg
201765b04b38Smrgstatic int
201865b04b38SmrgProcSyncAwaitFence(ClientPtr client)
201965b04b38Smrg{
202065b04b38Smrg    REQUEST(xSyncAwaitFenceReq);
202165b04b38Smrg    SyncAwaitUnion *pAwaitUnion;
202265b04b38Smrg    SyncAwait *pAwait;
2023f7df2e56Smrg
202465b04b38Smrg    /* Use CARD32 rather than XSyncFence because XIDs are hard-coded to
202565b04b38Smrg     * CARD32 in protocol definitions */
202665b04b38Smrg    CARD32 *pProtocolFences;
202765b04b38Smrg    int status;
202865b04b38Smrg    int len;
202965b04b38Smrg    int items;
203065b04b38Smrg    int i;
203165b04b38Smrg
203265b04b38Smrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
203365b04b38Smrg
203465b04b38Smrg    len = client->req_len << 2;
203565b04b38Smrg    len -= sz_xSyncAwaitFenceReq;
203665b04b38Smrg    items = len / sizeof(CARD32);
203765b04b38Smrg
2038f7df2e56Smrg    if (items * sizeof(CARD32) != len) {
2039f7df2e56Smrg        return BadLength;
204065b04b38Smrg    }
2041f7df2e56Smrg    if (items == 0) {
2042f7df2e56Smrg        client->errorValue = items;
2043f7df2e56Smrg        return BadValue;
204465b04b38Smrg    }
204565b04b38Smrg
204665b04b38Smrg    if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
2047f7df2e56Smrg        return BadAlloc;
204865b04b38Smrg
204965b04b38Smrg    /* don't need to do any more memory allocation for this request! */
205065b04b38Smrg
2051f7df2e56Smrg    pProtocolFences = (CARD32 *) &stuff[1];
2052f7df2e56Smrg
2053f7df2e56Smrg    pAwait = &(pAwaitUnion + 1)->await; /* skip over header */
2054f7df2e56Smrg    for (i = 0; i < items; i++, pProtocolFences++, pAwait++) {
2055f7df2e56Smrg        if (*pProtocolFences == None) {
2056f7df2e56Smrg            /*  this should take care of removing any triggers created by
2057f7df2e56Smrg             *  this request that have already been registered on sync objects
2058f7df2e56Smrg             */
2059f7df2e56Smrg            FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
2060f7df2e56Smrg            client->errorValue = *pProtocolFences;
2061f7df2e56Smrg            return SyncErrorBase + XSyncBadFence;
2062f7df2e56Smrg        }
2063f7df2e56Smrg
2064f7df2e56Smrg        pAwait->trigger.pSync = NULL;
2065f7df2e56Smrg        /* Provide acceptable values for these unused fields to
2066f7df2e56Smrg         * satisfy SyncInitTrigger's validation logic
2067f7df2e56Smrg         */
2068f7df2e56Smrg        pAwait->trigger.value_type = XSyncAbsolute;
20697e31ba66Smrg        pAwait->trigger.wait_value = 0;
2070f7df2e56Smrg        pAwait->trigger.test_type = 0;
2071f7df2e56Smrg
2072f7df2e56Smrg        status = SyncInitTrigger(client, &pAwait->trigger,
2073f7df2e56Smrg                                 *pProtocolFences, RTFence, XSyncCAAllTrigger);
2074f7df2e56Smrg        if (status != Success) {
2075f7df2e56Smrg            /*  this should take care of removing any triggers created by
2076f7df2e56Smrg             *  this request that have already been registered on sync objects
2077f7df2e56Smrg             */
2078f7df2e56Smrg            FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
2079f7df2e56Smrg            return status;
2080f7df2e56Smrg        }
2081f7df2e56Smrg        /* this is not a mistake -- same function works for both cases */
2082f7df2e56Smrg        pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
2083f7df2e56Smrg        pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
2084f7df2e56Smrg        /* event_threshold is unused for fence syncs */
20857e31ba66Smrg        pAwait->event_threshold = 0;
2086f7df2e56Smrg        pAwait->pHeader = &pAwaitUnion->header;
2087f7df2e56Smrg        pAwaitUnion->header.num_waitconditions++;
208865b04b38Smrg    }
208965b04b38Smrg
209065b04b38Smrg    SyncAwaitEpilogue(client, items, pAwaitUnion);
209165b04b38Smrg
20927e31ba66Smrg    return Success;
209365b04b38Smrg}
209465b04b38Smrg
209505b261ecSmrg/*
209605b261ecSmrg * ** Given an extension request, call the appropriate request procedure
209705b261ecSmrg */
20984202a189Smrgstatic int
20994202a189SmrgProcSyncDispatch(ClientPtr client)
210005b261ecSmrg{
210105b261ecSmrg    REQUEST(xReq);
210205b261ecSmrg
2103f7df2e56Smrg    switch (stuff->data) {
2104f7df2e56Smrg    case X_SyncInitialize:
2105f7df2e56Smrg        return ProcSyncInitialize(client);
2106f7df2e56Smrg    case X_SyncListSystemCounters:
2107f7df2e56Smrg        return ProcSyncListSystemCounters(client);
2108f7df2e56Smrg    case X_SyncCreateCounter:
2109f7df2e56Smrg        return ProcSyncCreateCounter(client);
2110f7df2e56Smrg    case X_SyncSetCounter:
2111f7df2e56Smrg        return ProcSyncSetCounter(client);
2112f7df2e56Smrg    case X_SyncChangeCounter:
2113f7df2e56Smrg        return ProcSyncChangeCounter(client);
2114f7df2e56Smrg    case X_SyncQueryCounter:
2115f7df2e56Smrg        return ProcSyncQueryCounter(client);
2116f7df2e56Smrg    case X_SyncDestroyCounter:
2117f7df2e56Smrg        return ProcSyncDestroyCounter(client);
2118f7df2e56Smrg    case X_SyncAwait:
2119f7df2e56Smrg        return ProcSyncAwait(client);
2120f7df2e56Smrg    case X_SyncCreateAlarm:
2121f7df2e56Smrg        return ProcSyncCreateAlarm(client);
2122f7df2e56Smrg    case X_SyncChangeAlarm:
2123f7df2e56Smrg        return ProcSyncChangeAlarm(client);
2124f7df2e56Smrg    case X_SyncQueryAlarm:
2125f7df2e56Smrg        return ProcSyncQueryAlarm(client);
2126f7df2e56Smrg    case X_SyncDestroyAlarm:
2127f7df2e56Smrg        return ProcSyncDestroyAlarm(client);
2128f7df2e56Smrg    case X_SyncSetPriority:
2129f7df2e56Smrg        return ProcSyncSetPriority(client);
2130f7df2e56Smrg    case X_SyncGetPriority:
2131f7df2e56Smrg        return ProcSyncGetPriority(client);
2132f7df2e56Smrg    case X_SyncCreateFence:
2133f7df2e56Smrg        return ProcSyncCreateFence(client);
2134f7df2e56Smrg    case X_SyncTriggerFence:
2135f7df2e56Smrg        return ProcSyncTriggerFence(client);
2136f7df2e56Smrg    case X_SyncResetFence:
2137f7df2e56Smrg        return ProcSyncResetFence(client);
2138f7df2e56Smrg    case X_SyncDestroyFence:
2139f7df2e56Smrg        return ProcSyncDestroyFence(client);
2140f7df2e56Smrg    case X_SyncQueryFence:
2141f7df2e56Smrg        return ProcSyncQueryFence(client);
2142f7df2e56Smrg    case X_SyncAwaitFence:
2143f7df2e56Smrg        return ProcSyncAwaitFence(client);
2144f7df2e56Smrg    default:
2145f7df2e56Smrg        return BadRequest;
214605b261ecSmrg    }
214705b261ecSmrg}
214805b261ecSmrg
214905b261ecSmrg/*
215005b261ecSmrg * Boring Swapping stuff ...
215105b261ecSmrg */
215205b261ecSmrg
21537e31ba66Smrgstatic int _X_COLD
21544202a189SmrgSProcSyncInitialize(ClientPtr client)
215505b261ecSmrg{
215605b261ecSmrg    REQUEST(xSyncInitializeReq);
2157f7df2e56Smrg    swaps(&stuff->length);
2158f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncInitializeReq);
215905b261ecSmrg
216005b261ecSmrg    return ProcSyncInitialize(client);
216105b261ecSmrg}
216205b261ecSmrg
21637e31ba66Smrgstatic int _X_COLD
21644202a189SmrgSProcSyncListSystemCounters(ClientPtr client)
216505b261ecSmrg{
216605b261ecSmrg    REQUEST(xSyncListSystemCountersReq);
2167f7df2e56Smrg    swaps(&stuff->length);
2168f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
216905b261ecSmrg
217005b261ecSmrg    return ProcSyncListSystemCounters(client);
217105b261ecSmrg}
217205b261ecSmrg
21737e31ba66Smrgstatic int _X_COLD
21744202a189SmrgSProcSyncCreateCounter(ClientPtr client)
217505b261ecSmrg{
217605b261ecSmrg    REQUEST(xSyncCreateCounterReq);
2177f7df2e56Smrg    swaps(&stuff->length);
2178f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
2179f7df2e56Smrg    swapl(&stuff->cid);
2180f7df2e56Smrg    swapl(&stuff->initial_value_lo);
2181f7df2e56Smrg    swapl(&stuff->initial_value_hi);
218205b261ecSmrg
218305b261ecSmrg    return ProcSyncCreateCounter(client);
218405b261ecSmrg}
218505b261ecSmrg
21867e31ba66Smrgstatic int _X_COLD
21874202a189SmrgSProcSyncSetCounter(ClientPtr client)
218805b261ecSmrg{
218905b261ecSmrg    REQUEST(xSyncSetCounterReq);
2190f7df2e56Smrg    swaps(&stuff->length);
2191f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncSetCounterReq);
2192f7df2e56Smrg    swapl(&stuff->cid);
2193f7df2e56Smrg    swapl(&stuff->value_lo);
2194f7df2e56Smrg    swapl(&stuff->value_hi);
219505b261ecSmrg
219605b261ecSmrg    return ProcSyncSetCounter(client);
219705b261ecSmrg}
219805b261ecSmrg
21997e31ba66Smrgstatic int _X_COLD
22004202a189SmrgSProcSyncChangeCounter(ClientPtr client)
220105b261ecSmrg{
220205b261ecSmrg    REQUEST(xSyncChangeCounterReq);
2203f7df2e56Smrg    swaps(&stuff->length);
2204f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
2205f7df2e56Smrg    swapl(&stuff->cid);
2206f7df2e56Smrg    swapl(&stuff->value_lo);
2207f7df2e56Smrg    swapl(&stuff->value_hi);
220805b261ecSmrg
220905b261ecSmrg    return ProcSyncChangeCounter(client);
221005b261ecSmrg}
221105b261ecSmrg
22127e31ba66Smrgstatic int _X_COLD
22134202a189SmrgSProcSyncQueryCounter(ClientPtr client)
221405b261ecSmrg{
221505b261ecSmrg    REQUEST(xSyncQueryCounterReq);
2216f7df2e56Smrg    swaps(&stuff->length);
2217f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
2218f7df2e56Smrg    swapl(&stuff->counter);
221905b261ecSmrg
222005b261ecSmrg    return ProcSyncQueryCounter(client);
222105b261ecSmrg}
222205b261ecSmrg
22237e31ba66Smrgstatic int _X_COLD
22244202a189SmrgSProcSyncDestroyCounter(ClientPtr client)
222505b261ecSmrg{
222605b261ecSmrg    REQUEST(xSyncDestroyCounterReq);
2227f7df2e56Smrg    swaps(&stuff->length);
2228f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
2229f7df2e56Smrg    swapl(&stuff->counter);
223005b261ecSmrg
223105b261ecSmrg    return ProcSyncDestroyCounter(client);
223205b261ecSmrg}
223305b261ecSmrg
22347e31ba66Smrgstatic int _X_COLD
22354202a189SmrgSProcSyncAwait(ClientPtr client)
223605b261ecSmrg{
223705b261ecSmrg    REQUEST(xSyncAwaitReq);
2238f7df2e56Smrg    swaps(&stuff->length);
223905b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
224005b261ecSmrg    SwapRestL(stuff);
224105b261ecSmrg
224205b261ecSmrg    return ProcSyncAwait(client);
224305b261ecSmrg}
224405b261ecSmrg
22457e31ba66Smrgstatic int _X_COLD
22464202a189SmrgSProcSyncCreateAlarm(ClientPtr client)
224705b261ecSmrg{
224805b261ecSmrg    REQUEST(xSyncCreateAlarmReq);
2249f7df2e56Smrg    swaps(&stuff->length);
225005b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
2251f7df2e56Smrg    swapl(&stuff->id);
2252f7df2e56Smrg    swapl(&stuff->valueMask);
225305b261ecSmrg    SwapRestL(stuff);
225405b261ecSmrg
225505b261ecSmrg    return ProcSyncCreateAlarm(client);
225605b261ecSmrg}
225705b261ecSmrg
22587e31ba66Smrgstatic int _X_COLD
22594202a189SmrgSProcSyncChangeAlarm(ClientPtr client)
226005b261ecSmrg{
226105b261ecSmrg    REQUEST(xSyncChangeAlarmReq);
2262f7df2e56Smrg    swaps(&stuff->length);
226305b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
2264f7df2e56Smrg    swapl(&stuff->alarm);
2265f7df2e56Smrg    swapl(&stuff->valueMask);
226605b261ecSmrg    SwapRestL(stuff);
226705b261ecSmrg    return ProcSyncChangeAlarm(client);
226805b261ecSmrg}
226905b261ecSmrg
22707e31ba66Smrgstatic int _X_COLD
22714202a189SmrgSProcSyncQueryAlarm(ClientPtr client)
227205b261ecSmrg{
227305b261ecSmrg    REQUEST(xSyncQueryAlarmReq);
2274f7df2e56Smrg    swaps(&stuff->length);
2275f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
2276f7df2e56Smrg    swapl(&stuff->alarm);
227705b261ecSmrg
227805b261ecSmrg    return ProcSyncQueryAlarm(client);
227905b261ecSmrg}
228005b261ecSmrg
22817e31ba66Smrgstatic int _X_COLD
22824202a189SmrgSProcSyncDestroyAlarm(ClientPtr client)
228305b261ecSmrg{
228405b261ecSmrg    REQUEST(xSyncDestroyAlarmReq);
2285f7df2e56Smrg    swaps(&stuff->length);
2286f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
2287f7df2e56Smrg    swapl(&stuff->alarm);
228805b261ecSmrg
228905b261ecSmrg    return ProcSyncDestroyAlarm(client);
229005b261ecSmrg}
229105b261ecSmrg
22927e31ba66Smrgstatic int _X_COLD
22934202a189SmrgSProcSyncSetPriority(ClientPtr client)
229405b261ecSmrg{
229505b261ecSmrg    REQUEST(xSyncSetPriorityReq);
2296f7df2e56Smrg    swaps(&stuff->length);
2297f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
2298f7df2e56Smrg    swapl(&stuff->id);
2299f7df2e56Smrg    swapl(&stuff->priority);
230005b261ecSmrg
230105b261ecSmrg    return ProcSyncSetPriority(client);
230205b261ecSmrg}
230305b261ecSmrg
23047e31ba66Smrgstatic int _X_COLD
23054202a189SmrgSProcSyncGetPriority(ClientPtr client)
230605b261ecSmrg{
230705b261ecSmrg    REQUEST(xSyncGetPriorityReq);
2308f7df2e56Smrg    swaps(&stuff->length);
2309f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
2310f7df2e56Smrg    swapl(&stuff->id);
231105b261ecSmrg
231205b261ecSmrg    return ProcSyncGetPriority(client);
231305b261ecSmrg}
231405b261ecSmrg
23157e31ba66Smrgstatic int _X_COLD
231665b04b38SmrgSProcSyncCreateFence(ClientPtr client)
231765b04b38Smrg{
231865b04b38Smrg    REQUEST(xSyncCreateFenceReq);
2319f7df2e56Smrg    swaps(&stuff->length);
2320f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncCreateFenceReq);
2321875c6e4fSmrg    swapl(&stuff->d);
2322f7df2e56Smrg    swapl(&stuff->fid);
232365b04b38Smrg
232465b04b38Smrg    return ProcSyncCreateFence(client);
232565b04b38Smrg}
232665b04b38Smrg
23277e31ba66Smrgstatic int _X_COLD
232865b04b38SmrgSProcSyncTriggerFence(ClientPtr client)
232965b04b38Smrg{
233065b04b38Smrg    REQUEST(xSyncTriggerFenceReq);
2331f7df2e56Smrg    swaps(&stuff->length);
2332f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncTriggerFenceReq);
2333f7df2e56Smrg    swapl(&stuff->fid);
233465b04b38Smrg
233565b04b38Smrg    return ProcSyncTriggerFence(client);
233665b04b38Smrg}
233765b04b38Smrg
23387e31ba66Smrgstatic int _X_COLD
233965b04b38SmrgSProcSyncResetFence(ClientPtr client)
234065b04b38Smrg{
234165b04b38Smrg    REQUEST(xSyncResetFenceReq);
2342f7df2e56Smrg    swaps(&stuff->length);
2343f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncResetFenceReq);
2344f7df2e56Smrg    swapl(&stuff->fid);
234565b04b38Smrg
234665b04b38Smrg    return ProcSyncResetFence(client);
234765b04b38Smrg}
234865b04b38Smrg
23497e31ba66Smrgstatic int _X_COLD
235065b04b38SmrgSProcSyncDestroyFence(ClientPtr client)
235165b04b38Smrg{
235265b04b38Smrg    REQUEST(xSyncDestroyFenceReq);
2353f7df2e56Smrg    swaps(&stuff->length);
2354f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncDestroyFenceReq);
2355f7df2e56Smrg    swapl(&stuff->fid);
235665b04b38Smrg
235765b04b38Smrg    return ProcSyncDestroyFence(client);
235865b04b38Smrg}
235965b04b38Smrg
23607e31ba66Smrgstatic int _X_COLD
236165b04b38SmrgSProcSyncQueryFence(ClientPtr client)
236265b04b38Smrg{
236365b04b38Smrg    REQUEST(xSyncQueryFenceReq);
2364f7df2e56Smrg    swaps(&stuff->length);
2365f7df2e56Smrg    REQUEST_SIZE_MATCH(xSyncQueryFenceReq);
2366f7df2e56Smrg    swapl(&stuff->fid);
236765b04b38Smrg
236865b04b38Smrg    return ProcSyncQueryFence(client);
236965b04b38Smrg}
237065b04b38Smrg
23717e31ba66Smrgstatic int _X_COLD
237265b04b38SmrgSProcSyncAwaitFence(ClientPtr client)
237365b04b38Smrg{
237465b04b38Smrg    REQUEST(xSyncAwaitFenceReq);
2375f7df2e56Smrg    swaps(&stuff->length);
237665b04b38Smrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
237765b04b38Smrg    SwapRestL(stuff);
237865b04b38Smrg
237965b04b38Smrg    return ProcSyncAwaitFence(client);
238065b04b38Smrg}
238105b261ecSmrg
23827e31ba66Smrgstatic int _X_COLD
23834202a189SmrgSProcSyncDispatch(ClientPtr client)
238405b261ecSmrg{
238505b261ecSmrg    REQUEST(xReq);
238605b261ecSmrg
2387f7df2e56Smrg    switch (stuff->data) {
2388f7df2e56Smrg    case X_SyncInitialize:
2389f7df2e56Smrg        return SProcSyncInitialize(client);
2390f7df2e56Smrg    case X_SyncListSystemCounters:
2391f7df2e56Smrg        return SProcSyncListSystemCounters(client);
2392f7df2e56Smrg    case X_SyncCreateCounter:
2393f7df2e56Smrg        return SProcSyncCreateCounter(client);
2394f7df2e56Smrg    case X_SyncSetCounter:
2395f7df2e56Smrg        return SProcSyncSetCounter(client);
2396f7df2e56Smrg    case X_SyncChangeCounter:
2397f7df2e56Smrg        return SProcSyncChangeCounter(client);
2398f7df2e56Smrg    case X_SyncQueryCounter:
2399f7df2e56Smrg        return SProcSyncQueryCounter(client);
2400f7df2e56Smrg    case X_SyncDestroyCounter:
2401f7df2e56Smrg        return SProcSyncDestroyCounter(client);
2402f7df2e56Smrg    case X_SyncAwait:
2403f7df2e56Smrg        return SProcSyncAwait(client);
2404f7df2e56Smrg    case X_SyncCreateAlarm:
2405f7df2e56Smrg        return SProcSyncCreateAlarm(client);
2406f7df2e56Smrg    case X_SyncChangeAlarm:
2407f7df2e56Smrg        return SProcSyncChangeAlarm(client);
2408f7df2e56Smrg    case X_SyncQueryAlarm:
2409f7df2e56Smrg        return SProcSyncQueryAlarm(client);
2410f7df2e56Smrg    case X_SyncDestroyAlarm:
2411f7df2e56Smrg        return SProcSyncDestroyAlarm(client);
2412f7df2e56Smrg    case X_SyncSetPriority:
2413f7df2e56Smrg        return SProcSyncSetPriority(client);
2414f7df2e56Smrg    case X_SyncGetPriority:
2415f7df2e56Smrg        return SProcSyncGetPriority(client);
2416f7df2e56Smrg    case X_SyncCreateFence:
2417f7df2e56Smrg        return SProcSyncCreateFence(client);
2418f7df2e56Smrg    case X_SyncTriggerFence:
2419f7df2e56Smrg        return SProcSyncTriggerFence(client);
2420f7df2e56Smrg    case X_SyncResetFence:
2421f7df2e56Smrg        return SProcSyncResetFence(client);
2422f7df2e56Smrg    case X_SyncDestroyFence:
2423f7df2e56Smrg        return SProcSyncDestroyFence(client);
2424f7df2e56Smrg    case X_SyncQueryFence:
2425f7df2e56Smrg        return SProcSyncQueryFence(client);
2426f7df2e56Smrg    case X_SyncAwaitFence:
2427f7df2e56Smrg        return SProcSyncAwaitFence(client);
2428f7df2e56Smrg    default:
2429f7df2e56Smrg        return BadRequest;
243005b261ecSmrg    }
243105b261ecSmrg}
243205b261ecSmrg
243305b261ecSmrg/*
243405b261ecSmrg * Event Swapping
243505b261ecSmrg */
243605b261ecSmrg
24377e31ba66Smrgstatic void _X_COLD
2438f7df2e56SmrgSCounterNotifyEvent(xSyncCounterNotifyEvent * from,
2439f7df2e56Smrg                    xSyncCounterNotifyEvent * to)
244005b261ecSmrg{
244105b261ecSmrg    to->type = from->type;
244205b261ecSmrg    to->kind = from->kind;
244305b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
244405b261ecSmrg    cpswapl(from->counter, to->counter);
244505b261ecSmrg    cpswapl(from->wait_value_lo, to->wait_value_lo);
244605b261ecSmrg    cpswapl(from->wait_value_hi, to->wait_value_hi);
244705b261ecSmrg    cpswapl(from->counter_value_lo, to->counter_value_lo);
244805b261ecSmrg    cpswapl(from->counter_value_hi, to->counter_value_hi);
244905b261ecSmrg    cpswapl(from->time, to->time);
245005b261ecSmrg    cpswaps(from->count, to->count);
245105b261ecSmrg    to->destroyed = from->destroyed;
245205b261ecSmrg}
245305b261ecSmrg
24547e31ba66Smrgstatic void _X_COLD
2455f7df2e56SmrgSAlarmNotifyEvent(xSyncAlarmNotifyEvent * from, xSyncAlarmNotifyEvent * to)
245605b261ecSmrg{
245705b261ecSmrg    to->type = from->type;
245805b261ecSmrg    to->kind = from->kind;
245905b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
246005b261ecSmrg    cpswapl(from->alarm, to->alarm);
246105b261ecSmrg    cpswapl(from->counter_value_lo, to->counter_value_lo);
246205b261ecSmrg    cpswapl(from->counter_value_hi, to->counter_value_hi);
246305b261ecSmrg    cpswapl(from->alarm_value_lo, to->alarm_value_lo);
246405b261ecSmrg    cpswapl(from->alarm_value_hi, to->alarm_value_hi);
246505b261ecSmrg    cpswapl(from->time, to->time);
246605b261ecSmrg    to->state = from->state;
246705b261ecSmrg}
246805b261ecSmrg
246905b261ecSmrg/*
247005b261ecSmrg * ** Close everything down. ** This is fairly simple for now.
247105b261ecSmrg */
247205b261ecSmrg/* ARGSUSED */
24734202a189Smrgstatic void
2474f7df2e56SmrgSyncResetProc(ExtensionEntry * extEntry)
247505b261ecSmrg{
247605b261ecSmrg    RTCounter = 0;
247705b261ecSmrg}
247805b261ecSmrg
247905b261ecSmrg/*
248005b261ecSmrg * ** Initialise the extension.
248105b261ecSmrg */
24824202a189Smrgvoid
24834202a189SmrgSyncExtensionInit(void)
248405b261ecSmrg{
248505b261ecSmrg    ExtensionEntry *extEntry;
2486f7df2e56Smrg    int s;
248765b04b38Smrg
248865b04b38Smrg    for (s = 0; s < screenInfo.numScreens; s++)
2489f7df2e56Smrg        miSyncSetup(screenInfo.screens[s]);
249005b261ecSmrg
24917e31ba66Smrg    RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
24927e31ba66Smrg    xorg_list_init(&SysCounterList);
24934202a189Smrg    RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm");
24944202a189Smrg    RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait");
249565b04b38Smrg    RTFence = CreateNewResourceType(FreeFence, "SyncFence");
24964202a189Smrg    if (RTAwait)
2497f7df2e56Smrg        RTAwait |= RC_NEVERRETAIN;
24984202a189Smrg    RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient");
24994202a189Smrg    if (RTAlarmClient)
2500f7df2e56Smrg        RTAlarmClient |= RC_NEVERRETAIN;
250105b261ecSmrg
250205b261ecSmrg    if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 ||
2503f7df2e56Smrg        RTAlarmClient == 0 ||
2504f7df2e56Smrg        (extEntry = AddExtension(SYNC_NAME,
2505f7df2e56Smrg                                 XSyncNumberEvents, XSyncNumberErrors,
2506f7df2e56Smrg                                 ProcSyncDispatch, SProcSyncDispatch,
2507f7df2e56Smrg                                 SyncResetProc, StandardMinorOpcode)) == NULL) {
2508f7df2e56Smrg        ErrorF("Sync Extension %d.%d failed to Initialise\n",
2509f7df2e56Smrg               SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
2510f7df2e56Smrg        return;
251105b261ecSmrg    }
251205b261ecSmrg
251305b261ecSmrg    SyncEventBase = extEntry->eventBase;
251405b261ecSmrg    SyncErrorBase = extEntry->errorBase;
2515f7df2e56Smrg    EventSwapVector[SyncEventBase + XSyncCounterNotify] =
2516f7df2e56Smrg        (EventSwapPtr) SCounterNotifyEvent;
2517f7df2e56Smrg    EventSwapVector[SyncEventBase + XSyncAlarmNotify] =
2518f7df2e56Smrg        (EventSwapPtr) SAlarmNotifyEvent;
251905b261ecSmrg
25204202a189Smrg    SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter);
25214202a189Smrg    SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm);
252265b04b38Smrg    SetResourceTypeErrorValue(RTFence, SyncErrorBase + XSyncBadFence);
25234202a189Smrg
252405b261ecSmrg    /*
252505b261ecSmrg     * Although SERVERTIME is implemented by the OS layer, we initialise it
252605b261ecSmrg     * here because doing it in OsInit() is too early. The resource database
252705b261ecSmrg     * is not initialised when OsInit() is called. This is just about OK
252805b261ecSmrg     * because there is always a servertime counter.
252905b261ecSmrg     */
253005b261ecSmrg    SyncInitServerTime();
253105b261ecSmrg    SyncInitIdleTime();
253205b261ecSmrg
253305b261ecSmrg#ifdef DEBUG
253405b261ecSmrg    fprintf(stderr, "Sync Extension %d.%d\n",
2535f7df2e56Smrg            SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
253605b261ecSmrg#endif
253705b261ecSmrg}
253805b261ecSmrg
253905b261ecSmrg/*
254005b261ecSmrg * ***** SERVERTIME implementation - should go in its own file in OS directory?
254105b261ecSmrg */
254205b261ecSmrg
2543f7df2e56Smrgstatic void *ServertimeCounter;
25447e31ba66Smrgstatic int64_t Now;
25457e31ba66Smrgstatic int64_t *pnext_time;
25467e31ba66Smrg
25477e31ba66Smrgstatic void GetTime(void)
25487e31ba66Smrg{
25497e31ba66Smrg    unsigned long millis = GetTimeInMillis();
25507e31ba66Smrg    unsigned long maxis = Now >> 32;
25517e31ba66Smrg
25527e31ba66Smrg    if (millis < (Now & 0xffffffff))
25537e31ba66Smrg        maxis++;
255405b261ecSmrg
25557e31ba66Smrg    Now = ((int64_t)maxis << 32) | millis;
255605b261ecSmrg}
255705b261ecSmrg
255805b261ecSmrg/*
255905b261ecSmrg*** Server Block Handler
25604202a189Smrg*** code inspired by multibuffer extension (now deprecated)
256105b261ecSmrg */
25627e31ba66Smrg/*ARGSUSED*/ static void
25637e31ba66SmrgServertimeBlockHandler(void *env, void *wt)
256405b261ecSmrg{
256505b261ecSmrg    unsigned long timeout;
256605b261ecSmrg
2567f7df2e56Smrg    if (pnext_time) {
256805b261ecSmrg        GetTime();
256905b261ecSmrg
25707e31ba66Smrg        if (Now >= *pnext_time) {
257105b261ecSmrg            timeout = 0;
25724202a189Smrg        }
2573f7df2e56Smrg        else {
25747e31ba66Smrg            timeout = *pnext_time - Now;
257505b261ecSmrg        }
2576f7df2e56Smrg        AdjustWaitForDelay(wt, timeout);        /* os/utils.c */
257705b261ecSmrg    }
257805b261ecSmrg}
257905b261ecSmrg
258005b261ecSmrg/*
258105b261ecSmrg*** Wakeup Handler
258205b261ecSmrg */
25837e31ba66Smrg/*ARGSUSED*/ static void
25847e31ba66SmrgServertimeWakeupHandler(void *env, int rc)
258505b261ecSmrg{
2586f7df2e56Smrg    if (pnext_time) {
258705b261ecSmrg        GetTime();
258805b261ecSmrg
25897e31ba66Smrg        if (Now >= *pnext_time) {
259005b261ecSmrg            SyncChangeCounter(ServertimeCounter, Now);
259105b261ecSmrg        }
259205b261ecSmrg    }
259305b261ecSmrg}
259405b261ecSmrg
259505b261ecSmrgstatic void
25967e31ba66SmrgServertimeQueryValue(void *pCounter, int64_t *pValue_return)
259705b261ecSmrg{
259805b261ecSmrg    GetTime();
259905b261ecSmrg    *pValue_return = Now;
260005b261ecSmrg}
260105b261ecSmrg
260205b261ecSmrgstatic void
26037e31ba66SmrgServertimeBracketValues(void *pCounter, int64_t *pbracket_less,
26047e31ba66Smrg                        int64_t *pbracket_greater)
260505b261ecSmrg{
2606f7df2e56Smrg    if (!pnext_time && pbracket_greater) {
2607f7df2e56Smrg        RegisterBlockAndWakeupHandlers(ServertimeBlockHandler,
2608f7df2e56Smrg                                       ServertimeWakeupHandler, NULL);
260905b261ecSmrg    }
2610f7df2e56Smrg    else if (pnext_time && !pbracket_greater) {
2611f7df2e56Smrg        RemoveBlockAndWakeupHandlers(ServertimeBlockHandler,
2612f7df2e56Smrg                                     ServertimeWakeupHandler, NULL);
261305b261ecSmrg    }
261405b261ecSmrg    pnext_time = pbracket_greater;
261505b261ecSmrg}
261605b261ecSmrg
261705b261ecSmrgstatic void
261805b261ecSmrgSyncInitServerTime(void)
261905b261ecSmrg{
26207e31ba66Smrg    int64_t resolution = 4;
262105b261ecSmrg
26227e31ba66Smrg    Now = GetTimeInMillis();
262305b261ecSmrg    ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution,
2624f7df2e56Smrg                                                XSyncCounterNeverDecreases,
2625f7df2e56Smrg                                                ServertimeQueryValue,
2626f7df2e56Smrg                                                ServertimeBracketValues);
262705b261ecSmrg    pnext_time = NULL;
262805b261ecSmrg}
262905b261ecSmrg
263005b261ecSmrg/*
263105b261ecSmrg * IDLETIME implementation
263205b261ecSmrg */
263305b261ecSmrg
2634f7df2e56Smrgtypedef struct {
26357e31ba66Smrg    int64_t *value_less;
26367e31ba66Smrg    int64_t *value_greater;
2637f7df2e56Smrg    int deviceid;
2638f7df2e56Smrg} IdleCounterPriv;
263905b261ecSmrg
264005b261ecSmrgstatic void
26417e31ba66SmrgIdleTimeQueryValue(void *pCounter, int64_t *pValue_return)
264205b261ecSmrg{
2643f7df2e56Smrg    int deviceid;
2644f7df2e56Smrg    CARD32 idle;
2645f7df2e56Smrg
2646f7df2e56Smrg    if (pCounter) {
2647f7df2e56Smrg        SyncCounter *counter = pCounter;
2648f7df2e56Smrg        IdleCounterPriv *priv = SysCounterGetPrivate(counter);
2649f7df2e56Smrg        deviceid = priv->deviceid;
2650f7df2e56Smrg    }
2651f7df2e56Smrg    else
2652f7df2e56Smrg        deviceid = XIAllDevices;
2653f7df2e56Smrg    idle = GetTimeInMillis() - LastEventTime(deviceid).milliseconds;
26547e31ba66Smrg    *pValue_return = idle;
265505b261ecSmrg}
265605b261ecSmrg
265705b261ecSmrgstatic void
26587e31ba66SmrgIdleTimeBlockHandler(void *pCounter, void *wt)
265905b261ecSmrg{
2660f7df2e56Smrg    SyncCounter *counter = pCounter;
2661f7df2e56Smrg    IdleCounterPriv *priv = SysCounterGetPrivate(counter);
26627e31ba66Smrg    int64_t *less = priv->value_less;
26637e31ba66Smrg    int64_t *greater = priv->value_greater;
26647e31ba66Smrg    int64_t idle, old_idle;
2665f7df2e56Smrg    SyncTriggerList *list = counter->sync.pTriglist;
266645801275Sjmcneill    SyncTrigger *trig;
266705b261ecSmrg
2668f7df2e56Smrg    if (!less && !greater)
2669f7df2e56Smrg        return;
2670f7df2e56Smrg
2671f7df2e56Smrg    old_idle = counter->value;
2672f7df2e56Smrg    IdleTimeQueryValue(counter, &idle);
2673f7df2e56Smrg    counter->value = idle;      /* push, so CheckTrigger works */
2674f7df2e56Smrg
2675f7df2e56Smrg    /**
2676f7df2e56Smrg     * There's an indefinite amount of time between ProcessInputEvents()
2677f7df2e56Smrg     * where the idle time is reset and the time we actually get here. idle
2678f7df2e56Smrg     * may be past the lower bracket if we dawdled with the events, so
2679f7df2e56Smrg     * check for whether we did reset and bomb out of select immediately.
2680f7df2e56Smrg     */
26817e31ba66Smrg    if (less && idle > *less &&
2682f7df2e56Smrg        LastEventTimeWasReset(priv->deviceid)) {
2683f7df2e56Smrg        AdjustWaitForDelay(wt, 0);
26847e31ba66Smrg    } else if (less && idle <= *less) {
2685f7df2e56Smrg        /*
2686f7df2e56Smrg         * We've been idle for less than the threshold value, and someone
2687f7df2e56Smrg         * wants to know about that, but now we need to know whether they
2688f7df2e56Smrg         * want level or edge trigger.  Check the trigger list against the
2689f7df2e56Smrg         * current idle time, and if any succeed, bomb out of select()
2690f7df2e56Smrg         * immediately so we can reschedule.
2691f7df2e56Smrg         */
2692f7df2e56Smrg
2693f7df2e56Smrg        for (list = counter->sync.pTriglist; list; list = list->next) {
2694f7df2e56Smrg            trig = list->pTrigger;
2695f7df2e56Smrg            if (trig->CheckTrigger(trig, old_idle)) {
2696f7df2e56Smrg                AdjustWaitForDelay(wt, 0);
2697f7df2e56Smrg                break;
2698f7df2e56Smrg            }
2699f7df2e56Smrg        }
2700f7df2e56Smrg        /*
2701f7df2e56Smrg         * We've been called exactly on the idle time, but we have a
2702f7df2e56Smrg         * NegativeTransition trigger which requires a transition from an
2703f7df2e56Smrg         * idle time greater than this.  Schedule a wakeup for the next
2704f7df2e56Smrg         * millisecond so we won't miss a transition.
2705f7df2e56Smrg         */
27067e31ba66Smrg        if (idle == *less)
2707f7df2e56Smrg            AdjustWaitForDelay(wt, 1);
2708f7df2e56Smrg    }
2709f7df2e56Smrg    else if (greater) {
2710f7df2e56Smrg        /*
2711f7df2e56Smrg         * There's a threshold in the positive direction.  If we've been
2712f7df2e56Smrg         * idle less than it, schedule a wakeup for sometime in the future.
2713f7df2e56Smrg         * If we've been idle more than it, and someone wants to know about
2714f7df2e56Smrg         * that level-triggered, schedule an immediate wakeup.
2715f7df2e56Smrg         */
2716f7df2e56Smrg
27177e31ba66Smrg        if (idle < *greater) {
27187e31ba66Smrg            AdjustWaitForDelay(wt, *greater - idle);
2719f7df2e56Smrg        }
2720f7df2e56Smrg        else {
2721f7df2e56Smrg            for (list = counter->sync.pTriglist; list;
2722f7df2e56Smrg                 list = list->next) {
2723f7df2e56Smrg                trig = list->pTrigger;
2724f7df2e56Smrg                if (trig->CheckTrigger(trig, old_idle)) {
2725f7df2e56Smrg                    AdjustWaitForDelay(wt, 0);
2726f7df2e56Smrg                    break;
2727f7df2e56Smrg                }
2728f7df2e56Smrg            }
2729f7df2e56Smrg        }
2730f7df2e56Smrg    }
2731f7df2e56Smrg
2732f7df2e56Smrg    counter->value = old_idle;  /* pop */
2733f7df2e56Smrg}
2734f7df2e56Smrg
2735f7df2e56Smrgstatic void
27367e31ba66SmrgIdleTimeCheckBrackets(SyncCounter *counter, int64_t idle,
27377e31ba66Smrg                      int64_t *less, int64_t *greater)
2738f7df2e56Smrg{
27397e31ba66Smrg    if ((greater && idle >= *greater) ||
27407e31ba66Smrg        (less && idle <= *less)) {
2741f7df2e56Smrg        SyncChangeCounter(counter, idle);
2742f7df2e56Smrg    }
2743f7df2e56Smrg    else
2744f7df2e56Smrg        SyncUpdateCounter(counter, idle);
274505b261ecSmrg}
274605b261ecSmrg
274705b261ecSmrgstatic void
27487e31ba66SmrgIdleTimeWakeupHandler(void *pCounter, int rc)
274905b261ecSmrg{
2750f7df2e56Smrg    SyncCounter *counter = pCounter;
2751f7df2e56Smrg    IdleCounterPriv *priv = SysCounterGetPrivate(counter);
27527e31ba66Smrg    int64_t *less = priv->value_less;
27537e31ba66Smrg    int64_t *greater = priv->value_greater;
27547e31ba66Smrg    int64_t idle;
275505b261ecSmrg
2756f7df2e56Smrg    if (!less && !greater)
2757f7df2e56Smrg        return;
275805b261ecSmrg
2759f7df2e56Smrg    IdleTimeQueryValue(pCounter, &idle);
276005b261ecSmrg
2761f7df2e56Smrg    /*
2762f7df2e56Smrg      There is no guarantee for the WakeupHandler to be called within a specific
2763f7df2e56Smrg      timeframe. Idletime may go to 0, but by the time we get here, it may be
2764f7df2e56Smrg      non-zero and alarms for a pos. transition on 0 won't get triggered.
2765f7df2e56Smrg      https://bugs.freedesktop.org/show_bug.cgi?id=70476
2766f7df2e56Smrg      */
2767f7df2e56Smrg    if (LastEventTimeWasReset(priv->deviceid)) {
2768f7df2e56Smrg        LastEventTimeToggleResetFlag(priv->deviceid, FALSE);
27697e31ba66Smrg        if (idle != 0) {
27707e31ba66Smrg            IdleTimeCheckBrackets(counter, 0, less, greater);
2771f7df2e56Smrg            less = priv->value_less;
2772f7df2e56Smrg            greater = priv->value_greater;
2773f7df2e56Smrg        }
277405b261ecSmrg    }
2775f7df2e56Smrg
2776f7df2e56Smrg    IdleTimeCheckBrackets(counter, idle, less, greater);
277705b261ecSmrg}
277805b261ecSmrg
277905b261ecSmrgstatic void
27807e31ba66SmrgIdleTimeBracketValues(void *pCounter, int64_t *pbracket_less,
27817e31ba66Smrg                      int64_t *pbracket_greater)
278205b261ecSmrg{
2783f7df2e56Smrg    SyncCounter *counter = pCounter;
2784f7df2e56Smrg    IdleCounterPriv *priv = SysCounterGetPrivate(counter);
27857e31ba66Smrg    int64_t *less = priv->value_less;
27867e31ba66Smrg    int64_t *greater = priv->value_greater;
2787f7df2e56Smrg    Bool registered = (less || greater);
278805b261ecSmrg
2789f7df2e56Smrg    if (registered && !pbracket_less && !pbracket_greater) {
2790f7df2e56Smrg        RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler,
2791f7df2e56Smrg                                     IdleTimeWakeupHandler, pCounter);
279205b261ecSmrg    }
2793f7df2e56Smrg    else if (!registered && (pbracket_less || pbracket_greater)) {
2794f7df2e56Smrg        /* Reset flag must be zero so we don't force a idle timer reset on
2795f7df2e56Smrg           the first wakeup */
2796f7df2e56Smrg        LastEventTimeToggleResetAll(FALSE);
2797f7df2e56Smrg        RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
2798f7df2e56Smrg                                       IdleTimeWakeupHandler, pCounter);
279905b261ecSmrg    }
280005b261ecSmrg
2801f7df2e56Smrg    priv->value_greater = pbracket_greater;
2802f7df2e56Smrg    priv->value_less = pbracket_less;
280305b261ecSmrg}
280405b261ecSmrg
2805f7df2e56Smrgstatic SyncCounter*
2806f7df2e56Smrginit_system_idle_counter(const char *name, int deviceid)
280705b261ecSmrg{
28087e31ba66Smrg    int64_t resolution = 4;
28097e31ba66Smrg    int64_t idle;
2810f7df2e56Smrg    SyncCounter *idle_time_counter;
2811f7df2e56Smrg
2812f7df2e56Smrg    IdleTimeQueryValue(NULL, &idle);
281305b261ecSmrg
2814f7df2e56Smrg    idle_time_counter = SyncCreateSystemCounter(name, idle, resolution,
2815f7df2e56Smrg                                                XSyncCounterUnrestricted,
2816f7df2e56Smrg                                                IdleTimeQueryValue,
2817f7df2e56Smrg                                                IdleTimeBracketValues);
281805b261ecSmrg
2819f7df2e56Smrg    if (idle_time_counter != NULL) {
2820f7df2e56Smrg        IdleCounterPriv *priv = malloc(sizeof(IdleCounterPriv));
282105b261ecSmrg
2822f7df2e56Smrg        priv->value_less = priv->value_greater = NULL;
2823f7df2e56Smrg        priv->deviceid = deviceid;
2824f7df2e56Smrg
2825f7df2e56Smrg        idle_time_counter->pSysCounterInfo->private = priv;
2826f7df2e56Smrg    }
2827f7df2e56Smrg
2828f7df2e56Smrg    return idle_time_counter;
2829f7df2e56Smrg}
2830f7df2e56Smrg
2831f7df2e56Smrgstatic void
2832f7df2e56SmrgSyncInitIdleTime(void)
2833f7df2e56Smrg{
2834f7df2e56Smrg    init_system_idle_counter("IDLETIME", XIAllDevices);
2835f7df2e56Smrg}
2836f7df2e56Smrg
2837f7df2e56SmrgSyncCounter*
2838f7df2e56SmrgSyncInitDeviceIdleTime(DeviceIntPtr dev)
2839f7df2e56Smrg{
2840f7df2e56Smrg    char timer_name[64];
2841f7df2e56Smrg    sprintf(timer_name, "DEVICEIDLETIME %d", dev->id);
2842f7df2e56Smrg
2843f7df2e56Smrg    return init_system_idle_counter(timer_name, dev->id);
2844f7df2e56Smrg}
2845f7df2e56Smrg
2846f7df2e56Smrgvoid SyncRemoveDeviceIdleTime(SyncCounter *counter)
2847f7df2e56Smrg{
2848f7df2e56Smrg    /* FreeAllResources() frees all system counters before the devices are
2849f7df2e56Smrg       shut down, check if there are any left before freeing the device's
2850f7df2e56Smrg       counter */
2851f7df2e56Smrg    if (counter && !xorg_list_is_empty(&SysCounterList))
2852f7df2e56Smrg        xorg_list_del(&counter->pSysCounterInfo->entry);
285305b261ecSmrg}
2854