2856 lines
		
	
	
		
			82 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			2856 lines
		
	
	
		
			82 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 <stdio.h>
 | 
						|
#include <X11/X.h>
 | 
						|
#include <X11/Xproto.h>
 | 
						|
#include <X11/Xmd.h>
 | 
						|
#include <X11/extensions/syncproto.h>
 | 
						|
 | 
						|
#include "dix/dix_priv.h"
 | 
						|
 | 
						|
#include "scrnintstr.h"
 | 
						|
#include "os.h"
 | 
						|
#include "extnsionst.h"
 | 
						|
#include "dixstruct.h"
 | 
						|
#include "pixmapstr.h"
 | 
						|
#include "resource.h"
 | 
						|
#include "syncsrv.h"
 | 
						|
#include "syncsdk.h"
 | 
						|
#include "protocol-versions.h"
 | 
						|
#include "inputstr.h"
 | 
						|
#include "misync_priv.h"
 | 
						|
 | 
						|
#if !defined(WIN32)
 | 
						|
#include <sys/time.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include "extinit_priv.h"
 | 
						|
 | 
						|
/*
 | 
						|
 * Local Global Variables
 | 
						|
 */
 | 
						|
static int SyncEventBase;
 | 
						|
static int SyncErrorBase;
 | 
						|
static RESTYPE RTCounter = 0;
 | 
						|
static RESTYPE RTAwait;
 | 
						|
static RESTYPE RTAlarm;
 | 
						|
static RESTYPE RTAlarmClient;
 | 
						|
static RESTYPE RTFence;
 | 
						|
static struct xorg_list SysCounterList;
 | 
						|
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))
 | 
						|
 | 
						|
/* 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 inline void*
 | 
						|
SysCounterGetPrivate(SyncCounter *counter)
 | 
						|
{
 | 
						|
    BUG_WARN(!IsSystemCounter(counter));
 | 
						|
 | 
						|
    return counter->pSysCounterInfo ? counter->pSysCounterInfo->private : NULL;
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
}
 | 
						|
 | 
						|
/*  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.
 | 
						|
 */
 | 
						|
void
 | 
						|
