#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 "scrnintstr.h"
#include "os.h"
#include "extnsionst.h"
#include "dixstruct.h"
#include "pixmapstr.h"
#include "resource.h"
#include "opaque.h"
#include <X11/extensions/syncproto.h>
#include "syncsrv.h"
#include "syncsdk.h"
#include "protocol-versions.h"
#include <stdio.h>
#if !defined(WIN32)
#include <sys/time.h>
#endif
#include "modinit.h"
static int SyncEventBase;
static int SyncErrorBase;
static RESTYPE RTCounter = 0;
static RESTYPE RTAwait;
static RESTYPE RTAlarm;
static RESTYPE RTAlarmClient;
static RESTYPE RTFence;
static int SyncNumSystemCounters = 0;
static SyncCounter **SysCounterList = NULL;
static int SyncNumInvalidCounterWarnings = 0;
#define MAX_INVALID_COUNTER_WARNINGS 5
static const char *WARN_INVALID_COUNTER_COMPARE =
"Warning: Non-counter XSync object using Counter-only\n"
" comparison. Result will never be true.\n";
static const char *WARN_INVALID_COUNTER_ALARM =
"Warning: Non-counter XSync object used in alarm. This is\n"
" the result of a programming error in the X server.\n";
#define IsSystemCounter(pCounter) \
(pCounter && (pCounter->sync.client == NULL))
#define XSyncCAAllTrigger \
(XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType)
static void SyncComputeBracketValues(SyncCounter *);
static void SyncInitServerTime(void);
static void SyncInitIdleTime(void);
static Bool
SyncCheckWarnIsCounter(const SyncObject* pSync, const char *warning)
{
if (pSync && (SYNC_COUNTER != pSync->type))
{
if (SyncNumInvalidCounterWarnings++ < MAX_INVALID_COUNTER_WARNINGS)
{
ErrorF("%s", warning);
ErrorF(" Counter type: %d\n", pSync->type);
}
return FALSE;
}
return TRUE;
}
static void
SyncDeleteTriggerFromSyncObject(SyncTrigger *pTrigger)
{
SyncTriggerList *pCur;
SyncTriggerList *pPrev;
SyncCounter *pCounter;
if (!pTrigger->pSync)
return;
pPrev = NULL;
pCur = pTrigger->pSync->pTriglist;
while (pCur)
{
if (pCur->pTrigger == pTrigger)
{
if (pPrev)
pPrev->next = pCur->next;
else
pTrigger->pSync->pTriglist = pCur->next;
free(pCur);
break;
}
pPrev = pCur;
pCur = pCur->next;
}
if (SYNC_COUNTER == pTrigger->pSync->type)
{
pCounter = (SyncCounter *)pTrigger->pSync;
if (IsSystemCounter(pCounter))
SyncComputeBracketValues(pCounter);
} else if (SYNC_FENCE == pTrigger->pSync->type) {
SyncFence* pFence = (SyncFence*) pTrigger->pSync;
pFence->funcs.DeleteTrigger(pTrigger);
}
}
static int
SyncAddTriggerToSyncObject(SyncTrigger *pTrigger)
{
SyncTriggerList *pCur;
SyncCounter *pCounter;
if (!pTrigger->pSync)
return Success;
for (pCur = pTrigger->pSync->pTriglist; pCur; pCur = pCur->next)
{
if (pCur->pTrigger == pTrigger)
return Success;
}
if (!(pCur = malloc(sizeof(SyncTriggerList))))
return BadAlloc;
pCur->pTrigger = pTrigger;
pCur->next = pTrigger->pSync->pTriglist;
pTrigger->pSync->pTriglist = pCur;
if (SYNC_COUNTER == pTrigger->pSync->type)
{
pCounter = (SyncCounter *)pTrigger->pSync;
if (IsSystemCounter(pCounter))
SyncComputeBracketValues(pCounter);
} else if (SYNC_FENCE == pTrigger->pSync->type) {
SyncFence* pFence = (SyncFence*) pTrigger->pSync;
pFence->funcs.AddTrigger(pTrigger);
}
return Success;
}
static Bool
SyncCheckTriggerPositiveComparison(SyncTrigger *pTrigger, CARD64 oldval)
{
SyncCounter *pCounter;
if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
return FALSE;
pCounter = (SyncCounter *)pTrigger->pSync;
return (pCounter == NULL ||
XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value));
}
static Bool
SyncCheckTriggerNegativeComparison(SyncTrigger *pTrigger, CARD64 oldval)
{
SyncCounter *pCounter;
if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
return FALSE;
pCounter = (SyncCounter *)pTrigger->pSync;
return (pCounter == NULL ||
XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value));
}
static Bool
SyncCheckTriggerPositiveTransition(SyncTrigger *pTrigger, CARD64 oldval)
{
SyncCounter *pCounter;
if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
return FALSE;
pCounter = (SyncCounter *)pTrigger->pSync;
return (pCounter == NULL ||
(XSyncValueLessThan(oldval, pTrigger->test_value) &&
XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value)));
}
static Bool
SyncCheckTriggerNegativeTransition(SyncTrigger *pTrigger, CARD64 oldval)
{
SyncCounter *pCounter;
if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
return FALSE;
pCounter = (SyncCounter *)pTrigger->pSync;
return (pCounter == NULL ||
(XSyncValueGreaterThan(oldval, pTrigger->test_value) &&
XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value)));
}
static Bool
SyncCheckTriggerFence(SyncTrigger *pTrigger, CARD64 unused)
{
SyncFence* pFence = (SyncFence*) pTrigger->pSync;
(void)unused;
return (pFence == NULL ||
pFence->funcs.CheckTriggered(pFence));
}
static int
SyncInitTrigger(ClientPtr client, SyncTrigger *pTrigger, XID syncObject,
RESTYPE resType, Mask changes)
{
SyncObject *pSync = pTrigger->pSync;
SyncCounter *pCounter = NULL;
int rc;
Bool newSyncObject = FALSE;
if (changes & XSyncCACounter)
{
if (syncObject == None)
pSync = NULL;
else if (Success != (rc = dixLookupResourceByType ((pointer *)&pSync,
syncObject, resType, client, DixReadAccess)))
{
client->errorValue = syncObject;
return rc;
}
if (pSync != pTrigger->pSync)
{
SyncDeleteTriggerFromSyncObject(pTrigger);
pTrigger->pSync = pSync;
newSyncObject = TRUE;
}
}
if (pSync && SYNC_COUNTER == pSync->type)
{
pCounter = (SyncCounter *)pSync;
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 (pSync && SYNC_FENCE == pSync->type)
{
pTrigger->CheckTrigger = SyncCheckTriggerFence;
}
else
{
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;
default:
client->errorValue = pTrigger->test_type;
return BadValue;
}
}
}
if (changes & (XSyncCAValueType | XSyncCAValue))
{
if (pTrigger->value_type == XSyncAbsolute)
pTrigger->test_value = pTrigger->wait_value;
else
{
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;
}
}
}
if (newSyncObject)
{
if ((rc = SyncAddTriggerToSyncObject(pTrigger)) != Success)
return rc;
}
else if (pCounter && IsSystemCounter(pCounter))
{
SyncComputeBracketValues(pCounter);
}
return Success;
}
static void
SyncSendAlarmNotifyEvents(SyncAlarm *pAlarm)
{
SyncAlarmClientList *pcl;
xSyncAlarmNotifyEvent ane;
SyncTrigger *pTrigger = &pAlarm->trigger;
SyncCounter *pCounter;
if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
return;
pCounter = (SyncCounter *)pTrigger->pSync;
UpdateCurrentTime();
ane.type = SyncEventBase + XSyncAlarmNotify;
ane.kind = XSyncAlarmNotify;
ane.alarm = pAlarm->alarm_id;
if (pTrigger->pSync && SYNC_COUNTER == pTrigger->pSync->type)
{
ane.counter_value_hi = XSyncValueHigh32(pCounter->value);
ane.counter_value_lo = XSyncValueLow32(pCounter->value);
}
else
{
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;
if (pAlarm->events)
WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane);
for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next)
WriteEventsToClient(pcl->client, 1, (xEvent *) &ane);
}
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->pSync->id;
pev->wait_value_lo = XSyncValueLow32(pTrigger->test_value);
pev->wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
if (SYNC_COUNTER == pTrigger->pSync->type)
{
SyncCounter *pCounter = (SyncCounter *)pTrigger->pSync;
pev->counter_value_lo = XSyncValueLow32(pCounter->value);
pev->counter_value_hi = XSyncValueHigh32(pCounter->value);
}
else
{
pev->counter_value_lo = 0;
pev->counter_value_hi = 0;
}
pev->time = currentTime.milliseconds;
pev->count = num_events - i - 1;
pev->destroyed = pTrigger->pSync->beingDestroyed;
}
WriteEventsToClient(client, num_events, (xEvent *)pEvents);
free(pEvents);
}
static void
SyncAlarmCounterDestroyed(SyncTrigger *pTrigger)
{
SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
pAlarm->state = XSyncAlarmInactive;
SyncSendAlarmNotifyEvents(pAlarm);
pTrigger->pSync = NULL;
}
static void
SyncAlarmTriggerFired(SyncTrigger *pTrigger)
{
SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
SyncCounter *pCounter;
CARD64 new_test_value;
if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
return;
pCounter = (SyncCounter *)pTrigger->pSync;
if (pAlarm->state != XSyncAlarmActive)
return;
if (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;
SyncCounter *paCounter;
if (!SyncCheckWarnIsCounter(paTrigger->pSync,
WARN_INVALID_COUNTER_ALARM))
return;
paCounter = (SyncCounter *)pTrigger->pSync;
oldvalue = paTrigger->test_value;
do
{
XSyncValueAdd(&paTrigger->test_value, paTrigger->test_value,
pAlarm->delta, &overflow);
} while (!overflow &&
(*paTrigger->CheckTrigger)(paTrigger,
paCounter->value));
new_test_value = paTrigger->test_value;
paTrigger->test_value = oldvalue;
if (overflow)
{
new_test_value = oldvalue;
pAlarm->state = XSyncAlarmInactive;
}
}
SyncSendAlarmNotifyEvents(pAlarm);
pTrigger->test_value = new_test_value;
}
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;
for ( ; numwaits; numwaits--, pAwait++)
{
CARD64 diff;
Bool overflow, diffgreater, diffequal;
if (pAwait->trigger.pSync->beingDestroyed)
{
ppAwait[num_events++] = pAwait;
continue;
}
if (SYNC_COUNTER == pAwait->trigger.pSync->type)
{
SyncCounter *pCounter = (SyncCounter *) pAwait->trigger.pSync;
XSyncValueSubtract(&diff, pCounter->value,
pAwait->trigger.test_value, &overflow);
if (overflow)
continue;
diffgreater = XSyncValueGreaterThan(diff, pAwait->event_threshold);
diffequal = XSyncValueEqual(diff, pAwait->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)
)
)
{
ppAwait[num_events++] = pAwait;
}
}
}
if (num_events)
SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait,
num_events);
free(ppAwait);
bail:
AttendClient(pAwaitUnion->header.client);
FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
}
void
SyncChangeCounter(SyncCounter *pCounter, CARD64 newval)
{
SyncTriggerList *ptl, *pnext;
CARD64 oldval;
oldval = pCounter->value;
pCounter->value = newval;
for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext)
{
pnext = ptl->next;
if ((*ptl->pTrigger->CheckTrigger)(ptl->pTrigger, oldval))
(*ptl->pTrigger->TriggerFired)(ptl->pTrigger);
}
if (IsSystemCounter(pCounter))
{
SyncComputeBracketValues(pCounter);
}
}
static Bool
SyncEventSelectForAlarm(SyncAlarm *pAlarm, ClientPtr client, Bool wantevents)
{
SyncAlarmClientList *pClients;
if (client == pAlarm->client)
{
pAlarm->events = wantevents;
return Success;
}
for (pClients = pAlarm->pEventClients; pClients;
pClients = pClients->next)
{
if (pClients->client == client)
{
if (!wantevents)
{
FreeResource(pClients->delete_id, RT_NONE);
}
return Success;
}
}
if (!wantevents)
return Success;
pClients = malloc(sizeof(SyncAlarmClientList));
if (!pClients)
return BadAlloc;
pClients->delete_id = FakeClientID(client->index);
pClients->next = pAlarm->pEventClients;
pAlarm->pEventClients = pClients;
pClients->client = client;
if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm))
return BadAlloc;
return Success;
}
static int
SyncChangeAlarmAttributes(ClientPtr client, SyncAlarm *pAlarm, Mask mask,
CARD32 *values)
{
int status;
XSyncCounter counter;
Mask origmask = mask;
counter =
pAlarm->trigger.pSync ? pAlarm->trigger.pSync->id : None;
while (mask)
{
int index2 = lowbit(mask);
mask &= ~index2;
switch (index2)
{
case XSyncCACounter:
mask &= ~XSyncCACounter;
counter = *values++;
break;
case XSyncCAValueType:
mask &= ~XSyncCAValueType;
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;
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 (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;
}
}
if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter,
origmask & XSyncCAAllTrigger)) != Success)
return status;
pAlarm->state = XSyncAlarmActive;
return Success;
}
static SyncObject *
SyncCreate(ClientPtr client, XID id, unsigned char type)
{
SyncObject *pSync;
switch (type) {
case SYNC_COUNTER:
pSync = malloc(sizeof(SyncCounter));
break;
case SYNC_FENCE:
pSync = (SyncObject*)dixAllocateObjectWithPrivates(SyncFence,
PRIVATE_SYNC_FENCE);
break;
default:
return NULL;
}
if (!pSync)
return NULL;
pSync->client = client;
pSync->id = id;
pSync->pTriglist = NULL;
pSync->beingDestroyed = FALSE;
pSync->type = type;
return pSync;
}
static SyncCounter *
SyncCreateCounter(ClientPtr client, XSyncCounter id, CARD64 initialvalue)
{
SyncCounter *pCounter;
if (!(pCounter = (SyncCounter *)SyncCreate(client,
id,
SYNC_COUNTER)))
return NULL;
pCounter->value = initialvalue;
pCounter->pSysCounterInfo = NULL;
if (!AddResource(id, RTCounter, (pointer) pCounter))
return NULL;
return pCounter;
}
static int FreeCounter(void *, XID);
pointer
SyncCreateSystemCounter(
char *name,
CARD64 initial,
CARD64 resolution,
SyncCounterType counterType,
void (*QueryValue)(pointer ,
CARD64 * ),
void (*BracketValues)(pointer ,
CARD64 * ,
CARD64 * )
)
{
SyncCounter *pCounter;
SysCounterList = realloc(SysCounterList,
(SyncNumSystemCounters+1)*sizeof(SyncCounter *));
if (!SysCounterList)
return NULL;
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->sync.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->sync.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->sync.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))
{
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))
{
psci->bracket_less = pTrigger->test_value;
pnewltval = &psci->bracket_less;
}
}
}
if (pnewgtval || pnewltval)
{
(*psci->BracketValues)((pointer)pCounter, pnewltval, pnewgtval);
}
}
static int
FreeAlarm(void *addr, XID id)
{
SyncAlarm *pAlarm = (SyncAlarm *) addr;
pAlarm->state = XSyncAlarmDestroyed;
SyncSendAlarmNotifyEvents(pAlarm);
while (pAlarm->pEventClients)
FreeResource(pAlarm->pEventClients->delete_id, RT_NONE);
SyncDeleteTriggerFromSyncObject(&pAlarm->trigger);
free(pAlarm);
return Success;
}
static int
FreeCounter(void *env, XID id)
{
SyncCounter *pCounter = (SyncCounter *) env;
SyncTriggerList *ptl, *pnext;
pCounter->sync.beingDestroyed = TRUE;
for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext)
{
(*ptl->pTrigger->CounterDestroyed)(ptl->pTrigger);
pnext = ptl->next;
free(ptl);
}
if (IsSystemCounter(pCounter))
{
int i, found = 0;
free(pCounter->pSysCounterInfo);
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;
}
static int
FreeAwait(void *addr, XID id)
{
SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr;
SyncAwait *pAwait;
int numwaits;
pAwait = &(pAwaitUnion+1)->await;
for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits;
numwaits--, pAwait++)
{
SyncObject *pSync = pAwait->trigger.pSync;
if (pSync && !pSync->beingDestroyed)
SyncDeleteTriggerFromSyncObject(&pAwait->trigger);
}
free(pAwaitUnion);
return Success;
}
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");
}
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;
}
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;
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]->sync.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;
}
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;
isItTimeToYield = TRUE;
dispatchException |= DE_PRIORITYCHANGE;
}
return Success;
}
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;
}
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;
}
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;
}
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)
{
client->errorValue = stuff->value_hi;
return BadValue;
}
SyncChangeCounter(pCounter, newvalue);
return Success;
}
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->sync.id, RT_NONE);
return Success;
}
static SyncAwaitUnion*
SyncAwaitPrologue(ClientPtr client, int items)
{
SyncAwaitUnion *pAwaitUnion;
pAwaitUnion = malloc((items+1) * sizeof(SyncAwaitUnion));
if (!pAwaitUnion)
return NULL;
pAwaitUnion->header.delete_id = FakeClientID(client->index);
pAwaitUnion->header.client = client;
pAwaitUnion->header.num_waitconditions = 0;
if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion))
return NULL;
return pAwaitUnion;
}
static void
SyncAwaitEpilogue(ClientPtr client, int items, SyncAwaitUnion *pAwaitUnion)
{
SyncAwait *pAwait;
int i;
IgnoreClient(client);
pAwait = &(pAwaitUnion+1)->await;
for (i = 0; i < items; i++, pAwait++)
{
CARD64 value;
switch (pAwait->trigger.pSync->type) {
case SYNC_COUNTER:
value = ((SyncCounter *)pAwait->trigger.pSync)->value;
break;
default:
XSyncIntToValue(&value, 0);
}
if ((*pAwait->trigger.CheckTrigger)(&pAwait->trigger, value))
{
(*pAwait->trigger.TriggerFired)(&pAwait->trigger);
break;
}
}
}
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;
return BadValue;
}
if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
return BadAlloc;
pProtocolWaitConds = (xSyncWaitCondition *) & stuff[1];
pAwait = &(pAwaitUnion+1)->await;
for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++)
{
if (pProtocolWaitConds->counter == None)
{
FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
client->errorValue = pProtocolWaitConds->counter;
return SyncErrorBase + XSyncBadCounter;
}
pAwait->trigger.pSync = 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, RTCounter,
XSyncCAAllTrigger);
if (status != Success)
{
FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
return status;
}
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++;
}
SyncAwaitEpilogue(client, items, pAwaitUnion);
return Success;
}
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 (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;
}
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));
if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
return BadLength;
if (!(pAlarm = malloc(sizeof(SyncAlarm))))
{
return BadAlloc;
}
pTrigger = &pAlarm->trigger;
pTrigger->pSync = 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, RTCounter,
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))
return BadAlloc;
if (!pTrigger->pSync)
{
pAlarm->state = XSyncAlarmInactive;
}
else
{
SyncCounter *pCounter;
if (!SyncCheckWarnIsCounter(pTrigger->pSync,
WARN_INVALID_COUNTER_ALARM))
{
FreeResource(stuff->id, RT_NONE);
return BadAlloc;
}
pCounter = (SyncCounter *)pTrigger->pSync;
if ((*pTrigger->CheckTrigger)(pTrigger, pCounter->value))
(*pTrigger->TriggerFired)(pTrigger);
}
return Success;
}
static int
ProcSyncChangeAlarm(ClientPtr client)
{
REQUEST(xSyncChangeAlarmReq);
SyncAlarm *pAlarm;
SyncCounter *pCounter = NULL;
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));
if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
return BadLength;
if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
(CARD32 *)&stuff[1])) != Success)
return status;
if (SyncCheckWarnIsCounter(pAlarm->trigger.pSync,
WARN_INVALID_COUNTER_ALARM))
pCounter = (SyncCounter *)pAlarm->trigger.pSync;
if (!pCounter ||
(*pAlarm->trigger.CheckTrigger)(&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->pSync) ? pTrigger->pSync->id : None;
#if 0
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;
}
static int
ProcSyncCreateFence(ClientPtr client)
{
REQUEST(xSyncCreateFenceReq);
DrawablePtr pDraw;
SyncFence *pFence;
int rc;
REQUEST_SIZE_MATCH(xSyncCreateFenceReq);
rc = dixLookupDrawable(&pDraw, stuff->d, client, M_ANY, DixGetAttrAccess);
if (rc != Success)
return rc;
LEGAL_NEW_RESOURCE(stuff->fid, client);
if (!(pFence = (SyncFence *)SyncCreate(client,
stuff->fid,
SYNC_FENCE)))
return BadAlloc;
miSyncInitFence(pDraw->pScreen, pFence, stuff->initially_triggered);
if (!AddResource(stuff->fid, RTFence, (pointer) pFence))
return BadAlloc;
return client->noClientException;
}
static int
FreeFence(void *obj, XID id)
{
SyncFence *pFence = (SyncFence *) obj;
miSyncDestroyFence(pFence);
return Success;
}
int SyncVerifyFence(SyncFence **ppSyncFence, XID fid,
ClientPtr client, Mask mode)
{
int rc = dixLookupResourceByType((pointer *)ppSyncFence, fid, RTFence,
client, mode);
if (rc != Success)
client->errorValue = fid;
return rc;
}
static int
ProcSyncTriggerFence(ClientPtr client)
{
REQUEST(xSyncTriggerFenceReq);
SyncFence *pFence;
int rc;
REQUEST_SIZE_MATCH(xSyncTriggerFenceReq);
rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
client, DixWriteAccess);
if (rc != Success)
return rc;
miSyncTriggerFence(pFence);
return client->noClientException;
}
static int
ProcSyncResetFence(ClientPtr client)
{
REQUEST(xSyncResetFenceReq);
SyncFence *pFence;
int rc;
REQUEST_SIZE_MATCH(xSyncResetFenceReq);
rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
client, DixWriteAccess);
if (rc != Success)
return rc;
if (pFence->funcs.CheckTriggered(pFence) != TRUE)
return BadMatch;
pFence->funcs.Reset(pFence);
return client->noClientException;
}
static int
ProcSyncDestroyFence(ClientPtr client)
{
REQUEST(xSyncDestroyFenceReq);
SyncFence *pFence;
int rc;
REQUEST_SIZE_MATCH(xSyncDestroyFenceReq);
rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
client, DixDestroyAccess);
if (rc != Success)
return rc;
FreeResource(stuff->fid, RT_NONE);
return client->noClientException;
}
static int
ProcSyncQueryFence(ClientPtr client)
{
REQUEST(xSyncQueryFenceReq);
xSyncQueryFenceReply rep;
SyncFence *pFence;
int rc;
REQUEST_SIZE_MATCH(xSyncQueryFenceReq);
rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid,
RTFence, client, DixReadAccess);
if (rc != Success)
return rc;
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
rep.triggered = pFence->funcs.CheckTriggered(pFence);
if (client->swapped)
{
char n;
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
}
WriteToClient(client, sizeof(xSyncQueryFenceReply), (char *) &rep);
return client->noClientException;
}
static int
ProcSyncAwaitFence(ClientPtr client)
{
REQUEST(xSyncAwaitFenceReq);
SyncAwaitUnion *pAwaitUnion;
SyncAwait *pAwait;
CARD32 *pProtocolFences;
int status;
int len;
int items;
int i;
REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
len = client->req_len << 2;
len -= sz_xSyncAwaitFenceReq;
items = len / sizeof(CARD32);
if (items * sizeof(CARD32) != len)
{
return BadLength;
}
if (items == 0)
{
client->errorValue = items;
return BadValue;
}
if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
return BadAlloc;
pProtocolFences = (CARD32 *) & stuff[1];
pAwait = &(pAwaitUnion+1)->await;
for (i = 0; i < items; i++, pProtocolFences++, pAwait++)
{
if (*pProtocolFences == None)
{
FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
client->errorValue = *pProtocolFences;
return SyncErrorBase + XSyncBadFence;
}
pAwait->trigger.pSync = NULL;
pAwait->trigger.value_type = XSyncAbsolute;
XSyncIntToValue(&pAwait->trigger.wait_value, 0);
pAwait->trigger.test_type = 0;
status = SyncInitTrigger(client, &pAwait->trigger,
*pProtocolFences, RTFence,
XSyncCAAllTrigger);
if (status != Success)
{
FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
return status;
}
pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
XSyncIntToValue(&pAwait->event_threshold, 0);
pAwait->pHeader = &pAwaitUnion->header;
pAwaitUnion->header.num_waitconditions++;
}
SyncAwaitEpilogue(client, items, pAwaitUnion);
return client->noClientException;
}
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);
case X_SyncCreateFence:
return ProcSyncCreateFence(client);
case X_SyncTriggerFence:
return ProcSyncTriggerFence(client);
case X_SyncResetFence:
return ProcSyncResetFence(client);
case X_SyncDestroyFence:
return ProcSyncDestroyFence(client);
case X_SyncQueryFence:
return ProcSyncQueryFence(client);
case X_SyncAwaitFence:
return ProcSyncAwaitFence(client);
default:
return BadRequest;
}
}
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
SProcSyncCreateFence(ClientPtr client)
{
REQUEST(xSyncCreateFenceReq);
char n;
swaps(&stuff->length, n);
REQUEST_SIZE_MATCH (xSyncCreateFenceReq);
swapl(&stuff->fid, n);
return ProcSyncCreateFence(client);
}
static int
SProcSyncTriggerFence(ClientPtr client)
{
REQUEST(xSyncTriggerFenceReq);
char n;
swaps(&stuff->length, n);
REQUEST_SIZE_MATCH (xSyncTriggerFenceReq);
swapl(&stuff->fid, n);
return ProcSyncTriggerFence(client);
}
static int
SProcSyncResetFence(ClientPtr client)
{
REQUEST(xSyncResetFenceReq);
char n;
swaps(&stuff->length, n);
REQUEST_SIZE_MATCH (xSyncResetFenceReq);
swapl(&stuff->fid, n);
return ProcSyncResetFence(client);
}
static int
SProcSyncDestroyFence(ClientPtr client)
{
REQUEST(xSyncDestroyFenceReq);
char n;
swaps(&stuff->length, n);
REQUEST_SIZE_MATCH (xSyncDestroyFenceReq);
swapl(&stuff->fid, n);
return ProcSyncDestroyFence(client);
}
static int
SProcSyncQueryFence(ClientPtr client)
{
REQUEST(xSyncQueryFenceReq);
char n;
swaps(&stuff->length, n);
REQUEST_SIZE_MATCH (xSyncQueryFenceReq);
swapl(&stuff->fid, n);
return ProcSyncQueryFence(client);
}
static int
SProcSyncAwaitFence(ClientPtr client)
{
REQUEST(xSyncAwaitFenceReq);
char n;
swaps(&stuff->length, n);
REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
SwapRestL(stuff);
return ProcSyncAwaitFence(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);
case X_SyncCreateFence:
return SProcSyncCreateFence(client);
case X_SyncTriggerFence:
return SProcSyncTriggerFence(client);
case X_SyncResetFence:
return SProcSyncResetFence(client);
case X_SyncDestroyFence:
return SProcSyncDestroyFence(client);
case X_SyncQueryFence:
return SProcSyncQueryFence(client);
case X_SyncAwaitFence:
return SProcSyncAwaitFence(client);
default:
return BadRequest;
}
}
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;
}
static void
SyncResetProc(ExtensionEntry *extEntry)
{
free(SysCounterList);
SysCounterList = NULL;
RTCounter = 0;
}
void
SyncExtensionInit(void)
{
ExtensionEntry *extEntry;
int s;
for (s = 0; s < screenInfo.numScreens; s++)
miSyncSetup(screenInfo.screens[s]);
if (RTCounter == 0)
{
RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
}
RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm");
RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait");
RTFence = CreateNewResourceType(FreeFence, "SyncFence");
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);
SetResourceTypeErrorValue(RTFence, SyncErrorBase + XSyncBadFence);
SyncInitServerTime();
SyncInitIdleTime();
#ifdef DEBUG
fprintf(stderr, "Sync Extension %d.%d\n",
SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
#endif
}
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);\
}
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);
}
}
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;
}
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->sync.pTriglist;
SyncTrigger *trig;
if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
return;
old_idle = IdleTimeCounter->value;
IdleTimeQueryValue (NULL, &idle);
IdleTimeCounter->value = idle;
if (pIdleTimeValueLess &&
XSyncValueLessOrEqual (idle, *pIdleTimeValueLess))
{
for (list = IdleTimeCounter->sync.pTriglist; list; list = list->next) {
trig = list->pTrigger;
if (trig->CheckTrigger(trig, old_idle)) {
AdjustWaitForDelay(wt, 0);
break;
}
}
if (XSyncValueEqual (idle, *pIdleTimeValueLess))
AdjustWaitForDelay(wt, 1);
}
else if (pIdleTimeValueGreater)
{
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->sync.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;
}
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;
}