sync.c revision 4202a189
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"
7005b261ecSmrg
7105b261ecSmrg#include <stdio.h>
72637ac9abSmrg#if !defined(WIN32)
7305b261ecSmrg#include <sys/time.h>
7405b261ecSmrg#endif
7505b261ecSmrg
7605b261ecSmrg#include "modinit.h"
7705b261ecSmrg
7805b261ecSmrg/*
7905b261ecSmrg * Local Global Variables
8005b261ecSmrg */
8105b261ecSmrgstatic int      SyncEventBase;
8205b261ecSmrgstatic int      SyncErrorBase;
8305b261ecSmrgstatic RESTYPE  RTCounter = 0;
8405b261ecSmrgstatic RESTYPE  RTAwait;
8505b261ecSmrgstatic RESTYPE  RTAlarm;
8605b261ecSmrgstatic RESTYPE  RTAlarmClient;
8705b261ecSmrgstatic int SyncNumSystemCounters = 0;
8805b261ecSmrgstatic SyncCounter **SysCounterList = NULL;
8905b261ecSmrg
9005b261ecSmrg#define IsSystemCounter(pCounter) \
9105b261ecSmrg    (pCounter && (pCounter->client == NULL))
9205b261ecSmrg
9305b261ecSmrg/* these are all the alarm attributes that pertain to the alarm's trigger */
9405b261ecSmrg#define XSyncCAAllTrigger \
9505b261ecSmrg    (XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType)
9605b261ecSmrg
974202a189Smrgstatic void SyncComputeBracketValues(SyncCounter *);
9805b261ecSmrg
994202a189Smrgstatic void SyncInitServerTime(void);
10005b261ecSmrg
1014202a189Smrgstatic void SyncInitIdleTime(void);
10205b261ecSmrg
10305b261ecSmrgstatic DISPATCH_PROC(ProcSyncAwait);
10405b261ecSmrgstatic DISPATCH_PROC(ProcSyncChangeAlarm);
10505b261ecSmrgstatic DISPATCH_PROC(ProcSyncChangeCounter);
10605b261ecSmrgstatic DISPATCH_PROC(ProcSyncCreateAlarm);
10705b261ecSmrgstatic DISPATCH_PROC(ProcSyncCreateCounter);
10805b261ecSmrgstatic DISPATCH_PROC(ProcSyncDestroyAlarm);
10905b261ecSmrgstatic DISPATCH_PROC(ProcSyncDestroyCounter);
11005b261ecSmrgstatic DISPATCH_PROC(ProcSyncDispatch);
11105b261ecSmrgstatic DISPATCH_PROC(ProcSyncGetPriority);
11205b261ecSmrgstatic DISPATCH_PROC(ProcSyncInitialize);
11305b261ecSmrgstatic DISPATCH_PROC(ProcSyncListSystemCounters);
11405b261ecSmrgstatic DISPATCH_PROC(ProcSyncQueryAlarm);
11505b261ecSmrgstatic DISPATCH_PROC(ProcSyncQueryCounter);
11605b261ecSmrgstatic DISPATCH_PROC(ProcSyncSetCounter);
11705b261ecSmrgstatic DISPATCH_PROC(ProcSyncSetPriority);
11805b261ecSmrgstatic DISPATCH_PROC(SProcSyncAwait);
11905b261ecSmrgstatic DISPATCH_PROC(SProcSyncChangeAlarm);
12005b261ecSmrgstatic DISPATCH_PROC(SProcSyncChangeCounter);
12105b261ecSmrgstatic DISPATCH_PROC(SProcSyncCreateAlarm);
12205b261ecSmrgstatic DISPATCH_PROC(SProcSyncCreateCounter);
12305b261ecSmrgstatic DISPATCH_PROC(SProcSyncDestroyAlarm);
12405b261ecSmrgstatic DISPATCH_PROC(SProcSyncDestroyCounter);
12505b261ecSmrgstatic DISPATCH_PROC(SProcSyncDispatch);
12605b261ecSmrgstatic DISPATCH_PROC(SProcSyncGetPriority);
12705b261ecSmrgstatic DISPATCH_PROC(SProcSyncInitialize);
12805b261ecSmrgstatic DISPATCH_PROC(SProcSyncListSystemCounters);
12905b261ecSmrgstatic DISPATCH_PROC(SProcSyncQueryAlarm);
13005b261ecSmrgstatic DISPATCH_PROC(SProcSyncQueryCounter);
13105b261ecSmrgstatic DISPATCH_PROC(SProcSyncSetCounter);
13205b261ecSmrgstatic DISPATCH_PROC(SProcSyncSetPriority);
13305b261ecSmrg
13405b261ecSmrg/*  Each counter maintains a simple linked list of triggers that are
13505b261ecSmrg *  interested in the counter.  The two functions below are used to
13605b261ecSmrg *  delete and add triggers on this list.
13705b261ecSmrg */
13805b261ecSmrgstatic void
1394202a189SmrgSyncDeleteTriggerFromCounter(SyncTrigger *pTrigger)
14005b261ecSmrg{
14105b261ecSmrg    SyncTriggerList *pCur;
14205b261ecSmrg    SyncTriggerList *pPrev;
14305b261ecSmrg
14405b261ecSmrg    /* pCounter needs to be stored in pTrigger before calling here. */
14505b261ecSmrg
14605b261ecSmrg    if (!pTrigger->pCounter)
14705b261ecSmrg	return;
14805b261ecSmrg
14905b261ecSmrg    pPrev = NULL;
15005b261ecSmrg    pCur = pTrigger->pCounter->pTriglist;
15105b261ecSmrg
15205b261ecSmrg    while (pCur)
15305b261ecSmrg    {
15405b261ecSmrg	if (pCur->pTrigger == pTrigger)
15505b261ecSmrg	{
15605b261ecSmrg	    if (pPrev)
15705b261ecSmrg		pPrev->next = pCur->next;
15805b261ecSmrg	    else
15905b261ecSmrg		pTrigger->pCounter->pTriglist = pCur->next;
1604202a189Smrg
1614202a189Smrg	    free(pCur);
16205b261ecSmrg	    break;
16305b261ecSmrg	}
16405b261ecSmrg
16505b261ecSmrg	pPrev = pCur;
16605b261ecSmrg	pCur = pCur->next;
16705b261ecSmrg    }
1684202a189Smrg
16905b261ecSmrg    if (IsSystemCounter(pTrigger->pCounter))
1704202a189Smrg	SyncComputeBracketValues(pTrigger->pCounter);
17105b261ecSmrg}
17205b261ecSmrg
17305b261ecSmrg
17405b261ecSmrgstatic int
1754202a189SmrgSyncAddTriggerToCounter(SyncTrigger *pTrigger)
17605b261ecSmrg{
17705b261ecSmrg    SyncTriggerList *pCur;
17805b261ecSmrg
17905b261ecSmrg    if (!pTrigger->pCounter)
18005b261ecSmrg	return Success;
18105b261ecSmrg
18205b261ecSmrg    /* don't do anything if it's already there */
18305b261ecSmrg    for (pCur = pTrigger->pCounter->pTriglist; pCur; pCur = pCur->next)
18405b261ecSmrg    {
18505b261ecSmrg	if (pCur->pTrigger == pTrigger)
18605b261ecSmrg	    return Success;
18705b261ecSmrg    }
18805b261ecSmrg
1894202a189Smrg    if (!(pCur = malloc(sizeof(SyncTriggerList))))
19005b261ecSmrg	return BadAlloc;
19105b261ecSmrg
19205b261ecSmrg    pCur->pTrigger = pTrigger;
19305b261ecSmrg    pCur->next = pTrigger->pCounter->pTriglist;
19405b261ecSmrg    pTrigger->pCounter->pTriglist = pCur;
19505b261ecSmrg
19605b261ecSmrg    if (IsSystemCounter(pTrigger->pCounter))
1974202a189Smrg	SyncComputeBracketValues(pTrigger->pCounter);
19805b261ecSmrg
19905b261ecSmrg    return Success;
20005b261ecSmrg}
20105b261ecSmrg
20205b261ecSmrg
2034202a189Smrg/*  Below are four possible functions that can be plugged into
20405b261ecSmrg *  pTrigger->CheckTrigger, corresponding to the four possible
20505b261ecSmrg *  test-types.  These functions are called after the counter's
20605b261ecSmrg *  value changes but are also passed the old counter value
20705b261ecSmrg *  so they can inspect both the old and new values.
20805b261ecSmrg *  (PositiveTransition and NegativeTransition need to see both
20905b261ecSmrg *  pieces of information.)  These functions return the truth value
21005b261ecSmrg *  of the trigger.
21105b261ecSmrg *
21205b261ecSmrg *  All of them include the condition pTrigger->pCounter == NULL.
2134202a189Smrg *  This is because the spec says that a trigger with a counter value
21405b261ecSmrg *  of None is always TRUE.
21505b261ecSmrg */
21605b261ecSmrg
21705b261ecSmrgstatic Bool
2184202a189SmrgSyncCheckTriggerPositiveComparison(SyncTrigger *pTrigger, CARD64 oldval)
21905b261ecSmrg{
22005b261ecSmrg    return (pTrigger->pCounter == NULL ||
22105b261ecSmrg	    XSyncValueGreaterOrEqual(pTrigger->pCounter->value,
22205b261ecSmrg				     pTrigger->test_value));
22305b261ecSmrg}
22405b261ecSmrg
22505b261ecSmrgstatic Bool
2264202a189SmrgSyncCheckTriggerNegativeComparison(SyncTrigger *pTrigger,  CARD64 oldval)
22705b261ecSmrg{
22805b261ecSmrg    return (pTrigger->pCounter == NULL ||
22905b261ecSmrg	    XSyncValueLessOrEqual(pTrigger->pCounter->value,
23005b261ecSmrg				  pTrigger->test_value));
23105b261ecSmrg}
23205b261ecSmrg
23305b261ecSmrgstatic Bool
2344202a189SmrgSyncCheckTriggerPositiveTransition(SyncTrigger *pTrigger, CARD64 oldval)
23505b261ecSmrg{
23605b261ecSmrg    return (pTrigger->pCounter == NULL ||
23705b261ecSmrg	    (XSyncValueLessThan(oldval, pTrigger->test_value) &&
23805b261ecSmrg	     XSyncValueGreaterOrEqual(pTrigger->pCounter->value,
23905b261ecSmrg				      pTrigger->test_value)));
24005b261ecSmrg}
24105b261ecSmrg
24205b261ecSmrgstatic Bool
2434202a189SmrgSyncCheckTriggerNegativeTransition(SyncTrigger *pTrigger, CARD64 oldval)
24405b261ecSmrg{
24505b261ecSmrg    return (pTrigger->pCounter == NULL ||
24605b261ecSmrg	    (XSyncValueGreaterThan(oldval, pTrigger->test_value) &&
24705b261ecSmrg	     XSyncValueLessOrEqual(pTrigger->pCounter->value,
24805b261ecSmrg				   pTrigger->test_value)));
24905b261ecSmrg}
25005b261ecSmrg
2514202a189Smrgstatic int
2524202a189SmrgSyncInitTrigger(ClientPtr client, SyncTrigger *pTrigger, XSyncCounter counter,
2534202a189Smrg		Mask changes)
25405b261ecSmrg{
25505b261ecSmrg    SyncCounter *pCounter = pTrigger->pCounter;
256637ac9abSmrg    int		rc;
25705b261ecSmrg    Bool	newcounter = FALSE;
25805b261ecSmrg
25905b261ecSmrg    if (changes & XSyncCACounter)
26005b261ecSmrg    {
26105b261ecSmrg	if (counter == None)
26205b261ecSmrg	    pCounter = NULL;
263f241d193Smrg	else if (Success != (rc = dixLookupResourceByType ((pointer *)&pCounter,
264637ac9abSmrg				counter, RTCounter, client, DixReadAccess)))
26505b261ecSmrg	{
26605b261ecSmrg	    client->errorValue = counter;
2674202a189Smrg	    return rc;
26805b261ecSmrg	}
26905b261ecSmrg	if (pCounter != pTrigger->pCounter)
27005b261ecSmrg	{ /* new counter for trigger */
27105b261ecSmrg	    SyncDeleteTriggerFromCounter(pTrigger);
27205b261ecSmrg	    pTrigger->pCounter = pCounter;
27305b261ecSmrg	    newcounter = TRUE;
27405b261ecSmrg	}
27505b261ecSmrg    }
27605b261ecSmrg
27705b261ecSmrg    /* if system counter, ask it what the current value is */
27805b261ecSmrg
27905b261ecSmrg    if (IsSystemCounter(pCounter))
28005b261ecSmrg    {
28105b261ecSmrg	(*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
28205b261ecSmrg						  &pCounter->value);
28305b261ecSmrg    }
28405b261ecSmrg
28505b261ecSmrg    if (changes & XSyncCAValueType)
28605b261ecSmrg    {
28705b261ecSmrg	if (pTrigger->value_type != XSyncRelative &&
28805b261ecSmrg	    pTrigger->value_type != XSyncAbsolute)
28905b261ecSmrg	{
29005b261ecSmrg	    client->errorValue = pTrigger->value_type;
29105b261ecSmrg	    return BadValue;
29205b261ecSmrg	}
29305b261ecSmrg    }
29405b261ecSmrg
29505b261ecSmrg    if (changes & XSyncCATestType)
29605b261ecSmrg    {
29705b261ecSmrg	if (pTrigger->test_type != XSyncPositiveTransition &&
29805b261ecSmrg	    pTrigger->test_type != XSyncNegativeTransition &&
29905b261ecSmrg	    pTrigger->test_type != XSyncPositiveComparison &&
30005b261ecSmrg	    pTrigger->test_type != XSyncNegativeComparison)
30105b261ecSmrg	{
30205b261ecSmrg	    client->errorValue = pTrigger->test_type;
30305b261ecSmrg	    return BadValue;
30405b261ecSmrg	}
30505b261ecSmrg	/* select appropriate CheckTrigger function */
30605b261ecSmrg
30705b261ecSmrg	switch (pTrigger->test_type)
30805b261ecSmrg	{
3094202a189Smrg        case XSyncPositiveTransition:
31005b261ecSmrg	    pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition;
31105b261ecSmrg	    break;
3124202a189Smrg        case XSyncNegativeTransition:
31305b261ecSmrg	    pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition;
31405b261ecSmrg	    break;
3154202a189Smrg        case XSyncPositiveComparison:
31605b261ecSmrg	    pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison;
31705b261ecSmrg	    break;
3184202a189Smrg        case XSyncNegativeComparison:
31905b261ecSmrg	    pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison;
32005b261ecSmrg	    break;
32105b261ecSmrg	}
32205b261ecSmrg    }
32305b261ecSmrg
32405b261ecSmrg    if (changes & (XSyncCAValueType | XSyncCAValue))
32505b261ecSmrg    {
32605b261ecSmrg	if (pTrigger->value_type == XSyncAbsolute)
32705b261ecSmrg	    pTrigger->test_value = pTrigger->wait_value;
32805b261ecSmrg	else /* relative */
32905b261ecSmrg	{
33005b261ecSmrg	    Bool overflow;
33105b261ecSmrg	    if (pCounter == NULL)
33205b261ecSmrg		return BadMatch;
33305b261ecSmrg
3344202a189Smrg	    XSyncValueAdd(&pTrigger->test_value, pCounter->value,
33505b261ecSmrg			  pTrigger->wait_value, &overflow);
33605b261ecSmrg	    if (overflow)
33705b261ecSmrg	    {
33805b261ecSmrg		client->errorValue = XSyncValueHigh32(pTrigger->wait_value);
33905b261ecSmrg		return BadValue;
34005b261ecSmrg	    }
34105b261ecSmrg	}
34205b261ecSmrg    }
34305b261ecSmrg
34405b261ecSmrg    /*  we wait until we're sure there are no errors before registering
34505b261ecSmrg     *  a new counter on a trigger
34605b261ecSmrg     */
34705b261ecSmrg    if (newcounter)
34805b261ecSmrg    {
349637ac9abSmrg	if ((rc = SyncAddTriggerToCounter(pTrigger)) != Success)
350637ac9abSmrg	    return rc;
35105b261ecSmrg    }
35205b261ecSmrg    else if (IsSystemCounter(pCounter))
35305b261ecSmrg    {
3544202a189Smrg	SyncComputeBracketValues(pCounter);
35505b261ecSmrg    }
3564202a189Smrg
35705b261ecSmrg    return Success;
35805b261ecSmrg}
35905b261ecSmrg
36005b261ecSmrg/*  AlarmNotify events happen in response to actions taken on an Alarm or
3614202a189Smrg *  the counter used by the alarm.  AlarmNotify may be sent to multiple
36205b261ecSmrg *  clients.  The alarm maintains a list of clients interested in events.
36305b261ecSmrg */
36405b261ecSmrgstatic void
3654202a189SmrgSyncSendAlarmNotifyEvents(SyncAlarm *pAlarm)
36605b261ecSmrg{
36705b261ecSmrg    SyncAlarmClientList *pcl;
36805b261ecSmrg    xSyncAlarmNotifyEvent ane;
36905b261ecSmrg    SyncTrigger *pTrigger = &pAlarm->trigger;
37005b261ecSmrg
37105b261ecSmrg    UpdateCurrentTime();
37205b261ecSmrg
37305b261ecSmrg    ane.type = SyncEventBase + XSyncAlarmNotify;
37405b261ecSmrg    ane.kind = XSyncAlarmNotify;
37505b261ecSmrg    ane.alarm = pAlarm->alarm_id;
37605b261ecSmrg    if (pTrigger->pCounter)
37705b261ecSmrg    {
37805b261ecSmrg	ane.counter_value_hi = XSyncValueHigh32(pTrigger->pCounter->value);
37905b261ecSmrg	ane.counter_value_lo = XSyncValueLow32(pTrigger->pCounter->value);
38005b261ecSmrg    }
38105b261ecSmrg    else
38205b261ecSmrg    { /* XXX what else can we do if there's no counter? */
38305b261ecSmrg	ane.counter_value_hi = ane.counter_value_lo = 0;
38405b261ecSmrg    }
38505b261ecSmrg
38605b261ecSmrg    ane.alarm_value_hi = XSyncValueHigh32(pTrigger->test_value);
38705b261ecSmrg    ane.alarm_value_lo = XSyncValueLow32(pTrigger->test_value);
38805b261ecSmrg    ane.time = currentTime.milliseconds;
38905b261ecSmrg    ane.state = pAlarm->state;
39005b261ecSmrg
39105b261ecSmrg    /* send to owner */
3924202a189Smrg    if (pAlarm->events)
39305b261ecSmrg	WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane);
39405b261ecSmrg
39505b261ecSmrg    /* send to other interested clients */
39605b261ecSmrg    for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next)
3974202a189Smrg	WriteEventsToClient(pcl->client, 1, (xEvent *) &ane);
39805b261ecSmrg}
39905b261ecSmrg
40005b261ecSmrg
4014202a189Smrg/*  CounterNotify events only occur in response to an Await.  The events
40205b261ecSmrg *  go only to the Awaiting client.
40305b261ecSmrg */
40405b261ecSmrgstatic void
4054202a189SmrgSyncSendCounterNotifyEvents(ClientPtr client, SyncAwait **ppAwait,
4064202a189Smrg			    int num_events)
40705b261ecSmrg{
40805b261ecSmrg    xSyncCounterNotifyEvent *pEvents, *pev;
40905b261ecSmrg    int i;
41005b261ecSmrg
41105b261ecSmrg    if (client->clientGone)
41205b261ecSmrg	return;
4134202a189Smrg    pev = pEvents = malloc(num_events * sizeof(xSyncCounterNotifyEvent));
4144202a189Smrg    if (!pEvents)
41505b261ecSmrg	return;
41605b261ecSmrg    UpdateCurrentTime();
41705b261ecSmrg    for (i = 0; i < num_events; i++, ppAwait++, pev++)
41805b261ecSmrg    {
41905b261ecSmrg	SyncTrigger *pTrigger = &(*ppAwait)->trigger;
42005b261ecSmrg	pev->type = SyncEventBase + XSyncCounterNotify;
42105b261ecSmrg	pev->kind = XSyncCounterNotify;
42205b261ecSmrg	pev->counter = pTrigger->pCounter->id;
42305b261ecSmrg	pev->wait_value_lo = XSyncValueLow32(pTrigger->test_value);
42405b261ecSmrg	pev->wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
42505b261ecSmrg	pev->counter_value_lo = XSyncValueLow32(pTrigger->pCounter->value);
42605b261ecSmrg	pev->counter_value_hi = XSyncValueHigh32(pTrigger->pCounter->value);
42705b261ecSmrg	pev->time = currentTime.milliseconds;
42805b261ecSmrg	pev->count = num_events - i - 1; /* events remaining */
42905b261ecSmrg	pev->destroyed = pTrigger->pCounter->beingDestroyed;
43005b261ecSmrg    }
43105b261ecSmrg    /* swapping will be taken care of by this */
43205b261ecSmrg    WriteEventsToClient(client, num_events, (xEvent *)pEvents);
4334202a189Smrg    free(pEvents);
43405b261ecSmrg}
43505b261ecSmrg
43605b261ecSmrg
43705b261ecSmrg/* This function is called when an alarm's counter is destroyed.
43805b261ecSmrg * It is plugged into pTrigger->CounterDestroyed (for alarm triggers).
43905b261ecSmrg */
4404202a189Smrgstatic void
4414202a189SmrgSyncAlarmCounterDestroyed(SyncTrigger *pTrigger)
44205b261ecSmrg{
44305b261ecSmrg    SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
44405b261ecSmrg
44505b261ecSmrg    pAlarm->state = XSyncAlarmInactive;
44605b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
44705b261ecSmrg    pTrigger->pCounter = NULL;
44805b261ecSmrg}
44905b261ecSmrg
45005b261ecSmrg
4514202a189Smrg/*  This function is called when an alarm "goes off."
45205b261ecSmrg *  It is plugged into pTrigger->TriggerFired (for alarm triggers).
45305b261ecSmrg */
45405b261ecSmrgstatic void
4554202a189SmrgSyncAlarmTriggerFired(SyncTrigger *pTrigger)
45605b261ecSmrg{
45705b261ecSmrg    SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
45805b261ecSmrg    CARD64 new_test_value;
45905b261ecSmrg
46005b261ecSmrg    /* no need to check alarm unless it's active */
46105b261ecSmrg    if (pAlarm->state != XSyncAlarmActive)
46205b261ecSmrg	return;
46305b261ecSmrg
46405b261ecSmrg    /*  " if the counter value is None, or if the delta is 0 and
46505b261ecSmrg     *    the test-type is PositiveComparison or NegativeComparison,
46605b261ecSmrg     *    no change is made to value (test-value) and the alarm
46705b261ecSmrg     *    state is changed to Inactive before the event is generated."
46805b261ecSmrg     */
46905b261ecSmrg    if (pAlarm->trigger.pCounter == NULL
47005b261ecSmrg	|| (XSyncValueIsZero(pAlarm->delta)
47105b261ecSmrg	    && (pAlarm->trigger.test_type == XSyncPositiveComparison
47205b261ecSmrg		|| pAlarm->trigger.test_type == XSyncNegativeComparison)))
47305b261ecSmrg	pAlarm->state = XSyncAlarmInactive;
47405b261ecSmrg
47505b261ecSmrg    new_test_value = pAlarm->trigger.test_value;
47605b261ecSmrg
47705b261ecSmrg    if (pAlarm->state == XSyncAlarmActive)
47805b261ecSmrg    {
47905b261ecSmrg	Bool overflow;
48005b261ecSmrg	CARD64 oldvalue;
48105b261ecSmrg	SyncTrigger *paTrigger = &pAlarm->trigger;
48205b261ecSmrg
48305b261ecSmrg	/* "The alarm is updated by repeatedly adding delta to the
48405b261ecSmrg	 *  value of the trigger and re-initializing it until it
48505b261ecSmrg	 *  becomes FALSE."
48605b261ecSmrg	 */
48705b261ecSmrg	oldvalue = paTrigger->test_value;
48805b261ecSmrg
48905b261ecSmrg	/* XXX really should do something smarter here */
49005b261ecSmrg
49105b261ecSmrg	do
49205b261ecSmrg	{
49305b261ecSmrg	    XSyncValueAdd(&paTrigger->test_value, paTrigger->test_value,
49405b261ecSmrg			  pAlarm->delta, &overflow);
4954202a189Smrg	} while (!overflow &&
49605b261ecSmrg	      (*paTrigger->CheckTrigger)(paTrigger,
49705b261ecSmrg					paTrigger->pCounter->value));
49805b261ecSmrg
49905b261ecSmrg	new_test_value = paTrigger->test_value;
50005b261ecSmrg	paTrigger->test_value = oldvalue;
50105b261ecSmrg
50205b261ecSmrg	/* "If this update would cause value to fall outside the range
50305b261ecSmrg	 *  for an INT64...no change is made to value (test-value) and
50405b261ecSmrg	 *  the alarm state is changed to Inactive before the event is
50505b261ecSmrg	 *  generated."
50605b261ecSmrg	 */
50705b261ecSmrg	if (overflow)
50805b261ecSmrg	{
50905b261ecSmrg	    new_test_value = oldvalue;
51005b261ecSmrg	    pAlarm->state = XSyncAlarmInactive;
51105b261ecSmrg	}
51205b261ecSmrg    }
51305b261ecSmrg    /*  The AlarmNotify event has to have the "new state of the alarm"
51405b261ecSmrg     *  which we can't be sure of until this point.  However, it has
51505b261ecSmrg     *  to have the "old" trigger test value.  That's the reason for
51605b261ecSmrg     *  all the newvalue/oldvalue shuffling above.  After we send the
51705b261ecSmrg     *  events, give the trigger its new test value.
51805b261ecSmrg     */
51905b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
52005b261ecSmrg    pTrigger->test_value = new_test_value;
52105b261ecSmrg}
52205b261ecSmrg
52305b261ecSmrg
52405b261ecSmrg/*  This function is called when an Await unblocks, either as a result
52505b261ecSmrg *  of the trigger firing OR the counter being destroyed.
52605b261ecSmrg *  It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed
52705b261ecSmrg *  (for Await triggers).
52805b261ecSmrg */
52905b261ecSmrgstatic void
5304202a189SmrgSyncAwaitTriggerFired(SyncTrigger *pTrigger)
53105b261ecSmrg{
53205b261ecSmrg    SyncAwait *pAwait = (SyncAwait *)pTrigger;
53305b261ecSmrg    int numwaits;
53405b261ecSmrg    SyncAwaitUnion *pAwaitUnion;
53505b261ecSmrg    SyncAwait **ppAwait;
53605b261ecSmrg    int num_events = 0;
53705b261ecSmrg
53805b261ecSmrg    pAwaitUnion = (SyncAwaitUnion *)pAwait->pHeader;
53905b261ecSmrg    numwaits = pAwaitUnion->header.num_waitconditions;
5404202a189Smrg    ppAwait = malloc(numwaits * sizeof(SyncAwait *));
54105b261ecSmrg    if (!ppAwait)
54205b261ecSmrg	goto bail;
54305b261ecSmrg
54405b261ecSmrg    pAwait = &(pAwaitUnion+1)->await;
54505b261ecSmrg
54605b261ecSmrg    /* "When a client is unblocked, all the CounterNotify events for
54705b261ecSmrg     *  the Await request are generated contiguously. If count is 0
54805b261ecSmrg     *  there are no more events to follow for this request. If
54905b261ecSmrg     *  count is n, there are at least n more events to follow."
55005b261ecSmrg     *
55105b261ecSmrg     *  Thus, it is best to find all the counters for which events
55205b261ecSmrg     *  need to be sent first, so that an accurate count field can
55305b261ecSmrg     *  be stored in the events.
55405b261ecSmrg     */
55505b261ecSmrg    for ( ; numwaits; numwaits--, pAwait++)
55605b261ecSmrg    {
55705b261ecSmrg	CARD64 diff;
55805b261ecSmrg	Bool overflow, diffgreater, diffequal;
55905b261ecSmrg
56005b261ecSmrg	/* "A CounterNotify event with the destroyed flag set to TRUE is
56105b261ecSmrg	 *  always generated if the counter for one of the triggers is
56205b261ecSmrg	 *  destroyed."
56305b261ecSmrg	 */
56405b261ecSmrg	if (pAwait->trigger.pCounter->beingDestroyed)
56505b261ecSmrg	{
56605b261ecSmrg	    ppAwait[num_events++] = pAwait;
56705b261ecSmrg	    continue;
56805b261ecSmrg	}
56905b261ecSmrg
57005b261ecSmrg	/* "The difference between the counter and the test value is
57105b261ecSmrg	 *  calculated by subtracting the test value from the value of
57205b261ecSmrg	 *  the counter."
57305b261ecSmrg	 */
57405b261ecSmrg	XSyncValueSubtract(&diff, pAwait->trigger.pCounter->value,
57505b261ecSmrg			   pAwait->trigger.test_value, &overflow);
57605b261ecSmrg
57705b261ecSmrg	/* "If the difference lies outside the range for an INT64, an
57805b261ecSmrg	 *  event is not generated."
57905b261ecSmrg	 */
58005b261ecSmrg	if (overflow)
58105b261ecSmrg	    continue;
58205b261ecSmrg	diffgreater = XSyncValueGreaterThan(diff, pAwait->event_threshold);
58305b261ecSmrg	diffequal   = XSyncValueEqual(diff, pAwait->event_threshold);
58405b261ecSmrg
58505b261ecSmrg	/* "If the test-type is PositiveTransition or
58605b261ecSmrg	 *  PositiveComparison, a CounterNotify event is generated if
58705b261ecSmrg	 *  the difference is at least event-threshold. If the test-type
58805b261ecSmrg	 *  is NegativeTransition or NegativeComparison, a CounterNotify
58905b261ecSmrg	 *  event is generated if the difference is at most
59005b261ecSmrg	 *  event-threshold."
59105b261ecSmrg	 */
59205b261ecSmrg
59305b261ecSmrg	if ( ((pAwait->trigger.test_type == XSyncPositiveComparison ||
59405b261ecSmrg	       pAwait->trigger.test_type == XSyncPositiveTransition)
59505b261ecSmrg	       && (diffgreater || diffequal))
59605b261ecSmrg	     ||
59705b261ecSmrg	     ((pAwait->trigger.test_type == XSyncNegativeComparison ||
59805b261ecSmrg	       pAwait->trigger.test_type == XSyncNegativeTransition)
59905b261ecSmrg	      && (!diffgreater) /* less or equal */
60005b261ecSmrg	      )
60105b261ecSmrg	   )
60205b261ecSmrg	{
60305b261ecSmrg	    ppAwait[num_events++] = pAwait;
60405b261ecSmrg	}
60505b261ecSmrg    }
60605b261ecSmrg    if (num_events)
60705b261ecSmrg	SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait,
60805b261ecSmrg				    num_events);
6094202a189Smrg    free(ppAwait);
61005b261ecSmrg
61105b261ecSmrgbail:
61205b261ecSmrg    /* unblock the client */
61305b261ecSmrg    AttendClient(pAwaitUnion->header.client);
61405b261ecSmrg    /* delete the await */
61505b261ecSmrg    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
61605b261ecSmrg}
61705b261ecSmrg
61805b261ecSmrg
61905b261ecSmrg/*  This function should always be used to change a counter's value so that
62005b261ecSmrg *  any triggers depending on the counter will be checked.
62105b261ecSmrg */
62205b261ecSmrgvoid
6234202a189SmrgSyncChangeCounter(SyncCounter *pCounter, CARD64 newval)
62405b261ecSmrg{
62505b261ecSmrg    SyncTriggerList       *ptl, *pnext;
62605b261ecSmrg    CARD64 oldval;
62705b261ecSmrg
62805b261ecSmrg    oldval = pCounter->value;
62905b261ecSmrg    pCounter->value = newval;
63005b261ecSmrg
63105b261ecSmrg    /* run through triggers to see if any become true */
63205b261ecSmrg    for (ptl = pCounter->pTriglist; ptl; ptl = pnext)
63305b261ecSmrg    {
63405b261ecSmrg	pnext = ptl->next;
63505b261ecSmrg	if ((*ptl->pTrigger->CheckTrigger)(ptl->pTrigger, oldval))
63605b261ecSmrg	    (*ptl->pTrigger->TriggerFired)(ptl->pTrigger);
63705b261ecSmrg    }
63805b261ecSmrg
63905b261ecSmrg    if (IsSystemCounter(pCounter))
64005b261ecSmrg    {
6414202a189Smrg	SyncComputeBracketValues(pCounter);
64205b261ecSmrg    }
64305b261ecSmrg}
64405b261ecSmrg
64505b261ecSmrg
64605b261ecSmrg/* loosely based on dix/events.c/EventSelectForWindow */
64705b261ecSmrgstatic Bool
6484202a189SmrgSyncEventSelectForAlarm(SyncAlarm *pAlarm, ClientPtr client, Bool wantevents)
64905b261ecSmrg{
65005b261ecSmrg    SyncAlarmClientList *pClients;
65105b261ecSmrg
65205b261ecSmrg    if (client == pAlarm->client) /* alarm owner */
65305b261ecSmrg    {
65405b261ecSmrg	pAlarm->events = wantevents;
65505b261ecSmrg	return Success;
65605b261ecSmrg    }
65705b261ecSmrg
65805b261ecSmrg    /* see if the client is already on the list (has events selected) */
65905b261ecSmrg
66005b261ecSmrg    for (pClients = pAlarm->pEventClients; pClients;
66105b261ecSmrg	 pClients = pClients->next)
66205b261ecSmrg    {
66305b261ecSmrg	if (pClients->client == client)
66405b261ecSmrg	{
6654202a189Smrg	    /* client's presence on the list indicates desire for
6664202a189Smrg	     * events.  If the client doesn't want events, remove it
66705b261ecSmrg	     * from the list.  If the client does want events, do
66805b261ecSmrg	     * nothing, since it's already got them.
66905b261ecSmrg	     */
67005b261ecSmrg	    if (!wantevents)
67105b261ecSmrg	    {
67205b261ecSmrg		FreeResource(pClients->delete_id, RT_NONE);
67305b261ecSmrg	    }
67405b261ecSmrg	    return Success;
67505b261ecSmrg	}
67605b261ecSmrg    }
67705b261ecSmrg
67805b261ecSmrg    /*  if we get here, this client does not currently have
67905b261ecSmrg     *  events selected on the alarm
68005b261ecSmrg     */
68105b261ecSmrg
68205b261ecSmrg    if (!wantevents)
6834202a189Smrg	/* client doesn't want events, and we just discovered that it
68405b261ecSmrg	 * doesn't have them, so there's nothing to do.
68505b261ecSmrg	 */
68605b261ecSmrg	return Success;
68705b261ecSmrg
68805b261ecSmrg    /* add new client to pAlarm->pEventClients */
68905b261ecSmrg
6904202a189Smrg    pClients = malloc(sizeof(SyncAlarmClientList));
69105b261ecSmrg    if (!pClients)
69205b261ecSmrg	return BadAlloc;
69305b261ecSmrg
6944202a189Smrg    /*  register it as a resource so it will be cleaned up
69505b261ecSmrg     *  if the client dies
69605b261ecSmrg     */
69705b261ecSmrg
69805b261ecSmrg    pClients->delete_id = FakeClientID(client->index);
69905b261ecSmrg    if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm))
70005b261ecSmrg    {
7014202a189Smrg	free(pClients);
70205b261ecSmrg	return BadAlloc;
70305b261ecSmrg    }
70405b261ecSmrg
70505b261ecSmrg    /* link it into list after we know all the allocations succeed */
70605b261ecSmrg
70705b261ecSmrg    pClients->next = pAlarm->pEventClients;
70805b261ecSmrg    pAlarm->pEventClients = pClients;
70905b261ecSmrg    pClients->client = client;
71005b261ecSmrg    return Success;
71105b261ecSmrg}
71205b261ecSmrg
71305b261ecSmrg/*
71405b261ecSmrg * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm
71505b261ecSmrg */
7164202a189Smrgstatic int
7174202a189SmrgSyncChangeAlarmAttributes(ClientPtr client, SyncAlarm *pAlarm, Mask mask,
7184202a189Smrg			  CARD32 *values)
71905b261ecSmrg{
72005b261ecSmrg    int		   status;
72105b261ecSmrg    XSyncCounter   counter;
72205b261ecSmrg    Mask	   origmask = mask;
72305b261ecSmrg
72405b261ecSmrg    counter = pAlarm->trigger.pCounter ? pAlarm->trigger.pCounter->id : None;
72505b261ecSmrg
72605b261ecSmrg    while (mask)
72705b261ecSmrg    {
72805b261ecSmrg	int    index2 = lowbit(mask);
72905b261ecSmrg	mask &= ~index2;
73005b261ecSmrg	switch (index2)
73105b261ecSmrg	{
73205b261ecSmrg	  case XSyncCACounter:
73305b261ecSmrg	    mask &= ~XSyncCACounter;
73405b261ecSmrg	    /* sanity check in SyncInitTrigger */
73505b261ecSmrg	    counter = *values++;
73605b261ecSmrg	    break;
73705b261ecSmrg
73805b261ecSmrg	  case XSyncCAValueType:
73905b261ecSmrg	    mask &= ~XSyncCAValueType;
74005b261ecSmrg	    /* sanity check in SyncInitTrigger */
74105b261ecSmrg	    pAlarm->trigger.value_type = *values++;
74205b261ecSmrg	    break;
74305b261ecSmrg
74405b261ecSmrg	  case XSyncCAValue:
74505b261ecSmrg	    mask &= ~XSyncCAValue;
74605b261ecSmrg	    XSyncIntsToValue(&pAlarm->trigger.wait_value, values[1], values[0]);
74705b261ecSmrg	    values += 2;
74805b261ecSmrg	    break;
74905b261ecSmrg
75005b261ecSmrg	  case XSyncCATestType:
75105b261ecSmrg	    mask &= ~XSyncCATestType;
75205b261ecSmrg	    /* sanity check in SyncInitTrigger */
75305b261ecSmrg	    pAlarm->trigger.test_type = *values++;
75405b261ecSmrg	    break;
75505b261ecSmrg
75605b261ecSmrg	  case XSyncCADelta:
75705b261ecSmrg	    mask &= ~XSyncCADelta;
75805b261ecSmrg	    XSyncIntsToValue(&pAlarm->delta, values[1], values[0]);
75905b261ecSmrg	    values += 2;
76005b261ecSmrg	    break;
76105b261ecSmrg
76205b261ecSmrg	  case XSyncCAEvents:
76305b261ecSmrg	    mask &= ~XSyncCAEvents;
76405b261ecSmrg	    if ((*values != xTrue) && (*values != xFalse))
76505b261ecSmrg	    {
76605b261ecSmrg		client->errorValue = *values;
76705b261ecSmrg		return BadValue;
76805b261ecSmrg	    }
76905b261ecSmrg	    status = SyncEventSelectForAlarm(pAlarm, client,
77005b261ecSmrg					     (Bool)(*values++));
77105b261ecSmrg	    if (status != Success)
77205b261ecSmrg		return status;
77305b261ecSmrg	    break;
77405b261ecSmrg
77505b261ecSmrg	  default:
77605b261ecSmrg	    client->errorValue = mask;
77705b261ecSmrg	    return BadValue;
77805b261ecSmrg	}
77905b261ecSmrg    }
78005b261ecSmrg
78105b261ecSmrg    /* "If the test-type is PositiveComparison or PositiveTransition
78205b261ecSmrg     *  and delta is less than zero, or if the test-type is
78305b261ecSmrg     *  NegativeComparison or NegativeTransition and delta is
78405b261ecSmrg     *  greater than zero, a Match error is generated."
78505b261ecSmrg     */
78605b261ecSmrg    if (origmask & (XSyncCADelta|XSyncCATestType))
78705b261ecSmrg    {
78805b261ecSmrg	CARD64 zero;
78905b261ecSmrg	XSyncIntToValue(&zero, 0);
79005b261ecSmrg	if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) ||
79105b261ecSmrg	      (pAlarm->trigger.test_type == XSyncPositiveTransition))
79205b261ecSmrg	     && XSyncValueLessThan(pAlarm->delta, zero))
79305b261ecSmrg	    ||
79405b261ecSmrg	    (((pAlarm->trigger.test_type == XSyncNegativeComparison) ||
79505b261ecSmrg	      (pAlarm->trigger.test_type == XSyncNegativeTransition))
79605b261ecSmrg	     && XSyncValueGreaterThan(pAlarm->delta, zero))
79705b261ecSmrg	   )
79805b261ecSmrg	{
79905b261ecSmrg	    return BadMatch;
80005b261ecSmrg	}
80105b261ecSmrg    }
80205b261ecSmrg
80305b261ecSmrg    /* postpone this until now, when we're sure nothing else can go wrong */
80405b261ecSmrg    if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter,
80505b261ecSmrg			     origmask & XSyncCAAllTrigger)) != Success)
80605b261ecSmrg	return status;
80705b261ecSmrg
80805b261ecSmrg    /* XXX spec does not really say to do this - needs clarification */
80905b261ecSmrg    pAlarm->state = XSyncAlarmActive;
81005b261ecSmrg    return Success;
81105b261ecSmrg}
81205b261ecSmrg
81305b261ecSmrg
81405b261ecSmrgstatic SyncCounter *
8154202a189SmrgSyncCreateCounter(ClientPtr client, XSyncCounter id, CARD64 initialvalue)
81605b261ecSmrg{
81705b261ecSmrg    SyncCounter *pCounter;
81805b261ecSmrg
8194202a189Smrg    if (!(pCounter = malloc(sizeof(SyncCounter))))
8204202a189Smrg	return NULL;
82105b261ecSmrg
82205b261ecSmrg    if (!AddResource(id, RTCounter, (pointer) pCounter))
82305b261ecSmrg    {
8244202a189Smrg	free(pCounter);
8254202a189Smrg	return NULL;
82605b261ecSmrg    }
82705b261ecSmrg
82805b261ecSmrg    pCounter->client = client;
82905b261ecSmrg    pCounter->id = id;
83005b261ecSmrg    pCounter->value = initialvalue;
83105b261ecSmrg    pCounter->pTriglist = NULL;
83205b261ecSmrg    pCounter->beingDestroyed = FALSE;
83305b261ecSmrg    pCounter->pSysCounterInfo = NULL;
83405b261ecSmrg    return pCounter;
83505b261ecSmrg}
83605b261ecSmrg
8374202a189Smrgstatic int FreeCounter(void *, XID);
83805b261ecSmrg
83905b261ecSmrg/*
84005b261ecSmrg * ***** System Counter utilities
84105b261ecSmrg */
84205b261ecSmrg
8434202a189Smrgpointer
8444202a189SmrgSyncCreateSystemCounter(
8454202a189Smrg	char *name,
8464202a189Smrg	CARD64 initial,
8474202a189Smrg	CARD64 resolution,
8484202a189Smrg	SyncCounterType counterType,
8494202a189Smrg	void (*QueryValue)(pointer /* pCounter */,
8504202a189Smrg	      	           CARD64 * /* pValue_return */),
8514202a189Smrg	void (*BracketValues)(pointer /* pCounter */,
8524202a189Smrg	       	              CARD64 * /* pbracket_less */,
8534202a189Smrg	                      CARD64 * /* pbracket_greater */)
8544202a189Smrg	)
85505b261ecSmrg{
85605b261ecSmrg    SyncCounter    *pCounter;
85705b261ecSmrg
8584202a189Smrg    SysCounterList = realloc(SysCounterList,
85905b261ecSmrg			    (SyncNumSystemCounters+1)*sizeof(SyncCounter *));
86005b261ecSmrg    if (!SysCounterList)
8614202a189Smrg	return NULL;
86205b261ecSmrg
86305b261ecSmrg    /* this function may be called before SYNC has been initialized, so we
86405b261ecSmrg     * have to make sure RTCounter is created.
86505b261ecSmrg     */
86605b261ecSmrg    if (RTCounter == 0)
86705b261ecSmrg    {
8684202a189Smrg	RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
86905b261ecSmrg	if (RTCounter == 0)
87005b261ecSmrg	{
8714202a189Smrg	    return NULL;
87205b261ecSmrg	}
87305b261ecSmrg    }
87405b261ecSmrg
8754202a189Smrg    pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial);
87605b261ecSmrg
87705b261ecSmrg    if (pCounter)
87805b261ecSmrg    {
87905b261ecSmrg	SysCounterInfo *psci;
88005b261ecSmrg
8814202a189Smrg	psci = malloc(sizeof(SysCounterInfo));
88205b261ecSmrg	if (!psci)
88305b261ecSmrg	{
88405b261ecSmrg	    FreeResource(pCounter->id, RT_NONE);
8854202a189Smrg	    return pCounter;
88605b261ecSmrg	}
88705b261ecSmrg	pCounter->pSysCounterInfo = psci;
88805b261ecSmrg	psci->name = name;
88905b261ecSmrg	psci->resolution = resolution;
89005b261ecSmrg	psci->counterType = counterType;
89105b261ecSmrg	psci->QueryValue = QueryValue;
89205b261ecSmrg	psci->BracketValues = BracketValues;
89305b261ecSmrg	XSyncMaxValue(&psci->bracket_greater);
89405b261ecSmrg	XSyncMinValue(&psci->bracket_less);
89505b261ecSmrg	SysCounterList[SyncNumSystemCounters++] = pCounter;
89605b261ecSmrg    }
8974202a189Smrg    return pCounter;
89805b261ecSmrg}
89905b261ecSmrg
90005b261ecSmrgvoid
9014202a189SmrgSyncDestroySystemCounter(pointer pSysCounter)
90205b261ecSmrg{
90305b261ecSmrg    SyncCounter *pCounter = (SyncCounter *)pSysCounter;
90405b261ecSmrg    FreeResource(pCounter->id, RT_NONE);
90505b261ecSmrg}
90605b261ecSmrg
90705b261ecSmrgstatic void
9084202a189SmrgSyncComputeBracketValues(SyncCounter *pCounter)
90905b261ecSmrg{
91005b261ecSmrg    SyncTriggerList *pCur;
91105b261ecSmrg    SyncTrigger *pTrigger;
91205b261ecSmrg    SysCounterInfo *psci;
91305b261ecSmrg    CARD64 *pnewgtval = NULL;
91405b261ecSmrg    CARD64 *pnewltval = NULL;
91505b261ecSmrg    SyncCounterType ct;
91605b261ecSmrg
91705b261ecSmrg    if (!pCounter)
91805b261ecSmrg	return;
91905b261ecSmrg
92005b261ecSmrg    psci = pCounter->pSysCounterInfo;
92105b261ecSmrg    ct = pCounter->pSysCounterInfo->counterType;
92205b261ecSmrg    if (ct == XSyncCounterNeverChanges)
92305b261ecSmrg	return;
92405b261ecSmrg
9254202a189Smrg    XSyncMaxValue(&psci->bracket_greater);
9264202a189Smrg    XSyncMinValue(&psci->bracket_less);
92705b261ecSmrg
92805b261ecSmrg    for (pCur = pCounter->pTriglist; pCur; pCur = pCur->next)
92905b261ecSmrg    {
93005b261ecSmrg	pTrigger = pCur->pTrigger;
93105b261ecSmrg
93205b261ecSmrg        if (pTrigger->test_type == XSyncPositiveComparison &&
93305b261ecSmrg	    ct != XSyncCounterNeverIncreases)
93405b261ecSmrg	{
93505b261ecSmrg	    if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
93605b261ecSmrg		XSyncValueLessThan(pTrigger->test_value,
93705b261ecSmrg				   psci->bracket_greater))
93805b261ecSmrg	    {
93905b261ecSmrg		psci->bracket_greater = pTrigger->test_value;
94005b261ecSmrg		pnewgtval = &psci->bracket_greater;
94105b261ecSmrg	    }
94205b261ecSmrg	}
94305b261ecSmrg	else if (pTrigger->test_type == XSyncNegativeComparison &&
94405b261ecSmrg		 ct != XSyncCounterNeverDecreases)
94505b261ecSmrg	{
94605b261ecSmrg	    if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
94705b261ecSmrg		XSyncValueGreaterThan(pTrigger->test_value,
94805b261ecSmrg				      psci->bracket_less))
94905b261ecSmrg	    {
95005b261ecSmrg		psci->bracket_less = pTrigger->test_value;
95105b261ecSmrg		pnewltval = &psci->bracket_less;
95205b261ecSmrg	    }
95305b261ecSmrg	}
954a0d10bb6Smrg	else if (pTrigger->test_type == XSyncNegativeTransition &&
95505b261ecSmrg		   ct != XSyncCounterNeverIncreases)
956a0d10bb6Smrg	{
957a0d10bb6Smrg	    if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
958a0d10bb6Smrg		XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less))
959a0d10bb6Smrg	    {
960a0d10bb6Smrg		psci->bracket_less = pTrigger->test_value;
961a0d10bb6Smrg		pnewltval = &psci->bracket_less;
962a0d10bb6Smrg	    }
963a0d10bb6Smrg	}
964a0d10bb6Smrg        else if (pTrigger->test_type == XSyncPositiveTransition &&
96505b261ecSmrg		  ct != XSyncCounterNeverDecreases)
96605b261ecSmrg	{
967a0d10bb6Smrg	    if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
968a0d10bb6Smrg		XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater))
96905b261ecSmrg	    {
970a0d10bb6Smrg		psci->bracket_greater = pTrigger->test_value;
971a0d10bb6Smrg		pnewgtval = &psci->bracket_greater;
97205b261ecSmrg	    }
97305b261ecSmrg	}
97405b261ecSmrg    } /* end for each trigger */
97505b261ecSmrg
97605b261ecSmrg    if (pnewgtval || pnewltval)
97705b261ecSmrg    {
97805b261ecSmrg	(*psci->BracketValues)((pointer)pCounter, pnewltval, pnewgtval);
97905b261ecSmrg    }
98005b261ecSmrg}
98105b261ecSmrg
98205b261ecSmrg/*
98305b261ecSmrg * *****  Resource delete functions
98405b261ecSmrg */
98505b261ecSmrg
98605b261ecSmrg/* ARGSUSED */
98705b261ecSmrgstatic int
9884202a189SmrgFreeAlarm(void *addr, XID id)
98905b261ecSmrg{
99005b261ecSmrg    SyncAlarm      *pAlarm = (SyncAlarm *) addr;
99105b261ecSmrg
99205b261ecSmrg    pAlarm->state = XSyncAlarmDestroyed;
99305b261ecSmrg
99405b261ecSmrg    SyncSendAlarmNotifyEvents(pAlarm);
99505b261ecSmrg
99605b261ecSmrg    /* delete event selections */
99705b261ecSmrg
99805b261ecSmrg    while (pAlarm->pEventClients)
99905b261ecSmrg	FreeResource(pAlarm->pEventClients->delete_id, RT_NONE);
100005b261ecSmrg
100105b261ecSmrg    SyncDeleteTriggerFromCounter(&pAlarm->trigger);
100205b261ecSmrg
10034202a189Smrg    free(pAlarm);
100405b261ecSmrg    return Success;
100505b261ecSmrg}
100605b261ecSmrg
100705b261ecSmrg
100805b261ecSmrg/*
100905b261ecSmrg * ** Cleanup after the destruction of a Counter
101005b261ecSmrg */
101105b261ecSmrg/* ARGSUSED */
101205b261ecSmrgstatic int
10134202a189SmrgFreeCounter(void *env, XID id)
101405b261ecSmrg{
101505b261ecSmrg    SyncCounter     *pCounter = (SyncCounter *) env;
101605b261ecSmrg    SyncTriggerList *ptl, *pnext;
101705b261ecSmrg
101805b261ecSmrg    pCounter->beingDestroyed = TRUE;
101905b261ecSmrg    /* tell all the counter's triggers that the counter has been destroyed */
102005b261ecSmrg    for (ptl = pCounter->pTriglist; ptl; ptl = pnext)
102105b261ecSmrg    {
102205b261ecSmrg	(*ptl->pTrigger->CounterDestroyed)(ptl->pTrigger);
102305b261ecSmrg	pnext = ptl->next;
10244202a189Smrg	free(ptl); /* destroy the trigger list as we go */
102505b261ecSmrg    }
102605b261ecSmrg    if (IsSystemCounter(pCounter))
102705b261ecSmrg    {
102805b261ecSmrg	int i, found = 0;
102905b261ecSmrg
10304202a189Smrg	free(pCounter->pSysCounterInfo);
103105b261ecSmrg
103205b261ecSmrg	/* find the counter in the list of system counters and remove it */
103305b261ecSmrg
103405b261ecSmrg	if (SysCounterList)
103505b261ecSmrg	{
103605b261ecSmrg	    for (i = 0; i < SyncNumSystemCounters; i++)
103705b261ecSmrg	    {
103805b261ecSmrg		if (SysCounterList[i] == pCounter)
103905b261ecSmrg		{
104005b261ecSmrg		    found = i;
104105b261ecSmrg		    break;
104205b261ecSmrg		}
104305b261ecSmrg	    }
104405b261ecSmrg	    if (found < (SyncNumSystemCounters-1))
104505b261ecSmrg	    {
104605b261ecSmrg		for (i = found; i < SyncNumSystemCounters-1; i++)
104705b261ecSmrg		{
104805b261ecSmrg		    SysCounterList[i] = SysCounterList[i+1];
104905b261ecSmrg		}
105005b261ecSmrg	    }
105105b261ecSmrg	}
105205b261ecSmrg	SyncNumSystemCounters--;
105305b261ecSmrg    }
10544202a189Smrg    free(pCounter);
105505b261ecSmrg    return Success;
105605b261ecSmrg}
105705b261ecSmrg
105805b261ecSmrg/*
105905b261ecSmrg * ** Cleanup after Await
106005b261ecSmrg */
106105b261ecSmrg/* ARGSUSED */
106205b261ecSmrgstatic int
10634202a189SmrgFreeAwait(void *addr, XID id)
106405b261ecSmrg{
106505b261ecSmrg    SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr;
106605b261ecSmrg    SyncAwait *pAwait;
106705b261ecSmrg    int numwaits;
106805b261ecSmrg
106905b261ecSmrg    pAwait = &(pAwaitUnion+1)->await; /* first await on list */
107005b261ecSmrg
107105b261ecSmrg    /* remove triggers from counters */
107205b261ecSmrg
107305b261ecSmrg    for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits;
107405b261ecSmrg	 numwaits--, pAwait++)
107505b261ecSmrg    {
10764202a189Smrg	/* If the counter is being destroyed, FreeCounter will delete
107705b261ecSmrg	 * the trigger list itself, so don't do it here.
107805b261ecSmrg	 */
107905b261ecSmrg	SyncCounter *pCounter = pAwait->trigger.pCounter;
108005b261ecSmrg	if (pCounter && !pCounter->beingDestroyed)
108105b261ecSmrg	    SyncDeleteTriggerFromCounter(&pAwait->trigger);
108205b261ecSmrg    }
10834202a189Smrg    free(pAwaitUnion);
108405b261ecSmrg    return Success;
108505b261ecSmrg}
108605b261ecSmrg
108705b261ecSmrg/* loosely based on dix/events.c/OtherClientGone */
108805b261ecSmrgstatic int
10894202a189SmrgFreeAlarmClient(void *value, XID id)
109005b261ecSmrg{
109105b261ecSmrg    SyncAlarm *pAlarm = (SyncAlarm *)value;
109205b261ecSmrg    SyncAlarmClientList *pCur, *pPrev;
109305b261ecSmrg
109405b261ecSmrg    for (pPrev = NULL, pCur = pAlarm->pEventClients;
109505b261ecSmrg	 pCur;
109605b261ecSmrg	 pPrev = pCur, pCur = pCur->next)
109705b261ecSmrg    {
109805b261ecSmrg	if (pCur->delete_id == id)
109905b261ecSmrg	{
110005b261ecSmrg	    if (pPrev)
110105b261ecSmrg		pPrev->next = pCur->next;
110205b261ecSmrg	    else
110305b261ecSmrg		pAlarm->pEventClients = pCur->next;
11044202a189Smrg	    free(pCur);
11054202a189Smrg	    return Success;
110605b261ecSmrg	}
110705b261ecSmrg    }
110805b261ecSmrg    FatalError("alarm client not on event list");
110905b261ecSmrg    /*NOTREACHED*/
111005b261ecSmrg}
111105b261ecSmrg
111205b261ecSmrg
111305b261ecSmrg/*
111405b261ecSmrg * *****  Proc functions
111505b261ecSmrg */
111605b261ecSmrg
111705b261ecSmrg
111805b261ecSmrg/*
111905b261ecSmrg * ** Initialize the extension
112005b261ecSmrg */
11214202a189Smrgstatic int
11224202a189SmrgProcSyncInitialize(ClientPtr client)
112305b261ecSmrg{
112405b261ecSmrg    xSyncInitializeReply  rep;
112505b261ecSmrg    int   n;
112605b261ecSmrg
112705b261ecSmrg    REQUEST_SIZE_MATCH(xSyncInitializeReq);
112805b261ecSmrg
11294202a189Smrg    memset(&rep, 0, sizeof(xSyncInitializeReply));
113005b261ecSmrg    rep.type = X_Reply;
113105b261ecSmrg    rep.sequenceNumber = client->sequence;
113205b261ecSmrg    rep.majorVersion = SYNC_MAJOR_VERSION;
113305b261ecSmrg    rep.minorVersion = SYNC_MINOR_VERSION;
113405b261ecSmrg    rep.length = 0;
113505b261ecSmrg
113605b261ecSmrg    if (client->swapped)
113705b261ecSmrg    {
113805b261ecSmrg	swaps(&rep.sequenceNumber, n);
113905b261ecSmrg    }
114005b261ecSmrg    WriteToClient(client, sizeof(rep), (char *) &rep);
11414202a189Smrg    return Success;
114205b261ecSmrg}
114305b261ecSmrg
114405b261ecSmrg/*
114505b261ecSmrg * ** Get list of system counters available through the extension
114605b261ecSmrg */
11474202a189Smrgstatic int
11484202a189SmrgProcSyncListSystemCounters(ClientPtr client)
114905b261ecSmrg{
115005b261ecSmrg    xSyncListSystemCountersReply  rep;
115105b261ecSmrg    int i, len;
115205b261ecSmrg    xSyncSystemCounter *list = NULL, *walklist = NULL;
11534202a189Smrg
115405b261ecSmrg    REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
115505b261ecSmrg
115605b261ecSmrg    rep.type = X_Reply;
115705b261ecSmrg    rep.sequenceNumber = client->sequence;
115805b261ecSmrg    rep.nCounters = SyncNumSystemCounters;
115905b261ecSmrg
116005b261ecSmrg    for (i = len = 0; i < SyncNumSystemCounters; i++)
116105b261ecSmrg    {
116205b261ecSmrg	char *name = SysCounterList[i]->pSysCounterInfo->name;
116305b261ecSmrg	/* pad to 4 byte boundary */
11644202a189Smrg	len += pad_to_int32(sz_xSyncSystemCounter + strlen(name));
116505b261ecSmrg    }
116605b261ecSmrg
116705b261ecSmrg    if (len)
116805b261ecSmrg    {
11694202a189Smrg	walklist = list = malloc(len);
117005b261ecSmrg	if (!list)
117105b261ecSmrg	    return BadAlloc;
117205b261ecSmrg    }
117305b261ecSmrg
11744202a189Smrg    rep.length = bytes_to_int32(len);
117505b261ecSmrg
117605b261ecSmrg    if (client->swapped)
117705b261ecSmrg    {
1178637ac9abSmrg	char n;
117905b261ecSmrg	swaps(&rep.sequenceNumber, n);
118005b261ecSmrg	swapl(&rep.length, n);
118105b261ecSmrg	swapl(&rep.nCounters, n);
118205b261ecSmrg    }
118305b261ecSmrg
118405b261ecSmrg    for (i = 0; i < SyncNumSystemCounters; i++)
118505b261ecSmrg    {
118605b261ecSmrg	int namelen;
118705b261ecSmrg	char *pname_in_reply;
118805b261ecSmrg	SysCounterInfo *psci = SysCounterList[i]->pSysCounterInfo;
118905b261ecSmrg
119005b261ecSmrg	walklist->counter = SysCounterList[i]->id;
119105b261ecSmrg	walklist->resolution_hi = XSyncValueHigh32(psci->resolution);
119205b261ecSmrg	walklist->resolution_lo = XSyncValueLow32(psci->resolution);
119305b261ecSmrg	namelen = strlen(psci->name);
119405b261ecSmrg	walklist->name_length = namelen;
119505b261ecSmrg
119605b261ecSmrg	if (client->swapped)
119705b261ecSmrg	{
1198637ac9abSmrg	    char n;
119905b261ecSmrg	    swapl(&walklist->counter, n);
120005b261ecSmrg	    swapl(&walklist->resolution_hi, n);
120105b261ecSmrg	    swapl(&walklist->resolution_lo, n);
120205b261ecSmrg	    swaps(&walklist->name_length, n);
120305b261ecSmrg	}
120405b261ecSmrg
120505b261ecSmrg	pname_in_reply = ((char *)walklist) + sz_xSyncSystemCounter;
120605b261ecSmrg	strncpy(pname_in_reply, psci->name, namelen);
12074202a189Smrg	walklist = (xSyncSystemCounter *) (((char *)walklist) +
12084202a189Smrg				pad_to_int32(sz_xSyncSystemCounter + namelen));
120905b261ecSmrg    }
121005b261ecSmrg
121105b261ecSmrg    WriteToClient(client, sizeof(rep), (char *) &rep);
12124202a189Smrg    if (len)
121305b261ecSmrg    {
121405b261ecSmrg	WriteToClient(client, len, (char *) list);
12154202a189Smrg	free(list);
121605b261ecSmrg    }
121705b261ecSmrg
12184202a189Smrg    return Success;
121905b261ecSmrg}
122005b261ecSmrg
122105b261ecSmrg/*
122205b261ecSmrg * ** Set client Priority
122305b261ecSmrg */
12244202a189Smrgstatic int
12254202a189SmrgProcSyncSetPriority(ClientPtr client)
122605b261ecSmrg{
122705b261ecSmrg    REQUEST(xSyncSetPriorityReq);
122805b261ecSmrg    ClientPtr priorityclient;
122905b261ecSmrg    int rc;
123005b261ecSmrg
123105b261ecSmrg    REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
123205b261ecSmrg
123305b261ecSmrg    if (stuff->id == None)
123405b261ecSmrg	priorityclient = client;
123505b261ecSmrg    else {
123605b261ecSmrg	rc = dixLookupClient(&priorityclient, stuff->id, client,
1237637ac9abSmrg			     DixSetAttrAccess);
123805b261ecSmrg	if (rc != Success)
123905b261ecSmrg	    return rc;
124005b261ecSmrg    }
124105b261ecSmrg
124205b261ecSmrg    if (priorityclient->priority != stuff->priority)
124305b261ecSmrg    {
124405b261ecSmrg	priorityclient->priority = stuff->priority;
124505b261ecSmrg
124605b261ecSmrg	/*  The following will force the server back into WaitForSomething
124705b261ecSmrg	 *  so that the change in this client's priority is immediately
124805b261ecSmrg	 *  reflected.
124905b261ecSmrg	 */
125005b261ecSmrg	isItTimeToYield = TRUE;
125105b261ecSmrg	dispatchException |= DE_PRIORITYCHANGE;
125205b261ecSmrg    }
125305b261ecSmrg    return Success;
125405b261ecSmrg}
125505b261ecSmrg
125605b261ecSmrg/*
125705b261ecSmrg * ** Get client Priority
125805b261ecSmrg */
12594202a189Smrgstatic int
12604202a189SmrgProcSyncGetPriority(ClientPtr client)
126105b261ecSmrg{
126205b261ecSmrg    REQUEST(xSyncGetPriorityReq);
126305b261ecSmrg    xSyncGetPriorityReply rep;
126405b261ecSmrg    ClientPtr priorityclient;
126505b261ecSmrg    int rc;
126605b261ecSmrg
126705b261ecSmrg    REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
126805b261ecSmrg
126905b261ecSmrg    if (stuff->id == None)
127005b261ecSmrg	priorityclient = client;
127105b261ecSmrg    else {
127205b261ecSmrg	rc = dixLookupClient(&priorityclient, stuff->id, client,
1273637ac9abSmrg			     DixGetAttrAccess);
127405b261ecSmrg	if (rc != Success)
127505b261ecSmrg	    return rc;
127605b261ecSmrg    }
127705b261ecSmrg
127805b261ecSmrg    rep.type = X_Reply;
127905b261ecSmrg    rep.length = 0;
128005b261ecSmrg    rep.sequenceNumber = client->sequence;
128105b261ecSmrg    rep.priority = priorityclient->priority;
128205b261ecSmrg
128305b261ecSmrg    if (client->swapped)
128405b261ecSmrg    {
1285637ac9abSmrg	char n;
128605b261ecSmrg	swaps(&rep.sequenceNumber, n);
128705b261ecSmrg	swapl(&rep.priority, n);
128805b261ecSmrg    }
128905b261ecSmrg
129005b261ecSmrg    WriteToClient(client, sizeof(xSyncGetPriorityReply), (char *) &rep);
129105b261ecSmrg
12924202a189Smrg    return Success;
129305b261ecSmrg}
129405b261ecSmrg
129505b261ecSmrg/*
129605b261ecSmrg * ** Create a new counter
129705b261ecSmrg */
12984202a189Smrgstatic int
12994202a189SmrgProcSyncCreateCounter(ClientPtr client)
130005b261ecSmrg{
130105b261ecSmrg    REQUEST(xSyncCreateCounterReq);
130205b261ecSmrg    CARD64          initial;
130305b261ecSmrg
130405b261ecSmrg    REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
130505b261ecSmrg
130605b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->cid, client);
130705b261ecSmrg
130805b261ecSmrg    XSyncIntsToValue(&initial, stuff->initial_value_lo, stuff->initial_value_hi);
130905b261ecSmrg    if (!SyncCreateCounter(client, stuff->cid, initial))
131005b261ecSmrg	return BadAlloc;
131105b261ecSmrg
13124202a189Smrg    return Success;
131305b261ecSmrg}
131405b261ecSmrg
131505b261ecSmrg/*
131605b261ecSmrg * ** Set Counter value
131705b261ecSmrg */
13184202a189Smrgstatic int
13194202a189SmrgProcSyncSetCounter(ClientPtr client)
132005b261ecSmrg{
132105b261ecSmrg    REQUEST(xSyncSetCounterReq);
132205b261ecSmrg    SyncCounter    *pCounter;
132305b261ecSmrg    CARD64	   newvalue;
13244202a189Smrg    int	rc;
132505b261ecSmrg
132605b261ecSmrg    REQUEST_SIZE_MATCH(xSyncSetCounterReq);
132705b261ecSmrg
13284202a189Smrg    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
13294202a189Smrg				 client, DixWriteAccess);
13304202a189Smrg    if (rc != Success)
13314202a189Smrg	return rc;
133205b261ecSmrg
133305b261ecSmrg    if (IsSystemCounter(pCounter))
133405b261ecSmrg    {
133505b261ecSmrg	client->errorValue = stuff->cid;
133605b261ecSmrg	return BadAccess;
133705b261ecSmrg    }
133805b261ecSmrg
133905b261ecSmrg    XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
134005b261ecSmrg    SyncChangeCounter(pCounter, newvalue);
134105b261ecSmrg    return Success;
134205b261ecSmrg}
134305b261ecSmrg
134405b261ecSmrg/*
134505b261ecSmrg * ** Change Counter value
134605b261ecSmrg */
13474202a189Smrgstatic int
13484202a189SmrgProcSyncChangeCounter(ClientPtr client)
134905b261ecSmrg{
135005b261ecSmrg    REQUEST(xSyncChangeCounterReq);
135105b261ecSmrg    SyncCounter    *pCounter;
135205b261ecSmrg    CARD64          newvalue;
135305b261ecSmrg    Bool	    overflow;
13544202a189Smrg    int	rc;
135505b261ecSmrg
135605b261ecSmrg    REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
135705b261ecSmrg
13584202a189Smrg    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
13594202a189Smrg				 client, DixWriteAccess);
13604202a189Smrg    if (rc != Success)
13614202a189Smrg	return rc;
136205b261ecSmrg
136305b261ecSmrg    if (IsSystemCounter(pCounter))
136405b261ecSmrg    {
136505b261ecSmrg	client->errorValue = stuff->cid;
136605b261ecSmrg	return BadAccess;
136705b261ecSmrg    }
136805b261ecSmrg
136905b261ecSmrg    XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
137005b261ecSmrg    XSyncValueAdd(&newvalue, pCounter->value, newvalue, &overflow);
137105b261ecSmrg    if (overflow)
137205b261ecSmrg    {
137305b261ecSmrg	/* XXX 64 bit value can't fit in 32 bits; do the best we can */
13744202a189Smrg	client->errorValue = stuff->value_hi;
137505b261ecSmrg	return BadValue;
137605b261ecSmrg    }
137705b261ecSmrg    SyncChangeCounter(pCounter, newvalue);
137805b261ecSmrg    return Success;
137905b261ecSmrg}
138005b261ecSmrg
138105b261ecSmrg/*
138205b261ecSmrg * ** Destroy a counter
138305b261ecSmrg */
13844202a189Smrgstatic int
13854202a189SmrgProcSyncDestroyCounter(ClientPtr client)
138605b261ecSmrg{
138705b261ecSmrg    REQUEST(xSyncDestroyCounterReq);
138805b261ecSmrg    SyncCounter    *pCounter;
13894202a189Smrg    int rc;
139005b261ecSmrg
139105b261ecSmrg    REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
139205b261ecSmrg
13934202a189Smrg    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter, RTCounter,
13944202a189Smrg				 client, DixDestroyAccess);
13954202a189Smrg    if (rc != Success)
13964202a189Smrg	return rc;
13974202a189Smrg
139805b261ecSmrg    if (IsSystemCounter(pCounter))
139905b261ecSmrg    {
140005b261ecSmrg	client->errorValue = stuff->counter;
140105b261ecSmrg	return BadAccess;
140205b261ecSmrg    }
140305b261ecSmrg    FreeResource(pCounter->id, RT_NONE);
140405b261ecSmrg    return Success;
140505b261ecSmrg}
140605b261ecSmrg
140705b261ecSmrg
140805b261ecSmrg/*
140905b261ecSmrg * ** Await
141005b261ecSmrg */
14114202a189Smrgstatic int
14124202a189SmrgProcSyncAwait(ClientPtr client)
141305b261ecSmrg{
141405b261ecSmrg    REQUEST(xSyncAwaitReq);
141505b261ecSmrg    int             len, items;
141605b261ecSmrg    int             i;
141705b261ecSmrg    xSyncWaitCondition *pProtocolWaitConds;
141805b261ecSmrg    SyncAwaitUnion *pAwaitUnion;
141905b261ecSmrg    SyncAwait	   *pAwait;
142005b261ecSmrg    int		   status;
142105b261ecSmrg
142205b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
142305b261ecSmrg
142405b261ecSmrg    len = client->req_len << 2;
142505b261ecSmrg    len -= sz_xSyncAwaitReq;
142605b261ecSmrg    items = len / sz_xSyncWaitCondition;
142705b261ecSmrg
142805b261ecSmrg    if (items * sz_xSyncWaitCondition != len)
142905b261ecSmrg    {
143005b261ecSmrg	return BadLength;
143105b261ecSmrg    }
143205b261ecSmrg    if (items == 0)
143305b261ecSmrg    {
143405b261ecSmrg	client->errorValue = items; /* XXX protocol change */
143505b261ecSmrg	return BadValue;
143605b261ecSmrg    }
143705b261ecSmrg
143805b261ecSmrg    pProtocolWaitConds = (xSyncWaitCondition *) & stuff[1];
143905b261ecSmrg
14404202a189Smrg    /*  all the memory for the entire await list is allocated
144105b261ecSmrg     *  here in one chunk
144205b261ecSmrg     */
14434202a189Smrg    pAwaitUnion = malloc((items+1) * sizeof(SyncAwaitUnion));
144405b261ecSmrg    if (!pAwaitUnion)
144505b261ecSmrg	return BadAlloc;
144605b261ecSmrg
144705b261ecSmrg    /* first item is the header, remainder are real wait conditions */
144805b261ecSmrg
144905b261ecSmrg    pAwaitUnion->header.delete_id = FakeClientID(client->index);
145005b261ecSmrg    if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion))
145105b261ecSmrg    {
14524202a189Smrg	free(pAwaitUnion);
145305b261ecSmrg	return BadAlloc;
145405b261ecSmrg    }
145505b261ecSmrg
145605b261ecSmrg    /* don't need to do any more memory allocation for this request! */
145705b261ecSmrg
145805b261ecSmrg    pAwaitUnion->header.client = client;
145905b261ecSmrg    pAwaitUnion->header.num_waitconditions = 0;
146005b261ecSmrg
146105b261ecSmrg    pAwait = &(pAwaitUnion+1)->await; /* skip over header */
146205b261ecSmrg    for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++)
146305b261ecSmrg    {
146405b261ecSmrg	if (pProtocolWaitConds->counter == None) /* XXX protocol change */
146505b261ecSmrg	{
146605b261ecSmrg	    /*  this should take care of removing any triggers created by
146705b261ecSmrg	     *  this request that have already been registered on counters
146805b261ecSmrg	     */
146905b261ecSmrg	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
147005b261ecSmrg	    client->errorValue = pProtocolWaitConds->counter;
147105b261ecSmrg	    return SyncErrorBase + XSyncBadCounter;
147205b261ecSmrg	}
147305b261ecSmrg
147405b261ecSmrg	/* sanity checks are in SyncInitTrigger */
147505b261ecSmrg	pAwait->trigger.pCounter = NULL;
147605b261ecSmrg	pAwait->trigger.value_type = pProtocolWaitConds->value_type;
147705b261ecSmrg	XSyncIntsToValue(&pAwait->trigger.wait_value,
147805b261ecSmrg			 pProtocolWaitConds->wait_value_lo,
147905b261ecSmrg			 pProtocolWaitConds->wait_value_hi);
148005b261ecSmrg	pAwait->trigger.test_type = pProtocolWaitConds->test_type;
148105b261ecSmrg
148205b261ecSmrg	status = SyncInitTrigger(client, &pAwait->trigger,
148305b261ecSmrg			 pProtocolWaitConds->counter, XSyncCAAllTrigger);
148405b261ecSmrg	if (status != Success)
148505b261ecSmrg	{
148605b261ecSmrg	    /*  this should take care of removing any triggers created by
148705b261ecSmrg	     *  this request that have already been registered on counters
148805b261ecSmrg	     */
148905b261ecSmrg	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
149005b261ecSmrg	    return status;
149105b261ecSmrg	}
149205b261ecSmrg	/* this is not a mistake -- same function works for both cases */
149305b261ecSmrg	pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
149405b261ecSmrg	pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
149505b261ecSmrg	XSyncIntsToValue(&pAwait->event_threshold,
149605b261ecSmrg			 pProtocolWaitConds->event_threshold_lo,
149705b261ecSmrg			 pProtocolWaitConds->event_threshold_hi);
149805b261ecSmrg	pAwait->pHeader = &pAwaitUnion->header;
149905b261ecSmrg	pAwaitUnion->header.num_waitconditions++;
150005b261ecSmrg    }
150105b261ecSmrg
150205b261ecSmrg    IgnoreClient(client);
150305b261ecSmrg
150405b261ecSmrg    /* see if any of the triggers are already true */
150505b261ecSmrg
150605b261ecSmrg    pAwait = &(pAwaitUnion+1)->await; /* skip over header */
150705b261ecSmrg    for (i = 0; i < items; i++, pAwait++)
150805b261ecSmrg    {
150905b261ecSmrg	/*  don't have to worry about NULL counters because the request
151005b261ecSmrg	 *  errors before we get here out if they occur
151105b261ecSmrg	 */
151205b261ecSmrg	if ((*pAwait->trigger.CheckTrigger)(&pAwait->trigger,
151305b261ecSmrg					    pAwait->trigger.pCounter->value))
151405b261ecSmrg	{
151505b261ecSmrg	    (*pAwait->trigger.TriggerFired)(&pAwait->trigger);
151605b261ecSmrg	    break; /* once is enough */
151705b261ecSmrg	}
151805b261ecSmrg    }
151905b261ecSmrg    return Success;
152005b261ecSmrg}
152105b261ecSmrg
152205b261ecSmrg
152305b261ecSmrg/*
152405b261ecSmrg * ** Query a counter
152505b261ecSmrg */
15264202a189Smrgstatic int
15274202a189SmrgProcSyncQueryCounter(ClientPtr client)
152805b261ecSmrg{
152905b261ecSmrg    REQUEST(xSyncQueryCounterReq);
153005b261ecSmrg    xSyncQueryCounterReply rep;
153105b261ecSmrg    SyncCounter    *pCounter;
15324202a189Smrg    int rc;
153305b261ecSmrg
153405b261ecSmrg    REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
153505b261ecSmrg
15364202a189Smrg    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter,
15374202a189Smrg				 RTCounter, client, DixReadAccess);
15384202a189Smrg    if (rc != Success)
15394202a189Smrg	return rc;
154005b261ecSmrg
154105b261ecSmrg    rep.type = X_Reply;
154205b261ecSmrg    rep.length = 0;
154305b261ecSmrg    rep.sequenceNumber = client->sequence;
154405b261ecSmrg
154505b261ecSmrg    /* if system counter, ask it what the current value is */
154605b261ecSmrg
154705b261ecSmrg    if (IsSystemCounter(pCounter))
154805b261ecSmrg    {
154905b261ecSmrg	(*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
155005b261ecSmrg						  &pCounter->value);
155105b261ecSmrg    }
155205b261ecSmrg
155305b261ecSmrg    rep.value_hi = XSyncValueHigh32(pCounter->value);
155405b261ecSmrg    rep.value_lo = XSyncValueLow32(pCounter->value);
155505b261ecSmrg    if (client->swapped)
155605b261ecSmrg    {
1557637ac9abSmrg	char n;
155805b261ecSmrg	swaps(&rep.sequenceNumber, n);
155905b261ecSmrg	swapl(&rep.length, n);
156005b261ecSmrg	swapl(&rep.value_hi, n);
156105b261ecSmrg	swapl(&rep.value_lo, n);
156205b261ecSmrg    }
156305b261ecSmrg    WriteToClient(client, sizeof(xSyncQueryCounterReply), (char *) &rep);
15644202a189Smrg    return Success;
156505b261ecSmrg}
156605b261ecSmrg
156705b261ecSmrg
156805b261ecSmrg/*
156905b261ecSmrg * ** Create Alarm
157005b261ecSmrg */
15714202a189Smrgstatic int
15724202a189SmrgProcSyncCreateAlarm(ClientPtr client)
157305b261ecSmrg{
157405b261ecSmrg    REQUEST(xSyncCreateAlarmReq);
157505b261ecSmrg    SyncAlarm      *pAlarm;
157605b261ecSmrg    int             status;
157705b261ecSmrg    unsigned long   len, vmask;
157805b261ecSmrg    SyncTrigger	    *pTrigger;
157905b261ecSmrg
158005b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
158105b261ecSmrg
158205b261ecSmrg    LEGAL_NEW_RESOURCE(stuff->id, client);
158305b261ecSmrg
158405b261ecSmrg    vmask = stuff->valueMask;
15854202a189Smrg    len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq));
158605b261ecSmrg    /* the "extra" call to Ones accounts for the presence of 64 bit values */
158705b261ecSmrg    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
158805b261ecSmrg	return BadLength;
158905b261ecSmrg
15904202a189Smrg    if (!(pAlarm = malloc(sizeof(SyncAlarm))))
159105b261ecSmrg    {
159205b261ecSmrg	return BadAlloc;
159305b261ecSmrg    }
159405b261ecSmrg
159505b261ecSmrg    /* set up defaults */
159605b261ecSmrg
159705b261ecSmrg    pTrigger = &pAlarm->trigger;
159805b261ecSmrg    pTrigger->pCounter = NULL;
159905b261ecSmrg    pTrigger->value_type = XSyncAbsolute;
160005b261ecSmrg    XSyncIntToValue(&pTrigger->wait_value, 0L);
160105b261ecSmrg    pTrigger->test_type = XSyncPositiveComparison;
160205b261ecSmrg    pTrigger->TriggerFired = SyncAlarmTriggerFired;
160305b261ecSmrg    pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed;
160405b261ecSmrg    status = SyncInitTrigger(client, pTrigger, None, XSyncCAAllTrigger);
160505b261ecSmrg    if (status != Success)
160605b261ecSmrg    {
16074202a189Smrg	free(pAlarm);
160805b261ecSmrg	return status;
160905b261ecSmrg    }
161005b261ecSmrg
161105b261ecSmrg    pAlarm->client = client;
161205b261ecSmrg    pAlarm->alarm_id = stuff->id;
161305b261ecSmrg    XSyncIntToValue(&pAlarm->delta, 1L);
161405b261ecSmrg    pAlarm->events = TRUE;
161505b261ecSmrg    pAlarm->state = XSyncAlarmInactive;
161605b261ecSmrg    pAlarm->pEventClients = NULL;
161705b261ecSmrg    status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
161805b261ecSmrg				       (CARD32 *)&stuff[1]);
161905b261ecSmrg    if (status != Success)
162005b261ecSmrg    {
16214202a189Smrg	free(pAlarm);
162205b261ecSmrg	return status;
162305b261ecSmrg    }
162405b261ecSmrg
162505b261ecSmrg    if (!AddResource(stuff->id, RTAlarm, pAlarm))
162605b261ecSmrg    {
16274202a189Smrg	free(pAlarm);
162805b261ecSmrg	return BadAlloc;
162905b261ecSmrg    }
163005b261ecSmrg
163105b261ecSmrg    /*  see if alarm already triggered.  NULL counter will not trigger
163205b261ecSmrg     *  in CreateAlarm and sets alarm state to Inactive.
163305b261ecSmrg     */
163405b261ecSmrg
163505b261ecSmrg    if (!pTrigger->pCounter)
163605b261ecSmrg    {
163705b261ecSmrg	pAlarm->state = XSyncAlarmInactive; /* XXX protocol change */
163805b261ecSmrg    }
163905b261ecSmrg    else if ((*pTrigger->CheckTrigger)(pTrigger, pTrigger->pCounter->value))
164005b261ecSmrg    {
164105b261ecSmrg	(*pTrigger->TriggerFired)(pTrigger);
164205b261ecSmrg    }
164305b261ecSmrg
164405b261ecSmrg    return Success;
164505b261ecSmrg}
164605b261ecSmrg
164705b261ecSmrg/*
164805b261ecSmrg * ** Change Alarm
164905b261ecSmrg */
16504202a189Smrgstatic int
16514202a189SmrgProcSyncChangeAlarm(ClientPtr client)
165205b261ecSmrg{
165305b261ecSmrg    REQUEST(xSyncChangeAlarmReq);
165405b261ecSmrg    SyncAlarm   *pAlarm;
165505b261ecSmrg    long        vmask;
165605b261ecSmrg    int         len, status;
165705b261ecSmrg
165805b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
165905b261ecSmrg
16604202a189Smrg    status = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
16614202a189Smrg				     client, DixWriteAccess);
16624202a189Smrg    if (status != Success)
16634202a189Smrg	return status;
166405b261ecSmrg
166505b261ecSmrg    vmask = stuff->valueMask;
16664202a189Smrg    len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq));
166705b261ecSmrg    /* the "extra" call to Ones accounts for the presence of 64 bit values */
166805b261ecSmrg    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
166905b261ecSmrg	return BadLength;
167005b261ecSmrg
16714202a189Smrg    if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
167205b261ecSmrg					    (CARD32 *)&stuff[1])) != Success)
167305b261ecSmrg	return status;
167405b261ecSmrg
167505b261ecSmrg    /*  see if alarm already triggered.  NULL counter WILL trigger
167605b261ecSmrg     *  in ChangeAlarm.
167705b261ecSmrg     */
167805b261ecSmrg
167905b261ecSmrg    if (!pAlarm->trigger.pCounter ||
168005b261ecSmrg	(*pAlarm->trigger.CheckTrigger)(&pAlarm->trigger,
168105b261ecSmrg					pAlarm->trigger.pCounter->value))
168205b261ecSmrg    {
168305b261ecSmrg	(*pAlarm->trigger.TriggerFired)(&pAlarm->trigger);
168405b261ecSmrg    }
168505b261ecSmrg    return Success;
168605b261ecSmrg}
168705b261ecSmrg
16884202a189Smrgstatic int
16894202a189SmrgProcSyncQueryAlarm(ClientPtr client)
169005b261ecSmrg{
169105b261ecSmrg    REQUEST(xSyncQueryAlarmReq);
169205b261ecSmrg    SyncAlarm      *pAlarm;
169305b261ecSmrg    xSyncQueryAlarmReply rep;
169405b261ecSmrg    SyncTrigger    *pTrigger;
16954202a189Smrg    int rc;
169605b261ecSmrg
169705b261ecSmrg    REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
169805b261ecSmrg
16994202a189Smrg    rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
17004202a189Smrg				 client, DixReadAccess);
17014202a189Smrg    if (rc != Success)
17024202a189Smrg	return rc;
170305b261ecSmrg
170405b261ecSmrg    rep.type = X_Reply;
17054202a189Smrg    rep.length = bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply));
170605b261ecSmrg    rep.sequenceNumber = client->sequence;
170705b261ecSmrg
170805b261ecSmrg    pTrigger = &pAlarm->trigger;
170905b261ecSmrg    rep.counter = (pTrigger->pCounter) ? pTrigger->pCounter->id : None;
171005b261ecSmrg
171105b261ecSmrg#if 0 /* XXX unclear what to do, depends on whether relative value-types
171205b261ecSmrg       * are "consumed" immediately and are considered absolute from then
171305b261ecSmrg       * on.
171405b261ecSmrg       */
171505b261ecSmrg    rep.value_type = pTrigger->value_type;
171605b261ecSmrg    rep.wait_value_hi = XSyncValueHigh32(pTrigger->wait_value);
171705b261ecSmrg    rep.wait_value_lo = XSyncValueLow32(pTrigger->wait_value);
171805b261ecSmrg#else
171905b261ecSmrg    rep.value_type = XSyncAbsolute;
172005b261ecSmrg    rep.wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
172105b261ecSmrg    rep.wait_value_lo = XSyncValueLow32(pTrigger->test_value);
172205b261ecSmrg#endif
172305b261ecSmrg
172405b261ecSmrg    rep.test_type = pTrigger->test_type;
172505b261ecSmrg    rep.delta_hi = XSyncValueHigh32(pAlarm->delta);
172605b261ecSmrg    rep.delta_lo = XSyncValueLow32(pAlarm->delta);
172705b261ecSmrg    rep.events = pAlarm->events;
172805b261ecSmrg    rep.state = pAlarm->state;
172905b261ecSmrg
173005b261ecSmrg    if (client->swapped)
173105b261ecSmrg    {
1732637ac9abSmrg	char n;
173305b261ecSmrg	swaps(&rep.sequenceNumber, n);
173405b261ecSmrg	swapl(&rep.length, n);
173505b261ecSmrg	swapl(&rep.counter, n);
173605b261ecSmrg	swapl(&rep.wait_value_hi, n);
173705b261ecSmrg	swapl(&rep.wait_value_lo, n);
173805b261ecSmrg	swapl(&rep.test_type, n);
173905b261ecSmrg	swapl(&rep.delta_hi, n);
174005b261ecSmrg	swapl(&rep.delta_lo, n);
174105b261ecSmrg    }
174205b261ecSmrg
174305b261ecSmrg    WriteToClient(client, sizeof(xSyncQueryAlarmReply), (char *) &rep);
17444202a189Smrg    return Success;
174505b261ecSmrg}
174605b261ecSmrg
17474202a189Smrgstatic int
17484202a189SmrgProcSyncDestroyAlarm(ClientPtr client)
174905b261ecSmrg{
17504202a189Smrg    SyncAlarm *pAlarm;
17514202a189Smrg    int rc;
175205b261ecSmrg    REQUEST(xSyncDestroyAlarmReq);
175305b261ecSmrg
175405b261ecSmrg    REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
175505b261ecSmrg
17564202a189Smrg    rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
17574202a189Smrg				 client, DixDestroyAccess);
17584202a189Smrg    if (rc != Success)
17594202a189Smrg	return rc;
176005b261ecSmrg
176105b261ecSmrg    FreeResource(stuff->alarm, RT_NONE);
17624202a189Smrg    return Success;
176305b261ecSmrg}
176405b261ecSmrg
176505b261ecSmrg/*
176605b261ecSmrg * ** Given an extension request, call the appropriate request procedure
176705b261ecSmrg */
17684202a189Smrgstatic int
17694202a189SmrgProcSyncDispatch(ClientPtr client)
177005b261ecSmrg{
177105b261ecSmrg    REQUEST(xReq);
177205b261ecSmrg
177305b261ecSmrg    switch (stuff->data)
177405b261ecSmrg    {
177505b261ecSmrg      case X_SyncInitialize:
177605b261ecSmrg	return ProcSyncInitialize(client);
177705b261ecSmrg      case X_SyncListSystemCounters:
177805b261ecSmrg	return ProcSyncListSystemCounters(client);
177905b261ecSmrg      case X_SyncCreateCounter:
178005b261ecSmrg	return ProcSyncCreateCounter(client);
178105b261ecSmrg      case X_SyncSetCounter:
178205b261ecSmrg	return ProcSyncSetCounter(client);
178305b261ecSmrg      case X_SyncChangeCounter:
178405b261ecSmrg	return ProcSyncChangeCounter(client);
178505b261ecSmrg      case X_SyncQueryCounter:
178605b261ecSmrg	return ProcSyncQueryCounter(client);
178705b261ecSmrg      case X_SyncDestroyCounter:
178805b261ecSmrg	return ProcSyncDestroyCounter(client);
178905b261ecSmrg      case X_SyncAwait:
179005b261ecSmrg	return ProcSyncAwait(client);
179105b261ecSmrg      case X_SyncCreateAlarm:
179205b261ecSmrg	return ProcSyncCreateAlarm(client);
179305b261ecSmrg      case X_SyncChangeAlarm:
179405b261ecSmrg	return ProcSyncChangeAlarm(client);
179505b261ecSmrg      case X_SyncQueryAlarm:
179605b261ecSmrg	return ProcSyncQueryAlarm(client);
179705b261ecSmrg      case X_SyncDestroyAlarm:
179805b261ecSmrg	return ProcSyncDestroyAlarm(client);
179905b261ecSmrg      case X_SyncSetPriority:
180005b261ecSmrg	return ProcSyncSetPriority(client);
180105b261ecSmrg      case X_SyncGetPriority:
180205b261ecSmrg	return ProcSyncGetPriority(client);
180305b261ecSmrg      default:
180405b261ecSmrg	return BadRequest;
180505b261ecSmrg    }
180605b261ecSmrg}
180705b261ecSmrg
180805b261ecSmrg/*
180905b261ecSmrg * Boring Swapping stuff ...
181005b261ecSmrg */
181105b261ecSmrg
18124202a189Smrgstatic int
18134202a189SmrgSProcSyncInitialize(ClientPtr client)
181405b261ecSmrg{
181505b261ecSmrg    REQUEST(xSyncInitializeReq);
1816637ac9abSmrg    char   n;
181705b261ecSmrg
181805b261ecSmrg    swaps(&stuff->length, n);
181905b261ecSmrg    REQUEST_SIZE_MATCH (xSyncInitializeReq);
182005b261ecSmrg
182105b261ecSmrg    return ProcSyncInitialize(client);
182205b261ecSmrg}
182305b261ecSmrg
18244202a189Smrgstatic int
18254202a189SmrgSProcSyncListSystemCounters(ClientPtr client)
182605b261ecSmrg{
182705b261ecSmrg    REQUEST(xSyncListSystemCountersReq);
1828637ac9abSmrg    char   n;
182905b261ecSmrg
183005b261ecSmrg    swaps(&stuff->length, n);
183105b261ecSmrg    REQUEST_SIZE_MATCH (xSyncListSystemCountersReq);
183205b261ecSmrg
183305b261ecSmrg    return ProcSyncListSystemCounters(client);
183405b261ecSmrg}
183505b261ecSmrg
18364202a189Smrgstatic int
18374202a189SmrgSProcSyncCreateCounter(ClientPtr client)
183805b261ecSmrg{
183905b261ecSmrg    REQUEST(xSyncCreateCounterReq);
1840637ac9abSmrg    char   n;
184105b261ecSmrg
184205b261ecSmrg    swaps(&stuff->length, n);
184305b261ecSmrg    REQUEST_SIZE_MATCH (xSyncCreateCounterReq);
184405b261ecSmrg    swapl(&stuff->cid, n);
184505b261ecSmrg    swapl(&stuff->initial_value_lo, n);
184605b261ecSmrg    swapl(&stuff->initial_value_hi, n);
184705b261ecSmrg
184805b261ecSmrg    return ProcSyncCreateCounter(client);
184905b261ecSmrg}
185005b261ecSmrg
18514202a189Smrgstatic int
18524202a189SmrgSProcSyncSetCounter(ClientPtr client)
185305b261ecSmrg{
185405b261ecSmrg    REQUEST(xSyncSetCounterReq);
1855637ac9abSmrg    char   n;
185605b261ecSmrg
185705b261ecSmrg    swaps(&stuff->length, n);
185805b261ecSmrg    REQUEST_SIZE_MATCH (xSyncSetCounterReq);
185905b261ecSmrg    swapl(&stuff->cid, n);
186005b261ecSmrg    swapl(&stuff->value_lo, n);
186105b261ecSmrg    swapl(&stuff->value_hi, n);
186205b261ecSmrg
186305b261ecSmrg    return ProcSyncSetCounter(client);
186405b261ecSmrg}
186505b261ecSmrg
18664202a189Smrgstatic int
18674202a189SmrgSProcSyncChangeCounter(ClientPtr client)
186805b261ecSmrg{
186905b261ecSmrg    REQUEST(xSyncChangeCounterReq);
1870637ac9abSmrg    char   n;
187105b261ecSmrg
187205b261ecSmrg    swaps(&stuff->length, n);
187305b261ecSmrg    REQUEST_SIZE_MATCH (xSyncChangeCounterReq);
187405b261ecSmrg    swapl(&stuff->cid, n);
187505b261ecSmrg    swapl(&stuff->value_lo, n);
187605b261ecSmrg    swapl(&stuff->value_hi, n);
187705b261ecSmrg
187805b261ecSmrg    return ProcSyncChangeCounter(client);
187905b261ecSmrg}
188005b261ecSmrg
18814202a189Smrgstatic int
18824202a189SmrgSProcSyncQueryCounter(ClientPtr client)
188305b261ecSmrg{
188405b261ecSmrg    REQUEST(xSyncQueryCounterReq);
1885637ac9abSmrg    char   n;
188605b261ecSmrg
188705b261ecSmrg    swaps(&stuff->length, n);
188805b261ecSmrg    REQUEST_SIZE_MATCH (xSyncQueryCounterReq);
188905b261ecSmrg    swapl(&stuff->counter, n);
189005b261ecSmrg
189105b261ecSmrg    return ProcSyncQueryCounter(client);
189205b261ecSmrg}
189305b261ecSmrg
18944202a189Smrgstatic int
18954202a189SmrgSProcSyncDestroyCounter(ClientPtr client)
189605b261ecSmrg{
189705b261ecSmrg    REQUEST(xSyncDestroyCounterReq);
1898637ac9abSmrg    char   n;
189905b261ecSmrg
190005b261ecSmrg    swaps(&stuff->length, n);
190105b261ecSmrg    REQUEST_SIZE_MATCH (xSyncDestroyCounterReq);
190205b261ecSmrg    swapl(&stuff->counter, n);
190305b261ecSmrg
190405b261ecSmrg    return ProcSyncDestroyCounter(client);
190505b261ecSmrg}
190605b261ecSmrg
19074202a189Smrgstatic int
19084202a189SmrgSProcSyncAwait(ClientPtr client)
190905b261ecSmrg{
191005b261ecSmrg    REQUEST(xSyncAwaitReq);
1911637ac9abSmrg    char   n;
191205b261ecSmrg
191305b261ecSmrg    swaps(&stuff->length, n);
191405b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
191505b261ecSmrg    SwapRestL(stuff);
191605b261ecSmrg
191705b261ecSmrg    return ProcSyncAwait(client);
191805b261ecSmrg}
191905b261ecSmrg
19204202a189Smrgstatic int
19214202a189SmrgSProcSyncCreateAlarm(ClientPtr client)
192205b261ecSmrg{
192305b261ecSmrg    REQUEST(xSyncCreateAlarmReq);
1924637ac9abSmrg    char   n;
192505b261ecSmrg
192605b261ecSmrg    swaps(&stuff->length, n);
192705b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
192805b261ecSmrg    swapl(&stuff->id, n);
192905b261ecSmrg    swapl(&stuff->valueMask, n);
193005b261ecSmrg    SwapRestL(stuff);
193105b261ecSmrg
193205b261ecSmrg    return ProcSyncCreateAlarm(client);
193305b261ecSmrg}
193405b261ecSmrg
19354202a189Smrgstatic int
19364202a189SmrgSProcSyncChangeAlarm(ClientPtr client)
193705b261ecSmrg{
193805b261ecSmrg    REQUEST(xSyncChangeAlarmReq);
1939637ac9abSmrg    char   n;
194005b261ecSmrg
194105b261ecSmrg    swaps(&stuff->length, n);
194205b261ecSmrg    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
194305b261ecSmrg    swapl(&stuff->alarm, n);
194405b261ecSmrg    swapl(&stuff->valueMask, n);
194505b261ecSmrg    SwapRestL(stuff);
194605b261ecSmrg    return ProcSyncChangeAlarm(client);
194705b261ecSmrg}
194805b261ecSmrg
19494202a189Smrgstatic int
19504202a189SmrgSProcSyncQueryAlarm(ClientPtr client)
195105b261ecSmrg{
195205b261ecSmrg    REQUEST(xSyncQueryAlarmReq);
1953637ac9abSmrg    char   n;
195405b261ecSmrg
195505b261ecSmrg    swaps(&stuff->length, n);
195605b261ecSmrg    REQUEST_SIZE_MATCH (xSyncQueryAlarmReq);
195705b261ecSmrg    swapl(&stuff->alarm, n);
195805b261ecSmrg
195905b261ecSmrg    return ProcSyncQueryAlarm(client);
196005b261ecSmrg}
196105b261ecSmrg
19624202a189Smrgstatic int
19634202a189SmrgSProcSyncDestroyAlarm(ClientPtr client)
196405b261ecSmrg{
196505b261ecSmrg    REQUEST(xSyncDestroyAlarmReq);
1966637ac9abSmrg    char   n;
196705b261ecSmrg
196805b261ecSmrg    swaps(&stuff->length, n);
196905b261ecSmrg    REQUEST_SIZE_MATCH (xSyncDestroyAlarmReq);
197005b261ecSmrg    swapl(&stuff->alarm, n);
197105b261ecSmrg
197205b261ecSmrg    return ProcSyncDestroyAlarm(client);
197305b261ecSmrg}
197405b261ecSmrg
19754202a189Smrgstatic int
19764202a189SmrgSProcSyncSetPriority(ClientPtr client)
197705b261ecSmrg{
197805b261ecSmrg    REQUEST(xSyncSetPriorityReq);
1979637ac9abSmrg    char   n;
198005b261ecSmrg
198105b261ecSmrg    swaps(&stuff->length, n);
198205b261ecSmrg    REQUEST_SIZE_MATCH (xSyncSetPriorityReq);
198305b261ecSmrg    swapl(&stuff->id, n);
198405b261ecSmrg    swapl(&stuff->priority, n);
198505b261ecSmrg
198605b261ecSmrg    return ProcSyncSetPriority(client);
198705b261ecSmrg}
198805b261ecSmrg
19894202a189Smrgstatic int
19904202a189SmrgSProcSyncGetPriority(ClientPtr client)
199105b261ecSmrg{
199205b261ecSmrg    REQUEST(xSyncGetPriorityReq);
1993637ac9abSmrg    char   n;
199405b261ecSmrg
199505b261ecSmrg    swaps(&stuff->length, n);
199605b261ecSmrg    REQUEST_SIZE_MATCH (xSyncGetPriorityReq);
199705b261ecSmrg    swapl(&stuff->id, n);
199805b261ecSmrg
199905b261ecSmrg    return ProcSyncGetPriority(client);
200005b261ecSmrg}
200105b261ecSmrg
200205b261ecSmrg
20034202a189Smrgstatic int
20044202a189SmrgSProcSyncDispatch(ClientPtr client)
200505b261ecSmrg{
200605b261ecSmrg    REQUEST(xReq);
200705b261ecSmrg
200805b261ecSmrg    switch (stuff->data)
200905b261ecSmrg    {
201005b261ecSmrg      case X_SyncInitialize:
201105b261ecSmrg	return SProcSyncInitialize(client);
201205b261ecSmrg      case X_SyncListSystemCounters:
201305b261ecSmrg	return SProcSyncListSystemCounters(client);
201405b261ecSmrg      case X_SyncCreateCounter:
201505b261ecSmrg	return SProcSyncCreateCounter(client);
201605b261ecSmrg      case X_SyncSetCounter:
201705b261ecSmrg	return SProcSyncSetCounter(client);
201805b261ecSmrg      case X_SyncChangeCounter:
201905b261ecSmrg	return SProcSyncChangeCounter(client);
202005b261ecSmrg      case X_SyncQueryCounter:
202105b261ecSmrg	return SProcSyncQueryCounter(client);
202205b261ecSmrg      case X_SyncDestroyCounter:
202305b261ecSmrg	return SProcSyncDestroyCounter(client);
202405b261ecSmrg      case X_SyncAwait:
202505b261ecSmrg	return SProcSyncAwait(client);
202605b261ecSmrg      case X_SyncCreateAlarm:
202705b261ecSmrg	return SProcSyncCreateAlarm(client);
202805b261ecSmrg      case X_SyncChangeAlarm:
202905b261ecSmrg	return SProcSyncChangeAlarm(client);
203005b261ecSmrg      case X_SyncQueryAlarm:
203105b261ecSmrg	return SProcSyncQueryAlarm(client);
203205b261ecSmrg      case X_SyncDestroyAlarm:
203305b261ecSmrg	return SProcSyncDestroyAlarm(client);
203405b261ecSmrg      case X_SyncSetPriority:
203505b261ecSmrg	return SProcSyncSetPriority(client);
203605b261ecSmrg      case X_SyncGetPriority:
203705b261ecSmrg	return SProcSyncGetPriority(client);
203805b261ecSmrg      default:
203905b261ecSmrg	return BadRequest;
204005b261ecSmrg    }
204105b261ecSmrg}
204205b261ecSmrg
204305b261ecSmrg/*
204405b261ecSmrg * Event Swapping
204505b261ecSmrg */
204605b261ecSmrg
20474202a189Smrgstatic void
20484202a189SmrgSCounterNotifyEvent(xSyncCounterNotifyEvent *from, xSyncCounterNotifyEvent *to)
204905b261ecSmrg{
205005b261ecSmrg    to->type = from->type;
205105b261ecSmrg    to->kind = from->kind;
205205b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
205305b261ecSmrg    cpswapl(from->counter, to->counter);
205405b261ecSmrg    cpswapl(from->wait_value_lo, to->wait_value_lo);
205505b261ecSmrg    cpswapl(from->wait_value_hi, to->wait_value_hi);
205605b261ecSmrg    cpswapl(from->counter_value_lo, to->counter_value_lo);
205705b261ecSmrg    cpswapl(from->counter_value_hi, to->counter_value_hi);
205805b261ecSmrg    cpswapl(from->time, to->time);
205905b261ecSmrg    cpswaps(from->count, to->count);
206005b261ecSmrg    to->destroyed = from->destroyed;
206105b261ecSmrg}
206205b261ecSmrg
206305b261ecSmrg
20644202a189Smrgstatic void
20654202a189SmrgSAlarmNotifyEvent(xSyncAlarmNotifyEvent *from, xSyncAlarmNotifyEvent *to)
206605b261ecSmrg{
206705b261ecSmrg    to->type = from->type;
206805b261ecSmrg    to->kind = from->kind;
206905b261ecSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
207005b261ecSmrg    cpswapl(from->alarm, to->alarm);
207105b261ecSmrg    cpswapl(from->counter_value_lo, to->counter_value_lo);
207205b261ecSmrg    cpswapl(from->counter_value_hi, to->counter_value_hi);
207305b261ecSmrg    cpswapl(from->alarm_value_lo, to->alarm_value_lo);
207405b261ecSmrg    cpswapl(from->alarm_value_hi, to->alarm_value_hi);
207505b261ecSmrg    cpswapl(from->time, to->time);
207605b261ecSmrg    to->state = from->state;
207705b261ecSmrg}
207805b261ecSmrg
207905b261ecSmrg/*
208005b261ecSmrg * ** Close everything down. ** This is fairly simple for now.
208105b261ecSmrg */
208205b261ecSmrg/* ARGSUSED */
20834202a189Smrgstatic void
20844202a189SmrgSyncResetProc(ExtensionEntry *extEntry)
208505b261ecSmrg{
20864202a189Smrg    free(SysCounterList);
208705b261ecSmrg    SysCounterList = NULL;
208805b261ecSmrg    RTCounter = 0;
208905b261ecSmrg}
209005b261ecSmrg
209105b261ecSmrg
209205b261ecSmrg/*
209305b261ecSmrg * ** Initialise the extension.
209405b261ecSmrg */
20954202a189Smrgvoid
20964202a189SmrgSyncExtensionInit(void)
209705b261ecSmrg{
209805b261ecSmrg    ExtensionEntry *extEntry;
209905b261ecSmrg
210005b261ecSmrg    if (RTCounter == 0)
210105b261ecSmrg    {
21024202a189Smrg	RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
210305b261ecSmrg    }
21044202a189Smrg    RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm");
21054202a189Smrg    RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait");
21064202a189Smrg    if (RTAwait)
21074202a189Smrg	RTAwait |= RC_NEVERRETAIN;
21084202a189Smrg    RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient");
21094202a189Smrg    if (RTAlarmClient)
21104202a189Smrg	RTAlarmClient |= RC_NEVERRETAIN;
211105b261ecSmrg
211205b261ecSmrg    if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 ||
211305b261ecSmrg	RTAlarmClient == 0 ||
211405b261ecSmrg	(extEntry = AddExtension(SYNC_NAME,
211505b261ecSmrg				 XSyncNumberEvents, XSyncNumberErrors,
211605b261ecSmrg				 ProcSyncDispatch, SProcSyncDispatch,
211705b261ecSmrg				 SyncResetProc,
211805b261ecSmrg				 StandardMinorOpcode)) == NULL)
211905b261ecSmrg    {
212005b261ecSmrg	ErrorF("Sync Extension %d.%d failed to Initialise\n",
212105b261ecSmrg		SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
212205b261ecSmrg	return;
212305b261ecSmrg    }
212405b261ecSmrg
212505b261ecSmrg    SyncEventBase = extEntry->eventBase;
212605b261ecSmrg    SyncErrorBase = extEntry->errorBase;
212705b261ecSmrg    EventSwapVector[SyncEventBase + XSyncCounterNotify] = (EventSwapPtr) SCounterNotifyEvent;
212805b261ecSmrg    EventSwapVector[SyncEventBase + XSyncAlarmNotify] = (EventSwapPtr) SAlarmNotifyEvent;
212905b261ecSmrg
21304202a189Smrg    SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter);
21314202a189Smrg    SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm);
21324202a189Smrg
213305b261ecSmrg    /*
213405b261ecSmrg     * Although SERVERTIME is implemented by the OS layer, we initialise it
213505b261ecSmrg     * here because doing it in OsInit() is too early. The resource database
213605b261ecSmrg     * is not initialised when OsInit() is called. This is just about OK
213705b261ecSmrg     * because there is always a servertime counter.
213805b261ecSmrg     */
213905b261ecSmrg    SyncInitServerTime();
214005b261ecSmrg    SyncInitIdleTime();
214105b261ecSmrg
214205b261ecSmrg#ifdef DEBUG
214305b261ecSmrg    fprintf(stderr, "Sync Extension %d.%d\n",
214405b261ecSmrg	    SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
214505b261ecSmrg#endif
214605b261ecSmrg}
214705b261ecSmrg
214805b261ecSmrg
214905b261ecSmrg/*
215005b261ecSmrg * ***** SERVERTIME implementation - should go in its own file in OS directory?
215105b261ecSmrg */
215205b261ecSmrg
215305b261ecSmrg
215405b261ecSmrg
215505b261ecSmrgstatic pointer ServertimeCounter;
215605b261ecSmrgstatic XSyncValue Now;
215705b261ecSmrgstatic XSyncValue *pnext_time;
215805b261ecSmrg
215905b261ecSmrg#define GetTime()\
216005b261ecSmrg{\
216105b261ecSmrg    unsigned long millis = GetTimeInMillis();\
216205b261ecSmrg    unsigned long maxis = XSyncValueHigh32(Now);\
216305b261ecSmrg    if (millis < XSyncValueLow32(Now)) maxis++;\
216405b261ecSmrg    XSyncIntsToValue(&Now, millis, maxis);\
216505b261ecSmrg}
216605b261ecSmrg
216705b261ecSmrg/*
216805b261ecSmrg*** Server Block Handler
21694202a189Smrg*** code inspired by multibuffer extension (now deprecated)
217005b261ecSmrg */
217105b261ecSmrg/*ARGSUSED*/
21724202a189Smrgstatic void
21734202a189SmrgServertimeBlockHandler(void *env, struct timeval **wt, void *LastSelectMask)
217405b261ecSmrg{
217505b261ecSmrg    XSyncValue delay;
217605b261ecSmrg    unsigned long timeout;
217705b261ecSmrg
217805b261ecSmrg    if (pnext_time)
217905b261ecSmrg    {
218005b261ecSmrg        GetTime();
218105b261ecSmrg
218205b261ecSmrg        if (XSyncValueGreaterOrEqual(Now, *pnext_time))
218305b261ecSmrg	{
218405b261ecSmrg            timeout = 0;
21854202a189Smrg        }
218605b261ecSmrg	else
218705b261ecSmrg	{
218805b261ecSmrg	    Bool overflow;
218905b261ecSmrg            XSyncValueSubtract(&delay, *pnext_time, Now, &overflow);
219005b261ecSmrg	    (void)overflow;
219105b261ecSmrg            timeout = XSyncValueLow32(delay);
219205b261ecSmrg        }
219305b261ecSmrg        AdjustWaitForDelay(wt, timeout); /* os/utils.c */
219405b261ecSmrg    }
219505b261ecSmrg}
219605b261ecSmrg
219705b261ecSmrg/*
219805b261ecSmrg*** Wakeup Handler
219905b261ecSmrg */
220005b261ecSmrg/*ARGSUSED*/
22014202a189Smrgstatic void
22024202a189SmrgServertimeWakeupHandler(void *env, int rc, void *LastSelectMask)
220305b261ecSmrg{
220405b261ecSmrg    if (pnext_time)
220505b261ecSmrg    {
220605b261ecSmrg        GetTime();
220705b261ecSmrg
220805b261ecSmrg        if (XSyncValueGreaterOrEqual(Now, *pnext_time))
220905b261ecSmrg	{
221005b261ecSmrg            SyncChangeCounter(ServertimeCounter, Now);
221105b261ecSmrg        }
221205b261ecSmrg    }
221305b261ecSmrg}
221405b261ecSmrg
221505b261ecSmrgstatic void
22164202a189SmrgServertimeQueryValue(void *pCounter, CARD64 *pValue_return)
221705b261ecSmrg{
221805b261ecSmrg    GetTime();
221905b261ecSmrg    *pValue_return = Now;
222005b261ecSmrg}
222105b261ecSmrg
222205b261ecSmrgstatic void
22234202a189SmrgServertimeBracketValues(void *pCounter, CARD64 *pbracket_less,
22244202a189Smrg			CARD64 *pbracket_greater)
222505b261ecSmrg{
222605b261ecSmrg    if (!pnext_time && pbracket_greater)
222705b261ecSmrg    {
222805b261ecSmrg	RegisterBlockAndWakeupHandlers(ServertimeBlockHandler,
222905b261ecSmrg				       ServertimeWakeupHandler,
223005b261ecSmrg				       NULL);
223105b261ecSmrg    }
223205b261ecSmrg    else if (pnext_time && !pbracket_greater)
223305b261ecSmrg    {
223405b261ecSmrg	RemoveBlockAndWakeupHandlers(ServertimeBlockHandler,
223505b261ecSmrg				     ServertimeWakeupHandler,
223605b261ecSmrg				     NULL);
223705b261ecSmrg    }
223805b261ecSmrg    pnext_time = pbracket_greater;
223905b261ecSmrg}
224005b261ecSmrg
224105b261ecSmrgstatic void
224205b261ecSmrgSyncInitServerTime(void)
224305b261ecSmrg{
224405b261ecSmrg    CARD64 resolution;
224505b261ecSmrg
224605b261ecSmrg    XSyncIntsToValue(&Now, GetTimeInMillis(), 0);
224705b261ecSmrg    XSyncIntToValue(&resolution, 4);
224805b261ecSmrg    ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution,
224905b261ecSmrg			    XSyncCounterNeverDecreases,
225005b261ecSmrg			    ServertimeQueryValue, ServertimeBracketValues);
225105b261ecSmrg    pnext_time = NULL;
225205b261ecSmrg}
225305b261ecSmrg
225405b261ecSmrg
225505b261ecSmrg
225605b261ecSmrg/*
225705b261ecSmrg * IDLETIME implementation
225805b261ecSmrg */
225905b261ecSmrg
226045801275Sjmcneillstatic SyncCounter *IdleTimeCounter;
226105b261ecSmrgstatic XSyncValue *pIdleTimeValueLess;
226205b261ecSmrgstatic XSyncValue *pIdleTimeValueGreater;
226305b261ecSmrg
226405b261ecSmrgstatic void
226505b261ecSmrgIdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return)
226605b261ecSmrg{
226705b261ecSmrg    CARD32 idle = GetTimeInMillis() - lastDeviceEventTime.milliseconds;
226805b261ecSmrg    XSyncIntsToValue (pValue_return, idle, 0);
226905b261ecSmrg}
227005b261ecSmrg
227105b261ecSmrgstatic void
227245801275SjmcneillIdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask)
227305b261ecSmrg{
227445801275Sjmcneill    XSyncValue idle, old_idle;
227545801275Sjmcneill    SyncTriggerList *list = IdleTimeCounter->pTriglist;
227645801275Sjmcneill    SyncTrigger *trig;
227705b261ecSmrg
227805b261ecSmrg    if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
227905b261ecSmrg	return;
228005b261ecSmrg
228145801275Sjmcneill    old_idle = IdleTimeCounter->value;
228205b261ecSmrg    IdleTimeQueryValue (NULL, &idle);
228345801275Sjmcneill    IdleTimeCounter->value = idle; /* push, so CheckTrigger works */
228405b261ecSmrg
228505b261ecSmrg    if (pIdleTimeValueLess &&
228605b261ecSmrg        XSyncValueLessOrEqual (idle, *pIdleTimeValueLess))
228705b261ecSmrg    {
228845801275Sjmcneill	/*
228945801275Sjmcneill	 * We've been idle for less than the threshold value, and someone
229045801275Sjmcneill	 * wants to know about that, but now we need to know whether they
229145801275Sjmcneill	 * want level or edge trigger.  Check the trigger list against the
229245801275Sjmcneill	 * current idle time, and if any succeed, bomb out of select()
229345801275Sjmcneill	 * immediately so we can reschedule.
229445801275Sjmcneill	 */
229545801275Sjmcneill
229645801275Sjmcneill	for (list = IdleTimeCounter->pTriglist; list; list = list->next) {
229745801275Sjmcneill	    trig = list->pTrigger;
229845801275Sjmcneill	    if (trig->CheckTrigger(trig, old_idle)) {
229945801275Sjmcneill		AdjustWaitForDelay(wt, 0);
230045801275Sjmcneill		break;
230145801275Sjmcneill	    }
230245801275Sjmcneill	}
230305b261ecSmrg    }
230405b261ecSmrg    else if (pIdleTimeValueGreater)
230505b261ecSmrg    {
230645801275Sjmcneill	/*
230745801275Sjmcneill	 * There's a threshold in the positive direction.  If we've been
230845801275Sjmcneill	 * idle less than it, schedule a wakeup for sometime in the future.
230945801275Sjmcneill	 * If we've been idle more than it, and someone wants to know about
231045801275Sjmcneill	 * that level-triggered, schedule an immediate wakeup.
231145801275Sjmcneill	 */
231245801275Sjmcneill	unsigned long timeout = -1;
231305b261ecSmrg
231445801275Sjmcneill	if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) {
231505b261ecSmrg	    XSyncValue value;
231605b261ecSmrg	    Bool overflow;
231705b261ecSmrg
231805b261ecSmrg	    XSyncValueSubtract (&value, *pIdleTimeValueGreater,
231905b261ecSmrg	                        idle, &overflow);
232045801275Sjmcneill	    timeout = min(timeout, XSyncValueLow32 (value));
232145801275Sjmcneill	} else {
232245801275Sjmcneill	    for (list = IdleTimeCounter->pTriglist; list; list = list->next) {
232345801275Sjmcneill		trig = list->pTrigger;
232445801275Sjmcneill		if (trig->CheckTrigger(trig, old_idle)) {
232545801275Sjmcneill		    timeout = min(timeout, 0);
232645801275Sjmcneill		    break;
232745801275Sjmcneill		}
232845801275Sjmcneill	    }
232905b261ecSmrg	}
233005b261ecSmrg
233105b261ecSmrg	AdjustWaitForDelay (wt, timeout);
233205b261ecSmrg    }
233345801275Sjmcneill
233445801275Sjmcneill    IdleTimeCounter->value = old_idle; /* pop */
233505b261ecSmrg}
233605b261ecSmrg
233705b261ecSmrgstatic void
23384202a189SmrgIdleTimeWakeupHandler (pointer env, int rc, pointer LastSelectMask)
233905b261ecSmrg{
234005b261ecSmrg    XSyncValue idle;
234105b261ecSmrg
234205b261ecSmrg    if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
234305b261ecSmrg	return;
234405b261ecSmrg
234505b261ecSmrg    IdleTimeQueryValue (NULL, &idle);
234605b261ecSmrg
234705b261ecSmrg    if ((pIdleTimeValueGreater &&
234805b261ecSmrg         XSyncValueGreaterOrEqual (idle, *pIdleTimeValueGreater)) ||
234905b261ecSmrg        (pIdleTimeValueLess &&
235005b261ecSmrg	 XSyncValueLessOrEqual (idle, *pIdleTimeValueLess)))
235105b261ecSmrg    {
235205b261ecSmrg	SyncChangeCounter (IdleTimeCounter, idle);
235305b261ecSmrg    }
235405b261ecSmrg}
235505b261ecSmrg
235605b261ecSmrgstatic void
23574202a189SmrgIdleTimeBracketValues (pointer pCounter, CARD64 *pbracket_less,
235805b261ecSmrg                       CARD64 *pbracket_greater)
235905b261ecSmrg{
236005b261ecSmrg    Bool registered = (pIdleTimeValueLess || pIdleTimeValueGreater);
236105b261ecSmrg
236205b261ecSmrg    if (registered && !pbracket_less && !pbracket_greater)
236305b261ecSmrg    {
236405b261ecSmrg	RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler,
236505b261ecSmrg	                             IdleTimeWakeupHandler,
236605b261ecSmrg	                             NULL);
236705b261ecSmrg    }
236805b261ecSmrg    else if (!registered && (pbracket_less || pbracket_greater))
236905b261ecSmrg    {
237005b261ecSmrg	RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
237105b261ecSmrg	                               IdleTimeWakeupHandler,
237205b261ecSmrg	                               NULL);
237305b261ecSmrg    }
237405b261ecSmrg
237505b261ecSmrg    pIdleTimeValueGreater = pbracket_greater;
237605b261ecSmrg    pIdleTimeValueLess    = pbracket_less;
237705b261ecSmrg}
237805b261ecSmrg
237905b261ecSmrgstatic void
238005b261ecSmrgSyncInitIdleTime (void)
238105b261ecSmrg{
238205b261ecSmrg    CARD64 resolution;
238305b261ecSmrg    XSyncValue idle;
238405b261ecSmrg
238505b261ecSmrg    IdleTimeQueryValue (NULL, &idle);
238605b261ecSmrg    XSyncIntToValue (&resolution, 4);
238705b261ecSmrg
238805b261ecSmrg    IdleTimeCounter = SyncCreateSystemCounter ("IDLETIME", idle, resolution,
238905b261ecSmrg                                               XSyncCounterUnrestricted,
239005b261ecSmrg                                               IdleTimeQueryValue,
239105b261ecSmrg                                               IdleTimeBracketValues);
239205b261ecSmrg
239305b261ecSmrg    pIdleTimeValueLess = pIdleTimeValueGreater = NULL;
239405b261ecSmrg}
2395