SyncDeleteTriggerFromSyncObject(SyncTrigger * pTrigger)
 | 
						|
{
 | 
						|
    SyncTriggerList *pCur;
 | 
						|
    SyncTriggerList *pPrev;
 | 
						|
    SyncCounter *pCounter;
 | 
						|
 | 
						|
    /* pSync needs to be stored in pTrigger before calling here. */
 | 
						|
 | 
						|
    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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
SyncAddTriggerToSyncObject(SyncTrigger * pTrigger)
 | 
						|
{
 | 
						|
    SyncTriggerList *pCur;
 | 
						|
    SyncCounter *pCounter;
 | 
						|
 | 
						|
    if (!pTrigger->pSync)
 | 
						|
        return Success;
 | 
						|
 | 
						|
    /* don't do anything if it's already there */
 | 
						|
    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;
 | 
						|
}
 | 
						|
 | 
						|
/*  Below are five possible functions that can be plugged into
 | 
						|
 *  pTrigger->CheckTrigger for counter sync objects, corresponding to
 | 
						|
 *  the four possible test-types, and the one possible function that
 | 
						|
 *  can be plugged into pTrigger->CheckTrigger for fence sync objects.
 | 
						|
 *  These functions are called after the sync object's state changes
 | 
						|
 *  but are also passed the old state 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->pSync == NULL.
 | 
						|
 *  This is because the spec says that a trigger with a sync value
 | 
						|
 *  of None is always TRUE.
 | 
						|
 */
 | 
						|
 | 
						|
static Bool
 | 
						|
SyncCheckTriggerPositiveComparison(SyncTrigger * pTrigger, int64_t oldval)
 | 
						|
{
 | 
						|
    SyncCounter *pCounter;
 | 
						|
 | 
						|
    /* Non-counter sync objects should never get here because they
 | 
						|
     * never trigger this comparison. */
 | 
						|
    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    pCounter = (SyncCounter *) pTrigger->pSync;
 | 
						|
 | 
						|
    return pCounter == NULL || pCounter->value >= pTrigger->test_value;
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
SyncCheckTriggerNegativeComparison(SyncTrigger * pTrigger, int64_t oldval)
 | 
						|
{
 | 
						|
    SyncCounter *pCounter;
 | 
						|
 | 
						|
    /* Non-counter sync objects should never get here because they
 | 
						|
     * never trigger this comparison. */
 | 
						|
    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    pCounter = (SyncCounter *) pTrigger->pSync;
 | 
						|
 | 
						|
    return pCounter == NULL || pCounter->value <= pTrigger->test_value;
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
SyncCheckTriggerPositiveTransition(SyncTrigger * pTrigger, int64_t oldval)
 | 
						|
{
 | 
						|
    SyncCounter *pCounter;
 | 
						|
 | 
						|
    /* Non-counter sync objects should never get here because they
 | 
						|
     * never trigger this comparison. */
 | 
						|
    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    pCounter = (SyncCounter *) pTrigger->pSync;
 | 
						|
 | 
						|
    return (pCounter == NULL ||
 | 
						|
            (oldval < pTrigger->test_value &&
 | 
						|
             pCounter->value >= pTrigger->test_value));
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
SyncCheckTriggerNegativeTransition(SyncTrigger * pTrigger, int64_t oldval)
 | 
						|
{
 | 
						|
    SyncCounter *pCounter;
 | 
						|
 | 
						|
    /* Non-counter sync objects should never get here because they
 | 
						|
     * never trigger this comparison. */
 | 
						|
    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    pCounter = (SyncCounter *) pTrigger->pSync;
 | 
						|
 | 
						|
    return (pCounter == NULL ||
 | 
						|
            (oldval > pTrigger->test_value &&
 | 
						|
             pCounter->value <= pTrigger->test_value));
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
SyncCheckTriggerFence(SyncTrigger * pTrigger, int64_t 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((void **) &pSync,
 | 
						|
                                                          syncObject, resType,
 | 
						|
                                                          client,
 | 
						|
                                                          DixReadAccess))) {
 | 
						|
            client->errorValue = syncObject;
 | 
						|
            return rc;
 | 
						|
        }
 | 
						|
        if (pSync != pTrigger->pSync) { /* new counter for trigger */
 | 
						|
            SyncDeleteTriggerFromSyncObject(pTrigger);
 | 
						|
            pTrigger->pSync = pSync;
 | 
						|
            newSyncObject = TRUE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* if system counter, ask it what the current value is */
 | 
						|
 | 
						|
    if (pSync && SYNC_COUNTER == pSync->type) {
 | 
						|
        pCounter = (SyncCounter *) pSync;
 | 
						|
 | 
						|
        if (IsSystemCounter(pCounter)) {
 | 
						|
            (*pCounter->pSysCounterInfo->QueryValue) ((void *) 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 {
 | 
						|
            /* 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;
 | 
						|
            default:
 | 
						|
                client->errorValue = pTrigger->test_type;
 | 
						|
                return BadValue;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (changes & (XSyncCAValueType | XSyncCAValue)) {
 | 
						|
        if (pTrigger->value_type == XSyncAbsolute)
 | 
						|
            pTrigger->test_value = pTrigger->wait_value;
 | 
						|
        else {                  /* relative */
 | 
						|
            Bool overflow;
 | 
						|
 | 
						|
            if (pCounter == NULL)
 | 
						|
                return BadMatch;
 | 
						|
 | 
						|
            overflow = checked_int64_add(&pTrigger->test_value,
 | 
						|
                                         pCounter->value, pTrigger->wait_value);
 | 
						|
            if (overflow) {
 | 
						|
                client->errorValue = pTrigger->wait_value >> 32;
 | 
						|
                return BadValue;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /*  we wait until we're sure there are no errors before registering
 | 
						|
     *  a new counter on a trigger
 | 
						|
     */
 | 
						|
    if (newSyncObject) {
 | 
						|
        if ((rc = SyncAddTriggerToSyncObject(pTrigger)) != Success)
 | 
						|
            return rc;
 | 
						|
    }
 | 
						|
    else if (pCounter && 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;
 | 
						|
    SyncCounter *pCounter;
 | 
						|
 | 
						|
    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
 | 
						|
        return;
 | 
						|
 | 
						|
    pCounter = (SyncCounter *) pTrigger->pSync;
 | 
						|
 | 
						|
    UpdateCurrentTime();
 | 
						|
 | 
						|
    ane = (xSyncAlarmNotifyEvent) {
 | 
						|
        .type = SyncEventBase + XSyncAlarmNotify,
 | 
						|
        .kind = XSyncAlarmNotify,
 | 
						|
        .alarm = pAlarm->alarm_id,
 | 
						|
        .alarm_value_hi = pTrigger->test_value >> 32,
 | 
						|
        .alarm_value_lo = pTrigger->test_value,
 | 
						|
        .time = currentTime.milliseconds,
 | 
						|
        .state = pAlarm->state
 | 
						|
    };
 | 
						|
 | 
						|
    if (pTrigger->pSync && SYNC_COUNTER == pTrigger->pSync->type) {
 | 
						|
        ane.counter_value_hi = pCounter->value >> 32;
 | 
						|
        ane.counter_value_lo = pCounter->value;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        /* XXX what else can we do if there's no counter? */
 | 
						|
        ane.counter_value_hi = ane.counter_value_lo = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    /* 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 = calloc(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 = pTrigger->test_value;
 | 
						|
        pev->wait_value_hi = pTrigger->test_value >> 32;
 | 
						|
        if (SYNC_COUNTER == pTrigger->pSync->type) {
 | 
						|
            SyncCounter *pCounter = (SyncCounter *) pTrigger->pSync;
 | 
						|
 | 
						|
            pev->counter_value_lo = pCounter->value;
 | 
						|
            pev->counter_value_hi = pCounter->value >> 32;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            pev->counter_value_lo = 0;
 | 
						|
            pev->counter_value_hi = 0;
 | 
						|
        }
 | 
						|
 | 
						|
        pev->time = currentTime.milliseconds;
 | 
						|
        pev->count = num_events - i - 1;        /* events remaining */
 | 
						|
        pev->destroyed = pTrigger->pSync->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->pSync = 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;
 | 
						|
    SyncCounter *pCounter;
 | 
						|
    int64_t new_test_value;
 | 
						|
 | 
						|
    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
 | 
						|
        return;
 | 
						|
 | 
						|
    pCounter = (SyncCounter *) pTrigger->pSync;
 | 
						|
 | 
						|
    /* 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 (pCounter == NULL || (pAlarm->delta == 0
 | 
						|
                             && (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;
 | 
						|
        int64_t oldvalue;
 | 
						|
        SyncTrigger *paTrigger = &pAlarm->trigger;
 | 
						|
        SyncCounter *paCounter;
 | 
						|
 | 
						|
        if (!SyncCheckWarnIsCounter(paTrigger->pSync,
 | 
						|
                                    WARN_INVALID_COUNTER_ALARM))
 | 
						|
            return;
 | 
						|
 | 
						|
        paCounter = (SyncCounter *) pTrigger->pSync;
 | 
						|
 | 
						|
        /* "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 {
 | 
						|
            overflow = checked_int64_add(&paTrigger->test_value,
 | 
						|
                                         paTrigger->test_value, pAlarm->delta);
 | 
						|
        } while (!overflow &&
 | 
						|
                 (*paTrigger->CheckTrigger) (paTrigger, paCounter->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 = xallocarray(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++) {
 | 
						|
        int64_t 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.pSync->beingDestroyed) {
 | 
						|
            ppAwait[num_events++] = pAwait;
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
 | 
						|
        if (SYNC_COUNTER == pAwait->trigger.pSync->type) {
 | 
						|
            SyncCounter *pCounter = (SyncCounter *) pAwait->trigger.pSync;
 | 
						|
 | 
						|
            /* "The difference between the counter and the test value is
 | 
						|
             *  calculated by subtracting the test value from the value of
 | 
						|
             *  the counter."
 | 
						|
             */
 | 
						|
            overflow = checked_int64_subtract(&diff, pCounter->value,
 | 
						|
                                              pAwait->trigger.test_value);
 | 
						|
 | 
						|
            /* "If the difference lies outside the range for an INT64, an
 | 
						|
             *  event is not generated."
 | 
						|
             */
 | 
						|
            if (overflow)
 | 
						|
                continue;
 | 
						|
            diffgreater = diff > pAwait->event_threshold;
 | 
						|
            diffequal = 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, X11_RESTYPE_NONE);
 | 
						|
}
 | 
						|
 | 
						|
static int64_t
 | 
						|
SyncUpdateCounter(SyncCounter *pCounter, int64_t newval)
 | 
						|
{
 | 
						|
    int64_t oldval = pCounter->value;
 | 
						|
    pCounter->value = newval;
 | 
						|
    return oldval;
 | 
						|
}
 | 
						|
 | 
						|
/*  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, int64_t newval)
 | 
						|
{
 | 
						|
    SyncTriggerList *ptl, *pnext;
 | 
						|
    int64_t oldval;
 | 
						|
 | 
						|
    oldval = SyncUpdateCounter(pCounter, newval);
 | 
						|
 | 
						|
    /* run through triggers to see if any become true */
 | 
						|
    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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* 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, X11_RESTYPE_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);
 | 
						|
 | 
						|
    /* link it into list after we know all the allocations succeed */
 | 
						|
    pClients->next = pAlarm->pEventClients;
 | 
						|
    pAlarm->pEventClients = pClients;
 | 
						|
    pClients->client = client;
 | 
						|
 | 
						|
    if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm))
 | 
						|
        return BadAlloc;
 | 
						|
 | 
						|
    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.pSync ? pAlarm->trigger.pSync->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;
 | 
						|
            pAlarm->trigger.wait_value = ((int64_t)values[0] << 32) | values[1];
 | 
						|
            values += 2;
 | 
						|
            break;
 | 
						|
 | 
						|
        case XSyncCATestType:
 | 
						|
            mask &= ~XSyncCATestType;
 | 
						|
            /* sanity check in SyncInitTrigger */
 | 
						|
            pAlarm->trigger.test_type = *values++;
 | 
						|
            break;
 | 
						|
 | 
						|
        case XSyncCADelta:
 | 
						|
            mask &= ~XSyncCADelta;
 | 
						|
            pAlarm->delta = ((int64_t)values[0] << 32) | values[1];
 | 
						|
            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)) {
 | 
						|
        if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) ||
 | 
						|
              (pAlarm->trigger.test_type == XSyncPositiveTransition))
 | 
						|
             && pAlarm->delta < 0)
 | 
						|
            ||
 | 
						|
            (((pAlarm->trigger.test_type == XSyncNegativeComparison) ||
 | 
						|
              (pAlarm->trigger.test_type == XSyncNegativeTransition))
 | 
						|
             && pAlarm->delta > 0)
 | 
						|
            ) {
 | 
						|
            return BadMatch;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* postpone this until now, when we're sure nothing else can go wrong */
 | 
						|
    if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter,
 | 
						|
                                  origmask & XSyncCAAllTrigger)) != Success)
 | 
						|
        return status;
 | 
						|
 | 
						|
    /* XXX spec does not really say to do this - needs clarification */
 | 
						|
    pAlarm->state = XSyncAlarmActive;
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
SyncObject *
 | 
						|
