sync.c revision 1b684552
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
2705b261ecSmrg
2805b261ecSmrgCopyright 1991, 1993 by Digital Equipment Corporation, Maynard, Massachusetts,
2905b261ecSmrgand Olivetti Research Limited, Cambridge, England.
3005b261ecSmrg
3105b261ecSmrg                        All Rights Reserved
3205b261ecSmrg
3305b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3405b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3505b261ecSmrgprovided that the above copyright notice appear in all copies and that
3605b261ecSmrgboth that copyright notice and this permission notice appear in
374202a189Smrgsupporting documentation, and that the names of Digital or Olivetti
3805b261ecSmrgnot be used in advertising or publicity pertaining to distribution of the
3905b261ecSmrgsoftware without specific, written prior permission.  Digital and Olivetti
4005b261ecSmrgmake no representations about the suitability of this software
4105b261ecSmrgfor any purpose.  It is provided "as is" without express or implied warranty.
4205b261ecSmrg
4305b261ecSmrgDIGITAL AND OLIVETTI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
4405b261ecSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
4505b261ecSmrgFITNESS, IN NO EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR
4605b261ecSmrgCONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
4705b261ecSmrgUSE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
4805b261ecSmrgOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
4905b261ecSmrgPERFORMANCE OF THIS SOFTWARE.
5005b261ecSmrg
5105b261ecSmrg*/
5205b261ecSmrg
5305b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5405b261ecSmrg#include <dix-config.h>
5505b261ecSmrg#endif
5605b261ecSmrg
5705b261ecSmrg#include <string.h>
5805b261ecSmrg
5905b261ecSmrg#include <X11/X.h>
6005b261ecSmrg#include <X11/Xproto.h>
6105b261ecSmrg#include <X11/Xmd.h>
6205b261ecSmrg#include "misc.h"
6305b261ecSmrg#include "os.h"
6405b261ecSmrg#include "extnsionst.h"
6505b261ecSmrg#include "dixstruct.h"
6605b261ecSmrg#include "resource.h"
6705b261ecSmrg#include "opaque.h"
684202a189Smrg#include <X11/extensions/syncproto.h>
694202a189Smrg#include "syncsrv.h"
701b684552Smrg#include "protocol-versions.h"
7105b261ecSmrg
7205b261ecSmrg#include <stdio.h>
73637ac9abSmrg#if !defined(WIN32)
7405b261ecSmrg#include <sys/time.h>
7505b261ecSmrg#endif
7605b261ecSmrg
7705b261ecSmrg#include "modinit.h"
7805b261ecSmrg
7905b261ecSmrg/*
8005b261ecSmrg * Local Global Variables
8105b261ecSmrg */
8205b261ecSmrgstatic int      SyncEventBase;
8305b261ecSmrgstatic int      SyncErrorBase;
8405b261ecSmrgstatic RESTYPE  RTCounter = 0;
8505b261ecSmrgstatic RESTYPE  RTAwait;
8605b261ecSmrgstatic RESTYPE  RTAlarm;
8705b261ecSmrgstatic RESTYPE  RTAlarmClient;
8805b261ecSmrgstatic int SyncNumSystemCounters = 0;
8905b261ecSmrgstatic SyncCounter **SysCounterList = NULL;
9005b261ecSmrg
9105b261ecSmrg#define IsSystemCounter(pCounter) \
9205b261ecSmrg    (pCounter && (pCounter->client == NULL))
9305b261ecSmrg
9405b261ecSmrg/* these are all the alarm attributes that pertain to the alarm's trigger */
9505b261ecSmrg#define XSyncCAAllTrigger \
9605b261ecSmrg    (XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType)
9705b261ecSmrg
984202a189Smrgstatic void SyncComputeBracketValues(SyncCounter *);
9905b261ecSmrg
1004202a189Smrgstatic void SyncInitServerTime(void);
10105b261ecSmrg
1024202a189Smrgstatic void SyncInitIdleTime(void);
10305b261ecSmrg
10405b261ecSmrgstatic DISPATCH_PROC(ProcSyncAwait);
10505b261ecSmrgstatic DISPATCH_PROC(ProcSyncChangeAlarm);
10605b261ecSmrgstatic DISPATCH_PROC(ProcSyncChangeCounter);
10705b261ecSmrgstatic DISPATCH_PROC(ProcSyncCreateAlarm);
10805b261ecSmrgstatic DISPATCH_PROC(ProcSyncCreateCounter);
10905b261ecSmrgstatic DISPATCH_PROC(ProcSyncDestroyAlarm);
11005b261ecSmrgstatic DISPATCH_PROC(ProcSyncDestroyCounter);
11105b261ecSmrgstatic DISPATCH_PROC(ProcSyncDispatch);
11205b261ecSmrgstatic DISPATCH_PROC(ProcSyncGetPriority);
11305b261ecSmrgstatic DISPATCH_PROC(ProcSyncInitialize);
11405b261ecSmrgstatic DISPATCH_PROC(ProcSyncListSystemCounters);
11505b261ecSmrgstatic DISPATCH_PROC(ProcSyncQueryAlarm);
11605b261ecSmrgstatic DISPATCH_PROC(ProcSyncQueryCounter);
11705b261ecSmrgstatic DISPATCH_PROC(ProcSyncSetCounter);
11805b261ecSmrgstatic DISPATCH_PROC(ProcSyncSetPriority);
11905b261ecSmrgstatic DISPATCH_PROC(SProcSyncAwait);
12005b261ecSmrgstatic DISPATCH_PROC(SProcSyncChangeAlarm);
12105b261ecSmrgstatic DISPATCH_PROC(SProcSyncChangeCounter);
12205b261ecSmrgstatic DISPATCH_PROC(SProcSyncCreateAlarm);
12305b261ecSmrgstatic DISPATCH_PROC(SProcSyncCreateCounter);
12405b261ecSmrgstatic DISPATCH_PROC(SProcSyncDestroyAlarm);
12505b261ecSmrgstatic DISPATCH_PROC(SProcSyncDestroyCounter);
12605b261ecSmrgstatic DISPATCH_PROC(SProcSyncDispatch);
12705b261ecSmrgstatic DISPATCH_PROC(SProcSyncGetPriority);
12805b261ecSmrgstatic DISPATCH_PROC(SProcSyncInitialize);
12905b261ecSmrgstatic DISPATCH_PROC(SProcSyncListSystemCounters);
13005b261ecSmrgstatic DISPATCH_PROC(SProcSyncQueryAlarm);
13105b261ecSmrgstatic DISPATCH_PROC(SProcSyncQueryCounter);
13205b261ecSmrgstatic DISPATCH_PROC(SProcSyncSetCounter);
13305b261ecSmrgstatic DISPATCH_PROC(SProcSyncSetPriority);
13405b261ecSmrg
13505b261ecSmrg/*  Each counter maintains a simple linked list of triggers that are
13605b261ecSmrg *  interested in the counter.  The two functions below are used to
13705b261ecSmrg *  delete and add triggers on this list.
13805b261ecSmrg */
13905b261ecSmrgstatic void
1404202a189SmrgSyncDeleteTriggerFromCounter(SyncTrigger *pTrigger)
14105b261ecSmrg{
14205b261ecSmrg    SyncTriggerList *pCur;
14305b261ecSmrg    SyncTriggerList *pPrev;
14405b261ecSmrg
14505b261ecSmrg    /* pCounter needs to be stored in pTrigger before calling here. */
14605b261ecSmrg
14705b261ecSmrg    if (!pTrigger->pCounter)
14805b261ecSmrg	return;
14905b261ecSmrg
15005b261ecSmrg    pPrev = NULL;
15105b261ecSmrg    pCur = pTrigger->pCounter->pTriglist;
15205b261ecSmrg
15305b261ecSmrg    while (pCur)
15405b261ecSmrg    {
15505b261ecSmrg	if (pCur->pTrigger == pTrigger)
15605b261ecSmrg	{
15705b261ecSmrg	    if (pPrev)
15805b261ecSmrg		pPrev->next = pCur->next;
15905b261ecSmrg	    else
16005b261ecSmrg		pTrigger->pCounter->pTriglist = pCur->next;
1614202a189Smrg
1624202a189Smrg	    free(pCur);
16305b261ecSmrg	    break;
16405b261ecSmrg	}
16505b261ecSmrg
16605b261ecSmrg	pPrev = pCur;
16705b261ecSmrg	pCur = pCur->next;
16805b261ecSmrg    }
1694202a189Smrg
17005b261ecSmrg    if (IsSystemCounter(pTrigger->pCounter))
1714202a189Smrg	SyncComputeBracketValues(pTrigger->pCounter);
17205b261ecSmrg}
17305b261ecSmrg
17405b261ecSmrg
17505b261ecSmrgstatic int
1764202a189SmrgSyncAddTriggerToCounter(SyncTrigger *pTrigger)
17705b261ecSmrg{
17805b261ecSmrg    SyncTriggerList *pCur;
17905b261ecSmrg
18005b261ecSmrg    if (!pTrigger->pCounter)
18105b261ecSmrg	return Success;
18205b261ecSmrg
18305b261ecSmrg    /* don't do anything if it's already there */
18405b261ecSmrg    for (pCur = pTrigger->pCounter->pTriglist; pCur; pCur = pCur->next)
18505b261ecSmrg    {
18605b261ecSmrg	if (pCur->pTrigger == pTrigger)
18705b261ecSmrg	    return Success;
18805b261ecSmrg    }
18905b261ecSmrg
1904202a189Smrg    if (!(pCur = malloc(sizeof(SyncTriggerList))))
19105b261ecSmrg	return BadAlloc;
19205b261ecSmrg
19305b261ecSmrg    pCur->pTrigger = pTrigger;
19405b261ecSmrg    pCur->next = pTrigger->pCounter->pTriglist;
19505b261ecSmrg    pTrigger->pCounter->pTriglist = pCur;
19605b261ecSmrg
19705b261ecSmrg    if (IsSystemCounter(pTrigger->pCounter))
1984202a189Smrg	SyncComputeBracketValues(pTrigger->pCounter);
19905b261ecSmrg
20005b261ecSmrg    return Success;
20105b261ecSmrg}
20205b261ecSmrg
20305b261ecSmrg
2044202a189Smrg/*  Below are four possible functions that can be plugged into
20505b261ecSmrg *  pTrigger->CheckTrigger, corresponding to the four possible
20605b261ecSmrg *  test-types.  These functions are called after the counter's
20705b261ecSmrg *  value changes but are also passed the old counter value
20805b261ecSmrg *  so they can inspect both the old and new values.
20905b261ecSmrg *  (PositiveTransition and NegativeTransition need to see both
21005b261ecSmrg *  pieces of information.)  These functions return the truth value
21105b261ecSmrg *  of the trigger.
21205b261ecSmrg *
21305b261ecSmrg *  All of them include the condition pTrigger->pCounter == NULL.
2144202a189Smrg *  This is because the spec says that a trigger with a counter value
21505b261ecSmrg *  of None is always TRUE.
21605b261ecSmrg */
21705b261ecSmrg
21805b261ecSmrgstatic Bool
2194202a189SmrgSyncCheckTriggerPositiveComparison(SyncTrigger *pTrigger, CARD64 oldval)
22005b261ecSmrg{
22105b261ecSmrg    return (pTrigger->pCounter == NULL ||
22205b261ecSmrg	    XSyncValueGreaterOrEqual(pTrigger->pCounter->value,
22305b261ecSmrg				     pTrigger->test_value));
22405b261ecSmrg}
22505b261ecSmrg
22605b261ecSmrgstatic Bool
2274202a189SmrgSyncCheckTriggerNegativeComparison(SyncTrigger *pTrigger,  CARD64 oldval)
22805b261ecSmrg{
22905b261ecSmrg    return (pTrigger->pCounter == NULL ||
23005b261ecSmrg	    XSyncValueLessOrEqual(pTrigger->pCounter->value,
23105b261ecSmrg				  pTrigger->test_value));
23205b261ecSmrg}
23305b261ecSmrg
23405b261ecSmrgstatic Bool
2354202a189SmrgSyncCheckTriggerPositiveTransition(SyncTrigger *pTrigger, CARD64 oldval)
23605b261ecSmrg{
23705b261ecSmrg    return (pTrigger->pCounter == NULL ||
23805b261ecSmrg	    (XSyncValueLessThan(oldval, pTrigger->test_value) &&
23905b261ecSmrg	     XSyncValueGreaterOrEqual(pTrigger->pCounter->value,
24005b261ecSmrg				      pTrigger->test_value)));
24105b261ecSmrg}
24205b261ecSmrg
24305b261ecSmrgstatic Bool
2444202a189SmrgSyncCheckTriggerNegativeTransition(SyncTrigger *pTrigger, CARD64 oldval)
24505b261ecSmrg{
24605b261ecSmrg    return (pTrigger->pCounter == NULL ||
24705b261ecSmrg	    (XSyncValueGreaterThan(oldval, pTrigger->test_value) &&
24805b261ecSmrg	     XSyncValueLessOrEqual(pTrigger->pCounter->value,
24905b261ecSmrg				   pTrigger->test_value)));
25005b261ecSmrg}
25105b261ecSmrg
2524202a189Smrgstatic int
2534202a189SmrgSyncInitTrigger(ClientPtr client, SyncTrigger *pTrigger, XSyncCounter counter,
2544202a189Smrg		Mask changes)
25505b261ecSmrg{
25605b261ecSmrg    SyncCounter *pCounter = pTrigger->pCounter;
257637ac9abSmrg    int		rc;
25805b261ecSmrg    Bool	newcounter = FALSE;
25905b261ecSmrg
26005b261ecSmrg    if (changes & XSyncCACounter)
26105b261ecSmrg    {
26205b261ecSmrg	if (counter == None)
26305b261ecSmrg	    pCounter = NULL;
264f241d193Smrg	else if (Success != (rc = dixLookupResourceByType ((pointer *)&pCounter,
265637ac9abSmrg				counter, RTCounter, client, DixReadAccess)))
26605b261ecSmrg	{
26705b261ecSmrg	    client->errorValue = counter;
2684202a189Smrg	    return rc;
26905b261ecSmrg	}
27005b261ecSmrg	if (pCounter != pTrigger->pCounter)
27105b261ecSmrg	{ /* new counter for trigger */
27205b261ecSmrg	    SyncDeleteTriggerFromCounter(pTrigger);
27305b261ecSmrg	    pTrigger->pCounter = pCounter;
27405b261ecSmrg	    newcounter = TRUE;
27505b261ecSmrg	}
27605b261ecSmrg    }
27705b261ecSmrg
27805b261ecSmrg    /* if system counter, ask it what the current value is */
27905b261ecSmrg
28005b261ecSmrg    if (IsSystemCounter(pCounter))
28105b261ecSmrg    {
28205b261ecSmrg	(*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
28305b261ecSmrg						  &pCounter->value);
28405b261ecSmrg    }
28505b261ecSmrg
28605b261ecSmrg    if (changes & XSyncCAValueType)
28705b261ecSmrg    {
28805b261ecSmrg	if (pTrigger->value_type != XSyncRelative &&
28905b261ecSmrg	    pTrigger->value_type != XSyncAbsolute)
29005b261ecSmrg	{
29105b261ecSmrg	    client->errorValue = pTrigger->value_type;
29205b261ecSmrg	    return BadValue;
29305b261ecSmrg	}
29405b261ecSmrg    }
29505b261ecSmrg
29605b261ecSmrg    if (changes & XSyncCATestType)
29705b261ecSmrg    {
29805b261ecSmrg	if (pTrigger->test_type != XSyncPositiveTransition &&
29905b261ecSmrg	    pTrigger->test_type != XSyncNegativeTransition &&
30005b261ecSmrg	    pTrigger->test_type != XSyncPositiveComparison &&
30105b261ecSmrg	    pTrigger->test_type != XSyncNegativeComparison)
30205b261ecSmrg	{
30305b261ecSmrg	    client->errorValue = pTrigger->test_type;
30405b261ecSmrg	    return BadValue;
30505b261ecSmrg	}
30605b261ecSmrg	/* select appropriate CheckTrigger function */
30705b261ecSmrg
30805b261ecSmrg	switch (pTrigger->test_type)
30905b261ecSmrg	{
3104202a189Smrg        case XSyncPositiveTransition:
31105b261ecSmrg	    pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition;
31205b261ecSmrg	    break;
3134202a189Smrg        case XSyncNegativeTransition:
31405b261ecSmrg	    pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition;
31505b261ecSmrg	    break;
3164202a189Smrg        case XSyncPositiveComparison:
31705b261ecSmrg	    pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison;
31805b261ecSmrg	    break;
3194202a189Smrg        case XSyncNegativeComparison:
32005b261ecSmrg	    pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison;
32105b261ecSmrg	    break;
32205b261ecSmrg	}
32305b261ecSmrg    }
32405b261ecSmrg
32505b261ecSmrg    if (changes & (XSyncCAValueType | XSyncCAValue))
32605b261ecSmrg    {
32705b261ecSmrg	if (pTrigger->value_type == XSyncAbsolute)
32805b261ecSmrg	    pTrigger->test_value = pTrigger->wait_value;
32905b261ecSmrg	else /* relative */
33005b261ecSmrg	{
33105b261ecSmrg	    Bool overflow;
33205b261ecSmrg	    if (pCounter == NULL)
33305b261ecSmrg		return BadMatch;
33405b261ecSmrg
3354202a189Smrg	    XSyncValueAdd(&pTrigger->test_value, pCounter->value,
33605b261ecSmrg			  pTrigger->wait_value, &overflow);
33705b261ecSmrg	    if (overflow)
33805b261ecSmrg	    {
33905b261ecSmrg		client->errorValue = XSyncValueHigh32(pTrigger->wait_value);
34005b261ecSmrg		return BadValue;
34105b261ecSmrg	    }
34205b261ecSmrg	}
34305b261ecSmrg    }
34405b261ecSmrg
34505b261ecSmrg    /*  we wait until we're sure there are no errors before registering
34605b261ecSmrg     *  a new counter on a trigger
34705b261ecSmrg     */
34805b261ecSmrg    if (newcounter)
34905b261ecSmrg    {
350637ac9abSmrg	if ((rc = SyncAddTriggerToCounter(pTrigger)) != Success)
351637ac9abSmrg	    return rc;
35205b261ecSmrg    }
35305b261ecSmrg    else if (IsSystemCounter(pCounter))
35405b261ecSmrg    {
3554202a189Smrg	SyncComputeBracketValues(pCounter);
35605b261ecSmrg    }
3574202a189Smrg
35805b261ecSmrg    return Success;
35905b261ecSmrg}
36005b261ecSmrg
36105b261ecSmrg/*  AlarmNotify events happen in response to actions taken on an Alarm or
3624202a189Smrg *  the counter used by the alarm.  AlarmNotify may be sent to multiple
36305b261ecSmrg *  clients.  The alarm maintains a list of clients interested in events.
36405b261ecSmrg */
36505b261ecSmrgstatic void
3664202a189SmrgSyncSendAlarmNotifyEvents(SyncAlarm *pAlarm)
36705b261ecSmrg{
36805b261ecSmrg    SyncAlarmClientList *pcl;
36905b261ecSmrg    xSyncAlarmNotifyEvent ane;
37005b261ecSmrg    SyncTrigger *pTrigger = &pAlarm->trigger;
37105b261ecSmrg
37205b261ecSmrg    UpdateCurrentTime();
37305b261ecSmrg
37405b261ecSmrg    ane.type = SyncEventBase + XSyncAlarmNotify;
37505b261ecSmrg    ane.kind = XSyncAlarmNotify;
37605b261ecSmrg    ane.alarm = pAlarm->alarm_id;
37705b261ecSmrg    if (pTrigger->pCounter)
37805b261ecSmrg    {
37905b261ecSmrg	ane.counter_value_hi = XSyncValueHigh32(pTrigger->pCounter->value);
38005b261ecSmrg	ane.counter_value_lo = XSyncValueLow32(pTrigger->pCounter->value);
38105b261ecSmrg    }
38205b261ecSmrg    else
38305b261ecSmrg    { /* XXX what else can we do if there's no counter? */
38405b261ecSmrg	ane.counter_value_hi = ane.counter_value_lo = 0;
38505b261ecSmrg    }
38605b261ecSmrg
38705b261ecSmrg    ane.alarm_value_hi = XSyncValueHigh32(pTrigger->test_value);
38805b261ecSmrg    ane.alarm_value_lo = XSyncValueLow32(pTrigger->test_value);
38905b261ecSmrg    ane.time = currentTime.milliseconds;
39005b261ecSmrg    ane.state = pAlarm->state;
39105b261ecSmrg
39205b261ecSmrg    /* send to owner */
3934202a189Smrg    if (pAlarm->events)
39405b261ecSmrg	WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane);
39505b261ecSmrg
39605b261ecSmrg    /* send to other interested clients */
39705b261ecSmrg    for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next)
3984202a189Smrg	WriteEventsToClient(pcl->client, 1, (xEvent *) &ane);
39905b261ecSmrg}
40005b261ecSmrg
40105b261ecSmrg
4024202a189Smrg/*  CounterNotify events only occur in response to an Await.  The events
40305b261ecSmrg *  go only to the Awaiting client.
40405b261ecSmrg */
40505b261ecSmrgstatic void
4064202a189SmrgSyncSendCounterNotifyEvents(ClientPtr client, SyncAwait **ppAwait,
4074202a189Smrg			    int num_events)
40805b261ecSmrg{
40905b261ecSmrg    xSyncCounterNotifyEvent *pEvents, *pev;
41005b261ecSmrg    int i;
41105b261ecSmrg
41205b261ecSmrg    if (client->clientGone)
41305b261ecSmrg	return;
4144202a189Smrg    pev = pEvents = malloc(num_events * sizeof(xSyncCounterNotifyEvent));
4154202a189Smrg    if (!pEvents)
41605b261ecSmrg	return;
41705b261ecSmrg    UpdateCurrentTime();
41805b261ecSmrg    for (i = 0; i < num_events; i++, ppAwait++, pev++)
41905b261ecSmrg    {
42005b261ecSmrg	SyncTrigger *pTrigger = &(*ppAwait)->trigger;
42105b261ecSmrg	pev->type = SyncEventBase + XSyncCounterNotify;
42205b261ecSmrg	pev->kind = XSyncCounterNotify;
42305b261ecSmrg	pev->counter = pTrigger->pCounter->id;
42405b261ecSmrg	pev->wait_value_lo = XSyncValueLow32(pTrigger->test_value);
42505b261ecSmrg	pev->wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
42605b261ecSmrg	pev->counter_value_lo = XSyncValueLow32(pTrigger->pCounter->value);
42705b261ecSmrg	pev->counter_value_hi = XSyncValueHigh32(pTrigger->pCounter->value);
42805b261ecSmrg	pev->time = currentTime.milliseconds;
42905b261ecSmrg	pev->count = num_events - i - 1; /* events remaining */
43005b261ecSmrg	pev->destroyed = pTrigger->pCounter->beingDestroyed;
43105b261ecSmrg    }
43205b261ecSmrg    /* swapping will be taken care of by this */
43305b261ecSmrg    WriteEventsToClient(client, num_events, (xEvent *)pEvents);
4344202a189Smrg    free(pEvents);
43505b261ecSmrg}
43605b261ecSmrg
43705b261ecSmrg
43805b261ecSmrg/* This function is called when an alarm's counter is destroyed.
43905b261ecSmrg * It is plugged into pTrigger->CounterDestroyed (for alarm triggers).
44005b261ecSmrg */
4414202a189Smrgstatic void
4424202a189SmrgSyncAlarmCounterDestroyed(SyncTrigger *pTrigger)
44305b261ecSmrg{
44405b261ecSmrg    SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
44505b261ecSmrg
44605b261ecSmrg    pAlarm->state = XSyncAlarmInactive;
44705b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
44805b261ecSmrg    pTrigger->pCounter = NULL;
44905b261ecSmrg}
45005b261ecSmrg
45105b261ecSmrg
4524202a189Smrg/*  This function is called when an alarm "goes off."
45305b261ecSmrg *  It is plugged into pTrigger->TriggerFired (for alarm triggers).
45405b261ecSmrg */
45505b261ecSmrgstatic void
4564202a189SmrgSyncAlarmTriggerFired(SyncTrigger *pTrigger)
45705b261ecSmrg{
45805b261ecSmrg    SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
45905b261ecSmrg    CARD64 new_test_value;
46005b261ecSmrg
46105b261ecSmrg    /* no need to check alarm unless it's active */
46205b261ecSmrg    if (pAlarm->state != XSyncAlarmActive)
46305b261ecSmrg	return;
46405b261ecSmrg
46505b261ecSmrg    /*  " if the counter value is None, or if the delta is 0 and
46605b261ecSmrg     *    the test-type is PositiveComparison or NegativeComparison,
46705b261ecSmrg     *    no change is made to value (test-value) and the alarm
46805b261ecSmrg     *    state is changed to Inactive before the event is generated."
46905b261ecSmrg     */
47005b261ecSmrg    if (pAlarm->trigger.pCounter == NULL
47105b261ecSmrg	|| (XSyncValueIsZero(pAlarm->delta)
47205b261ecSmrg	    && (pAlarm->trigger.test_type == XSyncPositiveComparison
47305b261ecSmrg		|| pAlarm->trigger.test_type == XSyncNegativeComparison)))
47405b261ecSmrg	pAlarm->state = XSyncAlarmInactive;
47505b261ecSmrg
47605b261ecSmrg    new_test_value = pAlarm->trigger.test_value;
47705b261ecSmrg
47805b261ecSmrg    if (pAlarm->state == XSyncAlarmActive)
47905b261ecSmrg    {
48005b261ecSmrg	Bool overflow;
48105b261ecSmrg	CARD64 oldvalue;
48205b261ecSmrg	SyncTrigger *paTrigger = &pAlarm->trigger;
48305b261ecSmrg
48405b261ecSmrg	/* "The alarm is updated by repeatedly adding delta to the
48505b261ecSmrg	 *  value of the trigger and re-initializing it until it
48605b261ecSmrg	 *  becomes FALSE."
48705b261ecSmrg	 */
48805b261ecSmrg	oldvalue = paTrigger->test_value;
48905b261ecSmrg
49005b261ecSmrg	/* XXX really should do something smarter here */
49105b261ecSmrg
49205b261ecSmrg	do
49305b261ecSmrg	{
49405b261ecSmrg	    XSyncValueAdd(&paTrigger->test_value, paTrigger->test_value,
49505b261ecSmrg			  pAlarm->delta, &overflow);
4964202a189Smrg	} while (!overflow &&
49705b261ecSmrg	      (*paTrigger->CheckTrigger)(paTrigger,
49805b261ecSmrg					paTrigger->pCounter->value));
49905b261ecSmrg
50005b261ecSmrg	new_test_value = paTrigger->test_value;
50105b261ecSmrg	paTrigger->test_value = oldvalue;
50205b261ecSmrg
50305b261ecSmrg	/* "If this update would cause value to fall outside the range
50405b261ecSmrg	 *  for an INT64...no change is made to value (test-value) and
50505b261ecSmrg	 *  the alarm state is changed to Inactive before the event is
50605b261ecSmrg	 *  generated."
50705b261ecSmrg	 */
50805b261ecSmrg	if (overflow)
50905b261ecSmrg	{
51005b261ecSmrg	    new_test_value = oldvalue;
51105b261ecSmrg	    pAlarm->state = XSyncAlarmInactive;
51205b261ecSmrg	}
51305b261ecSmrg    }
51405b261ecSmrg    /*  The AlarmNotify event has to have the "new state of the alarm"
51505b261ecSmrg     *  which we can't be sure of until this point.  However, it has
51605b261ecSmrg     *  to have the "old" trigger test value.  That's the reason for
51705b261ecSmrg     *  all the newvalue/oldvalue shuffling above.  After we send the
51805b261ecSmrg     *  events, give the trigger its new test value.
51905b261ecSmrg     */
52005b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
52105b261ecSmrg    pTrigger->test_value = new_test_value;
52205b261ecSmrg}
52305b261ecSmrg
52405b261ecSmrg
52505b261ecSmrg/*  This function is called when an Await unblocks, either as a result
52605b261ecSmrg *  of the trigger firing OR the counter being destroyed.
52705b261ecSmrg *  It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed
52805b261ecSmrg *  (for Await triggers).
52905b261ecSmrg */
53005b261ecSmrgstatic void
5314202a189SmrgSyncAwaitTriggerFired(SyncTrigger *pTrigger)
53205b261ecSmrg{
53305b261ecSmrg    SyncAwait *pAwait = (SyncAwait *)pTrigger;
53405b261ecSmrg    int numwaits;
53505b261ecSmrg    SyncAwaitUnion *pAwaitUnion;
53605b261ecSmrg    SyncAwait **ppAwait;
53705b261ecSmrg    int num_events = 0;
53805b261ecSmrg
53905b261ecSmrg    pAwaitUnion = (SyncAwaitUnion *)pAwait->pHeader;
54005b261ecSmrg    numwaits = pAwaitUnion->header.num_waitconditions;
5414202a189Smrg    ppAwait = malloc(numwaits * sizeof(SyncAwait *));
54205b261ecSmrg    if (!ppAwait)
54305b261ecSmrg	goto bail;
54405b261ecSmrg
54505b261ecSmrg    pAwait = &(pAwaitUnion+1)->await;
54605b261ecSmrg
54705b261ecSmrg    /* "When a client is unblocked, all the CounterNotify events for
54805b261ecSmrg     *  the Await request are generated contiguously. If count is 0
54905b261ecSmrg     *  there are no more events to follow for this request. If
55005b261ecSmrg     *  count is n, there are at least n more events to follow."
55105b261ecSmrg     *
55205b261ecSmrg     *  Thus, it is best to find all the counters for which events
55305b261ecSmrg     *  need to be sent first, so that an accurate count field can
55405b261ecSmrg     *  be stored in the events.
55505b261ecSmrg     */
55605b261ecSmrg    for ( ; numwaits; numwaits--, pAwait++)
55705b261ecSmrg    {
55805b261ecSmrg	CARD64 diff;
55905b261ecSmrg	Bool overflow, diffgreater, diffequal;
56005b261ecSmrg
56105b261ecSmrg	/* "A CounterNotify event with the destroyed flag set to TRUE is
56205b261ecSmrg	 *  always generated if the counter for one of the triggers is
56305b261ecSmrg	 *  destroyed."
56405b261ecSmrg	 */
56505b261ecSmrg	if (pAwait->trigger.pCounter->beingDestroyed)
56605b261ecSmrg	{
56705b261ecSmrg	    ppAwait[num_events++] = pAwait;
56805b261ecSmrg	    continue;
56905b261ecSmrg	}
57005b261ecSmrg
57105b261ecSmrg	/* "The difference between the counter and the test value is
57205b261ecSmrg	 *  calculated by subtracting the test value from the value of
57305b261ecSmrg	 *  the counter."
57405b261ecSmrg	 */
57505b261ecSmrg	XSyncValueSubtract(&diff, pAwait->trigger.pCounter->value,
57605b261ecSmrg			   pAwait->trigger.test_value, &overflow);
57705b261ecSmrg
57805b261ecSmrg	/* "If the difference lies outside the range for an INT64, an
57905b261ecSmrg	 *  event is not generated."
58005b261ecSmrg	 */
58105b261ecSmrg	if (overflow)
58205b261ecSmrg	    continue;
58305b261ecSmrg	diffgreater = XSyncValueGreaterThan(diff, pAwait->event_threshold);
58405b261ecSmrg	diffequal   = XSyncValueEqual(diff, pAwait->event_threshold);
58505b261ecSmrg
58605b261ecSmrg	/* "If the test-type is PositiveTransition or
58705b261ecSmrg	 *  PositiveComparison, a CounterNotify event is generated if
58805b261ecSmrg	 *  the difference is at least event-threshold. If the test-type
58905b261ecSmrg	 *  is NegativeTransition or NegativeComparison, a CounterNotify
59005b261ecSmrg	 *  event is generated if the difference is at most
59105b261ecSmrg	 *  event-threshold."
59205b261ecSmrg	 */
59305b261ecSmrg
59405b261ecSmrg	if ( ((pAwait->trigger.test_type == XSyncPositiveComparison ||
59505b261ecSmrg	       pAwait->trigger.test_type == XSyncPositiveTransition)
59605b261ecSmrg	       && (diffgreater || diffequal))
59705b261ecSmrg	     ||
59805b261ecSmrg	     ((pAwait->trigger.test_type == XSyncNegativeComparison ||
59905b261ecSmrg	       pAwait->trigger.test_type == XSyncNegativeTransition)
60005b261ecSmrg	      && (!diffgreater) /* less or equal */
60105b261ecSmrg	      )
60205b261ecSmrg	   )
60305b261ecSmrg	{
60405b261ecSmrg	    ppAwait[num_events++] = pAwait;
60505b261ecSmrg	}
60605b261ecSmrg    }
60705b261ecSmrg    if (num_events)
60805b261ecSmrg	SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait,
60905b261ecSmrg				    num_events);
6104202a189Smrg    free(ppAwait);
61105b261ecSmrg
61205b261ecSmrgbail:
61305b261ecSmrg    /* unblock the client */
61405b261ecSmrg    AttendClient(pAwaitUnion->header.client);
61505b261ecSmrg    /* delete the await */
61605b261ecSmrg    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
61705b261ecSmrg}
61805b261ecSmrg
61905b261ecSmrg
62005b261ecSmrg/*  This function should always be used to change a counter's value so that
62105b261ecSmrg *  any triggers depending on the counter will be checked.
62205b261ecSmrg */
62305b261ecSmrgvoid
6244202a189SmrgSyncChangeCounter(SyncCounter *pCounter, CARD64 newval)
62505b261ecSmrg{
62605b261ecSmrg    SyncTriggerList       *ptl, *pnext;
62705b261ecSmrg    CARD64 oldval;
62805b261ecSmrg
62905b261ecSmrg    oldval = pCounter->value;
63005b261ecSmrg    pCounter->value = newval;
63105b261ecSmrg
63205b261ecSmrg    /* run through triggers to see if any become true */
63305b261ecSmrg    for (ptl = pCounter->pTriglist; ptl; ptl = pnext)
63405b261ecSmrg    {
63505b261ecSmrg	pnext = ptl->next;
63605b261ecSmrg	if ((*ptl->pTrigger->CheckTrigger)(ptl->pTrigger, oldval))
63705b261ecSmrg	    (*ptl->pTrigger->TriggerFired)(ptl->pTrigger);
63805b261ecSmrg    }
63905b261ecSmrg
64005b261ecSmrg    if (IsSystemCounter(pCounter))
64105b261ecSmrg    {
6424202a189Smrg	SyncComputeBracketValues(pCounter);
64305b261ecSmrg    }
64405b261ecSmrg}
64505b261ecSmrg
64605b261ecSmrg
64705b261ecSmrg/* loosely based on dix/events.c/EventSelectForWindow */
64805b261ecSmrgstatic Bool
6494202a189SmrgSyncEventSelectForAlarm(SyncAlarm *pAlarm, ClientPtr client, Bool wantevents)
65005b261ecSmrg{
65105b261ecSmrg    SyncAlarmClientList *pClients;
65205b261ecSmrg
65305b261ecSmrg    if (client == pAlarm->client) /* alarm owner */
65405b261ecSmrg    {
65505b261ecSmrg	pAlarm->events = wantevents;
65605b261ecSmrg	return Success;
65705b261ecSmrg    }
65805b261ecSmrg
65905b261ecSmrg    /* see if the client is already on the list (has events selected) */
66005b261ecSmrg
66105b261ecSmrg    for (pClients = pAlarm->pEventClients; pClients;
66205b261ecSmrg	 pClients = pClients->next)
66305b261ecSmrg    {
66405b261ecSmrg	if (pClients->client == client)
66505b261ecSmrg	{
6664202a189Smrg	    /* client's presence on the list indicates desire for
6674202a189Smrg	     * events.  If the client doesn't want events, remove it
66805b261ecSmrg	     * from the list.  If the client does want events, do
66905b261ecSmrg	     * nothing, since it's already got them.
67005b261ecSmrg	     */
67105b261ecSmrg	    if (!wantevents)
67205b261ecSmrg	    {
67305b261ecSmrg		FreeResource(pClients->delete_id, RT_NONE);
67405b261ecSmrg	    }
67505b261ecSmrg	    return Success;
67605b261ecSmrg	}
67705b261ecSmrg    }
67805b261ecSmrg
67905b261ecSmrg    /*  if we get here, this client does not currently have
68005b261ecSmrg     *  events selected on the alarm
68105b261ecSmrg     */
68205b261ecSmrg
68305b261ecSmrg    if (!wantevents)
6844202a189Smrg	/* client doesn't want events, and we just discovered that it
68505b261ecSmrg	 * doesn't have them, so there's nothing to do.
68605b261ecSmrg	 */
68705b261ecSmrg	return Success;
68805b261ecSmrg
68905b261ecSmrg    /* add new client to pAlarm->pEventClients */
69005b261ecSmrg
6914202a189Smrg    pClients = malloc(sizeof(SyncAlarmClientList));
69205b261ecSmrg    if (!pClients)
69305b261ecSmrg	return BadAlloc;
69405b261ecSmrg
6954202a189Smrg    /*  register it as a resource so it will be cleaned up
69605b261ecSmrg     *  if the client dies
69705b261ecSmrg     */
69805b261ecSmrg
69905b261ecSmrg    pClients->delete_id = FakeClientID(client->index);
70005b261ecSmrg    if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm))
70105b261ecSmrg    {
7024202a189Smrg	free(pClients);
70305b261ecSmrg	return BadAlloc;
70405b261ecSmrg    }
70505b261ecSmrg
70605b261ecSmrg    /* link it into list after we know all the allocations succeed */
70705b261ecSmrg
70805b261ecSmrg    pClients->next = pAlarm->pEventClients;
70905b261ecSmrg    pAlarm->pEventClients = pClients;
71005b261ecSmrg    pClients->client = client;
71105b261ecSmrg    return Success;
71205b261ecSmrg}
71305b261ecSmrg
71405b261ecSmrg/*
71505b261ecSmrg * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm
71605b261ecSmrg */
7174202a189Smrgstatic int
7184202a189SmrgSyncChangeAlarmAttributes(ClientPtr client, SyncAlarm *pAlarm, Mask mask,
7194202a189Smrg			  CARD32 *values)
72005b261ecSmrg{
72105b261ecSmrg    int		   status;
72205b261ecSmrg    XSyncCounter   counter;
72305b261ecSmrg    Mask	   origmask = mask;
72405b261ecSmrg
72505b261ecSmrg    counter = pAlarm->trigger.pCounter ? pAlarm->trigger.pCounter->id : None;
72605b261ecSmrg
72705b261ecSmrg    while (mask)
72805b261ecSmrg    {
72905b261ecSmrg	int    index2 = lowbit(mask);
73005b261ecSmrg	mask &= ~index2;
73105b261ecSmrg	switch (index2)
73205b261ecSmrg	{
73305b261ecSmrg	  case XSyncCACounter:
73405b261ecSmrg	    mask &= ~XSyncCACounter;
73505b261ecSmrg	    /* sanity check in SyncInitTrigger */
73605b261ecSmrg	    counter = *values++;
73705b261ecSmrg	    break;
73805b261ecSmrg
73905b261ecSmrg	  case XSyncCAValueType:
74005b261ecSmrg	    mask &= ~XSyncCAValueType;
74105b261ecSmrg	    /* sanity check in SyncInitTrigger */
74205b261ecSmrg	    pAlarm->trigger.value_type = *values++;
74305b261ecSmrg	    break;
74405b261ecSmrg
74505b261ecSmrg	  case XSyncCAValue:
74605b261ecSmrg	    mask &= ~XSyncCAValue;
74705b261ecSmrg	    XSyncIntsToValue(&pAlarm->trigger.wait_value, values[1], values[0]);
74805b261ecSmrg	    values += 2;
74905b261ecSmrg	    break;
75005b261ecSmrg
75105b261ecSmrg	  case XSyncCATestType:
75205b261ecSmrg	    mask &= ~XSyncCATestType;
75305b261ecSmrg	    /* sanity check in SyncInitTrigger */
75405b261ecSmrg	    pAlarm->trigger.test_type = *values++;
75505b261ecSmrg	    break;
75605b261ecSmrg
75705b261ecSmrg	  case XSyncCADelta:
75805b261ecSmrg	    mask &= ~XSyncCADelta;
75905b261ecSmrg	    XSyncIntsToValue(&pAlarm->delta, values[1], values[0]);
76005b261ecSmrg	    values += 2;
76105b261ecSmrg	    break;
76205b261ecSmrg
76305b261ecSmrg	  case XSyncCAEvents:
76405b261ecSmrg	    mask &= ~XSyncCAEvents;
76505b261ecSmrg	    if ((*values != xTrue) && (*values != xFalse))
76605b261ecSmrg	    {
76705b261ecSmrg		client->errorValue = *values;
76805b261ecSmrg		return BadValue;
76905b261ecSmrg	    }
77005b261ecSmrg	    status = SyncEventSelectForAlarm(pAlarm, client,
77105b261ecSmrg					     (Bool)(*values++));
77205b261ecSmrg	    if (status != Success)
77305b261ecSmrg		return status;
77405b261ecSmrg	    break;
77505b261ecSmrg
77605b261ecSmrg	  default:
77705b261ecSmrg	    client->errorValue = mask;
77805b261ecSmrg	    return BadValue;
77905b261ecSmrg	}
78005b261ecSmrg    }
78105b261ecSmrg
78205b261ecSmrg    /* "If the test-type is PositiveComparison or PositiveTransition
78305b261ecSmrg     *  and delta is less than zero, or if the test-type is
78405b261ecSmrg     *  NegativeComparison or NegativeTransition and delta is
78505b261ecSmrg     *  greater than zero, a Match error is generated."
78605b261ecSmrg     */
78705b261ecSmrg    if (origmask & (XSyncCADelta|XSyncCATestType))
78805b261ecSmrg    {
78905b261ecSmrg	CARD64 zero;
79005b261ecSmrg	XSyncIntToValue(&zero, 0);
79105b261ecSmrg	if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) ||
79205b261ecSmrg	      (pAlarm->trigger.test_type == XSyncPositiveTransition))
79305b261ecSmrg	     && XSyncValueLessThan(pAlarm->delta, zero))
79405b261ecSmrg	    ||
79505b261ecSmrg	    (((pAlarm->trigger.test_type == XSyncNegativeComparison) ||
79605b261ecSmrg	      (pAlarm->trigger.test_type == XSyncNegativeTransition))
79705b261ecSmrg	     && XSyncValueGreaterThan(pAlarm->delta, zero))
79805b261ecSmrg	   )
79905b261ecSmrg	{
80005b261ecSmrg	    return BadMatch;
80105b261ecSmrg	}
80205b261ecSmrg    }
80305b261ecSmrg
80405b261ecSmrg    /* postpone this until now, when we're sure nothing else can go wrong */
80505b261ecSmrg    if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter,
80605b261ecSmrg			     origmask & XSyncCAAllTrigger)) != Success)
80705b261ecSmrg	return status;
80805b261ecSmrg
80905b261ecSmrg    /* XXX spec does not really say to do this - needs clarification */
81005b261ecSmrg    pAlarm->state = XSyncAlarmActive;
81105b261ecSmrg    return Success;
81205b261ecSmrg}
81305b261ecSmrg
81405b261ecSmrg
81505b261ecSmrgstatic SyncCounter *
8164202a189SmrgSyncCreateCounter(ClientPtr client, XSyncCounter id, CARD64 initialvalue)
81705b261ecSmrg{
81805b261ecSmrg    SyncCounter *pCounter;
81905b261ecSmrg
8204202a189Smrg    if (!(pCounter = malloc(sizeof(SyncCounter))))
8214202a189Smrg	return NULL;
82205b261ecSmrg
82305b261ecSmrg    if (!AddResource(id, RTCounter, (pointer) pCounter))
82405b261ecSmrg    {
8254202a189Smrg	free(pCounter);
8264202a189Smrg	return NULL;
82705b261ecSmrg    }
82805b261ecSmrg
82905b261ecSmrg    pCounter->client = client;
83005b261ecSmrg    pCounter->id = id;
83105b261ecSmrg    pCounter->value = initialvalue;
83205b261ecSmrg    pCounter->pTriglist = NULL;
83305b261ecSmrg    pCounter->beingDestroyed = FALSE;
83405b261ecSmrg    pCounter->pSysCounterInfo = NULL;
83505b261ecSmrg    return pCounter;
83605b261ecSmrg}
83705b261ecSmrg
8384202a189Smrgstatic int FreeCounter(void *, XID);
83905b261ecSmrg
84005b261ecSmrg/*
84105b261ecSmrg * ***** System Counter utilities
84205b261ecSmrg */
84305b261ecSmrg
8444202a189Smrgpointer
8454202a189SmrgSyncCreateSystemCounter(
8464202a189Smrg	char *name,
8474202a189Smrg	CARD64 initial,
8484202a189Smrg	CARD64 resolution,
8494202a189Smrg	SyncCounterType counterType,
8504202a189Smrg	void (*QueryValue)(pointer /* pCounter */,
8514202a189Smrg	      	           CARD64 * /* pValue_return */),
8524202a189Smrg	void (*BracketValues)(pointer /* pCounter */,
8534202a189Smrg	       	              CARD64 * /* pbracket_less */,
8544202a189Smrg	                      CARD64 * /* pbracket_greater */)
8554202a189Smrg	)
85605b261ecSmrg{
85705b261ecSmrg    SyncCounter    *pCounter;
85805b261ecSmrg
8594202a189Smrg    SysCounterList = realloc(SysCounterList,
86005b261ecSmrg			    (SyncNumSystemCounters+1)*sizeof(SyncCounter *));
86105b261ecSmrg    if (!SysCounterList)
8624202a189Smrg	return NULL;
86305b261ecSmrg
86405b261ecSmrg    /* this function may be called before SYNC has been initialized, so we
86505b261ecSmrg     * have to make sure RTCounter is created.
86605b261ecSmrg     */
86705b261ecSmrg    if (RTCounter == 0)
86805b261ecSmrg    {
8694202a189Smrg	RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
87005b261ecSmrg	if (RTCounter == 0)
87105b261ecSmrg	{
8724202a189Smrg	    return NULL;
87305b261ecSmrg	}
87405b261ecSmrg    }
87505b261ecSmrg
8764202a189Smrg    pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial);
87705b261ecSmrg
87805b261ecSmrg    if (pCounter)
87905b261ecSmrg    {
88005b261ecSmrg	SysCounterInfo *psci;
88105b261ecSmrg
8824202a189Smrg	psci = malloc(sizeof(SysCounterInfo));
88305b261ecSmrg	if (!psci)
88405b261ecSmrg	{
88505b261ecSmrg	    FreeResource(pCounter->id, RT_NONE);
8864202a189Smrg	    return pCounter;
88705b261ecSmrg	}
88805b261ecSmrg	pCounter->pSysCounterInfo = psci;
88905b261ecSmrg	psci->name = name;
89005b261ecSmrg	psci->resolution = resolution;
89105b261ecSmrg	psci->counterType = counterType;
89205b261ecSmrg	psci->QueryValue = QueryValue;
89305b261ecSmrg	psci->BracketValues = BracketValues;
89405b261ecSmrg	XSyncMaxValue(&psci->bracket_greater);
89505b261ecSmrg	XSyncMinValue(&psci->bracket_less);
89605b261ecSmrg	SysCounterList[SyncNumSystemCounters++] = pCounter;
89705b261ecSmrg    }
8984202a189Smrg    return pCounter;
89905b261ecSmrg}
90005b261ecSmrg
90105b261ecSmrgvoid
9024202a189SmrgSyncDestroySystemCounter(pointer pSysCounter)
90305b261ecSmrg{
90405b261ecSmrg    SyncCounter *pCounter = (SyncCounter *)pSysCounter;
90505b261ecSmrg    FreeResource(pCounter->id, RT_NONE);
90605b261ecSmrg}
90705b261ecSmrg
90805b261ecSmrgstatic void
9094202a189SmrgSyncComputeBracketValues(SyncCounter *pCounter)
91005b261ecSmrg{
91105b261ecSmrg    SyncTriggerList *pCur;
91205b261ecSmrg    SyncTrigger *pTrigger;
91305b261ecSmrg    SysCounterInfo *psci;
91405b261ecSmrg    CARD64 *pnewgtval = NULL;
91505b261ecSmrg    CARD64 *pnewltval = NULL;
91605b261ecSmrg    SyncCounterType ct;
91705b261ecSmrg
91805b261ecSmrg    if (!pCounter)
91905b261ecSmrg	return;
92005b261ecSmrg
92105b261ecSmrg    psci = pCounter->pSysCounterInfo;
92205b261ecSmrg    ct = pCounter->pSysCounterInfo->counterType;
92305b261ecSmrg    if (ct == XSyncCounterNeverChanges)
92405b261ecSmrg	return;
92505b261ecSmrg
9264202a189Smrg    XSyncMaxValue(&psci->bracket_greater);
9274202a189Smrg    XSyncMinValue(&psci->bracket_less);
92805b261ecSmrg
92905b261ecSmrg    for (pCur = pCounter->pTriglist; pCur; pCur = pCur->next)
93005b261ecSmrg    {
93105b261ecSmrg	pTrigger = pCur->pTrigger;
93205b261ecSmrg
93305b261ecSmrg        if (pTrigger->test_type == XSyncPositiveComparison &&
93405b261ecSmrg	    ct != XSyncCounterNeverIncreases)
93505b261ecSmrg	{
93605b261ecSmrg	    if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
93705b261ecSmrg		XSyncValueLessThan(pTrigger->test_value,
93805b261ecSmrg				   psci->bracket_greater))
93905b261ecSmrg	    {
94005b261ecSmrg		psci->bracket_greater = pTrigger->test_value;
94105b261ecSmrg		pnewgtval = &psci->bracket_greater;
94205b261ecSmrg	    }
94305b261ecSmrg	}
94405b261ecSmrg	else if (pTrigger->test_type == XSyncNegativeComparison &&
94505b261ecSmrg		 ct != XSyncCounterNeverDecreases)
94605b261ecSmrg	{
94705b261ecSmrg	    if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
94805b261ecSmrg		XSyncValueGreaterThan(pTrigger->test_value,
94905b261ecSmrg				      psci->bracket_less))
95005b261ecSmrg	    {
95105b261ecSmrg		psci->bracket_less = pTrigger->test_value;
95205b261ecSmrg		pnewltval = &psci->bracket_less;
95305b261ecSmrg	    }
95405b261ecSmrg	}
955a0d10bb6Smrg	else if (pTrigger->test_type == XSyncNegativeTransition &&
95605b261ecSmrg		   ct != XSyncCounterNeverIncreases)
957a0d10bb6Smrg	{
958a0d10bb6Smrg	    if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
959a0d10bb6Smrg		XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less))
960a0d10bb6Smrg	    {
961a0d10bb6Smrg		psci->bracket_less = pTrigger->test_value;
962a0d10bb6Smrg		pnewltval = &psci->bracket_less;
9631b684552Smrg	    } else if (XSyncValueEqual(pCounter->value, pTrigger->test_value) &&
9641b684552Smrg		       XSyncValueLessThan(pTrigger->test_value,
9651b684552Smrg					  psci->bracket_greater))
9661b684552Smrg	    {
9671b684552Smrg	        /*
9681b684552Smrg		 * The value is exactly equal to our threshold.  We want one
9691b684552Smrg		 * more event in the positive direction to ensure we pick up
9701b684552Smrg		 * when the value *exceeds* this threshold.
9711b684552Smrg		 */
9721b684552Smrg	        psci->bracket_greater = pTrigger->test_value;
9731b684552Smrg		pnewgtval = &psci->bracket_greater;
974a0d10bb6Smrg	    }
975a0d10bb6Smrg	}
976a0d10bb6Smrg        else if (pTrigger->test_type == XSyncPositiveTransition &&
97705b261ecSmrg		  ct != XSyncCounterNeverDecreases)
97805b261ecSmrg	{
979a0d10bb6Smrg	    if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
980a0d10bb6Smrg		XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater))
98105b261ecSmrg	    {
982a0d10bb6Smrg		psci->bracket_greater = pTrigger->test_value;
983a0d10bb6Smrg		pnewgtval = &psci->bracket_greater;
9841b684552Smrg	    } else if (XSyncValueEqual(pCounter->value, pTrigger->test_value) &&
9851b684552Smrg		       XSyncValueGreaterThan(pTrigger->test_value,
9861b684552Smrg					     psci->bracket_less))
9871b684552Smrg	    {
9881b684552Smrg	        /*
9891b684552Smrg		 * The value is exactly equal to our threshold.  We want one
9901b684552Smrg		 * more event in the negative direction to ensure we pick up
9911b684552Smrg		 * when the value is less than this threshold.
9921b684552Smrg		 */
9931b684552Smrg	        psci->bracket_less = pTrigger->test_value;
9941b684552Smrg		pnewltval = &psci->bracket_less;
99505b261ecSmrg	    }
99605b261ecSmrg	}
99705b261ecSmrg    } /* end for each trigger */
99805b261ecSmrg
99905b261ecSmrg    if (pnewgtval || pnewltval)
100005b261ecSmrg    {
100105b261ecSmrg	(*psci->BracketValues)((pointer)pCounter, pnewltval, pnewgtval);
100205b261ecSmrg    }
100305b261ecSmrg}
100405b261ecSmrg
100505b261ecSmrg/*
100605b261ecSmrg * *****  Resource delete functions
100705b261ecSmrg */
100805b261ecSmrg
100905b261ecSmrg/* ARGSUSED */
101005b261ecSmrgstatic int
10114202a189SmrgFreeAlarm(void *addr, XID id)
101205b261ecSmrg{
101305b261ecSmrg    SyncAlarm      *pAlarm = (SyncAlarm *) addr;
101405b261ecSmrg
101505b261ecSmrg    pAlarm->state = XSyncAlarmDestroyed;
101605b261ecSmrg
101705b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
101805b261ecSmrg
101905b261ecSmrg    /* delete event selections */
102005b261ecSmrg
102105b261ecSmrg    while (pAlarm->pEventClients)
102205b261ecSmrg	FreeResource(pAlarm->pEventClients->delete_id, RT_NONE);
102305b261ecSmrg
102405b261ecSmrg    SyncDeleteTriggerFromCounter(&pAlarm->trigger);
102505b261ecSmrg
10264202a189Smrg    free(pAlarm);
102705b261ecSmrg    return Success;
102805b261ecSmrg}
102905b261ecSmrg
103005b261ecSmrg
103105b261ecSmrg/*
103205b261ecSmrg * ** Cleanup after the destruction of a Counter
103305b261ecSmrg */
103405b261ecSmrg/* ARGSUSED */
103505b261ecSmrgstatic int
10364202a189SmrgFreeCounter(void *env, XID id)
103705b261ecSmrg{
103805b261ecSmrg    SyncCounter     *pCounter = (SyncCounter *) env;
103905b261ecSmrg    SyncTriggerList *ptl, *pnext;
104005b261ecSmrg
104105b261ecSmrg    pCounter->beingDestroyed = TRUE;
104205b261ecSmrg    /* tell all the counter's triggers that the counter has been destroyed */
104305b261ecSmrg    for (ptl = pCounter->pTriglist; ptl; ptl = pnext)
104405b261ecSmrg    {
104505b261ecSmrg	(*ptl->pTrigger->CounterDestroyed)(ptl->pTrigger);
104605b261ecSmrg	pnext = ptl->next;
10474202a189Smrg	free(ptl); /* destroy the trigger list as we go */
104805b261ecSmrg    }
104905b261ecSmrg    if (IsSystemCounter(pCounter))
105005b261ecSmrg    {
105105b261ecSmrg	int i, found = 0;
105205b261ecSmrg
10534202a189Smrg	free(pCounter->pSysCounterInfo);
105405b261ecSmrg
105505b261ecSmrg	/* find the counter in the list of system counters and remove it */
105605b261ecSmrg
105705b261ecSmrg	if (SysCounterList)
105805b261ecSmrg	{
105905b261ecSmrg	    for (i = 0; i < SyncNumSystemCounters; i++)
106005b261ecSmrg	    {
106105b261ecSmrg		if (SysCounterList[i] == pCounter)
106205b261ecSmrg		{
106305b261ecSmrg		    found = i;
106405b261ecSmrg		    break;
106505b261ecSmrg		}
106605b261ecSmrg	    }
106705b261ecSmrg	    if (found < (SyncNumSystemCounters-1))
106805b261ecSmrg	    {
106905b261ecSmrg		for (i = found; i < SyncNumSystemCounters-1; i++)
107005b261ecSmrg		{
107105b261ecSmrg		    SysCounterList[i] = SysCounterList[i+1];
107205b261ecSmrg		}
107305b261ecSmrg	    }
107405b261ecSmrg	}
107505b261ecSmrg	SyncNumSystemCounters--;
107605b261ecSmrg    }
10774202a189Smrg    free(pCounter);
107805b261ecSmrg    return Success;
107905b261ecSmrg}
108005b261ecSmrg
108105b261ecSmrg/*
108205b261ecSmrg * ** Cleanup after Await
108305b261ecSmrg */
108405b261ecSmrg/* ARGSUSED */
108505b261ecSmrgstatic int
10864202a189SmrgFreeAwait(void *addr, XID id)
108705b261ecSmrg{
108805b261ecSmrg    SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr;
108905b261ecSmrg    SyncAwait *pAwait;
109005b261ecSmrg    int numwaits;
109105b261ecSmrg
109205b261ecSmrg    pAwait = &(pAwaitUnion+1)->await; /* first await on list */
109305b261ecSmrg
109405b261ecSmrg    /* remove triggers from counters */
109505b261ecSmrg
109605b261ecSmrg    for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits;
109705b261ecSmrg	 numwaits--, pAwait++)
109805b261ecSmrg    {
10994202a189Smrg	/* If the counter is being destroyed, FreeCounter will delete
110005b261ecSmrg	 * the trigger list itself, so don't do it here.
110105b261ecSmrg	 */
110205b261ecSmrg	SyncCounter *pCounter = pAwait->trigger.pCounter;
110305b261ecSmrg	if (pCounter && !pCounter->beingDestroyed)
110405b261ecSmrg	    SyncDeleteTriggerFromCounter(&pAwait->trigger);
110505b261ecSmrg    }
11064202a189Smrg    free(pAwaitUnion);
110705b261ecSmrg    return Success;
110805b261ecSmrg}
110905b261ecSmrg
111005b261ecSmrg/* loosely based on dix/events.c/OtherClientGone */
111105b261ecSmrgstatic int
11124202a189SmrgFreeAlarmClient(void *value, XID id)
111305b261ecSmrg{
111405b261ecSmrg    SyncAlarm *pAlarm = (SyncAlarm *)value;
111505b261ecSmrg    SyncAlarmClientList *pCur, *pPrev;
111605b261ecSmrg
111705b261ecSmrg    for (pPrev = NULL, pCur = pAlarm->pEventClients;
111805b261ecSmrg	 pCur;
111905b261ecSmrg	 pPrev = pCur, pCur = pCur->next)
112005b261ecSmrg    {
112105b261ecSmrg	if (pCur->delete_id == id)
112205b261ecSmrg	{
112305b261ecSmrg	    if (pPrev)
112405b261ecSmrg		pPrev->next = pCur->next;
112505b261ecSmrg	    else
112605b261ecSmrg		pAlarm->pEventClients = pCur->next;
11274202a189Smrg	    free(pCur);
11284202a189Smrg	    return Success;
112905b261ecSmrg	}
113005b261ecSmrg    }
113105b261ecSmrg    FatalError("alarm client not on event list");
113205b261ecSmrg    /*NOTREACHED*/
113305b261ecSmrg}
113405b261ecSmrg
113505b261ecSmrg
113605b261ecSmrg/*
113705b261ecSmrg * *****  Proc functions
113805b261ecSmrg */
113905b261ecSmrg
114005b261ecSmrg
114105b261ecSmrg/*
114205b261ecSmrg * ** Initialize the extension
114305b261ecSmrg */
11444202a189Smrgstatic int
11454202a189SmrgProcSyncInitialize(ClientPtr client)
114605b261ecSmrg{
114705b261ecSmrg    xSyncInitializeReply  rep;
114805b261ecSmrg    int   n;
114905b261ecSmrg
115005b261ecSmrg    REQUEST_SIZE_MATCH(xSyncInitializeReq);
115105b261ecSmrg
11524202a189Smrg    memset(&rep, 0, sizeof(xSyncInitializeReply));
115305b261ecSmrg    rep.type = X_Reply;
115405b261ecSmrg    rep.sequenceNumber = client->sequence;
11551b684552Smrg    rep.majorVersion = SERVER_SYNC_MAJOR_VERSION;
11561b684552Smrg    rep.minorVersion = SERVER_SYNC_MINOR_VERSION;
115705b261ecSmrg    rep.length = 0;
115805b261ecSmrg
115905b261ecSmrg    if (client->swapped)
116005b261ecSmrg    {
116105b261ecSmrg	swaps(&rep.sequenceNumber, n);
116205b261ecSmrg    }
116305b261ecSmrg    WriteToClient(client, sizeof(rep), (char *) &rep);
11644202a189Smrg    return Success;
116505b261ecSmrg}
116605b261ecSmrg
116705b261ecSmrg/*
116805b261ecSmrg * ** Get list of system counters available through the extension
116905b261ecSmrg */
11704202a189Smrgstatic int
11714202a189SmrgProcSyncListSystemCounters(ClientPtr client)
117205b261ecSmrg{
117305b261ecSmrg    xSyncListSystemCountersReply  rep;
117405b261ecSmrg    int i, len;
117505b261ecSmrg    xSyncSystemCounter *list = NULL, *walklist = NULL;
11764202a189Smrg
117705b261ecSmrg    REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
117805b261ecSmrg
117905b261ecSmrg    rep.type = X_Reply;
118005b261ecSmrg    rep.sequenceNumber = client->sequence;
118105b261ecSmrg    rep.nCounters = SyncNumSystemCounters;
118205b261ecSmrg
118305b261ecSmrg    for (i = len = 0; i < SyncNumSystemCounters; i++)
118405b261ecSmrg    {
118505b261ecSmrg	char *name = SysCounterList[i]->pSysCounterInfo->name;
118605b261ecSmrg	/* pad to 4 byte boundary */
11874202a189Smrg	len += pad_to_int32(sz_xSyncSystemCounter + strlen(name));
118805b261ecSmrg    }
118905b261ecSmrg
119005b261ecSmrg    if (len)
119105b261ecSmrg    {
11924202a189Smrg	walklist = list = malloc(len);
119305b261ecSmrg	if (!list)
119405b261ecSmrg	    return BadAlloc;
119505b261ecSmrg    }
119605b261ecSmrg
11974202a189Smrg    rep.length = bytes_to_int32(len);
119805b261ecSmrg
119905b261ecSmrg    if (client->swapped)
120005b261ecSmrg    {
1201637ac9abSmrg	char n;
120205b261ecSmrg	swaps(&rep.sequenceNumber, n);
120305b261ecSmrg	swapl(&rep.length, n);
120405b261ecSmrg	swapl(&rep.nCounters, n);
120505b261ecSmrg    }
120605b261ecSmrg
120705b261ecSmrg    for (i = 0; i < SyncNumSystemCounters; i++)
120805b261ecSmrg    {
120905b261ecSmrg	int namelen;
121005b261ecSmrg	char *pname_in_reply;
121105b261ecSmrg	SysCounterInfo *psci = SysCounterList[i]->pSysCounterInfo;
121205b261ecSmrg
121305b261ecSmrg	walklist->counter = SysCounterList[i]->id;
121405b261ecSmrg	walklist->resolution_hi = XSyncValueHigh32(psci->resolution);
121505b261ecSmrg	walklist->resolution_lo = XSyncValueLow32(psci->resolution);
121605b261ecSmrg	namelen = strlen(psci->name);
121705b261ecSmrg	walklist->name_length = namelen;
121805b261ecSmrg
121905b261ecSmrg	if (client->swapped)
122005b261ecSmrg	{
1221637ac9abSmrg	    char n;
122205b261ecSmrg	    swapl(&walklist->counter, n);
122305b261ecSmrg	    swapl(&walklist->resolution_hi, n);
122405b261ecSmrg	    swapl(&walklist->resolution_lo, n);
122505b261ecSmrg	    swaps(&walklist->name_length, n);
122605b261ecSmrg	}
122705b261ecSmrg
122805b261ecSmrg	pname_in_reply = ((char *)walklist) + sz_xSyncSystemCounter;
122905b261ecSmrg	strncpy(pname_in_reply, psci->name, namelen);
12304202a189Smrg	walklist = (xSyncSystemCounter *) (((char *)walklist) +
12314202a189Smrg				pad_to_int32(sz_xSyncSystemCounter + namelen));
123205b261ecSmrg    }
123305b261ecSmrg
123405b261ecSmrg    WriteToClient(client, sizeof(rep), (char *) &rep);
12354202a189Smrg    if (len)
123605b261ecSmrg    {
123705b261ecSmrg	WriteToClient(client, len, (char *) list);
12384202a189Smrg	free(list);
123905b261ecSmrg    }
124005b261ecSmrg
12414202a189Smrg    return Success;
124205b261ecSmrg}
124305b261ecSmrg
124405b261ecSmrg/*
124505b261ecSmrg * ** Set client Priority
124605b261ecSmrg */
12474202a189Smrgstatic int
12484202a189SmrgProcSyncSetPriority(ClientPtr client)
124905b261ecSmrg{
125005b261ecSmrg    REQUEST(xSyncSetPriorityReq);
125105b261ecSmrg    ClientPtr priorityclient;
125205b261ecSmrg    int rc;
125305b261ecSmrg
125405b261ecSmrg    REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
125505b261ecSmrg
125605b261ecSmrg    if (stuff->id == None)
125705b261ecSmrg	priorityclient = client;
125805b261ecSmrg    else {
125905b261ecSmrg	rc = dixLookupClient(&priorityclient, stuff->id, client,
1260637ac9abSmrg			     DixSetAttrAccess);
126105b261ecSmrg	if (rc != Success)
126205b261ecSmrg	    return rc;
126305b261ecSmrg    }
126405b261ecSmrg
126505b261ecSmrg    if (priorityclient->priority != stuff->priority)
126605b261ecSmrg    {
126705b261ecSmrg	priorityclient->priority = stuff->priority;
126805b261ecSmrg
126905b261ecSmrg	/*  The following will force the server back into WaitForSomething
127005b261ecSmrg	 *  so that the change in this client's priority is immediately
127105b261ecSmrg	 *  reflected.
127205b261ecSmrg	 */
127305b261ecSmrg	isItTimeToYield = TRUE;
127405b261ecSmrg	dispatchException |= DE_PRIORITYCHANGE;
127505b261ecSmrg    }
127605b261ecSmrg    return Success;
127705b261ecSmrg}
127805b261ecSmrg
127905b261ecSmrg/*
128005b261ecSmrg * ** Get client Priority
128105b261ecSmrg */
12824202a189Smrgstatic int
12834202a189SmrgProcSyncGetPriority(ClientPtr client)
128405b261ecSmrg{
128505b261ecSmrg    REQUEST(xSyncGetPriorityReq);
128605b261ecSmrg    xSyncGetPriorityReply rep;
128705b261ecSmrg    ClientPtr priorityclient;
128805b261ecSmrg    int rc;
128905b261ecSmrg
129005b261ecSmrg    REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
129105b261ecSmrg
129205b261ecSmrg    if (stuff->id == None)
129305b261ecSmrg	priorityclient = client;
129405b261ecSmrg    else {
129505b261ecSmrg	rc = dixLookupClient(&priorityclient, stuff->id, client,
1296637ac9abSmrg			     DixGetAttrAccess);
129705b261ecSmrg	if (rc != Success)
129805b261ecSmrg	    return rc;
129905b261ecSmrg    }
130005b261ecSmrg
130105b261ecSmrg    rep.type = X_Reply;
130205b261ecSmrg    rep.length = 0;
130305b261ecSmrg    rep.sequenceNumber = client->sequence;
130405b261ecSmrg    rep.priority = priorityclient->priority;
130505b261ecSmrg
130605b261ecSmrg    if (client->swapped)
130705b261ecSmrg    {
1308637ac9abSmrg	char n;
130905b261ecSmrg	swaps(&rep.sequenceNumber, n);
131005b261ecSmrg	swapl(&rep.priority, n);
131105b261ecSmrg    }
131205b261ecSmrg
131305b261ecSmrg    WriteToClient(client, sizeof(xSyncGetPriorityReply), (char *) &rep);
131405b261ecSmrg
13154202a189Smrg    return Success;
131605b261ecSmrg}
131705b261ecSmrg
131805b261ecSmrg/*
131905b261ecSmrg * ** Create a new counter
132005b261ecSmrg */
13214202a189Smrgstatic int
13224202a189SmrgProcSyncCreateCounter(ClientPtr client)
132305b261ecSmrg{
132405b261ecSmrg    REQUEST(xSyncCreateCounterReq);
132505b261ecSmrg    CARD64          initial;
132605b261ecSmrg
132705b261ecSmrg    REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
132805b261ecSmrg
132905b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->cid, client);
133005b261ecSmrg
133105b261ecSmrg    XSyncIntsToValue(&initial, stuff->initial_value_lo, stuff->initial_value_hi);
133205b261ecSmrg    if (!SyncCreateCounter(client, stuff->cid, initial))
133305b261ecSmrg	return BadAlloc;
133405b261ecSmrg
13354202a189Smrg    return Success;
133605b261ecSmrg}
133705b261ecSmrg
133805b261ecSmrg/*
133905b261ecSmrg * ** Set Counter value
134005b261ecSmrg */
13414202a189Smrgstatic int
13424202a189SmrgProcSyncSetCounter(ClientPtr client)
134305b261ecSmrg{
134405b261ecSmrg    REQUEST(xSyncSetCounterReq);
134505b261ecSmrg    SyncCounter    *pCounter;
134605b261ecSmrg    CARD64	   newvalue;
13474202a189Smrg    int	rc;
134805b261ecSmrg
134905b261ecSmrg    REQUEST_SIZE_MATCH(xSyncSetCounterReq);
135005b261ecSmrg
13514202a189Smrg    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
13524202a189Smrg				 client, DixWriteAccess);
13534202a189Smrg    if (rc != Success)
13544202a189Smrg	return rc;
135505b261ecSmrg
135605b261ecSmrg    if (IsSystemCounter(pCounter))
135705b261ecSmrg    {
135805b261ecSmrg	client->errorValue = stuff->cid;
135905b261ecSmrg	return BadAccess;
136005b261ecSmrg    }
136105b261ecSmrg
136205b261ecSmrg    XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
136305b261ecSmrg    SyncChangeCounter(pCounter, newvalue);
136405b261ecSmrg    return Success;
136505b261ecSmrg}
136605b261ecSmrg
136705b261ecSmrg/*
136805b261ecSmrg * ** Change Counter value
136905b261ecSmrg */
13704202a189Smrgstatic int
13714202a189SmrgProcSyncChangeCounter(ClientPtr client)
137205b261ecSmrg{
137305b261ecSmrg    REQUEST(xSyncChangeCounterReq);
137405b261ecSmrg    SyncCounter    *pCounter;
137505b261ecSmrg    CARD64          newvalue;
137605b261ecSmrg    Bool	    overflow;
13774202a189Smrg    int	rc;
137805b261ecSmrg
137905b261ecSmrg    REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
138005b261ecSmrg
13814202a189Smrg    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
13824202a189Smrg				 client, DixWriteAccess);
13834202a189Smrg    if (rc != Success)
13844202a189Smrg	return rc;
138505b261ecSmrg
138605b261ecSmrg    if (IsSystemCounter(pCounter))
138705b261ecSmrg    {
138805b261ecSmrg	client->errorValue = stuff->cid;
138905b261ecSmrg	return BadAccess;
139005b261ecSmrg    }
139105b261ecSmrg
139205b261ecSmrg    XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
139305b261ecSmrg    XSyncValueAdd(&newvalue, pCounter->value, newvalue, &overflow);
139405b261ecSmrg    if (overflow)
139505b261ecSmrg    {
139605b261ecSmrg	/* XXX 64 bit value can't fit in 32 bits; do the best we can */
13974202a189Smrg	client->errorValue = stuff->value_hi;
139805b261ecSmrg	return BadValue;
139905b261ecSmrg    }
140005b261ecSmrg    SyncChangeCounter(pCounter, newvalue);
140105b261ecSmrg    return Success;
140205b261ecSmrg}
140305b261ecSmrg
140405b261ecSmrg/*
140505b261ecSmrg * ** Destroy a counter
140605b261ecSmrg */
14074202a189Smrgstatic int
14084202a189SmrgProcSyncDestroyCounter(ClientPtr client)
140905b261ecSmrg{
141005b261ecSmrg    REQUEST(xSyncDestroyCounterReq);
141105b261ecSmrg    SyncCounter    *pCounter;
14124202a189Smrg    int rc;
141305b261ecSmrg
141405b261ecSmrg    REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
141505b261ecSmrg
14164202a189Smrg    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter, RTCounter,
14174202a189Smrg				 client, DixDestroyAccess);
14184202a189Smrg    if (rc != Success)
14194202a189Smrg	return rc;
14204202a189Smrg
142105b261ecSmrg    if (IsSystemCounter(pCounter))
142205b261ecSmrg    {
142305b261ecSmrg	client->errorValue = stuff->counter;
142405b261ecSmrg	return BadAccess;
142505b261ecSmrg    }
142605b261ecSmrg    FreeResource(pCounter->id, RT_NONE);
142705b261ecSmrg    return Success;
142805b261ecSmrg}
142905b261ecSmrg
143005b261ecSmrg
143105b261ecSmrg/*
143205b261ecSmrg * ** Await
143305b261ecSmrg */
14344202a189Smrgstatic int
14354202a189SmrgProcSyncAwait(ClientPtr client)
143605b261ecSmrg{
143705b261ecSmrg    REQUEST(xSyncAwaitReq);
143805b261ecSmrg    int             len, items;
143905b261ecSmrg    int             i;
144005b261ecSmrg    xSyncWaitCondition *pProtocolWaitConds;
144105b261ecSmrg    SyncAwaitUnion *pAwaitUnion;
144205b261ecSmrg    SyncAwait	   *pAwait;
144305b261ecSmrg    int		   status;
144405b261ecSmrg
144505b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
144605b261ecSmrg
144705b261ecSmrg    len = client->req_len << 2;
144805b261ecSmrg    len -= sz_xSyncAwaitReq;
144905b261ecSmrg    items = len / sz_xSyncWaitCondition;
145005b261ecSmrg
145105b261ecSmrg    if (items * sz_xSyncWaitCondition != len)
145205b261ecSmrg    {
145305b261ecSmrg	return BadLength;
145405b261ecSmrg    }
145505b261ecSmrg    if (items == 0)
145605b261ecSmrg    {
145705b261ecSmrg	client->errorValue = items; /* XXX protocol change */
145805b261ecSmrg	return BadValue;
145905b261ecSmrg    }
146005b261ecSmrg
146105b261ecSmrg    pProtocolWaitConds = (xSyncWaitCondition *) & stuff[1];
146205b261ecSmrg
14634202a189Smrg    /*  all the memory for the entire await list is allocated
146405b261ecSmrg     *  here in one chunk
146505b261ecSmrg     */
14664202a189Smrg    pAwaitUnion = malloc((items+1) * sizeof(SyncAwaitUnion));
146705b261ecSmrg    if (!pAwaitUnion)
146805b261ecSmrg	return BadAlloc;
146905b261ecSmrg
147005b261ecSmrg    /* first item is the header, remainder are real wait conditions */
147105b261ecSmrg
147205b261ecSmrg    pAwaitUnion->header.delete_id = FakeClientID(client->index);
147305b261ecSmrg    if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion))
147405b261ecSmrg    {
14754202a189Smrg	free(pAwaitUnion);
147605b261ecSmrg	return BadAlloc;
147705b261ecSmrg    }
147805b261ecSmrg
147905b261ecSmrg    /* don't need to do any more memory allocation for this request! */
148005b261ecSmrg
148105b261ecSmrg    pAwaitUnion->header.client = client;
148205b261ecSmrg    pAwaitUnion->header.num_waitconditions = 0;
148305b261ecSmrg
148405b261ecSmrg    pAwait = &(pAwaitUnion+1)->await; /* skip over header */
148505b261ecSmrg    for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++)
148605b261ecSmrg    {
148705b261ecSmrg	if (pProtocolWaitConds->counter == None) /* XXX protocol change */
148805b261ecSmrg	{
148905b261ecSmrg	    /*  this should take care of removing any triggers created by
149005b261ecSmrg	     *  this request that have already been registered on counters
149105b261ecSmrg	     */
149205b261ecSmrg	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
149305b261ecSmrg	    client->errorValue = pProtocolWaitConds->counter;
149405b261ecSmrg	    return SyncErrorBase + XSyncBadCounter;
149505b261ecSmrg	}
149605b261ecSmrg
149705b261ecSmrg	/* sanity checks are in SyncInitTrigger */
149805b261ecSmrg	pAwait->trigger.pCounter = NULL;
149905b261ecSmrg	pAwait->trigger.value_type = pProtocolWaitConds->value_type;
150005b261ecSmrg	XSyncIntsToValue(&pAwait->trigger.wait_value,
150105b261ecSmrg			 pProtocolWaitConds->wait_value_lo,
150205b261ecSmrg			 pProtocolWaitConds->wait_value_hi);
150305b261ecSmrg	pAwait->trigger.test_type = pProtocolWaitConds->test_type;
150405b261ecSmrg
150505b261ecSmrg	status = SyncInitTrigger(client, &pAwait->trigger,
150605b261ecSmrg			 pProtocolWaitConds->counter, XSyncCAAllTrigger);
150705b261ecSmrg	if (status != Success)
150805b261ecSmrg	{
150905b261ecSmrg	    /*  this should take care of removing any triggers created by
151005b261ecSmrg	     *  this request that have already been registered on counters
151105b261ecSmrg	     */
151205b261ecSmrg	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
151305b261ecSmrg	    return status;
151405b261ecSmrg	}
151505b261ecSmrg	/* this is not a mistake -- same function works for both cases */
151605b261ecSmrg	pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
151705b261ecSmrg	pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
151805b261ecSmrg	XSyncIntsToValue(&pAwait->event_threshold,
151905b261ecSmrg			 pProtocolWaitConds->event_threshold_lo,
152005b261ecSmrg			 pProtocolWaitConds->event_threshold_hi);
152105b261ecSmrg	pAwait->pHeader = &pAwaitUnion->header;
152205b261ecSmrg	pAwaitUnion->header.num_waitconditions++;
152305b261ecSmrg    }
152405b261ecSmrg
152505b261ecSmrg    IgnoreClient(client);
152605b261ecSmrg
152705b261ecSmrg    /* see if any of the triggers are already true */
152805b261ecSmrg
152905b261ecSmrg    pAwait = &(pAwaitUnion+1)->await; /* skip over header */
153005b261ecSmrg    for (i = 0; i < items; i++, pAwait++)
153105b261ecSmrg    {
153205b261ecSmrg	/*  don't have to worry about NULL counters because the request
153305b261ecSmrg	 *  errors before we get here out if they occur
153405b261ecSmrg	 */
153505b261ecSmrg	if ((*pAwait->trigger.CheckTrigger)(&pAwait->trigger,
153605b261ecSmrg					    pAwait->trigger.pCounter->value))
153705b261ecSmrg	{
153805b261ecSmrg	    (*pAwait->trigger.TriggerFired)(&pAwait->trigger);
153905b261ecSmrg	    break; /* once is enough */
154005b261ecSmrg	}
154105b261ecSmrg    }
154205b261ecSmrg    return Success;
154305b261ecSmrg}
154405b261ecSmrg
154505b261ecSmrg
154605b261ecSmrg/*
154705b261ecSmrg * ** Query a counter
154805b261ecSmrg */
15494202a189Smrgstatic int
15504202a189SmrgProcSyncQueryCounter(ClientPtr client)
155105b261ecSmrg{
155205b261ecSmrg    REQUEST(xSyncQueryCounterReq);
155305b261ecSmrg    xSyncQueryCounterReply rep;
155405b261ecSmrg    SyncCounter    *pCounter;
15554202a189Smrg    int rc;
155605b261ecSmrg
155705b261ecSmrg    REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
155805b261ecSmrg
15594202a189Smrg    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter,
15604202a189Smrg				 RTCounter, client, DixReadAccess);
15614202a189Smrg    if (rc != Success)
15624202a189Smrg	return rc;
156305b261ecSmrg
156405b261ecSmrg    rep.type = X_Reply;
156505b261ecSmrg    rep.length = 0;
156605b261ecSmrg    rep.sequenceNumber = client->sequence;
156705b261ecSmrg
156805b261ecSmrg    /* if system counter, ask it what the current value is */
156905b261ecSmrg
157005b261ecSmrg    if (IsSystemCounter(pCounter))
157105b261ecSmrg    {
157205b261ecSmrg	(*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
157305b261ecSmrg						  &pCounter->value);
157405b261ecSmrg    }
157505b261ecSmrg
157605b261ecSmrg    rep.value_hi = XSyncValueHigh32(pCounter->value);
157705b261ecSmrg    rep.value_lo = XSyncValueLow32(pCounter->value);
157805b261ecSmrg    if (client->swapped)
157905b261ecSmrg    {
1580637ac9abSmrg	char n;
158105b261ecSmrg	swaps(&rep.sequenceNumber, n);
158205b261ecSmrg	swapl(&rep.length, n);
158305b261ecSmrg	swapl(&rep.value_hi, n);
158405b261ecSmrg	swapl(&rep.value_lo, n);
158505b261ecSmrg    }
158605b261ecSmrg    WriteToClient(client, sizeof(xSyncQueryCounterReply), (char *) &rep);
15874202a189Smrg    return Success;
158805b261ecSmrg}
158905b261ecSmrg
159005b261ecSmrg
159105b261ecSmrg/*
159205b261ecSmrg * ** Create Alarm
159305b261ecSmrg */
15944202a189Smrgstatic int
15954202a189SmrgProcSyncCreateAlarm(ClientPtr client)
159605b261ecSmrg{
159705b261ecSmrg    REQUEST(xSyncCreateAlarmReq);
159805b261ecSmrg    SyncAlarm      *pAlarm;
159905b261ecSmrg    int             status;
160005b261ecSmrg    unsigned long   len, vmask;
160105b261ecSmrg    SyncTrigger	    *pTrigger;
160205b261ecSmrg
160305b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
160405b261ecSmrg
160505b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->id, client);
160605b261ecSmrg
160705b261ecSmrg    vmask = stuff->valueMask;
16084202a189Smrg    len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq));
160905b261ecSmrg    /* the "extra" call to Ones accounts for the presence of 64 bit values */
161005b261ecSmrg    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
161105b261ecSmrg	return BadLength;
161205b261ecSmrg
16134202a189Smrg    if (!(pAlarm = malloc(sizeof(SyncAlarm))))
161405b261ecSmrg    {
161505b261ecSmrg	return BadAlloc;
161605b261ecSmrg    }
161705b261ecSmrg
161805b261ecSmrg    /* set up defaults */
161905b261ecSmrg
162005b261ecSmrg    pTrigger = &pAlarm->trigger;
162105b261ecSmrg    pTrigger->pCounter = NULL;
162205b261ecSmrg    pTrigger->value_type = XSyncAbsolute;
162305b261ecSmrg    XSyncIntToValue(&pTrigger->wait_value, 0L);
162405b261ecSmrg    pTrigger->test_type = XSyncPositiveComparison;
162505b261ecSmrg    pTrigger->TriggerFired = SyncAlarmTriggerFired;
162605b261ecSmrg    pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed;
162705b261ecSmrg    status = SyncInitTrigger(client, pTrigger, None, XSyncCAAllTrigger);
162805b261ecSmrg    if (status != Success)
162905b261ecSmrg    {
16304202a189Smrg	free(pAlarm);
163105b261ecSmrg	return status;
163205b261ecSmrg    }
163305b261ecSmrg
163405b261ecSmrg    pAlarm->client = client;
163505b261ecSmrg    pAlarm->alarm_id = stuff->id;
163605b261ecSmrg    XSyncIntToValue(&pAlarm->delta, 1L);
163705b261ecSmrg    pAlarm->events = TRUE;
163805b261ecSmrg    pAlarm->state = XSyncAlarmInactive;
163905b261ecSmrg    pAlarm->pEventClients = NULL;
164005b261ecSmrg    status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
164105b261ecSmrg				       (CARD32 *)&stuff[1]);
164205b261ecSmrg    if (status != Success)
164305b261ecSmrg    {
16444202a189Smrg	free(pAlarm);
164505b261ecSmrg	return status;
164605b261ecSmrg    }
164705b261ecSmrg
164805b261ecSmrg    if (!AddResource(stuff->id, RTAlarm, pAlarm))
164905b261ecSmrg    {
16504202a189Smrg	free(pAlarm);
165105b261ecSmrg	return BadAlloc;
165205b261ecSmrg    }
165305b261ecSmrg
165405b261ecSmrg    /*  see if alarm already triggered.  NULL counter will not trigger
165505b261ecSmrg     *  in CreateAlarm and sets alarm state to Inactive.
165605b261ecSmrg     */
165705b261ecSmrg
165805b261ecSmrg    if (!pTrigger->pCounter)
165905b261ecSmrg    {
166005b261ecSmrg	pAlarm->state = XSyncAlarmInactive; /* XXX protocol change */
166105b261ecSmrg    }
166205b261ecSmrg    else if ((*pTrigger->CheckTrigger)(pTrigger, pTrigger->pCounter->value))
166305b261ecSmrg    {
166405b261ecSmrg	(*pTrigger->TriggerFired)(pTrigger);
166505b261ecSmrg    }
166605b261ecSmrg
166705b261ecSmrg    return Success;
166805b261ecSmrg}
166905b261ecSmrg
167005b261ecSmrg/*
167105b261ecSmrg * ** Change Alarm
167205b261ecSmrg */
16734202a189Smrgstatic int
16744202a189SmrgProcSyncChangeAlarm(ClientPtr client)
167505b261ecSmrg{
167605b261ecSmrg    REQUEST(xSyncChangeAlarmReq);
167705b261ecSmrg    SyncAlarm   *pAlarm;
167805b261ecSmrg    long        vmask;
167905b261ecSmrg    int         len, status;
168005b261ecSmrg
168105b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
168205b261ecSmrg
16834202a189Smrg    status = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
16844202a189Smrg				     client, DixWriteAccess);
16854202a189Smrg    if (status != Success)
16864202a189Smrg	return status;
168705b261ecSmrg
168805b261ecSmrg    vmask = stuff->valueMask;
16894202a189Smrg    len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq));
169005b261ecSmrg    /* the "extra" call to Ones accounts for the presence of 64 bit values */
169105b261ecSmrg    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
169205b261ecSmrg	return BadLength;
169305b261ecSmrg
16944202a189Smrg    if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
169505b261ecSmrg					    (CARD32 *)&stuff[1])) != Success)
169605b261ecSmrg	return status;
169705b261ecSmrg
169805b261ecSmrg    /*  see if alarm already triggered.  NULL counter WILL trigger
169905b261ecSmrg     *  in ChangeAlarm.
170005b261ecSmrg     */
170105b261ecSmrg
170205b261ecSmrg    if (!pAlarm->trigger.pCounter ||
170305b261ecSmrg	(*pAlarm->trigger.CheckTrigger)(&pAlarm->trigger,
170405b261ecSmrg					pAlarm->trigger.pCounter->value))
170505b261ecSmrg    {
170605b261ecSmrg	(*pAlarm->trigger.TriggerFired)(&pAlarm->trigger);
170705b261ecSmrg    }
170805b261ecSmrg    return Success;
170905b261ecSmrg}
171005b261ecSmrg
17114202a189Smrgstatic int
17124202a189SmrgProcSyncQueryAlarm(ClientPtr client)
171305b261ecSmrg{
171405b261ecSmrg    REQUEST(xSyncQueryAlarmReq);
171505b261ecSmrg    SyncAlarm      *pAlarm;
171605b261ecSmrg    xSyncQueryAlarmReply rep;
171705b261ecSmrg    SyncTrigger    *pTrigger;
17184202a189Smrg    int rc;
171905b261ecSmrg
172005b261ecSmrg    REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
172105b261ecSmrg
17224202a189Smrg    rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
17234202a189Smrg				 client, DixReadAccess);
17244202a189Smrg    if (rc != Success)
17254202a189Smrg	return rc;
172605b261ecSmrg
172705b261ecSmrg    rep.type = X_Reply;
17284202a189Smrg    rep.length = bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply));
172905b261ecSmrg    rep.sequenceNumber = client->sequence;
173005b261ecSmrg
173105b261ecSmrg    pTrigger = &pAlarm->trigger;
173205b261ecSmrg    rep.counter = (pTrigger->pCounter) ? pTrigger->pCounter->id : None;
173305b261ecSmrg
173405b261ecSmrg#if 0 /* XXX unclear what to do, depends on whether relative value-types
173505b261ecSmrg       * are "consumed" immediately and are considered absolute from then
173605b261ecSmrg       * on.
173705b261ecSmrg       */
173805b261ecSmrg    rep.value_type = pTrigger->value_type;
173905b261ecSmrg    rep.wait_value_hi = XSyncValueHigh32(pTrigger->wait_value);
174005b261ecSmrg    rep.wait_value_lo = XSyncValueLow32(pTrigger->wait_value);
174105b261ecSmrg#else
174205b261ecSmrg    rep.value_type = XSyncAbsolute;
174305b261ecSmrg    rep.wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
174405b261ecSmrg    rep.wait_value_lo = XSyncValueLow32(pTrigger->test_value);
174505b261ecSmrg#endif
174605b261ecSmrg
174705b261ecSmrg    rep.test_type = pTrigger->test_type;
174805b261ecSmrg    rep.delta_hi = XSyncValueHigh32(pAlarm->delta);
174905b261ecSmrg    rep.delta_lo = XSyncValueLow32(pAlarm->delta);
175005b261ecSmrg    rep.events = pAlarm->events;
175105b261ecSmrg    rep.state = pAlarm->state;
175205b261ecSmrg
175305b261ecSmrg    if (client->swapped)
175405b261ecSmrg    {
1755637ac9abSmrg	char n;
175605b261ecSmrg	swaps(&rep.sequenceNumber, n);
175705b261ecSmrg	swapl(&rep.length, n);
175805b261ecSmrg	swapl(&rep.counter, n);
175905b261ecSmrg	swapl(&rep.wait_value_hi, n);
176005b261ecSmrg	swapl(&rep.wait_value_lo, n);
176105b261ecSmrg	swapl(&rep.test_type, n);
176205b261ecSmrg	swapl(&rep.delta_hi, n);
176305b261ecSmrg	swapl(&rep.delta_lo, n);
176405b261ecSmrg    }
176505b261ecSmrg
176605b261ecSmrg    WriteToClient(client, sizeof(xSyncQueryAlarmReply), (char *) &rep);
17674202a189Smrg    return Success;
176805b261ecSmrg}
176905b261ecSmrg
17704202a189Smrgstatic int
17714202a189SmrgProcSyncDestroyAlarm(ClientPtr client)
177205b261ecSmrg{
17734202a189Smrg    SyncAlarm *pAlarm;
17744202a189Smrg    int rc;
177505b261ecSmrg    REQUEST(xSyncDestroyAlarmReq);
177605b261ecSmrg
177705b261ecSmrg    REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
177805b261ecSmrg
17794202a189Smrg    rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
17804202a189Smrg				 client, DixDestroyAccess);
17814202a189Smrg    if (rc != Success)
17824202a189Smrg	return rc;
178305b261ecSmrg
178405b261ecSmrg    FreeResource(stuff->alarm, RT_NONE);
17854202a189Smrg    return Success;
178605b261ecSmrg}
178705b261ecSmrg
178805b261ecSmrg/*
178905b261ecSmrg * ** Given an extension request, call the appropriate request procedure
179005b261ecSmrg */
17914202a189Smrgstatic int
17924202a189SmrgProcSyncDispatch(ClientPtr client)
179305b261ecSmrg{
179405b261ecSmrg    REQUEST(xReq);
179505b261ecSmrg
179605b261ecSmrg    switch (stuff->data)
179705b261ecSmrg    {
179805b261ecSmrg      case X_SyncInitialize:
179905b261ecSmrg	return ProcSyncInitialize(client);
180005b261ecSmrg      case X_SyncListSystemCounters:
180105b261ecSmrg	return ProcSyncListSystemCounters(client);
180205b261ecSmrg      case X_SyncCreateCounter:
180305b261ecSmrg	return ProcSyncCreateCounter(client);
180405b261ecSmrg      case X_SyncSetCounter:
180505b261ecSmrg	return ProcSyncSetCounter(client);
180605b261ecSmrg      case X_SyncChangeCounter:
180705b261ecSmrg	return ProcSyncChangeCounter(client);
180805b261ecSmrg      case X_SyncQueryCounter:
180905b261ecSmrg	return ProcSyncQueryCounter(client);
181005b261ecSmrg      case X_SyncDestroyCounter:
181105b261ecSmrg	return ProcSyncDestroyCounter(client);
181205b261ecSmrg      case X_SyncAwait:
181305b261ecSmrg	return ProcSyncAwait(client);
181405b261ecSmrg      case X_SyncCreateAlarm:
181505b261ecSmrg	return ProcSyncCreateAlarm(client);
181605b261ecSmrg      case X_SyncChangeAlarm:
181705b261ecSmrg	return ProcSyncChangeAlarm(client);
181805b261ecSmrg      case X_SyncQueryAlarm:
181905b261ecSmrg	return ProcSyncQueryAlarm(client);
182005b261ecSmrg      case X_SyncDestroyAlarm:
182105b261ecSmrg	return ProcSyncDestroyAlarm(client);
182205b261ecSmrg      case X_SyncSetPriority:
182305b261ecSmrg	return ProcSyncSetPriority(client);
182405b261ecSmrg      case X_SyncGetPriority:
182505b261ecSmrg	return ProcSyncGetPriority(client);
182605b261ecSmrg      default:
182705b261ecSmrg	return BadRequest;
182805b261ecSmrg    }
182905b261ecSmrg}
183005b261ecSmrg
183105b261ecSmrg/*
183205b261ecSmrg * Boring Swapping stuff ...
183305b261ecSmrg */
183405b261ecSmrg
18354202a189Smrgstatic int
18364202a189SmrgSProcSyncInitialize(ClientPtr client)
183705b261ecSmrg{
183805b261ecSmrg    REQUEST(xSyncInitializeReq);
1839637ac9abSmrg    char   n;
184005b261ecSmrg
184105b261ecSmrg    swaps(&stuff->length, n);
184205b261ecSmrg    REQUEST_SIZE_MATCH (xSyncInitializeReq);
184305b261ecSmrg
184405b261ecSmrg    return ProcSyncInitialize(client);
184505b261ecSmrg}
184605b261ecSmrg
18474202a189Smrgstatic int
18484202a189SmrgSProcSyncListSystemCounters(ClientPtr client)
184905b261ecSmrg{
185005b261ecSmrg    REQUEST(xSyncListSystemCountersReq);
1851637ac9abSmrg    char   n;
185205b261ecSmrg
185305b261ecSmrg    swaps(&stuff->length, n);
185405b261ecSmrg    REQUEST_SIZE_MATCH (xSyncListSystemCountersReq);
185505b261ecSmrg
185605b261ecSmrg    return ProcSyncListSystemCounters(client);
185705b261ecSmrg}
185805b261ecSmrg
18594202a189Smrgstatic int
18604202a189SmrgSProcSyncCreateCounter(ClientPtr client)
186105b261ecSmrg{
186205b261ecSmrg    REQUEST(xSyncCreateCounterReq);
1863637ac9abSmrg    char   n;
186405b261ecSmrg
186505b261ecSmrg    swaps(&stuff->length, n);
186605b261ecSmrg    REQUEST_SIZE_MATCH (xSyncCreateCounterReq);
186705b261ecSmrg    swapl(&stuff->cid, n);
186805b261ecSmrg    swapl(&stuff->initial_value_lo, n);
186905b261ecSmrg    swapl(&stuff->initial_value_hi, n);
187005b261ecSmrg
187105b261ecSmrg    return ProcSyncCreateCounter(client);
187205b261ecSmrg}
187305b261ecSmrg
18744202a189Smrgstatic int
18754202a189SmrgSProcSyncSetCounter(ClientPtr client)
187605b261ecSmrg{
187705b261ecSmrg    REQUEST(xSyncSetCounterReq);
1878637ac9abSmrg    char   n;
187905b261ecSmrg
188005b261ecSmrg    swaps(&stuff->length, n);
188105b261ecSmrg    REQUEST_SIZE_MATCH (xSyncSetCounterReq);
188205b261ecSmrg    swapl(&stuff->cid, n);
188305b261ecSmrg    swapl(&stuff->value_lo, n);
188405b261ecSmrg    swapl(&stuff->value_hi, n);
188505b261ecSmrg
188605b261ecSmrg    return ProcSyncSetCounter(client);
188705b261ecSmrg}
188805b261ecSmrg
18894202a189Smrgstatic int
18904202a189SmrgSProcSyncChangeCounter(ClientPtr client)
189105b261ecSmrg{
189205b261ecSmrg    REQUEST(xSyncChangeCounterReq);
1893637ac9abSmrg    char   n;
189405b261ecSmrg
189505b261ecSmrg    swaps(&stuff->length, n);
189605b261ecSmrg    REQUEST_SIZE_MATCH (xSyncChangeCounterReq);
189705b261ecSmrg    swapl(&stuff->cid, n);
189805b261ecSmrg    swapl(&stuff->value_lo, n);
189905b261ecSmrg    swapl(&stuff->value_hi, n);
190005b261ecSmrg
190105b261ecSmrg    return ProcSyncChangeCounter(client);
190205b261ecSmrg}
190305b261ecSmrg
19044202a189Smrgstatic int
19054202a189SmrgSProcSyncQueryCounter(ClientPtr client)
190605b261ecSmrg{
190705b261ecSmrg    REQUEST(xSyncQueryCounterReq);
1908637ac9abSmrg    char   n;
190905b261ecSmrg
191005b261ecSmrg    swaps(&stuff->length, n);
191105b261ecSmrg    REQUEST_SIZE_MATCH (xSyncQueryCounterReq);
191205b261ecSmrg    swapl(&stuff->counter, n);
191305b261ecSmrg
191405b261ecSmrg    return ProcSyncQueryCounter(client);
191505b261ecSmrg}
191605b261ecSmrg
19174202a189Smrgstatic int
19184202a189SmrgSProcSyncDestroyCounter(ClientPtr client)
191905b261ecSmrg{
192005b261ecSmrg    REQUEST(xSyncDestroyCounterReq);
1921637ac9abSmrg    char   n;
192205b261ecSmrg
192305b261ecSmrg    swaps(&stuff->length, n);
192405b261ecSmrg    REQUEST_SIZE_MATCH (xSyncDestroyCounterReq);
192505b261ecSmrg    swapl(&stuff->counter, n);
192605b261ecSmrg
192705b261ecSmrg    return ProcSyncDestroyCounter(client);
192805b261ecSmrg}
192905b261ecSmrg
19304202a189Smrgstatic int
19314202a189SmrgSProcSyncAwait(ClientPtr client)
193205b261ecSmrg{
193305b261ecSmrg    REQUEST(xSyncAwaitReq);
1934637ac9abSmrg    char   n;
193505b261ecSmrg
193605b261ecSmrg    swaps(&stuff->length, n);
193705b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
193805b261ecSmrg    SwapRestL(stuff);
193905b261ecSmrg
194005b261ecSmrg    return ProcSyncAwait(client);
194105b261ecSmrg}
194205b261ecSmrg
19434202a189Smrgstatic int
19444202a189SmrgSProcSyncCreateAlarm(ClientPtr client)
194505b261ecSmrg{
194605b261ecSmrg    REQUEST(xSyncCreateAlarmReq);
1947637ac9abSmrg    char   n;
194805b261ecSmrg
194905b261ecSmrg    swaps(&stuff->length, n);
195005b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
195105b261ecSmrg    swapl(&stuff->id, n);
195205b261ecSmrg    swapl(&stuff->valueMask, n);
195305b261ecSmrg    SwapRestL(stuff);
195405b261ecSmrg
195505b261ecSmrg    return ProcSyncCreateAlarm(client);
195605b261ecSmrg}
195705b261ecSmrg
19584202a189Smrgstatic int
19594202a189SmrgSProcSyncChangeAlarm(ClientPtr client)
196005b261ecSmrg{
196105b261ecSmrg    REQUEST(xSyncChangeAlarmReq);
1962637ac9abSmrg    char   n;
196305b261ecSmrg
196405b261ecSmrg    swaps(&stuff->length, n);
196505b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
196605b261ecSmrg    swapl(&stuff->alarm, n);
196705b261ecSmrg    swapl(&stuff->valueMask, n);
196805b261ecSmrg    SwapRestL(stuff);
196905b261ecSmrg    return ProcSyncChangeAlarm(client);
197005b261ecSmrg}
197105b261ecSmrg
19724202a189Smrgstatic int
19734202a189SmrgSProcSyncQueryAlarm(ClientPtr client)
197405b261ecSmrg{
197505b261ecSmrg    REQUEST(xSyncQueryAlarmReq);
1976637ac9abSmrg    char   n;
197705b261ecSmrg
197805b261ecSmrg    swaps(&stuff->length, n);
197905b261ecSmrg    REQUEST_SIZE_MATCH (xSyncQueryAlarmReq);
198005b261ecSmrg    swapl(&stuff->alarm, n);
198105b261ecSmrg
198205b261ecSmrg    return ProcSyncQueryAlarm(client);
198305b261ecSmrg}
198405b261ecSmrg
19854202a189Smrgstatic int
19864202a189SmrgSProcSyncDestroyAlarm(ClientPtr client)
198705b261ecSmrg{
198805b261ecSmrg    REQUEST(xSyncDestroyAlarmReq);
1989637ac9abSmrg    char   n;
199005b261ecSmrg
199105b261ecSmrg    swaps(&stuff->length, n);
199205b261ecSmrg    REQUEST_SIZE_MATCH (xSyncDestroyAlarmReq);
199305b261ecSmrg    swapl(&stuff->alarm, n);
199405b261ecSmrg
199505b261ecSmrg    return ProcSyncDestroyAlarm(client);
199605b261ecSmrg}
199705b261ecSmrg
19984202a189Smrgstatic int
19994202a189SmrgSProcSyncSetPriority(ClientPtr client)
200005b261ecSmrg{
200105b261ecSmrg    REQUEST(xSyncSetPriorityReq);
2002637ac9abSmrg    char   n;
200305b261ecSmrg
200405b261ecSmrg    swaps(&stuff->length, n);
200505b261ecSmrg    REQUEST_SIZE_MATCH (xSyncSetPriorityReq);
200605b261ecSmrg    swapl(&stuff->id, n);
200705b261ecSmrg    swapl(&stuff->priority, n);
200805b261ecSmrg
200905b261ecSmrg    return ProcSyncSetPriority(client);
201005b261ecSmrg}
201105b261ecSmrg
20124202a189Smrgstatic int
20134202a189SmrgSProcSyncGetPriority(ClientPtr client)
201405b261ecSmrg{
201505b261ecSmrg    REQUEST(xSyncGetPriorityReq);
2016637ac9abSmrg    char   n;
201705b261ecSmrg
201805b261ecSmrg    swaps(&stuff->length, n);
201905b261ecSmrg    REQUEST_SIZE_MATCH (xSyncGetPriorityReq);
202005b261ecSmrg    swapl(&stuff->id, n);
202105b261ecSmrg
202205b261ecSmrg    return ProcSyncGetPriority(client);
202305b261ecSmrg}
202405b261ecSmrg
202505b261ecSmrg
20264202a189Smrgstatic int
20274202a189SmrgSProcSyncDispatch(ClientPtr client)
202805b261ecSmrg{
202905b261ecSmrg    REQUEST(xReq);
203005b261ecSmrg
203105b261ecSmrg    switch (stuff->data)
203205b261ecSmrg    {
203305b261ecSmrg      case X_SyncInitialize:
203405b261ecSmrg	return SProcSyncInitialize(client);
203505b261ecSmrg      case X_SyncListSystemCounters:
203605b261ecSmrg	return SProcSyncListSystemCounters(client);
203705b261ecSmrg      case X_SyncCreateCounter:
203805b261ecSmrg	return SProcSyncCreateCounter(client);
203905b261ecSmrg      case X_SyncSetCounter:
204005b261ecSmrg	return SProcSyncSetCounter(client);
204105b261ecSmrg      case X_SyncChangeCounter:
204205b261ecSmrg	return SProcSyncChangeCounter(client);
204305b261ecSmrg      case X_SyncQueryCounter:
204405b261ecSmrg	return SProcSyncQueryCounter(client);
204505b261ecSmrg      case X_SyncDestroyCounter:
204605b261ecSmrg	return SProcSyncDestroyCounter(client);
204705b261ecSmrg      case X_SyncAwait:
204805b261ecSmrg	return SProcSyncAwait(client);
204905b261ecSmrg      case X_SyncCreateAlarm:
205005b261ecSmrg	return SProcSyncCreateAlarm(client);
205105b261ecSmrg      case X_SyncChangeAlarm:
205205b261ecSmrg	return SProcSyncChangeAlarm(client);
205305b261ecSmrg      case X_SyncQueryAlarm:
205405b261ecSmrg	return SProcSyncQueryAlarm(client);
205505b261ecSmrg      case X_SyncDestroyAlarm:
205605b261ecSmrg	return SProcSyncDestroyAlarm(client);
205705b261ecSmrg      case X_SyncSetPriority:
205805b261ecSmrg	return SProcSyncSetPriority(client);
205905b261ecSmrg      case X_SyncGetPriority:
206005b261ecSmrg	return SProcSyncGetPriority(client);
206105b261ecSmrg      default:
206205b261ecSmrg	return BadRequest;
206305b261ecSmrg    }
206405b261ecSmrg}
206505b261ecSmrg
206605b261ecSmrg/*
206705b261ecSmrg * Event Swapping
206805b261ecSmrg */
206905b261ecSmrg
20704202a189Smrgstatic void
20714202a189SmrgSCounterNotifyEvent(xSyncCounterNotifyEvent *from, xSyncCounterNotifyEvent *to)
207205b261ecSmrg{
207305b261ecSmrg    to->type = from->type;
207405b261ecSmrg    to->kind = from->kind;
207505b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
207605b261ecSmrg    cpswapl(from->counter, to->counter);
207705b261ecSmrg    cpswapl(from->wait_value_lo, to->wait_value_lo);
207805b261ecSmrg    cpswapl(from->wait_value_hi, to->wait_value_hi);
207905b261ecSmrg    cpswapl(from->counter_value_lo, to->counter_value_lo);
208005b261ecSmrg    cpswapl(from->counter_value_hi, to->counter_value_hi);
208105b261ecSmrg    cpswapl(from->time, to->time);
208205b261ecSmrg    cpswaps(from->count, to->count);
208305b261ecSmrg    to->destroyed = from->destroyed;
208405b261ecSmrg}
208505b261ecSmrg
208605b261ecSmrg
20874202a189Smrgstatic void
20884202a189SmrgSAlarmNotifyEvent(xSyncAlarmNotifyEvent *from, xSyncAlarmNotifyEvent *to)
208905b261ecSmrg{
209005b261ecSmrg    to->type = from->type;
209105b261ecSmrg    to->kind = from->kind;
209205b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
209305b261ecSmrg    cpswapl(from->alarm, to->alarm);
209405b261ecSmrg    cpswapl(from->counter_value_lo, to->counter_value_lo);
209505b261ecSmrg    cpswapl(from->counter_value_hi, to->counter_value_hi);
209605b261ecSmrg    cpswapl(from->alarm_value_lo, to->alarm_value_lo);
209705b261ecSmrg    cpswapl(from->alarm_value_hi, to->alarm_value_hi);
209805b261ecSmrg    cpswapl(from->time, to->time);
209905b261ecSmrg    to->state = from->state;
210005b261ecSmrg}
210105b261ecSmrg
210205b261ecSmrg/*
210305b261ecSmrg * ** Close everything down. ** This is fairly simple for now.
210405b261ecSmrg */
210505b261ecSmrg/* ARGSUSED */
21064202a189Smrgstatic void
21074202a189SmrgSyncResetProc(ExtensionEntry *extEntry)
210805b261ecSmrg{
21094202a189Smrg    free(SysCounterList);
211005b261ecSmrg    SysCounterList = NULL;
211105b261ecSmrg    RTCounter = 0;
211205b261ecSmrg}
211305b261ecSmrg
211405b261ecSmrg
211505b261ecSmrg/*
211605b261ecSmrg * ** Initialise the extension.
211705b261ecSmrg */
21184202a189Smrgvoid
21194202a189SmrgSyncExtensionInit(void)
212005b261ecSmrg{
212105b261ecSmrg    ExtensionEntry *extEntry;
212205b261ecSmrg
212305b261ecSmrg    if (RTCounter == 0)
212405b261ecSmrg    {
21254202a189Smrg	RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
212605b261ecSmrg    }
21274202a189Smrg    RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm");
21284202a189Smrg    RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait");
21294202a189Smrg    if (RTAwait)
21304202a189Smrg	RTAwait |= RC_NEVERRETAIN;
21314202a189Smrg    RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient");
21324202a189Smrg    if (RTAlarmClient)
21334202a189Smrg	RTAlarmClient |= RC_NEVERRETAIN;
213405b261ecSmrg
213505b261ecSmrg    if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 ||
213605b261ecSmrg	RTAlarmClient == 0 ||
213705b261ecSmrg	(extEntry = AddExtension(SYNC_NAME,
213805b261ecSmrg				 XSyncNumberEvents, XSyncNumberErrors,
213905b261ecSmrg				 ProcSyncDispatch, SProcSyncDispatch,
214005b261ecSmrg				 SyncResetProc,
214105b261ecSmrg				 StandardMinorOpcode)) == NULL)
214205b261ecSmrg    {
214305b261ecSmrg	ErrorF("Sync Extension %d.%d failed to Initialise\n",
214405b261ecSmrg		SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
214505b261ecSmrg	return;
214605b261ecSmrg    }
214705b261ecSmrg
214805b261ecSmrg    SyncEventBase = extEntry->eventBase;
214905b261ecSmrg    SyncErrorBase = extEntry->errorBase;
215005b261ecSmrg    EventSwapVector[SyncEventBase + XSyncCounterNotify] = (EventSwapPtr) SCounterNotifyEvent;
215105b261ecSmrg    EventSwapVector[SyncEventBase + XSyncAlarmNotify] = (EventSwapPtr) SAlarmNotifyEvent;
215205b261ecSmrg
21534202a189Smrg    SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter);
21544202a189Smrg    SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm);
21554202a189Smrg
215605b261ecSmrg    /*
215705b261ecSmrg     * Although SERVERTIME is implemented by the OS layer, we initialise it
215805b261ecSmrg     * here because doing it in OsInit() is too early. The resource database
215905b261ecSmrg     * is not initialised when OsInit() is called. This is just about OK
216005b261ecSmrg     * because there is always a servertime counter.
216105b261ecSmrg     */
216205b261ecSmrg    SyncInitServerTime();
216305b261ecSmrg    SyncInitIdleTime();
216405b261ecSmrg
216505b261ecSmrg#ifdef DEBUG
216605b261ecSmrg    fprintf(stderr, "Sync Extension %d.%d\n",
216705b261ecSmrg	    SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
216805b261ecSmrg#endif
216905b261ecSmrg}
217005b261ecSmrg
217105b261ecSmrg
217205b261ecSmrg/*
217305b261ecSmrg * ***** SERVERTIME implementation - should go in its own file in OS directory?
217405b261ecSmrg */
217505b261ecSmrg
217605b261ecSmrg
217705b261ecSmrg
217805b261ecSmrgstatic pointer ServertimeCounter;
217905b261ecSmrgstatic XSyncValue Now;
218005b261ecSmrgstatic XSyncValue *pnext_time;
218105b261ecSmrg
218205b261ecSmrg#define GetTime()\
218305b261ecSmrg{\
218405b261ecSmrg    unsigned long millis = GetTimeInMillis();\
218505b261ecSmrg    unsigned long maxis = XSyncValueHigh32(Now);\
218605b261ecSmrg    if (millis < XSyncValueLow32(Now)) maxis++;\
218705b261ecSmrg    XSyncIntsToValue(&Now, millis, maxis);\
218805b261ecSmrg}
218905b261ecSmrg
219005b261ecSmrg/*
219105b261ecSmrg*** Server Block Handler
21924202a189Smrg*** code inspired by multibuffer extension (now deprecated)
219305b261ecSmrg */
219405b261ecSmrg/*ARGSUSED*/
21954202a189Smrgstatic void
21964202a189SmrgServertimeBlockHandler(void *env, struct timeval **wt, void *LastSelectMask)
219705b261ecSmrg{
219805b261ecSmrg    XSyncValue delay;
219905b261ecSmrg    unsigned long timeout;
220005b261ecSmrg
220105b261ecSmrg    if (pnext_time)
220205b261ecSmrg    {
220305b261ecSmrg        GetTime();
220405b261ecSmrg
220505b261ecSmrg        if (XSyncValueGreaterOrEqual(Now, *pnext_time))
220605b261ecSmrg	{
220705b261ecSmrg            timeout = 0;
22084202a189Smrg        }
220905b261ecSmrg	else
221005b261ecSmrg	{
221105b261ecSmrg	    Bool overflow;
221205b261ecSmrg            XSyncValueSubtract(&delay, *pnext_time, Now, &overflow);
221305b261ecSmrg	    (void)overflow;
221405b261ecSmrg            timeout = XSyncValueLow32(delay);
221505b261ecSmrg        }
221605b261ecSmrg        AdjustWaitForDelay(wt, timeout); /* os/utils.c */
221705b261ecSmrg    }
221805b261ecSmrg}
221905b261ecSmrg
222005b261ecSmrg/*
222105b261ecSmrg*** Wakeup Handler
222205b261ecSmrg */
222305b261ecSmrg/*ARGSUSED*/
22244202a189Smrgstatic void
22254202a189SmrgServertimeWakeupHandler(void *env, int rc, void *LastSelectMask)
222605b261ecSmrg{
222705b261ecSmrg    if (pnext_time)
222805b261ecSmrg    {
222905b261ecSmrg        GetTime();
223005b261ecSmrg
223105b261ecSmrg        if (XSyncValueGreaterOrEqual(Now, *pnext_time))
223205b261ecSmrg	{
223305b261ecSmrg            SyncChangeCounter(ServertimeCounter, Now);
223405b261ecSmrg        }
223505b261ecSmrg    }
223605b261ecSmrg}
223705b261ecSmrg
223805b261ecSmrgstatic void
22394202a189SmrgServertimeQueryValue(void *pCounter, CARD64 *pValue_return)
224005b261ecSmrg{
224105b261ecSmrg    GetTime();
224205b261ecSmrg    *pValue_return = Now;
224305b261ecSmrg}
224405b261ecSmrg
224505b261ecSmrgstatic void
22464202a189SmrgServertimeBracketValues(void *pCounter, CARD64 *pbracket_less,
22474202a189Smrg			CARD64 *pbracket_greater)
224805b261ecSmrg{
224905b261ecSmrg    if (!pnext_time && pbracket_greater)
225005b261ecSmrg    {
225105b261ecSmrg	RegisterBlockAndWakeupHandlers(ServertimeBlockHandler,
225205b261ecSmrg				       ServertimeWakeupHandler,
225305b261ecSmrg				       NULL);
225405b261ecSmrg    }
225505b261ecSmrg    else if (pnext_time && !pbracket_greater)
225605b261ecSmrg    {
225705b261ecSmrg	RemoveBlockAndWakeupHandlers(ServertimeBlockHandler,
225805b261ecSmrg				     ServertimeWakeupHandler,
225905b261ecSmrg				     NULL);
226005b261ecSmrg    }
226105b261ecSmrg    pnext_time = pbracket_greater;
226205b261ecSmrg}
226305b261ecSmrg
226405b261ecSmrgstatic void
226505b261ecSmrgSyncInitServerTime(void)
226605b261ecSmrg{
226705b261ecSmrg    CARD64 resolution;
226805b261ecSmrg
226905b261ecSmrg    XSyncIntsToValue(&Now, GetTimeInMillis(), 0);
227005b261ecSmrg    XSyncIntToValue(&resolution, 4);
227105b261ecSmrg    ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution,
227205b261ecSmrg			    XSyncCounterNeverDecreases,
227305b261ecSmrg			    ServertimeQueryValue, ServertimeBracketValues);
227405b261ecSmrg    pnext_time = NULL;
227505b261ecSmrg}
227605b261ecSmrg
227705b261ecSmrg
227805b261ecSmrg
227905b261ecSmrg/*
228005b261ecSmrg * IDLETIME implementation
228105b261ecSmrg */
228205b261ecSmrg
228345801275Sjmcneillstatic SyncCounter *IdleTimeCounter;
228405b261ecSmrgstatic XSyncValue *pIdleTimeValueLess;
228505b261ecSmrgstatic XSyncValue *pIdleTimeValueGreater;
228605b261ecSmrg
228705b261ecSmrgstatic void
228805b261ecSmrgIdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return)
228905b261ecSmrg{
229005b261ecSmrg    CARD32 idle = GetTimeInMillis() - lastDeviceEventTime.milliseconds;
229105b261ecSmrg    XSyncIntsToValue (pValue_return, idle, 0);
229205b261ecSmrg}
229305b261ecSmrg
229405b261ecSmrgstatic void
229545801275SjmcneillIdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask)
229605b261ecSmrg{
229745801275Sjmcneill    XSyncValue idle, old_idle;
229845801275Sjmcneill    SyncTriggerList *list = IdleTimeCounter->pTriglist;
229945801275Sjmcneill    SyncTrigger *trig;
230005b261ecSmrg
230105b261ecSmrg    if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
230205b261ecSmrg	return;
230305b261ecSmrg
230445801275Sjmcneill    old_idle = IdleTimeCounter->value;
230505b261ecSmrg    IdleTimeQueryValue (NULL, &idle);
230645801275Sjmcneill    IdleTimeCounter->value = idle; /* push, so CheckTrigger works */
230705b261ecSmrg
230805b261ecSmrg    if (pIdleTimeValueLess &&
230905b261ecSmrg        XSyncValueLessOrEqual (idle, *pIdleTimeValueLess))
231005b261ecSmrg    {
231145801275Sjmcneill	/*
231245801275Sjmcneill	 * We've been idle for less than the threshold value, and someone
231345801275Sjmcneill	 * wants to know about that, but now we need to know whether they
231445801275Sjmcneill	 * want level or edge trigger.  Check the trigger list against the
231545801275Sjmcneill	 * current idle time, and if any succeed, bomb out of select()
231645801275Sjmcneill	 * immediately so we can reschedule.
231745801275Sjmcneill	 */
231845801275Sjmcneill
231945801275Sjmcneill	for (list = IdleTimeCounter->pTriglist; list; list = list->next) {
232045801275Sjmcneill	    trig = list->pTrigger;
232145801275Sjmcneill	    if (trig->CheckTrigger(trig, old_idle)) {
232245801275Sjmcneill		AdjustWaitForDelay(wt, 0);
232345801275Sjmcneill		break;
232445801275Sjmcneill	    }
232545801275Sjmcneill	}
23261b684552Smrg	/*
23271b684552Smrg	 * We've been called exactly on the idle time, but we have a
23281b684552Smrg	 * NegativeTransition trigger which requires a transition from an
23291b684552Smrg	 * idle time greater than this.  Schedule a wakeup for the next
23301b684552Smrg	 * millisecond so we won't miss a transition.
23311b684552Smrg	 */
23321b684552Smrg	if (XSyncValueEqual (idle, *pIdleTimeValueLess))
23331b684552Smrg	    AdjustWaitForDelay(wt, 1);
233405b261ecSmrg    }
233505b261ecSmrg    else if (pIdleTimeValueGreater)
233605b261ecSmrg    {
233745801275Sjmcneill	/*
233845801275Sjmcneill	 * There's a threshold in the positive direction.  If we've been
233945801275Sjmcneill	 * idle less than it, schedule a wakeup for sometime in the future.
234045801275Sjmcneill	 * If we've been idle more than it, and someone wants to know about
234145801275Sjmcneill	 * that level-triggered, schedule an immediate wakeup.
234245801275Sjmcneill	 */
234345801275Sjmcneill	unsigned long timeout = -1;
234405b261ecSmrg
234545801275Sjmcneill	if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) {
234605b261ecSmrg	    XSyncValue value;
234705b261ecSmrg	    Bool overflow;
234805b261ecSmrg
234905b261ecSmrg	    XSyncValueSubtract (&value, *pIdleTimeValueGreater,
235005b261ecSmrg	                        idle, &overflow);
235145801275Sjmcneill	    timeout = min(timeout, XSyncValueLow32 (value));
235245801275Sjmcneill	} else {
235345801275Sjmcneill	    for (list = IdleTimeCounter->pTriglist; list; list = list->next) {
235445801275Sjmcneill		trig = list->pTrigger;
235545801275Sjmcneill		if (trig->CheckTrigger(trig, old_idle)) {
235645801275Sjmcneill		    timeout = min(timeout, 0);
235745801275Sjmcneill		    break;
235845801275Sjmcneill		}
235945801275Sjmcneill	    }
236005b261ecSmrg	}
236105b261ecSmrg
236205b261ecSmrg	AdjustWaitForDelay (wt, timeout);
236305b261ecSmrg    }
236445801275Sjmcneill
236545801275Sjmcneill    IdleTimeCounter->value = old_idle; /* pop */
236605b261ecSmrg}
236705b261ecSmrg
236805b261ecSmrgstatic void
23694202a189SmrgIdleTimeWakeupHandler (pointer env, int rc, pointer LastSelectMask)
237005b261ecSmrg{
237105b261ecSmrg    XSyncValue idle;
237205b261ecSmrg
237305b261ecSmrg    if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
237405b261ecSmrg	return;
237505b261ecSmrg
237605b261ecSmrg    IdleTimeQueryValue (NULL, &idle);
237705b261ecSmrg
237805b261ecSmrg    if ((pIdleTimeValueGreater &&
237905b261ecSmrg         XSyncValueGreaterOrEqual (idle, *pIdleTimeValueGreater)) ||
238005b261ecSmrg        (pIdleTimeValueLess &&
238105b261ecSmrg	 XSyncValueLessOrEqual (idle, *pIdleTimeValueLess)))
238205b261ecSmrg    {
238305b261ecSmrg	SyncChangeCounter (IdleTimeCounter, idle);
238405b261ecSmrg    }
238505b261ecSmrg}
238605b261ecSmrg
238705b261ecSmrgstatic void
23884202a189SmrgIdleTimeBracketValues (pointer pCounter, CARD64 *pbracket_less,
238905b261ecSmrg                       CARD64 *pbracket_greater)
239005b261ecSmrg{
239105b261ecSmrg    Bool registered = (pIdleTimeValueLess || pIdleTimeValueGreater);
239205b261ecSmrg
239305b261ecSmrg    if (registered && !pbracket_less && !pbracket_greater)
239405b261ecSmrg    {
239505b261ecSmrg	RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler,
239605b261ecSmrg	                             IdleTimeWakeupHandler,
239705b261ecSmrg	                             NULL);
239805b261ecSmrg    }
239905b261ecSmrg    else if (!registered && (pbracket_less || pbracket_greater))
240005b261ecSmrg    {
240105b261ecSmrg	RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
240205b261ecSmrg	                               IdleTimeWakeupHandler,
240305b261ecSmrg	                               NULL);
240405b261ecSmrg    }
240505b261ecSmrg
240605b261ecSmrg    pIdleTimeValueGreater = pbracket_greater;
240705b261ecSmrg    pIdleTimeValueLess    = pbracket_less;
240805b261ecSmrg}
240905b261ecSmrg
241005b261ecSmrgstatic void
241105b261ecSmrgSyncInitIdleTime (void)
241205b261ecSmrg{
241305b261ecSmrg    CARD64 resolution;
241405b261ecSmrg    XSyncValue idle;
241505b261ecSmrg
241605b261ecSmrg    IdleTimeQueryValue (NULL, &idle);
241705b261ecSmrg    XSyncIntToValue (&resolution, 4);
241805b261ecSmrg
241905b261ecSmrg    IdleTimeCounter = SyncCreateSystemCounter ("IDLETIME", idle, resolution,
242005b261ecSmrg                                               XSyncCounterUnrestricted,
242105b261ecSmrg                                               IdleTimeQueryValue,
242205b261ecSmrg                                               IdleTimeBracketValues);
242305b261ecSmrg
242405b261ecSmrg    pIdleTimeValueLess = pIdleTimeValueGreater = NULL;
242505b261ecSmrg}
2426