2426 lines
62 KiB
C
2426 lines
62 KiB
C
/*
|
|
|
|
Copyright 1991, 1993, 1998 The Open Group
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
the above copyright notice appear in all copies and that both that
|
|
copyright notice and this permission notice appear in supporting
|
|
documentation.
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall
|
|
not be used in advertising or otherwise to promote the sale, use or
|
|
other dealings in this Software without prior written authorization
|
|
from The Open Group.
|
|
|
|
|
|
Copyright 1991, 1993 by Digital Equipment Corporation, Maynard, Massachusetts,
|
|
and Olivetti Research Limited, Cambridge, England.
|
|
|
|
All Rights Reserved
|
|
|
|
Permission to use, copy, modify, and distribute this software and its
|
|
documentation for any purpose and without fee is hereby granted,
|
|
provided that the above copyright notice appear in all copies and that
|
|
both that copyright notice and this permission notice appear in
|
|
supporting documentation, and that the names of Digital or Olivetti
|
|
not be used in advertising or publicity pertaining to distribution of the
|
|
software without specific, written prior permission. Digital and Olivetti
|
|
make no representations about the suitability of this software
|
|
for any purpose. It is provided "as is" without express or implied warranty.
|
|
|
|
DIGITAL AND OLIVETTI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
|
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS, IN NO EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
|
USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
#include <X11/X.h>
|
|
#include <X11/Xproto.h>
|
|
#include <X11/Xmd.h>
|
|
#include "misc.h"
|
|
#include "os.h"
|
|
#include "extnsionst.h"
|
|
#include "dixstruct.h"
|
|
#include "resource.h"
|
|
#include "opaque.h"
|
|
#include <X11/extensions/syncproto.h>
|
|
#include "syncsrv.h"
|
|
#include "protocol-versions.h"
|
|
|
|
#include <stdio.h>
|
|
#if !defined(WIN32)
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
#include "modinit.h"
|
|
|
|
/*
|
|
* Local Global Variables
|
|
*/
|
|
static int SyncEventBase;
|
|
static int SyncErrorBase;
|
|
static RESTYPE RTCounter = 0;
|
|
static RESTYPE RTAwait;
|
|
static RESTYPE RTAlarm;
|
|
static RESTYPE RTAlarmClient;
|
|
static int SyncNumSystemCounters = 0;
|
|
static SyncCounter **SysCounterList = NULL;
|
|
|
|
#define IsSystemCounter(pCounter) \
|
|
(pCounter && (pCounter->client == NULL))
|
|
|
|
/* these are all the alarm attributes that pertain to the alarm's trigger */
|
|
#define XSyncCAAllTrigger \
|
|
(XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType)
|
|
|
|
static void SyncComputeBracketValues(SyncCounter *);
|
|
|
|
static void SyncInitServerTime(void);
|
|
|
|
static void SyncInitIdleTime(void);
|
|
|
|
static DISPATCH_PROC(ProcSyncAwait);
|
|
static DISPATCH_PROC(ProcSyncChangeAlarm);
|
|
static DISPATCH_PROC(ProcSyncChangeCounter);
|
|
static DISPATCH_PROC(ProcSyncCreateAlarm);
|
|
static DISPATCH_PROC(ProcSyncCreateCounter);
|
|
static DISPATCH_PROC(ProcSyncDestroyAlarm);
|
|
static DISPATCH_PROC(ProcSyncDestroyCounter);
|
|
static DISPATCH_PROC(ProcSyncDispatch);
|
|
static DISPATCH_PROC(ProcSyncGetPriority);
|
|
static DISPATCH_PROC(ProcSyncInitialize);
|
|
static DISPATCH_PROC(ProcSyncListSystemCounters);
|
|
static DISPATCH_PROC(ProcSyncQueryAlarm);
|
|
static DISPATCH_PROC(ProcSyncQueryCounter);
|
|
static DISPATCH_PROC(ProcSyncSetCounter);
|
|
static DISPATCH_PROC(ProcSyncSetPriority);
|
|
static DISPATCH_PROC(SProcSyncAwait);
|
|
static DISPATCH_PROC(SProcSyncChangeAlarm);
|
|
static DISPATCH_PROC(SProcSyncChangeCounter);
|
|
static DISPATCH_PROC(SProcSyncCreateAlarm);
|
|
static DISPATCH_PROC(SProcSyncCreateCounter);
|
|
static DISPATCH_PROC(SProcSyncDestroyAlarm);
|
|
static DISPATCH_PROC(SProcSyncDestroyCounter);
|
|
static DISPATCH_PROC(SProcSyncDispatch);
|
|
static DISPATCH_PROC(SProcSyncGetPriority);
|
|
static DISPATCH_PROC(SProcSyncInitialize);
|
|
static DISPATCH_PROC(SProcSyncListSystemCounters);
|
|
static DISPATCH_PROC(SProcSyncQueryAlarm);
|
|
static DISPATCH_PROC(SProcSyncQueryCounter);
|
|
static DISPATCH_PROC(SProcSyncSetCounter);
|
|
static DISPATCH_PROC(SProcSyncSetPriority);
|
|
|
|
/* Each counter maintains a simple linked list of triggers that are
|
|
* interested in the counter. The two functions below are used to
|
|
* delete and add triggers on this list.
|
|
*/
|
|
static void
|
|
SyncDeleteTriggerFromCounter(SyncTrigger *pTrigger)
|
|
{
|
|
SyncTriggerList *pCur;
|
|
SyncTriggerList *pPrev;
|
|
|
|
/* pCounter needs to be stored in pTrigger before calling here. */
|
|
|
|
if (!pTrigger->pCounter)
|
|
return;
|
|
|
|
pPrev = NULL;
|
|
pCur = pTrigger->pCounter->pTriglist;
|
|
|
|
while (pCur)
|
|
{
|
|
if (pCur->pTrigger == pTrigger)
|
|
{
|
|
if (pPrev)
|
|
pPrev->next = pCur->next;
|
|
else
|
|
pTrigger->pCounter->pTriglist = pCur->next;
|
|
|
|
free(pCur);
|
|
break;
|
|
}
|
|
|
|
pPrev = pCur;
|
|
pCur = pCur->next;
|
|
}
|
|
|
|
if (IsSystemCounter(pTrigger->pCounter))
|
|
SyncComputeBracketValues(pTrigger->pCounter);
|
|
}
|
|
|
|
|
|
static int
|
|
SyncAddTriggerToCounter(SyncTrigger *pTrigger)
|
|
{
|
|
SyncTriggerList *pCur;
|
|
|
|
if (!pTrigger->pCounter)
|
|
return Success;
|
|
|
|
/* don't do anything if it's already there */
|
|
for (pCur = pTrigger->pCounter->pTriglist; pCur; pCur = pCur->next)
|
|
{
|
|
if (pCur->pTrigger == pTrigger)
|
|
return Success;
|
|
}
|
|
|
|
if (!(pCur = malloc(sizeof(SyncTriggerList))))
|
|
return BadAlloc;
|
|
|
|
pCur->pTrigger = pTrigger;
|
|
pCur->next = pTrigger->pCounter->pTriglist;
|
|
pTrigger->pCounter->pTriglist = pCur;
|
|
|
|
if (IsSystemCounter(pTrigger->pCounter))
|
|
SyncComputeBracketValues(pTrigger->pCounter);
|
|
|
|
return Success;
|
|
}
|
|
|
|
|
|
/* Below are four possible functions that can be plugged into
|
|
* pTrigger->CheckTrigger, corresponding to the four possible
|
|
* test-types. These functions are called after the counter's
|
|
* value changes but are also passed the old counter value
|
|
* so they can inspect both the old and new values.
|
|
* (PositiveTransition and NegativeTransition need to see both
|
|
* pieces of information.) These functions return the truth value
|
|
* of the trigger.
|
|
*
|
|
* All of them include the condition pTrigger->pCounter == NULL.
|
|
* This is because the spec says that a trigger with a counter value
|
|
* of None is always TRUE.
|
|
*/
|
|
|
|
static Bool
|
|
SyncCheckTriggerPositiveComparison(SyncTrigger *pTrigger, CARD64 oldval)
|
|
{
|
|
return (pTrigger->pCounter == NULL ||
|
|
XSyncValueGreaterOrEqual(pTrigger->pCounter->value,
|
|
pTrigger->test_value));
|
|
}
|
|
|
|
static Bool
|
|
SyncCheckTriggerNegativeComparison(SyncTrigger *pTrigger, CARD64 oldval)
|
|
{
|
|
return (pTrigger->pCounter == NULL ||
|
|
XSyncValueLessOrEqual(pTrigger->pCounter->value,
|
|
pTrigger->test_value));
|
|
}
|
|
|
|
static Bool
|
|
SyncCheckTriggerPositiveTransition(SyncTrigger *pTrigger, CARD64 oldval)
|
|
{
|
|
return (pTrigger->pCounter == NULL ||
|
|
(XSyncValueLessThan(oldval, pTrigger->test_value) &&
|
|
XSyncValueGreaterOrEqual(pTrigger->pCounter->value,
|
|
pTrigger->test_value)));
|
|
}
|
|
|
|
static Bool
|
|
SyncCheckTriggerNegativeTransition(SyncTrigger *pTrigger, CARD64 oldval)
|
|
{
|
|
return (pTrigger->pCounter == NULL ||
|
|
(XSyncValueGreaterThan(oldval, pTrigger->test_value) &&
|
|
XSyncValueLessOrEqual(pTrigger->pCounter->value,
|
|
pTrigger->test_value)));
|
|
}
|
|
|
|
static int
|
|
SyncInitTrigger(ClientPtr client, SyncTrigger *pTrigger, XSyncCounter counter,
|
|
Mask changes)
|
|
{
|
|
SyncCounter *pCounter = pTrigger->pCounter;
|
|
int rc;
|
|
Bool newcounter = FALSE;
|
|
|
|
if (changes & XSyncCACounter)
|
|
{
|
|
if (counter == None)
|
|
pCounter = NULL;
|
|
else if (Success != (rc = dixLookupResourceByType ((pointer *)&pCounter,
|
|
counter, RTCounter, client, DixReadAccess)))
|
|
{
|
|
client->errorValue = counter;
|
|
return rc;
|
|
}
|
|
if (pCounter != pTrigger->pCounter)
|
|
{ /* new counter for trigger */
|
|
SyncDeleteTriggerFromCounter(pTrigger);
|
|
pTrigger->pCounter = pCounter;
|
|
newcounter = TRUE;
|
|
}
|
|
}
|
|
|
|
/* if system counter, ask it what the current value is */
|
|
|
|
if (IsSystemCounter(pCounter))
|
|
{
|
|
(*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
|
|
&pCounter->value);
|
|
}
|
|
|
|
if (changes & XSyncCAValueType)
|
|
{
|
|
if (pTrigger->value_type != XSyncRelative &&
|
|
pTrigger->value_type != XSyncAbsolute)
|
|
{
|
|
client->errorValue = pTrigger->value_type;
|
|
return BadValue;
|
|
}
|
|
}
|
|
|
|
if (changes & XSyncCATestType)
|
|
{
|
|
if (pTrigger->test_type != XSyncPositiveTransition &&
|
|
pTrigger->test_type != XSyncNegativeTransition &&
|
|
pTrigger->test_type != XSyncPositiveComparison &&
|
|
pTrigger->test_type != XSyncNegativeComparison)
|
|
{
|
|
client->errorValue = pTrigger->test_type;
|
|
return BadValue;
|
|
}
|
|
/* select appropriate CheckTrigger function */
|
|
|
|
switch (pTrigger->test_type)
|
|
{
|
|
case XSyncPositiveTransition:
|
|
pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition;
|
|
break;
|
|
case XSyncNegativeTransition:
|
|
pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition;
|
|
break;
|
|
case XSyncPositiveComparison:
|
|
pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison;
|
|
break;
|
|
case XSyncNegativeComparison:
|
|
pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (changes & (XSyncCAValueType | XSyncCAValue))
|
|
{
|
|
if (pTrigger->value_type == XSyncAbsolute)
|
|
pTrigger->test_value = pTrigger->wait_value;
|
|
else /* relative */
|
|
{
|
|
Bool overflow;
|
|
if (pCounter == NULL)
|
|
return BadMatch;
|
|
|
|
XSyncValueAdd(&pTrigger->test_value, pCounter->value,
|
|
pTrigger->wait_value, &overflow);
|
|
if (overflow)
|
|
{
|
|
client->errorValue = XSyncValueHigh32(pTrigger->wait_value);
|
|
return BadValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* we wait until we're sure there are no errors before registering
|
|
* a new counter on a trigger
|
|
*/
|
|
if (newcounter)
|
|
{
|
|
if ((rc = SyncAddTriggerToCounter(pTrigger)) != Success)
|
|
return rc;
|
|
}
|
|
else if (IsSystemCounter(pCounter))
|
|
{
|
|
SyncComputeBracketValues(pCounter);
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
/* AlarmNotify events happen in response to actions taken on an Alarm or
|
|
* the counter used by the alarm. AlarmNotify may be sent to multiple
|
|
* clients. The alarm maintains a list of clients interested in events.
|
|
*/
|
|
static void
|
|
SyncSendAlarmNotifyEvents(SyncAlarm *pAlarm)
|
|
{
|
|
SyncAlarmClientList *pcl;
|
|
xSyncAlarmNotifyEvent ane;
|
|
SyncTrigger *pTrigger = &pAlarm->trigger;
|
|
|
|
UpdateCurrentTime();
|
|
|
|
ane.type = SyncEventBase + XSyncAlarmNotify;
|
|
ane.kind = XSyncAlarmNotify;
|
|
ane.alarm = pAlarm->alarm_id;
|
|
if (pTrigger->pCounter)
|
|
{
|
|
ane.counter_value_hi = XSyncValueHigh32(pTrigger->pCounter->value);
|
|
ane.counter_value_lo = XSyncValueLow32(pTrigger->pCounter->value);
|
|
}
|
|
else
|
|
{ /* XXX what else can we do if there's no counter? */
|
|
ane.counter_value_hi = ane.counter_value_lo = 0;
|
|
}
|
|
|
|
ane.alarm_value_hi = XSyncValueHigh32(pTrigger->test_value);
|
|
ane.alarm_value_lo = XSyncValueLow32(pTrigger->test_value);
|
|
ane.time = currentTime.milliseconds;
|
|
ane.state = pAlarm->state;
|
|
|
|
/* send to owner */
|
|
if (pAlarm->events)
|
|
WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane);
|
|
|
|
/* send to other interested clients */
|
|
for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next)
|
|
WriteEventsToClient(pcl->client, 1, (xEvent *) &ane);
|
|
}
|
|
|
|
|
|
/* CounterNotify events only occur in response to an Await. The events
|
|
* go only to the Awaiting client.
|
|
*/
|
|
static void
|
|
SyncSendCounterNotifyEvents(ClientPtr client, SyncAwait **ppAwait,
|
|
int num_events)
|
|
{
|
|
xSyncCounterNotifyEvent *pEvents, *pev;
|
|
int i;
|
|
|
|
if (client->clientGone)
|
|
return;
|
|
pev = pEvents = malloc(num_events * sizeof(xSyncCounterNotifyEvent));
|
|
if (!pEvents)
|
|
return;
|
|
UpdateCurrentTime();
|
|
for (i = 0; i < num_events; i++, ppAwait++, pev++)
|
|
{
|
|
SyncTrigger *pTrigger = &(*ppAwait)->trigger;
|
|
pev->type = SyncEventBase + XSyncCounterNotify;
|
|
pev->kind = XSyncCounterNotify;
|
|
pev->counter = pTrigger->pCounter->id;
|
|
pev->wait_value_lo = XSyncValueLow32(pTrigger->test_value);
|
|
pev->wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
|
|
pev->counter_value_lo = XSyncValueLow32(pTrigger->pCounter->value);
|
|
pev->counter_value_hi = XSyncValueHigh32(pTrigger->pCounter->value);
|
|
pev->time = currentTime.milliseconds;
|
|
pev->count = num_events - i - 1; /* events remaining */
|
|
pev->destroyed = pTrigger->pCounter->beingDestroyed;
|
|
}
|
|
/* swapping will be taken care of by this */
|
|
WriteEventsToClient(client, num_events, (xEvent *)pEvents);
|
|
free(pEvents);
|
|
}
|
|
|
|
|
|
/* This function is called when an alarm's counter is destroyed.
|
|
* It is plugged into pTrigger->CounterDestroyed (for alarm triggers).
|
|
*/
|
|
static void
|
|
SyncAlarmCounterDestroyed(SyncTrigger *pTrigger)
|
|
{
|
|
SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
|
|
|
|
pAlarm->state = XSyncAlarmInactive;
|
|
SyncSendAlarmNotifyEvents(pAlarm);
|
|
pTrigger->pCounter = NULL;
|
|
}
|
|
|
|
|
|
/* This function is called when an alarm "goes off."
|
|
* It is plugged into pTrigger->TriggerFired (for alarm triggers).
|
|
*/
|
|
static void
|
|
SyncAlarmTriggerFired(SyncTrigger *pTrigger)
|
|
{
|
|
SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
|
|
CARD64 new_test_value;
|
|
|
|
/* no need to check alarm unless it's active */
|
|
if (pAlarm->state != XSyncAlarmActive)
|
|
return;
|
|
|
|
/* " if the counter value is None, or if the delta is 0 and
|
|
* the test-type is PositiveComparison or NegativeComparison,
|
|
* no change is made to value (test-value) and the alarm
|
|
* state is changed to Inactive before the event is generated."
|
|
*/
|
|
if (pAlarm->trigger.pCounter == NULL
|
|
|| (XSyncValueIsZero(pAlarm->delta)
|
|
&& (pAlarm->trigger.test_type == XSyncPositiveComparison
|
|
|| pAlarm->trigger.test_type == XSyncNegativeComparison)))
|
|
pAlarm->state = XSyncAlarmInactive;
|
|
|
|
new_test_value = pAlarm->trigger.test_value;
|
|
|
|
if (pAlarm->state == XSyncAlarmActive)
|
|
{
|
|
Bool overflow;
|
|
CARD64 oldvalue;
|
|
SyncTrigger *paTrigger = &pAlarm->trigger;
|
|
|
|
/* "The alarm is updated by repeatedly adding delta to the
|
|
* value of the trigger and re-initializing it until it
|
|
* becomes FALSE."
|
|
*/
|
|
oldvalue = paTrigger->test_value;
|
|
|
|
/* XXX really should do something smarter here */
|
|
|
|
do
|
|
{
|
|
XSyncValueAdd(&paTrigger->test_value, paTrigger->test_value,
|
|
pAlarm->delta, &overflow);
|
|
} while (!overflow &&
|
|
(*paTrigger->CheckTrigger)(paTrigger,
|
|
paTrigger->pCounter->value));
|
|
|
|
new_test_value = paTrigger->test_value;
|
|
paTrigger->test_value = oldvalue;
|
|
|
|
/* "If this update would cause value to fall outside the range
|
|
* for an INT64...no change is made to value (test-value) and
|
|
* the alarm state is changed to Inactive before the event is
|
|
* generated."
|
|
*/
|
|
if (overflow)
|
|
{
|
|
new_test_value = oldvalue;
|
|
pAlarm->state = XSyncAlarmInactive;
|
|
}
|
|
}
|
|
/* The AlarmNotify event has to have the "new state of the alarm"
|
|
* which we can't be sure of until this point. However, it has
|
|
* to have the "old" trigger test value. That's the reason for
|
|
* all the newvalue/oldvalue shuffling above. After we send the
|
|
* events, give the trigger its new test value.
|
|
*/
|
|
SyncSendAlarmNotifyEvents(pAlarm);
|
|
pTrigger->test_value = new_test_value;
|
|
}
|
|
|
|
|
|
/* This function is called when an Await unblocks, either as a result
|
|
* of the trigger firing OR the counter being destroyed.
|
|
* It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed
|
|
* (for Await triggers).
|
|
*/
|
|
static void
|
|
SyncAwaitTriggerFired(SyncTrigger *pTrigger)
|
|
{
|
|
SyncAwait *pAwait = (SyncAwait *)pTrigger;
|
|
int numwaits;
|
|
SyncAwaitUnion *pAwaitUnion;
|
|
SyncAwait **ppAwait;
|
|
int num_events = 0;
|
|
|
|
pAwaitUnion = (SyncAwaitUnion *)pAwait->pHeader;
|
|
numwaits = pAwaitUnion->header.num_waitconditions;
|
|
ppAwait = malloc(numwaits * sizeof(SyncAwait *));
|
|
if (!ppAwait)
|
|
goto bail;
|
|
|
|
pAwait = &(pAwaitUnion+1)->await;
|
|
|
|
/* "When a client is unblocked, all the CounterNotify events for
|
|
* the Await request are generated contiguously. If count is 0
|
|
* there are no more events to follow for this request. If
|
|
* count is n, there are at least n more events to follow."
|
|
*
|
|
* Thus, it is best to find all the counters for which events
|
|
* need to be sent first, so that an accurate count field can
|
|
* be stored in the events.
|
|
*/
|
|
for ( ; numwaits; numwaits--, pAwait++)
|
|
{
|
|
CARD64 diff;
|
|
Bool overflow, diffgreater, diffequal;
|
|
|
|
/* "A CounterNotify event with the destroyed flag set to TRUE is
|
|
* always generated if the counter for one of the triggers is
|
|
* destroyed."
|
|
*/
|
|
if (pAwait->trigger.pCounter->beingDestroyed)
|
|
{
|
|
ppAwait[num_events++] = pAwait;
|
|
continue;
|
|
}
|
|
|
|
/* "The difference between the counter and the test value is
|
|
* calculated by subtracting the test value from the value of
|
|
* the counter."
|
|
*/
|
|
XSyncValueSubtract(&diff, pAwait->trigger.pCounter->value,
|
|
pAwait->trigger.test_value, &overflow);
|
|
|
|
/* "If the difference lies outside the range for an INT64, an
|
|
* event is not generated."
|
|
*/
|
|
if (overflow)
|
|
continue;
|
|
diffgreater = XSyncValueGreaterThan(diff, pAwait->event_threshold);
|
|
diffequal = XSyncValueEqual(diff, pAwait->event_threshold);
|
|
|
|
/* "If the test-type is PositiveTransition or
|
|
* PositiveComparison, a CounterNotify event is generated if
|
|
* the difference is at least event-threshold. If the test-type
|
|
* is NegativeTransition or NegativeComparison, a CounterNotify
|
|
* event is generated if the difference is at most
|
|
* event-threshold."
|
|
*/
|
|
|
|
if ( ((pAwait->trigger.test_type == XSyncPositiveComparison ||
|
|
pAwait->trigger.test_type == XSyncPositiveTransition)
|
|
&& (diffgreater || diffequal))
|
|
||
|
|
((pAwait->trigger.test_type == XSyncNegativeComparison ||
|
|
pAwait->trigger.test_type == XSyncNegativeTransition)
|
|
&& (!diffgreater) /* less or equal */
|
|
)
|
|
)
|
|
{
|
|
ppAwait[num_events++] = pAwait;
|
|
}
|
|
}
|
|
if (num_events)
|
|
SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait,
|
|
num_events);
|
|
free(ppAwait);
|
|
|
|
bail:
|
|
/* unblock the client */
|
|
AttendClient(pAwaitUnion->header.client);
|
|
/* delete the await */
|
|
FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
|
|
}
|
|
|
|
|
|
/* This function should always be used to change a counter's value so that
|
|
* any triggers depending on the counter will be checked.
|
|
*/
|
|
void
|
|
SyncChangeCounter(SyncCounter *pCounter, CARD64 newval)
|
|
{
|
|
SyncTriggerList *ptl, *pnext;
|
|
CARD64 oldval;
|
|
|
|
oldval = pCounter->value;
|
|
pCounter->value = newval;
|
|
|
|
/* run through triggers to see if any become true */
|
|
for (ptl = pCounter->pTriglist; ptl; ptl = pnext)
|
|
{
|
|
pnext = ptl->next;
|
|
if ((*ptl->pTrigger->CheckTrigger)(ptl->pTrigger, oldval))
|
|
(*ptl->pTrigger->TriggerFired)(ptl->pTrigger);
|
|
}
|
|
|
|
if (IsSystemCounter(pCounter))
|
|
{
|
|
SyncComputeBracketValues(pCounter);
|
|
}
|
|
}
|
|
|
|
|
|
/* loosely based on dix/events.c/EventSelectForWindow */
|
|
static Bool
|
|
SyncEventSelectForAlarm(SyncAlarm *pAlarm, ClientPtr client, Bool wantevents)
|
|
{
|
|
SyncAlarmClientList *pClients;
|
|
|
|
if (client == pAlarm->client) /* alarm owner */
|
|
{
|
|
pAlarm->events = wantevents;
|
|
return Success;
|
|
}
|
|
|
|
/* see if the client is already on the list (has events selected) */
|
|
|
|
for (pClients = pAlarm->pEventClients; pClients;
|
|
pClients = pClients->next)
|
|
{
|
|
if (pClients->client == client)
|
|
{
|
|
/* client's presence on the list indicates desire for
|
|
* events. If the client doesn't want events, remove it
|
|
* from the list. If the client does want events, do
|
|
* nothing, since it's already got them.
|
|
*/
|
|
if (!wantevents)
|
|
{
|
|
FreeResource(pClients->delete_id, RT_NONE);
|
|
}
|
|
return Success;
|
|
}
|
|
}
|
|
|
|
/* if we get here, this client does not currently have
|
|
* events selected on the alarm
|
|
*/
|
|
|
|
if (!wantevents)
|
|
/* client doesn't want events, and we just discovered that it
|
|
* doesn't have them, so there's nothing to do.
|
|
*/
|
|
return Success;
|
|
|
|
/* add new client to pAlarm->pEventClients */
|
|
|
|
pClients = malloc(sizeof(SyncAlarmClientList));
|
|
if (!pClients)
|
|
return BadAlloc;
|
|
|
|
/* register it as a resource so it will be cleaned up
|
|
* if the client dies
|
|
*/
|
|
|
|
pClients->delete_id = FakeClientID(client->index);
|
|
if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm))
|
|
{
|
|
free(pClients);
|
|
return BadAlloc;
|
|
}
|
|
|
|
/* link it into list after we know all the allocations succeed */
|
|
|
|
pClients->next = pAlarm->pEventClients;
|
|
pAlarm->pEventClients = pClients;
|
|
pClients->client = client;
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
* ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm
|
|
*/
|
|
static int
|
|
SyncChangeAlarmAttributes(ClientPtr client, SyncAlarm *pAlarm, Mask mask,
|
|
CARD32 *values)
|
|
{
|
|
int status;
|
|
XSyncCounter counter;
|
|
Mask origmask = mask;
|
|
|
|
counter = pAlarm->trigger.pCounter ? pAlarm->trigger.pCounter->id : None;
|
|
|
|
while (mask)
|
|
{
|
|
int index2 = lowbit(mask);
|
|
mask &= ~index2;
|
|
switch (index2)
|
|
{
|
|
case XSyncCACounter:
|
|
mask &= ~XSyncCACounter;
|
|
/* sanity check in SyncInitTrigger */
|
|
counter = *values++;
|
|
break;
|
|
|
|
case XSyncCAValueType:
|
|
mask &= ~XSyncCAValueType;
|
|
/* sanity check in SyncInitTrigger */
|
|
pAlarm->trigger.value_type = *values++;
|
|
break;
|
|
|
|
case XSyncCAValue:
|
|
mask &= ~XSyncCAValue;
|
|
XSyncIntsToValue(&pAlarm->trigger.wait_value, values[1], values[0]);
|
|
values += 2;
|
|
break;
|
|
|
|
case XSyncCATestType:
|
|
mask &= ~XSyncCATestType;
|
|
/* sanity check in SyncInitTrigger */
|
|
pAlarm->trigger.test_type = *values++;
|
|
break;
|
|
|
|
case XSyncCADelta:
|
|
mask &= ~XSyncCADelta;
|
|
XSyncIntsToValue(&pAlarm->delta, values[1], values[0]);
|
|
values += 2;
|
|
break;
|
|
|
|
case XSyncCAEvents:
|
|
mask &= ~XSyncCAEvents;
|
|
if ((*values != xTrue) && (*values != xFalse))
|
|
{
|
|
client->errorValue = *values;
|
|
return BadValue;
|
|
}
|
|
status = SyncEventSelectForAlarm(pAlarm, client,
|
|
(Bool)(*values++));
|
|
if (status != Success)
|
|
return status;
|
|
break;
|
|
|
|
default:
|
|
client->errorValue = mask;
|
|
return BadValue;
|
|
}
|
|
}
|
|
|
|
/* "If the test-type is PositiveComparison or PositiveTransition
|
|
* and delta is less than zero, or if the test-type is
|
|
* NegativeComparison or NegativeTransition and delta is
|
|
* greater than zero, a Match error is generated."
|
|
*/
|
|
if (origmask & (XSyncCADelta|XSyncCATestType))
|
|
{
|
|
CARD64 zero;
|
|
XSyncIntToValue(&zero, 0);
|
|
if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) ||
|
|
(pAlarm->trigger.test_type == XSyncPositiveTransition))
|
|
&& XSyncValueLessThan(pAlarm->delta, zero))
|
|
||
|
|
(((pAlarm->trigger.test_type == XSyncNegativeComparison) ||
|
|
(pAlarm->trigger.test_type == XSyncNegativeTransition))
|
|
&& XSyncValueGreaterThan(pAlarm->delta, zero))
|
|
)
|
|
{
|
|
return BadMatch;
|
|
}
|
|
}
|
|
|
|
/* postpone this until now, when we're sure nothing else can go wrong */
|
|
if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter,
|
|
origmask & XSyncCAAllTrigger)) != Success)
|
|
return status;
|
|
|
|
/* XXX spec does not really say to do this - needs clarification */
|
|
pAlarm->state = XSyncAlarmActive;
|
|
return Success;
|
|
}
|
|
|
|
|
|
static SyncCounter *
|
|
SyncCreateCounter(ClientPtr client, XSyncCounter id, CARD64 initialvalue)
|
|
{
|
|
SyncCounter *pCounter;
|
|
|
|
if (!(pCounter = malloc(sizeof(SyncCounter))))
|
|
return NULL;
|
|
|
|
if (!AddResource(id, RTCounter, (pointer) pCounter))
|
|
{
|
|
free(pCounter);
|
|
return NULL;
|
|
}
|
|
|
|
pCounter->client = client;
|
|
pCounter->id = id;
|
|
pCounter->value = initialvalue;
|
|
pCounter->pTriglist = NULL;
|
|
pCounter->beingDestroyed = FALSE;
|
|
pCounter->pSysCounterInfo = NULL;
|
|
return pCounter;
|
|
}
|
|
|
|
static int FreeCounter(void *, XID);
|
|
|
|
/*
|
|
* ***** System Counter utilities
|
|
*/
|
|
|
|
pointer
|
|
SyncCreateSystemCounter(
|
|
char *name,
|
|
CARD64 initial,
|
|
CARD64 resolution,
|
|
SyncCounterType counterType,
|
|
void (*QueryValue)(pointer /* pCounter */,
|
|
CARD64 * /* pValue_return */),
|
|
void (*BracketValues)(pointer /* pCounter */,
|
|
CARD64 * /* pbracket_less */,
|
|
CARD64 * /* pbracket_greater */)
|
|
)
|
|
{
|
|
SyncCounter *pCounter;
|
|
|
|
SysCounterList = realloc(SysCounterList,
|
|
(SyncNumSystemCounters+1)*sizeof(SyncCounter *));
|
|
if (!SysCounterList)
|
|
return NULL;
|
|
|
|
/* this function may be called before SYNC has been initialized, so we
|
|
* have to make sure RTCounter is created.
|
|
*/
|
|
if (RTCounter == 0)
|
|
{
|
|
RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
|
|
if (RTCounter == 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial);
|
|
|
|
if (pCounter)
|
|
{
|
|
SysCounterInfo *psci;
|
|
|
|
psci = malloc(sizeof(SysCounterInfo));
|
|
if (!psci)
|
|
{
|
|
FreeResource(pCounter->id, RT_NONE);
|
|
return pCounter;
|
|
}
|
|
pCounter->pSysCounterInfo = psci;
|
|
psci->name = name;
|
|
psci->resolution = resolution;
|
|
psci->counterType = counterType;
|
|
psci->QueryValue = QueryValue;
|
|
psci->BracketValues = BracketValues;
|
|
XSyncMaxValue(&psci->bracket_greater);
|
|
XSyncMinValue(&psci->bracket_less);
|
|
SysCounterList[SyncNumSystemCounters++] = pCounter;
|
|
}
|
|
return pCounter;
|
|
}
|
|
|
|
void
|
|
SyncDestroySystemCounter(pointer pSysCounter)
|
|
{
|
|
SyncCounter *pCounter = (SyncCounter *)pSysCounter;
|
|
FreeResource(pCounter->id, RT_NONE);
|
|
}
|
|
|
|
static void
|
|
SyncComputeBracketValues(SyncCounter *pCounter)
|
|
{
|
|
SyncTriggerList *pCur;
|
|
SyncTrigger *pTrigger;
|
|
SysCounterInfo *psci;
|
|
CARD64 *pnewgtval = NULL;
|
|
CARD64 *pnewltval = NULL;
|
|
SyncCounterType ct;
|
|
|
|
if (!pCounter)
|
|
return;
|
|
|
|
psci = pCounter->pSysCounterInfo;
|
|
ct = pCounter->pSysCounterInfo->counterType;
|
|
if (ct == XSyncCounterNeverChanges)
|
|
return;
|
|
|
|
XSyncMaxValue(&psci->bracket_greater);
|
|
XSyncMinValue(&psci->bracket_less);
|
|
|
|
for (pCur = pCounter->pTriglist; pCur; pCur = pCur->next)
|
|
{
|
|
pTrigger = pCur->pTrigger;
|
|
|
|
if (pTrigger->test_type == XSyncPositiveComparison &&
|
|
ct != XSyncCounterNeverIncreases)
|
|
{
|
|
if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
|
|
XSyncValueLessThan(pTrigger->test_value,
|
|
psci->bracket_greater))
|
|
{
|
|
psci->bracket_greater = pTrigger->test_value;
|
|
pnewgtval = &psci->bracket_greater;
|
|
}
|
|
}
|
|
else if (pTrigger->test_type == XSyncNegativeComparison &&
|
|
ct != XSyncCounterNeverDecreases)
|
|
{
|
|
if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
|
|
XSyncValueGreaterThan(pTrigger->test_value,
|
|
psci->bracket_less))
|
|
{
|
|
psci->bracket_less = pTrigger->test_value;
|
|
pnewltval = &psci->bracket_less;
|
|
}
|
|
}
|
|
else if (pTrigger->test_type == XSyncNegativeTransition &&
|
|
ct != XSyncCounterNeverIncreases)
|
|
{
|
|
if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
|
|
XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less))
|
|
{
|
|
psci->bracket_less = pTrigger->test_value;
|
|
pnewltval = &psci->bracket_less;
|
|
} else if (XSyncValueEqual(pCounter->value, pTrigger->test_value) &&
|
|
XSyncValueLessThan(pTrigger->test_value,
|
|
psci->bracket_greater))
|
|
{
|
|
/*
|
|
* The value is exactly equal to our threshold. We want one
|
|
* more event in the positive direction to ensure we pick up
|
|
* when the value *exceeds* this threshold.
|
|
*/
|
|
psci->bracket_greater = pTrigger->test_value;
|
|
pnewgtval = &psci->bracket_greater;
|
|
}
|
|
}
|
|
else if (pTrigger->test_type == XSyncPositiveTransition &&
|
|
ct != XSyncCounterNeverDecreases)
|
|
{
|
|
if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
|
|
XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater))
|
|
{
|
|
psci->bracket_greater = pTrigger->test_value;
|
|
pnewgtval = &psci->bracket_greater;
|
|
} else if (XSyncValueEqual(pCounter->value, pTrigger->test_value) &&
|
|
XSyncValueGreaterThan(pTrigger->test_value,
|
|
psci->bracket_less))
|
|
{
|
|
/*
|
|
* The value is exactly equal to our threshold. We want one
|
|
* more event in the negative direction to ensure we pick up
|
|
* when the value is less than this threshold.
|
|
*/
|
|
psci->bracket_less = pTrigger->test_value;
|
|
pnewltval = &psci->bracket_less;
|
|
}
|
|
}
|
|
} /* end for each trigger */
|
|
|
|
if (pnewgtval || pnewltval)
|
|
{
|
|
(*psci->BracketValues)((pointer)pCounter, pnewltval, pnewgtval);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ***** Resource delete functions
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
static int
|
|
FreeAlarm(void *addr, XID id)
|
|
{
|
|
SyncAlarm *pAlarm = (SyncAlarm *) addr;
|
|
|
|
pAlarm->state = XSyncAlarmDestroyed;
|
|
|
|
SyncSendAlarmNotifyEvents(pAlarm);
|
|
|
|
/* delete event selections */
|
|
|
|
while (pAlarm->pEventClients)
|
|
FreeResource(pAlarm->pEventClients->delete_id, RT_NONE);
|
|
|
|
SyncDeleteTriggerFromCounter(&pAlarm->trigger);
|
|
|
|
free(pAlarm);
|
|
return Success;
|
|
}
|
|
|
|
|
|
/*
|
|
* ** Cleanup after the destruction of a Counter
|
|
*/
|
|
/* ARGSUSED */
|
|
static int
|
|
FreeCounter(void *env, XID id)
|
|
{
|
|
SyncCounter *pCounter = (SyncCounter *) env;
|
|
SyncTriggerList *ptl, *pnext;
|
|
|
|
pCounter->beingDestroyed = TRUE;
|
|
/* tell all the counter's triggers that the counter has been destroyed */
|
|
for (ptl = pCounter->pTriglist; ptl; ptl = pnext)
|
|
{
|
|
(*ptl->pTrigger->CounterDestroyed)(ptl->pTrigger);
|
|
pnext = ptl->next;
|
|
free(ptl); /* destroy the trigger list as we go */
|
|
}
|
|
if (IsSystemCounter(pCounter))
|
|
{
|
|
int i, found = 0;
|
|
|
|
free(pCounter->pSysCounterInfo);
|
|
|
|
/* find the counter in the list of system counters and remove it */
|
|
|
|
if (SysCounterList)
|
|
{
|
|
for (i = 0; i < SyncNumSystemCounters; i++)
|
|
{
|
|
if (SysCounterList[i] == pCounter)
|
|
{
|
|
found = i;
|
|
break;
|
|
}
|
|
}
|
|
if (found < (SyncNumSystemCounters-1))
|
|
{
|
|
for (i = found; i < SyncNumSystemCounters-1; i++)
|
|
{
|
|
SysCounterList[i] = SysCounterList[i+1];
|
|
}
|
|
}
|
|
}
|
|
SyncNumSystemCounters--;
|
|
}
|
|
free(pCounter);
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
* ** Cleanup after Await
|
|
*/
|
|
/* ARGSUSED */
|
|
static int
|
|
FreeAwait(void *addr, XID id)
|
|
{
|
|
SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr;
|
|
SyncAwait *pAwait;
|
|
int numwaits;
|
|
|
|
pAwait = &(pAwaitUnion+1)->await; /* first await on list */
|
|
|
|
/* remove triggers from counters */
|
|
|
|
for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits;
|
|
numwaits--, pAwait++)
|
|
{
|
|
/* If the counter is being destroyed, FreeCounter will delete
|
|
* the trigger list itself, so don't do it here.
|
|
*/
|
|
SyncCounter *pCounter = pAwait->trigger.pCounter;
|
|
if (pCounter && !pCounter->beingDestroyed)
|
|
SyncDeleteTriggerFromCounter(&pAwait->trigger);
|
|
}
|
|
free(pAwaitUnion);
|
|
return Success;
|
|
}
|
|
|
|
/* loosely based on dix/events.c/OtherClientGone */
|
|
static int
|
|
FreeAlarmClient(void *value, XID id)
|
|
{
|
|
SyncAlarm *pAlarm = (SyncAlarm *)value;
|
|
SyncAlarmClientList *pCur, *pPrev;
|
|
|
|
for (pPrev = NULL, pCur = pAlarm->pEventClients;
|
|
pCur;
|
|
pPrev = pCur, pCur = pCur->next)
|
|
{
|
|
if (pCur->delete_id == id)
|
|
{
|
|
if (pPrev)
|
|
pPrev->next = pCur->next;
|
|
else
|
|
pAlarm->pEventClients = pCur->next;
|
|
free(pCur);
|
|
return Success;
|
|
}
|
|
}
|
|
FatalError("alarm client not on event list");
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
|
|
/*
|
|
* ***** Proc functions
|
|
*/
|
|
|
|
|
|
/*
|
|
* ** Initialize the extension
|
|
*/
|
|
static int
|
|
ProcSyncInitialize(ClientPtr client)
|
|
{
|
|
xSyncInitializeReply rep;
|
|
int n;
|
|
|
|
REQUEST_SIZE_MATCH(xSyncInitializeReq);
|
|
|
|
memset(&rep, 0, sizeof(xSyncInitializeReply));
|
|
rep.type = X_Reply;
|
|
rep.sequenceNumber = client->sequence;
|
|
rep.majorVersion = SERVER_SYNC_MAJOR_VERSION;
|
|
rep.minorVersion = SERVER_SYNC_MINOR_VERSION;
|
|
rep.length = 0;
|
|
|
|
if (client->swapped)
|
|
{
|
|
swaps(&rep.sequenceNumber, n);
|
|
}
|
|
WriteToClient(client, sizeof(rep), (char *) &rep);
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
* ** Get list of system counters available through the extension
|
|
*/
|
|
static int
|
|
ProcSyncListSystemCounters(ClientPtr client)
|
|
{
|
|
xSyncListSystemCountersReply rep;
|
|
int i, len;
|
|
xSyncSystemCounter *list = NULL, *walklist = NULL;
|
|
|
|
REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
|
|
|
|
rep.type = X_Reply;
|
|
rep.sequenceNumber = client->sequence;
|
|
rep.nCounters = SyncNumSystemCounters;
|
|
|
|
for (i = len = 0; i < SyncNumSystemCounters; i++)
|
|
{
|
|
char *name = SysCounterList[i]->pSysCounterInfo->name;
|
|
/* pad to 4 byte boundary */
|
|
len += pad_to_int32(sz_xSyncSystemCounter + strlen(name));
|
|
}
|
|
|
|
if (len)
|
|
{
|
|
walklist = list = malloc(len);
|
|
if (!list)
|
|
return BadAlloc;
|
|
}
|
|
|
|
rep.length = bytes_to_int32(len);
|
|
|
|
if (client->swapped)
|
|
{
|
|
char n;
|
|
swaps(&rep.sequenceNumber, n);
|
|
swapl(&rep.length, n);
|
|
swapl(&rep.nCounters, n);
|
|
}
|
|
|
|
for (i = 0; i < SyncNumSystemCounters; i++)
|
|
{
|
|
int namelen;
|
|
char *pname_in_reply;
|
|
SysCounterInfo *psci = SysCounterList[i]->pSysCounterInfo;
|
|
|
|
walklist->counter = SysCounterList[i]->id;
|
|
walklist->resolution_hi = XSyncValueHigh32(psci->resolution);
|
|
walklist->resolution_lo = XSyncValueLow32(psci->resolution);
|
|
namelen = strlen(psci->name);
|
|
walklist->name_length = namelen;
|
|
|
|
if (client->swapped)
|
|
{
|
|
char n;
|
|
swapl(&walklist->counter, n);
|
|
swapl(&walklist->resolution_hi, n);
|
|
swapl(&walklist->resolution_lo, n);
|
|
swaps(&walklist->name_length, n);
|
|
}
|
|
|
|
pname_in_reply = ((char *)walklist) + sz_xSyncSystemCounter;
|
|
strncpy(pname_in_reply, psci->name, namelen);
|
|
walklist = (xSyncSystemCounter *) (((char *)walklist) +
|
|
pad_to_int32(sz_xSyncSystemCounter + namelen));
|
|
}
|
|
|
|
WriteToClient(client, sizeof(rep), (char *) &rep);
|
|
if (len)
|
|
{
|
|
WriteToClient(client, len, (char *) list);
|
|
free(list);
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
* ** Set client Priority
|
|
*/
|
|
static int
|
|
ProcSyncSetPriority(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncSetPriorityReq);
|
|
ClientPtr priorityclient;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
|
|
|
|
if (stuff->id == None)
|
|
priorityclient = client;
|
|
else {
|
|
rc = dixLookupClient(&priorityclient, stuff->id, client,
|
|
DixSetAttrAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
}
|
|
|
|
if (priorityclient->priority != stuff->priority)
|
|
{
|
|
priorityclient->priority = stuff->priority;
|
|
|
|
/* The following will force the server back into WaitForSomething
|
|
* so that the change in this client's priority is immediately
|
|
* reflected.
|
|
*/
|
|
isItTimeToYield = TRUE;
|
|
dispatchException |= DE_PRIORITYCHANGE;
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
* ** Get client Priority
|
|
*/
|
|
static int
|
|
ProcSyncGetPriority(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncGetPriorityReq);
|
|
xSyncGetPriorityReply rep;
|
|
ClientPtr priorityclient;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
|
|
|
|
if (stuff->id == None)
|
|
priorityclient = client;
|
|
else {
|
|
rc = dixLookupClient(&priorityclient, stuff->id, client,
|
|
DixGetAttrAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
}
|
|
|
|
rep.type = X_Reply;
|
|
rep.length = 0;
|
|
rep.sequenceNumber = client->sequence;
|
|
rep.priority = priorityclient->priority;
|
|
|
|
if (client->swapped)
|
|
{
|
|
char n;
|
|
swaps(&rep.sequenceNumber, n);
|
|
swapl(&rep.priority, n);
|
|
}
|
|
|
|
WriteToClient(client, sizeof(xSyncGetPriorityReply), (char *) &rep);
|
|
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
* ** Create a new counter
|
|
*/
|
|
static int
|
|
ProcSyncCreateCounter(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncCreateCounterReq);
|
|
CARD64 initial;
|
|
|
|
REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
|
|
|
|
LEGAL_NEW_RESOURCE(stuff->cid, client);
|
|
|
|
XSyncIntsToValue(&initial, stuff->initial_value_lo, stuff->initial_value_hi);
|
|
if (!SyncCreateCounter(client, stuff->cid, initial))
|
|
return BadAlloc;
|
|
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
* ** Set Counter value
|
|
*/
|
|
static int
|
|
ProcSyncSetCounter(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncSetCounterReq);
|
|
SyncCounter *pCounter;
|
|
CARD64 newvalue;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xSyncSetCounterReq);
|
|
|
|
rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
|
|
client, DixWriteAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
if (IsSystemCounter(pCounter))
|
|
{
|
|
client->errorValue = stuff->cid;
|
|
return BadAccess;
|
|
}
|
|
|
|
XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
|
|
SyncChangeCounter(pCounter, newvalue);
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
* ** Change Counter value
|
|
*/
|
|
static int
|
|
ProcSyncChangeCounter(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncChangeCounterReq);
|
|
SyncCounter *pCounter;
|
|
CARD64 newvalue;
|
|
Bool overflow;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
|
|
|
|
rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
|
|
client, DixWriteAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
if (IsSystemCounter(pCounter))
|
|
{
|
|
client->errorValue = stuff->cid;
|
|
return BadAccess;
|
|
}
|
|
|
|
XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
|
|
XSyncValueAdd(&newvalue, pCounter->value, newvalue, &overflow);
|
|
if (overflow)
|
|
{
|
|
/* XXX 64 bit value can't fit in 32 bits; do the best we can */
|
|
client->errorValue = stuff->value_hi;
|
|
return BadValue;
|
|
}
|
|
SyncChangeCounter(pCounter, newvalue);
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
* ** Destroy a counter
|
|
*/
|
|
static int
|
|
ProcSyncDestroyCounter(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncDestroyCounterReq);
|
|
SyncCounter *pCounter;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
|
|
|
|
rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter, RTCounter,
|
|
client, DixDestroyAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
if (IsSystemCounter(pCounter))
|
|
{
|
|
client->errorValue = stuff->counter;
|
|
return BadAccess;
|
|
}
|
|
FreeResource(pCounter->id, RT_NONE);
|
|
return Success;
|
|
}
|
|
|
|
|
|
/*
|
|
* ** Await
|
|
*/
|
|
static int
|
|
ProcSyncAwait(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncAwaitReq);
|
|
int len, items;
|
|
int i;
|
|
xSyncWaitCondition *pProtocolWaitConds;
|
|
SyncAwaitUnion *pAwaitUnion;
|
|
SyncAwait *pAwait;
|
|
int status;
|
|
|
|
REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
|
|
|
|
len = client->req_len << 2;
|
|
len -= sz_xSyncAwaitReq;
|
|
items = len / sz_xSyncWaitCondition;
|
|
|
|
if (items * sz_xSyncWaitCondition != len)
|
|
{
|
|
return BadLength;
|
|
}
|
|
if (items == 0)
|
|
{
|
|
client->errorValue = items; /* XXX protocol change */
|
|
return BadValue;
|
|
}
|
|
|
|
pProtocolWaitConds = (xSyncWaitCondition *) & stuff[1];
|
|
|
|
/* all the memory for the entire await list is allocated
|
|
* here in one chunk
|
|
*/
|
|
pAwaitUnion = malloc((items+1) * sizeof(SyncAwaitUnion));
|
|
if (!pAwaitUnion)
|
|
return BadAlloc;
|
|
|
|
/* first item is the header, remainder are real wait conditions */
|
|
|
|
pAwaitUnion->header.delete_id = FakeClientID(client->index);
|
|
if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion))
|
|
{
|
|
free(pAwaitUnion);
|
|
return BadAlloc;
|
|
}
|
|
|
|
/* don't need to do any more memory allocation for this request! */
|
|
|
|
pAwaitUnion->header.client = client;
|
|
pAwaitUnion->header.num_waitconditions = 0;
|
|
|
|
pAwait = &(pAwaitUnion+1)->await; /* skip over header */
|
|
for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++)
|
|
{
|
|
if (pProtocolWaitConds->counter == None) /* XXX protocol change */
|
|
{
|
|
/* this should take care of removing any triggers created by
|
|
* this request that have already been registered on counters
|
|
*/
|
|
FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
|
|
client->errorValue = pProtocolWaitConds->counter;
|
|
return SyncErrorBase + XSyncBadCounter;
|
|
}
|
|
|
|
/* sanity checks are in SyncInitTrigger */
|
|
pAwait->trigger.pCounter = NULL;
|
|
pAwait->trigger.value_type = pProtocolWaitConds->value_type;
|
|
XSyncIntsToValue(&pAwait->trigger.wait_value,
|
|
pProtocolWaitConds->wait_value_lo,
|
|
pProtocolWaitConds->wait_value_hi);
|
|
pAwait->trigger.test_type = pProtocolWaitConds->test_type;
|
|
|
|
status = SyncInitTrigger(client, &pAwait->trigger,
|
|
pProtocolWaitConds->counter, XSyncCAAllTrigger);
|
|
if (status != Success)
|
|
{
|
|
/* this should take care of removing any triggers created by
|
|
* this request that have already been registered on counters
|
|
*/
|
|
FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
|
|
return status;
|
|
}
|
|
/* this is not a mistake -- same function works for both cases */
|
|
pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
|
|
pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
|
|
XSyncIntsToValue(&pAwait->event_threshold,
|
|
pProtocolWaitConds->event_threshold_lo,
|
|
pProtocolWaitConds->event_threshold_hi);
|
|
pAwait->pHeader = &pAwaitUnion->header;
|
|
pAwaitUnion->header.num_waitconditions++;
|
|
}
|
|
|
|
IgnoreClient(client);
|
|
|
|
/* see if any of the triggers are already true */
|
|
|
|
pAwait = &(pAwaitUnion+1)->await; /* skip over header */
|
|
for (i = 0; i < items; i++, pAwait++)
|
|
{
|
|
/* don't have to worry about NULL counters because the request
|
|
* errors before we get here out if they occur
|
|
*/
|
|
if ((*pAwait->trigger.CheckTrigger)(&pAwait->trigger,
|
|
pAwait->trigger.pCounter->value))
|
|
{
|
|
(*pAwait->trigger.TriggerFired)(&pAwait->trigger);
|
|
break; /* once is enough */
|
|
}
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
|
|
/*
|
|
* ** Query a counter
|
|
*/
|
|
static int
|
|
ProcSyncQueryCounter(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncQueryCounterReq);
|
|
xSyncQueryCounterReply rep;
|
|
SyncCounter *pCounter;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
|
|
|
|
rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter,
|
|
RTCounter, client, DixReadAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
rep.type = X_Reply;
|
|
rep.length = 0;
|
|
rep.sequenceNumber = client->sequence;
|
|
|
|
/* if system counter, ask it what the current value is */
|
|
|
|
if (IsSystemCounter(pCounter))
|
|
{
|
|
(*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
|
|
&pCounter->value);
|
|
}
|
|
|
|
rep.value_hi = XSyncValueHigh32(pCounter->value);
|
|
rep.value_lo = XSyncValueLow32(pCounter->value);
|
|
if (client->swapped)
|
|
{
|
|
char n;
|
|
swaps(&rep.sequenceNumber, n);
|
|
swapl(&rep.length, n);
|
|
swapl(&rep.value_hi, n);
|
|
swapl(&rep.value_lo, n);
|
|
}
|
|
WriteToClient(client, sizeof(xSyncQueryCounterReply), (char *) &rep);
|
|
return Success;
|
|
}
|
|
|
|
|
|
/*
|
|
* ** Create Alarm
|
|
*/
|
|
static int
|
|
ProcSyncCreateAlarm(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncCreateAlarmReq);
|
|
SyncAlarm *pAlarm;
|
|
int status;
|
|
unsigned long len, vmask;
|
|
SyncTrigger *pTrigger;
|
|
|
|
REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
|
|
|
|
LEGAL_NEW_RESOURCE(stuff->id, client);
|
|
|
|
vmask = stuff->valueMask;
|
|
len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq));
|
|
/* the "extra" call to Ones accounts for the presence of 64 bit values */
|
|
if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
|
|
return BadLength;
|
|
|
|
if (!(pAlarm = malloc(sizeof(SyncAlarm))))
|
|
{
|
|
return BadAlloc;
|
|
}
|
|
|
|
/* set up defaults */
|
|
|
|
pTrigger = &pAlarm->trigger;
|
|
pTrigger->pCounter = NULL;
|
|
pTrigger->value_type = XSyncAbsolute;
|
|
XSyncIntToValue(&pTrigger->wait_value, 0L);
|
|
pTrigger->test_type = XSyncPositiveComparison;
|
|
pTrigger->TriggerFired = SyncAlarmTriggerFired;
|
|
pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed;
|
|
status = SyncInitTrigger(client, pTrigger, None, XSyncCAAllTrigger);
|
|
if (status != Success)
|
|
{
|
|
free(pAlarm);
|
|
return status;
|
|
}
|
|
|
|
pAlarm->client = client;
|
|
pAlarm->alarm_id = stuff->id;
|
|
XSyncIntToValue(&pAlarm->delta, 1L);
|
|
pAlarm->events = TRUE;
|
|
pAlarm->state = XSyncAlarmInactive;
|
|
pAlarm->pEventClients = NULL;
|
|
status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
|
|
(CARD32 *)&stuff[1]);
|
|
if (status != Success)
|
|
{
|
|
free(pAlarm);
|
|
return status;
|
|
}
|
|
|
|
if (!AddResource(stuff->id, RTAlarm, pAlarm))
|
|
{
|
|
free(pAlarm);
|
|
return BadAlloc;
|
|
}
|
|
|
|
/* see if alarm already triggered. NULL counter will not trigger
|
|
* in CreateAlarm and sets alarm state to Inactive.
|
|
*/
|
|
|
|
if (!pTrigger->pCounter)
|
|
{
|
|
pAlarm->state = XSyncAlarmInactive; /* XXX protocol change */
|
|
}
|
|
else if ((*pTrigger->CheckTrigger)(pTrigger, pTrigger->pCounter->value))
|
|
{
|
|
(*pTrigger->TriggerFired)(pTrigger);
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
* ** Change Alarm
|
|
*/
|
|
static int
|
|
ProcSyncChangeAlarm(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncChangeAlarmReq);
|
|
SyncAlarm *pAlarm;
|
|
long vmask;
|
|
int len, status;
|
|
|
|
REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
|
|
|
|
status = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
|
|
client, DixWriteAccess);
|
|
if (status != Success)
|
|
return status;
|
|
|
|
vmask = stuff->valueMask;
|
|
len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq));
|
|
/* the "extra" call to Ones accounts for the presence of 64 bit values */
|
|
if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
|
|
return BadLength;
|
|
|
|
if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
|
|
(CARD32 *)&stuff[1])) != Success)
|
|
return status;
|
|
|
|
/* see if alarm already triggered. NULL counter WILL trigger
|
|
* in ChangeAlarm.
|
|
*/
|
|
|
|
if (!pAlarm->trigger.pCounter ||
|
|
(*pAlarm->trigger.CheckTrigger)(&pAlarm->trigger,
|
|
pAlarm->trigger.pCounter->value))
|
|
{
|
|
(*pAlarm->trigger.TriggerFired)(&pAlarm->trigger);
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
ProcSyncQueryAlarm(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncQueryAlarmReq);
|
|
SyncAlarm *pAlarm;
|
|
xSyncQueryAlarmReply rep;
|
|
SyncTrigger *pTrigger;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
|
|
|
|
rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
|
|
client, DixReadAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
rep.type = X_Reply;
|
|
rep.length = bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply));
|
|
rep.sequenceNumber = client->sequence;
|
|
|
|
pTrigger = &pAlarm->trigger;
|
|
rep.counter = (pTrigger->pCounter) ? pTrigger->pCounter->id : None;
|
|
|
|
#if 0 /* XXX unclear what to do, depends on whether relative value-types
|
|
* are "consumed" immediately and are considered absolute from then
|
|
* on.
|
|
*/
|
|
rep.value_type = pTrigger->value_type;
|
|
rep.wait_value_hi = XSyncValueHigh32(pTrigger->wait_value);
|
|
rep.wait_value_lo = XSyncValueLow32(pTrigger->wait_value);
|
|
#else
|
|
rep.value_type = XSyncAbsolute;
|
|
rep.wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
|
|
rep.wait_value_lo = XSyncValueLow32(pTrigger->test_value);
|
|
#endif
|
|
|
|
rep.test_type = pTrigger->test_type;
|
|
rep.delta_hi = XSyncValueHigh32(pAlarm->delta);
|
|
rep.delta_lo = XSyncValueLow32(pAlarm->delta);
|
|
rep.events = pAlarm->events;
|
|
rep.state = pAlarm->state;
|
|
|
|
if (client->swapped)
|
|
{
|
|
char n;
|
|
swaps(&rep.sequenceNumber, n);
|
|
swapl(&rep.length, n);
|
|
swapl(&rep.counter, n);
|
|
swapl(&rep.wait_value_hi, n);
|
|
swapl(&rep.wait_value_lo, n);
|
|
swapl(&rep.test_type, n);
|
|
swapl(&rep.delta_hi, n);
|
|
swapl(&rep.delta_lo, n);
|
|
}
|
|
|
|
WriteToClient(client, sizeof(xSyncQueryAlarmReply), (char *) &rep);
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
ProcSyncDestroyAlarm(ClientPtr client)
|
|
{
|
|
SyncAlarm *pAlarm;
|
|
int rc;
|
|
REQUEST(xSyncDestroyAlarmReq);
|
|
|
|
REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
|
|
|
|
rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
|
|
client, DixDestroyAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
FreeResource(stuff->alarm, RT_NONE);
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
* ** Given an extension request, call the appropriate request procedure
|
|
*/
|
|
static int
|
|
ProcSyncDispatch(ClientPtr client)
|
|
{
|
|
REQUEST(xReq);
|
|
|
|
switch (stuff->data)
|
|
{
|
|
case X_SyncInitialize:
|
|
return ProcSyncInitialize(client);
|
|
case X_SyncListSystemCounters:
|
|
return ProcSyncListSystemCounters(client);
|
|
case X_SyncCreateCounter:
|
|
return ProcSyncCreateCounter(client);
|
|
case X_SyncSetCounter:
|
|
return ProcSyncSetCounter(client);
|
|
case X_SyncChangeCounter:
|
|
return ProcSyncChangeCounter(client);
|
|
case X_SyncQueryCounter:
|
|
return ProcSyncQueryCounter(client);
|
|
case X_SyncDestroyCounter:
|
|
return ProcSyncDestroyCounter(client);
|
|
case X_SyncAwait:
|
|
return ProcSyncAwait(client);
|
|
case X_SyncCreateAlarm:
|
|
return ProcSyncCreateAlarm(client);
|
|
case X_SyncChangeAlarm:
|
|
return ProcSyncChangeAlarm(client);
|
|
case X_SyncQueryAlarm:
|
|
return ProcSyncQueryAlarm(client);
|
|
case X_SyncDestroyAlarm:
|
|
return ProcSyncDestroyAlarm(client);
|
|
case X_SyncSetPriority:
|
|
return ProcSyncSetPriority(client);
|
|
case X_SyncGetPriority:
|
|
return ProcSyncGetPriority(client);
|
|
default:
|
|
return BadRequest;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Boring Swapping stuff ...
|
|
*/
|
|
|
|
static int
|
|
SProcSyncInitialize(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncInitializeReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_SIZE_MATCH (xSyncInitializeReq);
|
|
|
|
return ProcSyncInitialize(client);
|
|
}
|
|
|
|
static int
|
|
SProcSyncListSystemCounters(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncListSystemCountersReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_SIZE_MATCH (xSyncListSystemCountersReq);
|
|
|
|
return ProcSyncListSystemCounters(client);
|
|
}
|
|
|
|
static int
|
|
SProcSyncCreateCounter(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncCreateCounterReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_SIZE_MATCH (xSyncCreateCounterReq);
|
|
swapl(&stuff->cid, n);
|
|
swapl(&stuff->initial_value_lo, n);
|
|
swapl(&stuff->initial_value_hi, n);
|
|
|
|
return ProcSyncCreateCounter(client);
|
|
}
|
|
|
|
static int
|
|
SProcSyncSetCounter(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncSetCounterReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_SIZE_MATCH (xSyncSetCounterReq);
|
|
swapl(&stuff->cid, n);
|
|
swapl(&stuff->value_lo, n);
|
|
swapl(&stuff->value_hi, n);
|
|
|
|
return ProcSyncSetCounter(client);
|
|
}
|
|
|
|
static int
|
|
SProcSyncChangeCounter(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncChangeCounterReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_SIZE_MATCH (xSyncChangeCounterReq);
|
|
swapl(&stuff->cid, n);
|
|
swapl(&stuff->value_lo, n);
|
|
swapl(&stuff->value_hi, n);
|
|
|
|
return ProcSyncChangeCounter(client);
|
|
}
|
|
|
|
static int
|
|
SProcSyncQueryCounter(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncQueryCounterReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_SIZE_MATCH (xSyncQueryCounterReq);
|
|
swapl(&stuff->counter, n);
|
|
|
|
return ProcSyncQueryCounter(client);
|
|
}
|
|
|
|
static int
|
|
SProcSyncDestroyCounter(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncDestroyCounterReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_SIZE_MATCH (xSyncDestroyCounterReq);
|
|
swapl(&stuff->counter, n);
|
|
|
|
return ProcSyncDestroyCounter(client);
|
|
}
|
|
|
|
static int
|
|
SProcSyncAwait(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncAwaitReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
|
|
SwapRestL(stuff);
|
|
|
|
return ProcSyncAwait(client);
|
|
}
|
|
|
|
static int
|
|
SProcSyncCreateAlarm(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncCreateAlarmReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
|
|
swapl(&stuff->id, n);
|
|
swapl(&stuff->valueMask, n);
|
|
SwapRestL(stuff);
|
|
|
|
return ProcSyncCreateAlarm(client);
|
|
}
|
|
|
|
static int
|
|
SProcSyncChangeAlarm(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncChangeAlarmReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
|
|
swapl(&stuff->alarm, n);
|
|
swapl(&stuff->valueMask, n);
|
|
SwapRestL(stuff);
|
|
return ProcSyncChangeAlarm(client);
|
|
}
|
|
|
|
static int
|
|
SProcSyncQueryAlarm(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncQueryAlarmReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_SIZE_MATCH (xSyncQueryAlarmReq);
|
|
swapl(&stuff->alarm, n);
|
|
|
|
return ProcSyncQueryAlarm(client);
|
|
}
|
|
|
|
static int
|
|
SProcSyncDestroyAlarm(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncDestroyAlarmReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_SIZE_MATCH (xSyncDestroyAlarmReq);
|
|
swapl(&stuff->alarm, n);
|
|
|
|
return ProcSyncDestroyAlarm(client);
|
|
}
|
|
|
|
static int
|
|
SProcSyncSetPriority(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncSetPriorityReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_SIZE_MATCH (xSyncSetPriorityReq);
|
|
swapl(&stuff->id, n);
|
|
swapl(&stuff->priority, n);
|
|
|
|
return ProcSyncSetPriority(client);
|
|
}
|
|
|
|
static int
|
|
SProcSyncGetPriority(ClientPtr client)
|
|
{
|
|
REQUEST(xSyncGetPriorityReq);
|
|
char n;
|
|
|
|
swaps(&stuff->length, n);
|
|
REQUEST_SIZE_MATCH (xSyncGetPriorityReq);
|
|
swapl(&stuff->id, n);
|
|
|
|
return ProcSyncGetPriority(client);
|
|
}
|
|
|
|
|
|
static int
|
|
SProcSyncDispatch(ClientPtr client)
|
|
{
|
|
REQUEST(xReq);
|
|
|
|
switch (stuff->data)
|
|
{
|
|
case X_SyncInitialize:
|
|
return SProcSyncInitialize(client);
|
|
case X_SyncListSystemCounters:
|
|
return SProcSyncListSystemCounters(client);
|
|
case X_SyncCreateCounter:
|
|
return SProcSyncCreateCounter(client);
|
|
case X_SyncSetCounter:
|
|
return SProcSyncSetCounter(client);
|
|
case X_SyncChangeCounter:
|
|
return SProcSyncChangeCounter(client);
|
|
case X_SyncQueryCounter:
|
|
return SProcSyncQueryCounter(client);
|
|
case X_SyncDestroyCounter:
|
|
return SProcSyncDestroyCounter(client);
|
|
case X_SyncAwait:
|
|
return SProcSyncAwait(client);
|
|
case X_SyncCreateAlarm:
|
|
return SProcSyncCreateAlarm(client);
|
|
case X_SyncChangeAlarm:
|
|
return SProcSyncChangeAlarm(client);
|
|
case X_SyncQueryAlarm:
|
|
return SProcSyncQueryAlarm(client);
|
|
case X_SyncDestroyAlarm:
|
|
return SProcSyncDestroyAlarm(client);
|
|
case X_SyncSetPriority:
|
|
return SProcSyncSetPriority(client);
|
|
case X_SyncGetPriority:
|
|
return SProcSyncGetPriority(client);
|
|
default:
|
|
return BadRequest;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Event Swapping
|
|
*/
|
|
|
|
static void
|
|
SCounterNotifyEvent(xSyncCounterNotifyEvent *from, xSyncCounterNotifyEvent *to)
|
|
{
|
|
to->type = from->type;
|
|
to->kind = from->kind;
|
|
cpswaps(from->sequenceNumber, to->sequenceNumber);
|
|
cpswapl(from->counter, to->counter);
|
|
cpswapl(from->wait_value_lo, to->wait_value_lo);
|
|
cpswapl(from->wait_value_hi, to->wait_value_hi);
|
|
cpswapl(from->counter_value_lo, to->counter_value_lo);
|
|
cpswapl(from->counter_value_hi, to->counter_value_hi);
|
|
cpswapl(from->time, to->time);
|
|
cpswaps(from->count, to->count);
|
|
to->destroyed = from->destroyed;
|
|
}
|
|
|
|
|
|
static void
|
|
SAlarmNotifyEvent(xSyncAlarmNotifyEvent *from, xSyncAlarmNotifyEvent *to)
|
|
{
|
|
to->type = from->type;
|
|
to->kind = from->kind;
|
|
cpswaps(from->sequenceNumber, to->sequenceNumber);
|
|
cpswapl(from->alarm, to->alarm);
|
|
cpswapl(from->counter_value_lo, to->counter_value_lo);
|
|
cpswapl(from->counter_value_hi, to->counter_value_hi);
|
|
cpswapl(from->alarm_value_lo, to->alarm_value_lo);
|
|
cpswapl(from->alarm_value_hi, to->alarm_value_hi);
|
|
cpswapl(from->time, to->time);
|
|
to->state = from->state;
|
|
}
|
|
|
|
/*
|
|
* ** Close everything down. ** This is fairly simple for now.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
SyncResetProc(ExtensionEntry *extEntry)
|
|
{
|
|
free(SysCounterList);
|
|
SysCounterList = NULL;
|
|
RTCounter = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* ** Initialise the extension.
|
|
*/
|
|
void
|
|
SyncExtensionInit(void)
|
|
{
|
|
ExtensionEntry *extEntry;
|
|
|
|
if (RTCounter == 0)
|
|
{
|
|
RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
|
|
}
|
|
RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm");
|
|
RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait");
|
|
if (RTAwait)
|
|
RTAwait |= RC_NEVERRETAIN;
|
|
RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient");
|
|
if (RTAlarmClient)
|
|
RTAlarmClient |= RC_NEVERRETAIN;
|
|
|
|
if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 ||
|
|
RTAlarmClient == 0 ||
|
|
(extEntry = AddExtension(SYNC_NAME,
|
|
XSyncNumberEvents, XSyncNumberErrors,
|
|
ProcSyncDispatch, SProcSyncDispatch,
|
|
SyncResetProc,
|
|
StandardMinorOpcode)) == NULL)
|
|
{
|
|
ErrorF("Sync Extension %d.%d failed to Initialise\n",
|
|
SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
|
|
return;
|
|
}
|
|
|
|
SyncEventBase = extEntry->eventBase;
|
|
SyncErrorBase = extEntry->errorBase;
|
|
EventSwapVector[SyncEventBase + XSyncCounterNotify] = (EventSwapPtr) SCounterNotifyEvent;
|
|
EventSwapVector[SyncEventBase + XSyncAlarmNotify] = (EventSwapPtr) SAlarmNotifyEvent;
|
|
|
|
SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter);
|
|
SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm);
|
|
|
|
/*
|
|
* Although SERVERTIME is implemented by the OS layer, we initialise it
|
|
* here because doing it in OsInit() is too early. The resource database
|
|
* is not initialised when OsInit() is called. This is just about OK
|
|
* because there is always a servertime counter.
|
|
*/
|
|
SyncInitServerTime();
|
|
SyncInitIdleTime();
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "Sync Extension %d.%d\n",
|
|
SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* ***** SERVERTIME implementation - should go in its own file in OS directory?
|
|
*/
|
|
|
|
|
|
|
|
static pointer ServertimeCounter;
|
|
static XSyncValue Now;
|
|
static XSyncValue *pnext_time;
|
|
|
|
#define GetTime()\
|
|
{\
|
|
unsigned long millis = GetTimeInMillis();\
|
|
unsigned long maxis = XSyncValueHigh32(Now);\
|
|
if (millis < XSyncValueLow32(Now)) maxis++;\
|
|
XSyncIntsToValue(&Now, millis, maxis);\
|
|
}
|
|
|
|
/*
|
|
*** Server Block Handler
|
|
*** code inspired by multibuffer extension (now deprecated)
|
|
*/
|
|
/*ARGSUSED*/
|
|
static void
|
|
ServertimeBlockHandler(void *env, struct timeval **wt, void *LastSelectMask)
|
|
{
|
|
XSyncValue delay;
|
|
unsigned long timeout;
|
|
|
|
if (pnext_time)
|
|
{
|
|
GetTime();
|
|
|
|
if (XSyncValueGreaterOrEqual(Now, *pnext_time))
|
|
{
|
|
timeout = 0;
|
|
}
|
|
else
|
|
{
|
|
Bool overflow;
|
|
XSyncValueSubtract(&delay, *pnext_time, Now, &overflow);
|
|
(void)overflow;
|
|
timeout = XSyncValueLow32(delay);
|
|
}
|
|
AdjustWaitForDelay(wt, timeout); /* os/utils.c */
|
|
}
|
|
}
|
|
|
|
/*
|
|
*** Wakeup Handler
|
|
*/
|
|
/*ARGSUSED*/
|
|
static void
|
|
ServertimeWakeupHandler(void *env, int rc, void *LastSelectMask)
|
|
{
|
|
if (pnext_time)
|
|
{
|
|
GetTime();
|
|
|
|
if (XSyncValueGreaterOrEqual(Now, *pnext_time))
|
|
{
|
|
SyncChangeCounter(ServertimeCounter, Now);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
ServertimeQueryValue(void *pCounter, CARD64 *pValue_return)
|
|
{
|
|
GetTime();
|
|
*pValue_return = Now;
|
|
}
|
|
|
|
static void
|
|
ServertimeBracketValues(void *pCounter, CARD64 *pbracket_less,
|
|
CARD64 *pbracket_greater)
|
|
{
|
|
if (!pnext_time && pbracket_greater)
|
|
{
|
|
RegisterBlockAndWakeupHandlers(ServertimeBlockHandler,
|
|
ServertimeWakeupHandler,
|
|
NULL);
|
|
}
|
|
else if (pnext_time && !pbracket_greater)
|
|
{
|
|
RemoveBlockAndWakeupHandlers(ServertimeBlockHandler,
|
|
ServertimeWakeupHandler,
|
|
NULL);
|
|
}
|
|
pnext_time = pbracket_greater;
|
|
}
|
|
|
|
static void
|
|
SyncInitServerTime(void)
|
|
{
|
|
CARD64 resolution;
|
|
|
|
XSyncIntsToValue(&Now, GetTimeInMillis(), 0);
|
|
XSyncIntToValue(&resolution, 4);
|
|
ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution,
|
|
XSyncCounterNeverDecreases,
|
|
ServertimeQueryValue, ServertimeBracketValues);
|
|
pnext_time = NULL;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* IDLETIME implementation
|
|
*/
|
|
|
|
static SyncCounter *IdleTimeCounter;
|
|
static XSyncValue *pIdleTimeValueLess;
|
|
static XSyncValue *pIdleTimeValueGreater;
|
|
|
|
static void
|
|
IdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return)
|
|
{
|
|
CARD32 idle = GetTimeInMillis() - lastDeviceEventTime.milliseconds;
|
|
XSyncIntsToValue (pValue_return, idle, 0);
|
|
}
|
|
|
|
static void
|
|
IdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask)
|
|
{
|
|
XSyncValue idle, old_idle;
|
|
SyncTriggerList *list = IdleTimeCounter->pTriglist;
|
|
SyncTrigger *trig;
|
|
|
|
if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
|
|
return;
|
|
|
|
old_idle = IdleTimeCounter->value;
|
|
IdleTimeQueryValue (NULL, &idle);
|
|
IdleTimeCounter->value = idle; /* push, so CheckTrigger works */
|
|
|
|
if (pIdleTimeValueLess &&
|
|
XSyncValueLessOrEqual (idle, *pIdleTimeValueLess))
|
|
{
|
|
/*
|
|
* We've been idle for less than the threshold value, and someone
|
|
* wants to know about that, but now we need to know whether they
|
|
* want level or edge trigger. Check the trigger list against the
|
|
* current idle time, and if any succeed, bomb out of select()
|
|
* immediately so we can reschedule.
|
|
*/
|
|
|
|
for (list = IdleTimeCounter->pTriglist; list; list = list->next) {
|
|
trig = list->pTrigger;
|
|
if (trig->CheckTrigger(trig, old_idle)) {
|
|
AdjustWaitForDelay(wt, 0);
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* We've been called exactly on the idle time, but we have a
|
|
* NegativeTransition trigger which requires a transition from an
|
|
* idle time greater than this. Schedule a wakeup for the next
|
|
* millisecond so we won't miss a transition.
|
|
*/
|
|
if (XSyncValueEqual (idle, *pIdleTimeValueLess))
|
|
AdjustWaitForDelay(wt, 1);
|
|
}
|
|
else if (pIdleTimeValueGreater)
|
|
{
|
|
/*
|
|
* There's a threshold in the positive direction. If we've been
|
|
* idle less than it, schedule a wakeup for sometime in the future.
|
|
* If we've been idle more than it, and someone wants to know about
|
|
* that level-triggered, schedule an immediate wakeup.
|
|
*/
|
|
unsigned long timeout = -1;
|
|
|
|
if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) {
|
|
XSyncValue value;
|
|
Bool overflow;
|
|
|
|
XSyncValueSubtract (&value, *pIdleTimeValueGreater,
|
|
idle, &overflow);
|
|
timeout = min(timeout, XSyncValueLow32 (value));
|
|
} else {
|
|
for (list = IdleTimeCounter->pTriglist; list; list = list->next) {
|
|
trig = list->pTrigger;
|
|
if (trig->CheckTrigger(trig, old_idle)) {
|
|
timeout = min(timeout, 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
AdjustWaitForDelay (wt, timeout);
|
|
}
|
|
|
|
IdleTimeCounter->value = old_idle; /* pop */
|
|
}
|
|
|
|
static void
|
|
IdleTimeWakeupHandler (pointer env, int rc, pointer LastSelectMask)
|
|
{
|
|
XSyncValue idle;
|
|
|
|
if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
|
|
return;
|
|
|
|
IdleTimeQueryValue (NULL, &idle);
|
|
|
|
if ((pIdleTimeValueGreater &&
|
|
XSyncValueGreaterOrEqual (idle, *pIdleTimeValueGreater)) ||
|
|
(pIdleTimeValueLess &&
|
|
XSyncValueLessOrEqual (idle, *pIdleTimeValueLess)))
|
|
{
|
|
SyncChangeCounter (IdleTimeCounter, idle);
|
|
}
|
|
}
|
|
|
|
static void
|
|
IdleTimeBracketValues (pointer pCounter, CARD64 *pbracket_less,
|
|
CARD64 *pbracket_greater)
|
|
{
|
|
Bool registered = (pIdleTimeValueLess || pIdleTimeValueGreater);
|
|
|
|
if (registered && !pbracket_less && !pbracket_greater)
|
|
{
|
|
RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler,
|
|
IdleTimeWakeupHandler,
|
|
NULL);
|
|
}
|
|
else if (!registered && (pbracket_less || pbracket_greater))
|
|
{
|
|
RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
|
|
IdleTimeWakeupHandler,
|
|
NULL);
|
|
}
|
|
|
|
pIdleTimeValueGreater = pbracket_greater;
|
|
pIdleTimeValueLess = pbracket_less;
|
|
}
|
|
|
|
static void
|
|
SyncInitIdleTime (void)
|
|
{
|
|
CARD64 resolution;
|
|
XSyncValue idle;
|
|
|
|
IdleTimeQueryValue (NULL, &idle);
|
|
XSyncIntToValue (&resolution, 4);
|
|
|
|
IdleTimeCounter = SyncCreateSystemCounter ("IDLETIME", idle, resolution,
|
|
XSyncCounterUnrestricted,
|
|
IdleTimeQueryValue,
|
|
IdleTimeBracketValues);
|
|
|
|
pIdleTimeValueLess = pIdleTimeValueGreater = NULL;
|
|
}
|