SyncCreate(ClientPtr client, XID id, unsigned char type)
 | 
						|
{
 | 
						|
    SyncObject *pSync;
 | 
						|
    RESTYPE resType;
 | 
						|
 | 
						|
    switch (type) {
 | 
						|
    case SYNC_COUNTER:
 | 
						|
        pSync = malloc(sizeof(SyncCounter));
 | 
						|
        resType = RTCounter;
 | 
						|
        break;
 | 
						|
    case SYNC_FENCE:
 | 
						|
        pSync = (SyncObject *) dixAllocateObjectWithPrivates(SyncFence,
 | 
						|
                                                             PRIVATE_SYNC_FENCE);
 | 
						|
        resType = RTFence;
 | 
						|
        break;
 | 
						|
    default:
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!pSync)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    pSync->initialized = FALSE;
 | 
						|
 | 
						|
    if (!AddResource(id, resType, (void *) pSync))
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    pSync->client = client;
 | 
						|
    pSync->id = id;
 | 
						|
    pSync->pTriglist = NULL;
 | 
						|
    pSync->beingDestroyed = FALSE;
 | 
						|
    pSync->type = type;
 | 
						|
 | 
						|
    return pSync;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
SyncCreateFenceFromFD(ClientPtr client, DrawablePtr pDraw, XID id, int fd, BOOL initially_triggered)
 | 
						|
{
 | 
						|
#ifdef HAVE_XSHMFENCE
 | 
						|
    SyncFence  *pFence;
 | 
						|
    int         status;
 | 
						|
 | 
						|
    pFence = (SyncFence *) SyncCreate(client, id, SYNC_FENCE);
 | 
						|
    if (!pFence)
 | 
						|
        return BadAlloc;
 | 
						|
 | 
						|
    status = miSyncInitFenceFromFD(pDraw, pFence, fd, initially_triggered);
 | 
						|
    if (status != Success) {
 | 
						|
        FreeResource(pFence->sync.id, X11_RESTYPE_NONE);
 | 
						|
        return status;
 | 
						|
    }
 | 
						|
 | 
						|
    return Success;
 | 
						|
#else
 | 
						|
    return BadImplementation;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
SyncFDFromFence(ClientPtr client, DrawablePtr pDraw, SyncFence *pFence)
 | 
						|
{
 | 
						|
#ifdef HAVE_XSHMFENCE
 | 
						|
    return miSyncFDFromFence(pDraw, pFence);
 | 
						|
#else
 | 
						|
    return BadImplementation;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
static SyncCounter *
 | 
						|
SyncCreateCounter(ClientPtr client, XSyncCounter id, int64_t initialvalue)
 | 
						|
{
 | 
						|
    SyncCounter *pCounter;
 | 
						|
 | 
						|
    if (!(pCounter = (SyncCounter *) SyncCreate(client, id, SYNC_COUNTER)))
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    pCounter->value = initialvalue;
 | 
						|
    pCounter->pSysCounterInfo = NULL;
 | 
						|
 | 
						|
    pCounter->sync.initialized = TRUE;
 | 
						|
 | 
						|
    return pCounter;
 | 
						|
}
 | 
						|
 | 
						|
static int FreeCounter(void *, XID);
 | 
						|
 | 
						|
/*
 | 
						|
 * ***** System Counter utilities
 | 
						|
 */
 | 
						|
 | 
						|
SyncCounter*
 | 
						|
SyncCreateSystemCounter(const char *name,
 | 
						|
                        int64_t initial,
 | 
						|
                        int64_t resolution,
 | 
						|
                        SyncCounterType counterType,
 | 
						|
                        SyncSystemCounterQueryValue QueryValue,
 | 
						|
                        SyncSystemCounterBracketValues BracketValues
 | 
						|
    )
 | 
						|
{
 | 
						|
    SyncCounter *pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial);
 | 
						|
 | 
						|
    if (pCounter) {
 | 
						|
        SysCounterInfo *psci;
 | 
						|
 | 
						|
        psci = malloc(sizeof(SysCounterInfo));
 | 
						|
        if (!psci) {
 | 
						|
            FreeResource(pCounter->sync.id, X11_RESTYPE_NONE);
 | 
						|
            return pCounter;
 | 
						|
        }
 | 
						|
        pCounter->pSysCounterInfo = psci;
 | 
						|
        psci->pCounter = pCounter;
 | 
						|
        psci->name = strdup(name);
 | 
						|
        psci->resolution = resolution;
 | 
						|
        psci->counterType = counterType;
 | 
						|
        psci->QueryValue = QueryValue;
 | 
						|
        psci->BracketValues = BracketValues;
 | 
						|
        psci->private = NULL;
 | 
						|
        psci->bracket_greater = LLONG_MAX;
 | 
						|
        psci->bracket_less = LLONG_MIN;
 | 
						|
        xorg_list_add(&psci->entry, &SysCounterList);
 | 
						|
    }
 | 
						|
    return pCounter;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
SyncDestroySystemCounter(void *pSysCounter)
 | 
						|
{
 | 
						|
    SyncCounter *pCounter = (SyncCounter *) pSysCounter;
 | 
						|
 | 
						|
    FreeResource(pCounter->sync.id, X11_RESTYPE_NONE);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
SyncComputeBracketValues(SyncCounter * pCounter)
 | 
						|
{
 | 
						|
    SyncTriggerList *pCur;
 | 
						|
    SyncTrigger *pTrigger;
 | 
						|
    SysCounterInfo *psci;
 | 
						|
    int64_t *pnewgtval = NULL;
 | 
						|
    int64_t *pnewltval = NULL;
 | 
						|
    SyncCounterType ct;
 | 
						|
 | 
						|
    if (!pCounter)
 | 
						|
        return;
 | 
						|
 | 
						|
    psci = pCounter->pSysCounterInfo;
 | 
						|
    ct = pCounter->pSysCounterInfo->counterType;
 | 
						|
    if (ct == XSyncCounterNeverChanges)
 | 
						|
        return;
 | 
						|
 | 
						|
    psci->bracket_greater = LLONG_MAX;
 | 
						|
    psci->bracket_less = LLONG_MIN;
 | 
						|
 | 
						|
    for (pCur = pCounter->sync.pTriglist; pCur; pCur = pCur->next) {
 | 
						|
        pTrigger = pCur->pTrigger;
 | 
						|
 | 
						|
        if (pTrigger->test_type == XSyncPositiveComparison &&
 | 
						|
            ct != XSyncCounterNeverIncreases) {
 | 
						|
            if (pCounter->value < pTrigger->test_value &&
 | 
						|
                pTrigger->test_value < psci->bracket_greater) {
 | 
						|
                psci->bracket_greater = pTrigger->test_value;
 | 
						|
                pnewgtval = &psci->bracket_greater;
 | 
						|
            }
 | 
						|
            else if (pCounter->value > pTrigger->test_value &&
 | 
						|
                     pTrigger->test_value > psci->bracket_less) {
 | 
						|
                    psci->bracket_less = pTrigger->test_value;
 | 
						|
                    pnewltval = &psci->bracket_less;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else if (pTrigger->test_type == XSyncNegativeComparison &&
 | 
						|
                 ct != XSyncCounterNeverDecreases) {
 | 
						|
            if (pCounter->value > pTrigger->test_value &&
 | 
						|
                pTrigger->test_value > psci->bracket_less) {
 | 
						|
                psci->bracket_less = pTrigger->test_value;
 | 
						|
                pnewltval = &psci->bracket_less;
 | 
						|
            }
 | 
						|
            else if (pCounter->value < pTrigger->test_value &&
 | 
						|
                     pTrigger->test_value < psci->bracket_greater) {
 | 
						|
                    psci->bracket_greater = pTrigger->test_value;
 | 
						|
                    pnewgtval = &psci->bracket_greater;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else if (pTrigger->test_type == XSyncNegativeTransition &&
 | 
						|
                 ct != XSyncCounterNeverIncreases) {
 | 
						|
            if (pCounter->value >= pTrigger->test_value &&
 | 
						|
                pTrigger->test_value > psci->bracket_less) {
 | 
						|
                    /*
 | 
						|
                     * If 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;
 | 
						|
            }
 | 
						|
            else if (pCounter->value < pTrigger->test_value &&
 | 
						|
                     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 (pCounter->value <= pTrigger->test_value &&
 | 
						|
                pTrigger->test_value < psci->bracket_greater) {
 | 
						|
                    /*
 | 
						|
                     * If 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 (pCounter->value > pTrigger->test_value &&
 | 
						|
                     pTrigger->test_value > psci->bracket_less) {
 | 
						|
                    psci->bracket_less = pTrigger->test_value;
 | 
						|
                    pnewltval = &psci->bracket_less;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }                           /* end for each trigger */
 | 
						|
 | 
						|
    (*psci->BracketValues) ((void *) 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, X11_RESTYPE_NONE);
 | 
						|
 | 
						|
    SyncDeleteTriggerFromSyncObject(&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;
 | 
						|
 | 
						|
    pCounter->sync.beingDestroyed = TRUE;
 | 
						|
 | 
						|
    if (pCounter->sync.initialized) {
 | 
						|
        SyncTriggerList *ptl, *pnext;
 | 
						|
 | 
						|
        /* tell all the counter's triggers that counter has been destroyed */
 | 
						|
        for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) {
 | 
						|
            (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger);
 | 
						|
            pnext = ptl->next;
 | 
						|
            free(ptl); /* destroy the trigger list as we go */
 | 
						|
        }
 | 
						|
        if (IsSystemCounter(pCounter)) {
 | 
						|
            xorg_list_del(&pCounter->pSysCounterInfo->entry);
 | 
						|
            free(pCounter->pSysCounterInfo->name);
 | 
						|
            free(pCounter->pSysCounterInfo->private);
 | 
						|
            free(pCounter->pSysCounterInfo);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    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.
 | 
						|
         */
 | 
						|
        SyncObject *pSync = pAwait->trigger.pSync;
 | 
						|
 | 
						|
        if (pSync && !pSync->beingDestroyed)
 | 
						|
            SyncDeleteTriggerFromSyncObject(&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 = {
 | 
						|
        .type = X_Reply,
 | 
						|
        .sequenceNumber = client->sequence,
 | 
						|
        .length = 0,
 | 
						|
        .majorVersion = SERVER_SYNC_MAJOR_VERSION,
 | 
						|
        .minorVersion = SERVER_SYNC_MINOR_VERSION,
 | 
						|
    };
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xSyncInitializeReq);
 | 
						|
 | 
						|
    if (client->swapped) {
 | 
						|
        swaps(&rep.sequenceNumber);
 | 
						|
    }
 | 
						|
    WriteToClient(client, sizeof(rep), &rep);
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * ** Get list of system counters available through the extension
 | 
						|
 */
 | 
						|
static int
 | 
						|
ProcSyncListSystemCounters(ClientPtr client)
 | 
						|
{
 | 
						|
    xSyncListSystemCountersReply rep = {
 | 
						|
        .type = X_Reply,
 | 
						|
        .sequenceNumber = client->sequence,
 | 
						|
        .nCounters = 0,
 | 
						|
    };
 | 
						|
    SysCounterInfo *psci;
 | 
						|
    int len = 0;
 | 
						|
    xSyncSystemCounter *list = NULL, *walklist = NULL;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
 | 
						|
 | 
						|
    xorg_list_for_each_entry(psci, &SysCounterList, entry) {
 | 
						|
        /* pad to 4 byte boundary */
 | 
						|
        len += pad_to_int32(sz_xSyncSystemCounter + strlen(psci->name));
 | 
						|
        ++rep.nCounters;
 | 
						|
    }
 | 
						|
 | 
						|
    if (len) {
 | 
						|
        walklist = list = malloc(len);
 | 
						|
        if (!list)
 | 
						|
            return BadAlloc;
 | 
						|
    }
 | 
						|
 | 
						|
    rep.length = bytes_to_int32(len);
 | 
						|
 | 
						|
    if (client->swapped) {
 | 
						|
        swaps(&rep.sequenceNumber);
 | 
						|
        swapl(&rep.length);
 | 
						|
        swapl(&rep.nCounters);
 | 
						|
    }
 | 
						|
 | 
						|
    xorg_list_for_each_entry(psci, &SysCounterList, entry) {
 | 
						|
        int namelen;
 | 
						|
        char *pname_in_reply;
 | 
						|
 | 
						|
        walklist->counter = psci->pCounter->sync.id;
 | 
						|
        walklist->resolution_hi = psci->resolution >> 32;
 | 
						|
        walklist->resolution_lo = psci->resolution;
 | 
						|
        namelen = strlen(psci->name);
 | 
						|
        walklist->name_length = namelen;
 | 
						|
 | 
						|
        if (client->swapped) {
 | 
						|
            swapl(&walklist->counter);
 | 
						|
            swapl(&walklist->resolution_hi);
 | 
						|
            swapl(&walklist->resolution_lo);
 | 
						|
            swaps(&walklist->name_length);
 | 
						|
        }
 | 
						|
 | 
						|
        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), &rep);
 | 
						|
    if (len) {
 | 
						|
        WriteToClient(client, len, 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 = (xSyncGetPriorityReply) {
 | 
						|
        .type = X_Reply,
 | 
						|
        .sequenceNumber = client->sequence,
 | 
						|
        .length = 0,
 | 
						|
        .priority = priorityclient->priority
 | 
						|
    };
 | 
						|
 | 
						|
    if (client->swapped) {
 | 
						|
        swaps(&rep.sequenceNumber);
 | 
						|
        swapl(&rep.priority);
 | 
						|
    }
 | 
						|
 | 
						|
    WriteToClient(client, sizeof(xSyncGetPriorityReply), &rep);
 | 
						|
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * ** Create a new counter
 | 
						|
 */
 | 
						|
static int
 | 
						|
ProcSyncCreateCounter(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncCreateCounterReq);
 | 
						|
    int64_t initial;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
 | 
						|
 | 
						|
    LEGAL_NEW_RESOURCE(stuff->cid, client);
 | 
						|
 | 
						|
    initial = ((int64_t)stuff->initial_value_hi << 32) | stuff->initial_value_lo;
 | 
						|
 | 
						|
    if (!SyncCreateCounter(client, stuff->cid, initial))
 | 
						|
        return BadAlloc;
 | 
						|
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * ** Set Counter value
 | 
						|
 */
 | 
						|
static int
 | 
						|
ProcSyncSetCounter(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncSetCounterReq);
 | 
						|
    SyncCounter *pCounter;
 | 
						|
    int64_t newvalue;
 | 
						|
    int rc;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xSyncSetCounterReq);
 | 
						|
 | 
						|
    rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter,
 | 
						|
                                 client, DixWriteAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    if (IsSystemCounter(pCounter)) {
 | 
						|
        client->errorValue = stuff->cid;
 | 
						|
        return BadAccess;
 | 
						|
    }
 | 
						|
 | 
						|
    newvalue = ((int64_t)stuff->value_hi << 32) | stuff->value_lo;
 | 
						|
    SyncChangeCounter(pCounter, newvalue);
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * ** Change Counter value
 | 
						|
 */
 | 
						|
static int
 | 
						|
ProcSyncChangeCounter(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncChangeCounterReq);
 | 
						|
    SyncCounter *pCounter;
 | 
						|
    int64_t newvalue;
 | 
						|
    Bool overflow;
 | 
						|
    int rc;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
 | 
						|
 | 
						|
    rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter,
 | 
						|
                                 client, DixWriteAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    if (IsSystemCounter(pCounter)) {
 | 
						|
        client->errorValue = stuff->cid;
 | 
						|
        return BadAccess;
 | 
						|
    }
 | 
						|
 | 
						|
    newvalue = (int64_t)stuff->value_hi << 32 | stuff->value_lo;
 | 
						|
    overflow = checked_int64_add(&newvalue, newvalue, pCounter->value);
 | 
						|
    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((void **) &pCounter, stuff->counter,
 | 
						|
                                 RTCounter, client, DixDestroyAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    if (IsSystemCounter(pCounter)) {
 | 
						|
        client->errorValue = stuff->counter;
 | 
						|
        return BadAccess;
 | 
						|
    }
 | 
						|
    FreeResource(pCounter->sync.id, X11_RESTYPE_NONE);
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static SyncAwaitUnion *
 | 
						|
SyncAwaitPrologue(ClientPtr client, int items)
 | 
						|
{
 | 
						|
    SyncAwaitUnion *pAwaitUnion;
 | 
						|
 | 
						|
    /*  all the memory for the entire await list is allocated
 | 
						|
     *  here in one chunk
 | 
						|
     */
 | 
						|
    pAwaitUnion = xallocarray(items + 1, sizeof(SyncAwaitUnion));
 | 
						|
    if (!pAwaitUnion)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    /* first item is the header, remainder are real wait conditions */
 | 
						|
 | 
						|
    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);
 | 
						|
 | 
						|
    /* see if any of the triggers are already true */
 | 
						|
 | 
						|
    pAwait = &(pAwaitUnion + 1)->await; /* skip over header */
 | 
						|
    for (i = 0; i < items; i++, pAwait++) {
 | 
						|
        int64_t value;
 | 
						|
 | 
						|
        /*  don't have to worry about NULL counters because the request
 | 
						|
         *  errors before we get here out if they occur
 | 
						|
         */
 | 
						|
        switch (pAwait->trigger.pSync->type) {
 | 
						|
        case SYNC_COUNTER:
 | 
						|
            value = ((SyncCounter *) pAwait->trigger.pSync)->value;
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            value = 0;
 | 
						|
        }
 | 
						|
 | 
						|
        if ((*pAwait->trigger.CheckTrigger) (&pAwait->trigger, value)) {
 | 
						|
            (*pAwait->trigger.TriggerFired) (&pAwait->trigger);
 | 
						|
            break;              /* once is enough */
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * ** 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;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
 | 
						|
        return BadAlloc;
 | 
						|
 | 
						|
    /* don't need to do any more memory allocation for this request! */
 | 
						|
 | 
						|
    pProtocolWaitConds = (xSyncWaitCondition *) &stuff[1];
 | 
						|
 | 
						|
    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 sync objects
 | 
						|
             */
 | 
						|
            FreeResource(pAwaitUnion->header.delete_id, X11_RESTYPE_NONE);
 | 
						|
            client->errorValue = pProtocolWaitConds->counter;
 | 
						|
            return SyncErrorBase + XSyncBadCounter;
 | 
						|
        }
 | 
						|
 | 
						|
        /* sanity checks are in SyncInitTrigger */
 | 
						|
        pAwait->trigger.pSync = NULL;
 | 
						|
        pAwait->trigger.value_type = pProtocolWaitConds->value_type;
 | 
						|
        pAwait->trigger.wait_value =
 | 
						|
            ((int64_t)pProtocolWaitConds->wait_value_hi << 32) |
 | 
						|
            pProtocolWaitConds->wait_value_lo;
 | 
						|
        pAwait->trigger.test_type = pProtocolWaitConds->test_type;
 | 
						|
 | 
						|
        status = SyncInitTrigger(client, &pAwait->trigger,
 | 
						|
                                 pProtocolWaitConds->counter, RTCounter,
 | 
						|
                                 XSyncCAAllTrigger);
 | 
						|
        if (status != Success) {
 | 
						|
            /*  this should take care of removing any triggers created by
 | 
						|
             *  this request that have already been registered on sync objects
 | 
						|
             */
 | 
						|
            FreeResource(pAwaitUnion->header.delete_id, X11_RESTYPE_NONE);
 | 
						|
            return status;
 | 
						|
        }
 | 
						|
        /* this is not a mistake -- same function works for both cases */
 | 
						|
        pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
 | 
						|
        pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
 | 
						|
        pAwait->event_threshold =
 | 
						|
            ((int64_t) pProtocolWaitConds->event_threshold_hi << 32) |
 | 
						|
            pProtocolWaitConds->event_threshold_lo;
 | 
						|
 | 
						|
        pAwait->pHeader = &pAwaitUnion->header;
 | 
						|
        pAwaitUnion->header.num_waitconditions++;
 | 
						|
    }
 | 
						|
 | 
						|
    SyncAwaitEpilogue(client, items, pAwaitUnion);
 | 
						|
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * ** Query a counter
 | 
						|
 */
 | 
						|
static int
 | 
						|
ProcSyncQueryCounter(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncQueryCounterReq);
 | 
						|
    xSyncQueryCounterReply rep;
 | 
						|
    SyncCounter *pCounter;
 | 
						|
    int rc;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
 | 
						|
 | 
						|
    rc = dixLookupResourceByType((void **) &pCounter, stuff->counter,
 | 
						|
                                 RTCounter, client, DixReadAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    /* if system counter, ask it what the current value is */
 | 
						|
    if (IsSystemCounter(pCounter)) {
 | 
						|
        (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter,
 | 
						|
                                                  &pCounter->value);
 | 
						|
    }
 | 
						|
 | 
						|
    rep = (xSyncQueryCounterReply) {
 | 
						|
        .type = X_Reply,
 | 
						|
        .sequenceNumber = client->sequence,
 | 
						|
        .length = 0,
 | 
						|
        .value_hi = pCounter->value >> 32,
 | 
						|
        .value_lo = pCounter->value
 | 
						|
    };
 | 
						|
 | 
						|
    if (client->swapped) {
 | 
						|
        swaps(&rep.sequenceNumber);
 | 
						|
        swapl(&rep.length);
 | 
						|
        swapl(&rep.value_hi);
 | 
						|
        swapl(&rep.value_lo);
 | 
						|
    }
 | 
						|
    WriteToClient(client, sizeof(xSyncQueryCounterReply), &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->pSync = NULL;
 | 
						|
    pTrigger->value_type = XSyncAbsolute;
 | 
						|
    pTrigger->wait_value = 0;
 | 
						|
    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;
 | 
						|
    pAlarm->delta = 1;
 | 
						|
    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;
 | 
						|
 | 
						|
    /*  see if alarm already triggered.  NULL counter will not trigger
 | 
						|
     *  in CreateAlarm and sets alarm state to Inactive.
 | 
						|
     */
 | 
						|
 | 
						|
    if (!pTrigger->pSync) {
 | 
						|
        pAlarm->state = XSyncAlarmInactive;     /* XXX protocol change */
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        SyncCounter *pCounter;
 | 
						|
 | 
						|
        if (!SyncCheckWarnIsCounter(pTrigger->pSync,
 | 
						|
                                    WARN_INVALID_COUNTER_ALARM)) {
 | 
						|
            FreeResource(stuff->id, X11_RESTYPE_NONE);
 | 
						|
            return BadAlloc;
 | 
						|
        }
 | 
						|
 | 
						|
        pCounter = (SyncCounter *) pTrigger->pSync;
 | 
						|
 | 
						|
        if ((*pTrigger->CheckTrigger) (pTrigger, pCounter->value))
 | 
						|
            (*pTrigger->TriggerFired) (pTrigger);
 | 
						|
    }
 | 
						|
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * ** Change Alarm
 | 
						|
 */
 | 
						|
static int
 | 
						|
ProcSyncChangeAlarm(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncChangeAlarmReq);
 | 
						|
    SyncAlarm *pAlarm;
 | 
						|
    SyncCounter *pCounter = NULL;
 | 
						|
    long vmask;
 | 
						|
    int len, status;
 | 
						|
 | 
						|
    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
 | 
						|
 | 
						|
    status = dixLookupResourceByType((void **) &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;
 | 
						|
 | 
						|
    if (SyncCheckWarnIsCounter(pAlarm->trigger.pSync,
 | 
						|
                               WARN_INVALID_COUNTER_ALARM))
 | 
						|
        pCounter = (SyncCounter *) pAlarm->trigger.pSync;
 | 
						|
 | 
						|
    /*  see if alarm already triggered.  NULL counter WILL trigger
 | 
						|
     *  in ChangeAlarm.
 | 
						|
     */
 | 
						|
 | 
						|
    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((void **) &pAlarm, stuff->alarm, RTAlarm,
 | 
						|
                                 client, DixReadAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    pTrigger = &pAlarm->trigger;
 | 
						|
    rep = (xSyncQueryAlarmReply) {
 | 
						|
        .type = X_Reply,
 | 
						|
        .sequenceNumber = client->sequence,
 | 
						|
        .length =
 | 
						|
          bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply)),
 | 
						|
        .counter = (pTrigger->pSync) ? pTrigger->pSync->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.
 | 
						|
        */
 | 
						|
        .value_type = pTrigger->value_type,
 | 
						|
        .wait_value_hi = pTrigger->wait_value >> 32,
 | 
						|
        .wait_value_lo = pTrigger->wait_value,
 | 
						|
#else
 | 
						|
        .value_type = XSyncAbsolute,
 | 
						|
        .wait_value_hi = pTrigger->test_value >> 32,
 | 
						|
        .wait_value_lo = pTrigger->test_value,
 | 
						|
#endif
 | 
						|
 | 
						|
        .test_type = pTrigger->test_type,
 | 
						|
        .delta_hi = pAlarm->delta >> 32,
 | 
						|
        .delta_lo = pAlarm->delta,
 | 
						|
        .events = pAlarm->events,
 | 
						|
        .state = pAlarm->state
 | 
						|
    };
 | 
						|
 | 
						|
    if (client->swapped) {
 | 
						|
        swaps(&rep.sequenceNumber);
 | 
						|
        swapl(&rep.length);
 | 
						|
        swapl(&rep.counter);
 | 
						|
        swapl(&rep.wait_value_hi);
 | 
						|
        swapl(&rep.wait_value_lo);
 | 
						|
        swapl(&rep.test_type);
 | 
						|
        swapl(&rep.delta_hi);
 | 
						|
        swapl(&rep.delta_lo);
 | 
						|
    }
 | 
						|
 | 
						|
    WriteToClient(client, sizeof(xSyncQueryAlarmReply), &rep);
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ProcSyncDestroyAlarm(ClientPtr client)
 | 
						|
{
 | 
						|
    SyncAlarm *pAlarm;
 | 
						|
    int rc;
 | 
						|
 | 
						|
    REQUEST(xSyncDestroyAlarmReq);
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
 | 
						|
 | 
						|
    rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm,
 | 
						|
                                 client, DixDestroyAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    FreeResource(stuff->alarm, X11_RESTYPE_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);
 | 
						|
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
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((void **) 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((void **) &pFence, stuff->fid, RTFence,
 | 
						|
                                 client, DixWriteAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    miSyncTriggerFence(pFence);
 | 
						|
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ProcSyncResetFence(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncResetFenceReq);
 | 
						|
    SyncFence *pFence;
 | 
						|
    int rc;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xSyncResetFenceReq);
 | 
						|
 | 
						|
    rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence,
 | 
						|
                                 client, DixWriteAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    if (pFence->funcs.CheckTriggered(pFence) != TRUE)
 | 
						|
        return BadMatch;
 | 
						|
 | 
						|
    pFence->funcs.Reset(pFence);
 | 
						|
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ProcSyncDestroyFence(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncDestroyFenceReq);
 | 
						|
    SyncFence *pFence;
 | 
						|
    int rc;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xSyncDestroyFenceReq);
 | 
						|
 | 
						|
    rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence,
 | 
						|
                                 client, DixDestroyAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    FreeResource(stuff->fid, X11_RESTYPE_NONE);
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ProcSyncQueryFence(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncQueryFenceReq);
 | 
						|
    xSyncQueryFenceReply rep;
 | 
						|
    SyncFence *pFence;
 | 
						|
    int rc;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xSyncQueryFenceReq);
 | 
						|
 | 
						|
    rc = dixLookupResourceByType((void **) &pFence, stuff->fid,
 | 
						|
                                 RTFence, client, DixReadAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    rep = (xSyncQueryFenceReply) {
 | 
						|
        .type = X_Reply,
 | 
						|
        .sequenceNumber = client->sequence,
 | 
						|
        .length = 0,
 | 
						|
 | 
						|
        .triggered = pFence->funcs.CheckTriggered(pFence)
 | 
						|
    };
 | 
						|
 | 
						|
    if (client->swapped) {
 | 
						|
        swaps(&rep.sequenceNumber);
 | 
						|
        swapl(&rep.length);
 | 
						|
    }
 | 
						|
 | 
						|
    WriteToClient(client, sizeof(xSyncQueryFenceReply), &rep);
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ProcSyncAwaitFence(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncAwaitFenceReq);
 | 
						|
    SyncAwaitUnion *pAwaitUnion;
 | 
						|
    SyncAwait *pAwait;
 | 
						|
 | 
						|
    /* Use CARD32 rather than XSyncFence because XIDs are hard-coded to
 | 
						|
     * CARD32 in protocol definitions */
 | 
						|
    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;
 | 
						|
 | 
						|
    /* don't need to do any more memory allocation for this request! */
 | 
						|
 | 
						|
    pProtocolFences = (CARD32 *) &stuff[1];
 | 
						|
 | 
						|
    pAwait = &(pAwaitUnion + 1)->await; /* skip over header */
 | 
						|
    for (i = 0; i < items; i++, pProtocolFences++, pAwait++) {
 | 
						|
        if (*pProtocolFences == None) {
 | 
						|
            /*  this should take care of removing any triggers created by
 | 
						|
             *  this request that have already been registered on sync objects
 | 
						|
             */
 | 
						|
            FreeResource(pAwaitUnion->header.delete_id, X11_RESTYPE_NONE);
 | 
						|
            client->errorValue = *pProtocolFences;
 | 
						|
            return SyncErrorBase + XSyncBadFence;
 | 
						|
        }
 | 
						|
 | 
						|
        pAwait->trigger.pSync = NULL;
 | 
						|
        /* Provide acceptable values for these unused fields to
 | 
						|
         * satisfy SyncInitTrigger's validation logic
 | 
						|
         */
 | 
						|
        pAwait->trigger.value_type = XSyncAbsolute;
 | 
						|
        pAwait->trigger.wait_value = 0;
 | 
						|
        pAwait->trigger.test_type = 0;
 | 
						|
 | 
						|
        status = SyncInitTrigger(client, &pAwait->trigger,
 | 
						|
                                 *pProtocolFences, RTFence, XSyncCAAllTrigger);
 | 
						|
        if (status != Success) {
 | 
						|
            /*  this should take care of removing any triggers created by
 | 
						|
             *  this request that have already been registered on sync objects
 | 
						|
             */
 | 
						|
            FreeResource(pAwaitUnion->header.delete_id, X11_RESTYPE_NONE);
 | 
						|
            return status;
 | 
						|
        }
 | 
						|
        /* this is not a mistake -- same function works for both cases */
 | 
						|
        pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
 | 
						|
        pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
 | 
						|
        /* event_threshold is unused for fence syncs */
 | 
						|
        pAwait->event_threshold = 0;
 | 
						|
        pAwait->pHeader = &pAwaitUnion->header;
 | 
						|
        pAwaitUnion->header.num_waitconditions++;
 | 
						|
    }
 | 
						|
 | 
						|
    SyncAwaitEpilogue(client, items, pAwaitUnion);
 | 
						|
 | 
						|
    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);
 | 
						|
    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;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Boring Swapping stuff ...
 | 
						|
 */
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncInitialize(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncInitializeReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncInitializeReq);
 | 
						|
 | 
						|
    return ProcSyncInitialize(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncListSystemCounters(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncListSystemCountersReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
 | 
						|
 | 
						|
    return ProcSyncListSystemCounters(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncCreateCounter(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncCreateCounterReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
 | 
						|
    swapl(&stuff->cid);
 | 
						|
    swapl(&stuff->initial_value_lo);
 | 
						|
    swapl(&stuff->initial_value_hi);
 | 
						|
 | 
						|
    return ProcSyncCreateCounter(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncSetCounter(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncSetCounterReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncSetCounterReq);
 | 
						|
    swapl(&stuff->cid);
 | 
						|
    swapl(&stuff->value_lo);
 | 
						|
    swapl(&stuff->value_hi);
 | 
						|
 | 
						|
    return ProcSyncSetCounter(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncChangeCounter(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncChangeCounterReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
 | 
						|
    swapl(&stuff->cid);
 | 
						|
    swapl(&stuff->value_lo);
 | 
						|
    swapl(&stuff->value_hi);
 | 
						|
 | 
						|
    return ProcSyncChangeCounter(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncQueryCounter(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncQueryCounterReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
 | 
						|
    swapl(&stuff->counter);
 | 
						|
 | 
						|
    return ProcSyncQueryCounter(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncDestroyCounter(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncDestroyCounterReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
 | 
						|
    swapl(&stuff->counter);
 | 
						|
 | 
						|
    return ProcSyncDestroyCounter(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncAwait(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncAwaitReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
 | 
						|
    SwapRestL(stuff);
 | 
						|
 | 
						|
    return ProcSyncAwait(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncCreateAlarm(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncCreateAlarmReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
 | 
						|
    swapl(&stuff->id);
 | 
						|
    swapl(&stuff->valueMask);
 | 
						|
    SwapRestL(stuff);
 | 
						|
 | 
						|
    return ProcSyncCreateAlarm(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncChangeAlarm(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncChangeAlarmReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
 | 
						|
    swapl(&stuff->alarm);
 | 
						|
    swapl(&stuff->valueMask);
 | 
						|
    SwapRestL(stuff);
 | 
						|
    return ProcSyncChangeAlarm(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncQueryAlarm(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncQueryAlarmReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
 | 
						|
    swapl(&stuff->alarm);
 | 
						|
 | 
						|
    return ProcSyncQueryAlarm(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncDestroyAlarm(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncDestroyAlarmReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
 | 
						|
    swapl(&stuff->alarm);
 | 
						|
 | 
						|
    return ProcSyncDestroyAlarm(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncSetPriority(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncSetPriorityReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
 | 
						|
    swapl(&stuff->id);
 | 
						|
    swapl(&stuff->priority);
 | 
						|
 | 
						|
    return ProcSyncSetPriority(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncGetPriority(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncGetPriorityReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
 | 
						|
    swapl(&stuff->id);
 | 
						|
 | 
						|
    return ProcSyncGetPriority(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncCreateFence(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncCreateFenceReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncCreateFenceReq);
 | 
						|
    swapl(&stuff->d);
 | 
						|
    swapl(&stuff->fid);
 | 
						|
 | 
						|
    return ProcSyncCreateFence(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncTriggerFence(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncTriggerFenceReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncTriggerFenceReq);
 | 
						|
    swapl(&stuff->fid);
 | 
						|
 | 
						|
    return ProcSyncTriggerFence(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncResetFence(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncResetFenceReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncResetFenceReq);
 | 
						|
    swapl(&stuff->fid);
 | 
						|
 | 
						|
    return ProcSyncResetFence(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncDestroyFence(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncDestroyFenceReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncDestroyFenceReq);
 | 
						|
    swapl(&stuff->fid);
 | 
						|
 | 
						|
    return ProcSyncDestroyFence(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncQueryFence(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncQueryFenceReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_SIZE_MATCH(xSyncQueryFenceReq);
 | 
						|
    swapl(&stuff->fid);
 | 
						|
 | 
						|
    return ProcSyncQueryFence(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
SProcSyncAwaitFence(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xSyncAwaitFenceReq);
 | 
						|
    swaps(&stuff->length);
 | 
						|
    REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
 | 
						|
    SwapRestL(stuff);
 | 
						|
 | 
						|
    return ProcSyncAwaitFence(client);
 | 
						|
}
 | 
						|
 | 
						|
static int _X_COLD
 | 
						|
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;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Event Swapping
 | 
						|
 */
 | 
						|
 | 
						|
static void _X_COLD
 | 
						|
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 _X_COLD
 | 
						|
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)
 | 
						|
{
 | 
						|
    RTCounter = 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * ** Initialise the extension.
 | 
						|
 */
 | 
						|
void
 | 
						|
SyncExtensionInit(void)
 | 
						|
{
 | 
						|
    ExtensionEntry *extEntry;
 | 
						|
    int s;
 | 
						|
 | 
						|
    for (s = 0; s < screenInfo.numScreens; s++)
 | 
						|
        miSyncSetup(screenInfo.screens[s]);
 | 
						|
 | 
						|
    RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
 | 
						|
    xorg_list_init(&SysCounterList);
 | 
						|
    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);
 | 
						|
 | 
						|
    /*
 | 
						|
     * 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 void *ServertimeCounter;
 | 
						|
static int64_t Now;
 | 
						|
static int64_t *pnext_time;
 | 
						|
 | 
						|
static void GetTime(void)
 | 
						|
{
 | 
						|
    unsigned long millis = GetTimeInMillis();
 | 
						|
    unsigned long maxis = Now >> 32;
 | 
						|
 | 
						|
    if (millis < (Now & 0xffffffff))
 | 
						|
        maxis++;
 | 
						|
 | 
						|
    Now = ((int64_t)maxis << 32) | millis;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
*** Server Block Handler
 | 
						|
*** code inspired by multibuffer extension (now deprecated)
 | 
						|
 */
 | 
						|
/*ARGSUSED*/ static void
 | 
						|
ServertimeBlockHandler(void *env, void *wt)
 | 
						|
{
 | 
						|
    unsigned long timeout;
 | 
						|
 | 
						|
    if (pnext_time) {
 | 
						|
        GetTime();
 | 
						|
 | 
						|
        if (Now >= *pnext_time) {
 | 
						|
            timeout = 0;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            timeout = *pnext_time - Now;
 | 
						|
        }
 | 
						|
        AdjustWaitForDelay(wt, timeout);        /* os/utils.c */
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
*** Wakeup Handler
 | 
						|
 */
 | 
						|
/*ARGSUSED*/ static void
 | 
						|
ServertimeWakeupHandler(void *env, int rc)
 | 
						|
{
 | 
						|
    if (pnext_time) {
 | 
						|
        GetTime();
 | 
						|
 | 
						|
        if (Now >= *pnext_time) {
 | 
						|
            SyncChangeCounter(ServertimeCounter, Now);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ServertimeQueryValue(void *pCounter, int64_t *pValue_return)
 | 
						|
{
 | 
						|
    GetTime();
 | 
						|
    *pValue_return = Now;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ServertimeBracketValues(void *pCounter, int64_t *pbracket_less,
 | 
						|
                        int64_t *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)
 | 
						|
{
 | 
						|
    int64_t resolution = 4;
 | 
						|
 | 
						|
    Now = GetTimeInMillis();
 | 
						|
    ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution,
 | 
						|
                                                XSyncCounterNeverDecreases,
 | 
						|
                                                ServertimeQueryValue,
 | 
						|
                                                ServertimeBracketValues);
 | 
						|
    pnext_time = NULL;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * IDLETIME implementation
 | 
						|
 */
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    int64_t *value_less;
 | 
						|
    int64_t *value_greater;
 | 
						|
    int deviceid;
 | 
						|
} IdleCounterPriv;
 | 
						|
 | 
						|
static void
 | 
						|
IdleTimeQueryValue(void *pCounter, int64_t *pValue_return)
 | 
						|
{
 | 
						|
    int deviceid;
 | 
						|
    CARD32 idle;
 | 
						|
 | 
						|
    if (pCounter) {
 | 
						|
        SyncCounter *counter = pCounter;
 | 
						|
        IdleCounterPriv *priv = SysCounterGetPrivate(counter);
 | 
						|
        deviceid = priv->deviceid;
 | 
						|
    }
 | 
						|
    else
 | 
						|
        deviceid = XIAllDevices;
 | 
						|
    idle = GetTimeInMillis() - LastEventTime(deviceid).milliseconds;
 | 
						|
    *pValue_return = idle;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
IdleTimeBlockHandler(void *pCounter, void *wt)
 | 
						|
{
 | 
						|
    SyncCounter *counter = pCounter;
 | 
						|
    IdleCounterPriv *priv = SysCounterGetPrivate(counter);
 | 
						|
    int64_t *less = priv->value_less;
 | 
						|
    int64_t *greater = priv->value_greater;
 | 
						|
    int64_t idle, old_idle;
 | 
						|
    SyncTriggerList *list = counter->sync.pTriglist;
 | 
						|
    SyncTrigger *trig;
 | 
						|
 | 
						|
    if (!less && !greater)
 | 
						|
        return;
 | 
						|
 | 
						|
    old_idle = counter->value;
 | 
						|
    IdleTimeQueryValue(counter, &idle);
 | 
						|
    counter->value = idle;      /* push, so CheckTrigger works */
 | 
						|
 | 
						|
    /**
 | 
						|
     * There's an indefinite amount of time between ProcessInputEvents()
 | 
						|
     * where the idle time is reset and the time we actually get here. idle
 | 
						|
     * may be past the lower bracket if we dawdled with the events, so
 | 
						|
     * check for whether we did reset and bomb out of select immediately.
 | 
						|
     */
 | 
						|
    if (less && idle > *less &&
 | 
						|
        LastEventTimeWasReset(priv->deviceid)) {
 | 
						|
        AdjustWaitForDelay(wt, 0);
 | 
						|
    } else if (less && idle <= *less) {
 | 
						|
        /*
 | 
						|
         * 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 = counter->sync.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 (idle == *less)
 | 
						|
            AdjustWaitForDelay(wt, 1);
 | 
						|
    }
 | 
						|
    else if (greater) {
 | 
						|
        /*
 | 
						|
         * 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.
 | 
						|
         */
 | 
						|
 | 
						|
        if (idle < *greater) {
 | 
						|
            AdjustWaitForDelay(wt, *greater - idle);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            for (list = counter->sync.pTriglist; list;
 | 
						|
                 list = list->next) {
 | 
						|
                trig = list->pTrigger;
 | 
						|
                if (trig->CheckTrigger(trig, old_idle)) {
 | 
						|
                    AdjustWaitForDelay(wt, 0);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    counter->value = old_idle;  /* pop */
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
IdleTimeCheckBrackets(SyncCounter *counter, int64_t idle,
 | 
						|
                      int64_t *less, int64_t *greater)
 | 
						|
{
 | 
						|
    if ((greater && idle >= *greater) ||
 | 
						|
        (less && idle <= *less)) {
 | 
						|
        SyncChangeCounter(counter, idle);
 | 
						|
    }
 | 
						|
    else
 | 
						|
        SyncUpdateCounter(counter, idle);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
IdleTimeWakeupHandler(void *pCounter, int rc)
 | 
						|
{
 | 
						|
    SyncCounter *counter = pCounter;
 | 
						|
    IdleCounterPriv *priv = SysCounterGetPrivate(counter);
 | 
						|
    int64_t *less = priv->value_less;
 | 
						|
    int64_t *greater = priv->value_greater;
 | 
						|
    int64_t idle;
 | 
						|
 | 
						|
    if (!less && !greater)
 | 
						|
        return;
 | 
						|
 | 
						|
    IdleTimeQueryValue(pCounter, &idle);
 | 
						|
 | 
						|
    /*
 | 
						|
      There is no guarantee for the WakeupHandler to be called within a specific
 | 
						|
      timeframe. Idletime may go to 0, but by the time we get here, it may be
 | 
						|
      non-zero and alarms for a pos. transition on 0 won't get triggered.
 | 
						|
      https://bugs.freedesktop.org/show_bug.cgi?id=70476
 | 
						|
      */
 | 
						|
    if (LastEventTimeWasReset(priv->deviceid)) {
 | 
						|
        LastEventTimeToggleResetFlag(priv->deviceid, FALSE);
 | 
						|
        if (idle != 0) {
 | 
						|
            IdleTimeCheckBrackets(counter, 0, less, greater);
 | 
						|
            less = priv->value_less;
 | 
						|
            greater = priv->value_greater;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    IdleTimeCheckBrackets(counter, idle, less, greater);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
IdleTimeBracketValues(void *pCounter, int64_t *pbracket_less,
 | 
						|
                      int64_t *pbracket_greater)
 | 
						|
{
 | 
						|
    SyncCounter *counter = pCounter;
 | 
						|
    IdleCounterPriv *priv = SysCounterGetPrivate(counter);
 | 
						|
    int64_t *less = priv->value_less;
 | 
						|
    int64_t *greater = priv->value_greater;
 | 
						|
    Bool registered = (less || greater);
 | 
						|
 | 
						|
    if (registered && !pbracket_less && !pbracket_greater) {
 | 
						|
        RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler,
 | 
						|
                                     IdleTimeWakeupHandler, pCounter);
 | 
						|
    }
 | 
						|
    else if (!registered && (pbracket_less || pbracket_greater)) {
 | 
						|
        /* Reset flag must be zero so we don't force a idle timer reset on
 | 
						|
           the first wakeup */
 | 
						|
        LastEventTimeToggleResetAll(FALSE);
 | 
						|
        RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
 | 
						|
                                       IdleTimeWakeupHandler, pCounter);
 | 
						|
    }
 | 
						|
 | 
						|
    priv->value_greater = pbracket_greater;
 | 
						|
    priv->value_less = pbracket_less;
 | 
						|
}
 | 
						|
 | 
						|
static SyncCounter*
 | 
						|
init_system_idle_counter(const char *name, int deviceid)
 | 
						|
{
 | 
						|
    int64_t resolution = 4;
 | 
						|
    int64_t idle;
 | 
						|
    SyncCounter *idle_time_counter;
 | 
						|
 | 
						|
    IdleTimeQueryValue(NULL, &idle);
 | 
						|
 | 
						|
    idle_time_counter = SyncCreateSystemCounter(name, idle, resolution,
 | 
						|
                                                XSyncCounterUnrestricted,
 | 
						|
                                                IdleTimeQueryValue,
 | 
						|
                                                IdleTimeBracketValues);
 | 
						|
 | 
						|
    if (idle_time_counter != NULL) {
 | 
						|
        IdleCounterPriv *priv = malloc(sizeof(IdleCounterPriv));
 | 
						|
 | 
						|
        priv->value_less = priv->value_greater = NULL;
 | 
						|
        priv->deviceid = deviceid;
 | 
						|
 | 
						|
        idle_time_counter->pSysCounterInfo->private = priv;
 | 
						|
    }
 | 
						|
 | 
						|
    return idle_time_counter;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
SyncInitIdleTime(void)
 | 
						|
{
 | 
						|
    init_system_idle_counter("IDLETIME", XIAllDevices);
 | 
						|
}
 | 
						|
 | 
						|
SyncCounter*
 | 
						|
SyncInitDeviceIdleTime(DeviceIntPtr dev)
 | 
						|
{
 | 
						|
    char timer_name[64];
 | 
						|
    sprintf(timer_name, "DEVICEIDLETIME %d", dev->id);
 | 
						|
 | 
						|
    return init_system_idle_counter(timer_name, dev->id);
 | 
						|
}
 | 
						|
 | 
						|
void SyncRemoveDeviceIdleTime(SyncCounter *counter)
 | 
						|
{
 | 
						|
    /* FreeAllResources() frees all system counters before the devices are
 | 
						|
       shut down, check if there are any left before freeing the device's
 | 
						|
       counter */
 | 
						|
    if (counter && !xorg_list_is_empty(&SysCounterList))
 | 
						|
        xorg_list_del(&counter->pSysCounterInfo->entry);
 | 
						|
}
 |