2869 lines
		
	
	
		
			82 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			2869 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.
 | |
| 
 | |
| */
 | |
| 
 | |
| #include <dix-config.h>
 | |
| 
 | |
| #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 "os/bug_priv.h"
 | |
| #include "os/osdep.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;
 | |
|     }
 | |
| 
 | |
|     /* Failure is not an option, it's succeed or burst! */
 | |
|     pCur = XNFalloc(sizeof(SyncTriggerList));
 | |
| 
 | |
|     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 inline Bool
 | |
| checked_int64_add(int64_t *out, int64_t a, int64_t b)
 | |
| {
 | |
|     /* Do the potentially overflowing math as uint64_t, as signed
 | |
|      * integers in C are undefined on overflow (and the compiler may
 | |
|      * optimize out our overflow check below, otherwise)
 | |
|      */
 | |
|     int64_t result = (uint64_t)a + (uint64_t)b;
 | |
|     /* signed addition overflows if operands have the same sign, and
 | |
|      * the sign of the result doesn't match the sign of the inputs.
 | |
|      */
 | |
|     Bool overflow = (a < 0) == (b < 0) && (a < 0) != (result < 0);
 | |
| 
 | |
|     *out = result;
 | |
| 
 | |
|     return overflow;
 | |
| }
 | |
| 
 | |
| static inline Bool
 | |
| checked_int64_subtract(int64_t *out, int64_t a, int64_t b)
 | |
| {
 | |
|     int64_t result = (uint64_t)a - (uint64_t)b;
 | |
|     Bool overflow = (a < 0) != (b < 0) && (a < 0) != (result < 0);
 | |
| 
 | |
|     *out = result;
 | |
| 
 | |
|     return overflow;
 | |
| }
 | |
| 
 | |
| 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 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 & (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;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     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 & XSyncCACounter) {
 | |
|         if (pSync != pTrigger->pSync) { /* new counter for trigger */
 | |
|             SyncDeleteTriggerFromSyncObject(pTrigger);
 | |
|             pTrigger->pSync = pSync;
 | |
|             newSyncObject = TRUE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /*  we wait until we're sure there are no errors before registering
 | |
|      *  a new counter on a trigger
 | |
|      */
 | |
|     if (newSyncObject) {
 | |
|         SyncAddTriggerToSyncObject(pTrigger);
 | |
|     }
 | |
|     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 = calloc(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)
 | |
| {
 | |
|     if (client == pAlarm->client) {     /* alarm owner */
 | |
|         pAlarm->events = wantevents;
 | |
|         return Success;
 | |
|     }
 | |
| 
 | |
|     /* see if the client is already on the list (has events selected) */
 | |
| 
 | |
|     for (SyncAlarmClientList *pClients = 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 */
 | |
| 
 | |
|     SyncAlarmClientList *pClients = calloc(1, 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;
 | |
|     SyncTrigger trigger;
 | |
|     Bool select_events_changed = FALSE;
 | |
|     Bool select_events_value = FALSE;
 | |
|     int64_t delta;
 | |
| 
 | |
|     trigger = pAlarm->trigger;
 | |
|     delta = pAlarm->delta;
 | |
|     counter = trigger.pSync ? 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 */
 | |
|             trigger.value_type = *values++;
 | |
|             break;
 | |
| 
 | |
|         case XSyncCAValue:
 | |
|             mask &= ~XSyncCAValue;
 | |
|             trigger.wait_value = ((int64_t)values[0] << 32) | values[1];
 | |
|             values += 2;
 | |
|             break;
 | |
| 
 | |
|         case XSyncCATestType:
 | |
|             mask &= ~XSyncCATestType;
 | |
|             /* sanity check in SyncInitTrigger */
 | |
|             trigger.test_type = *values++;
 | |
|             break;
 | |
| 
 | |
|         case XSyncCADelta:
 | |
|             mask &= ~XSyncCADelta;
 | |
|             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;
 | |
|             }
 | |
|             select_events_value = (Bool) (*values++);
 | |
|             select_events_changed = TRUE;
 | |
|             break;
 | |
| 
 | |
|         default:
 | |
|             client->errorValue = mask;
 | |
|             return BadValue;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (select_events_changed) {
 | |
|         status = SyncEventSelectForAlarm(pAlarm, client, select_events_value);
 | |
|         if (status != Success)
 | |
|             return status;
 | |
|     }
 | |
| 
 | |
|     /* "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 ((((trigger.test_type == XSyncPositiveComparison) ||
 | |
|               (trigger.test_type == XSyncPositiveTransition))
 | |
|              && delta < 0)
 | |
|             ||
 | |
|             (((trigger.test_type == XSyncNegativeComparison) ||
 | |
|               (trigger.test_type == XSyncNegativeTransition))
 | |
|              && delta > 0)
 | |
|             ) {
 | |
|             return BadMatch;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* postpone this until now, when we're sure nothing else can go wrong */
 | |
|     pAlarm->delta = delta;
 | |
|     pAlarm->trigger = trigger;
 | |
|     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 = calloc(1, 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 = calloc(1, 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 = calloc(1, 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 the priority of the client owning given resource.
 | |
|  * If the resource ID is None then set the priority of calling client.
 | |
|  */
 | |
| static int
 | |
| ProcSyncSetPriority(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncSetPriorityReq);
 | |
|     ClientPtr priorityclient;
 | |
|     int rc;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
 | |
| 
 | |
|     if (stuff->id == None)
 | |
|         priorityclient = client;
 | |
|     else {
 | |
|         rc = dixLookupResourceOwner(&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;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Retrieve the priority of the client owning given resource.
 | |
|  * If the resource ID is None then retrieve the priority of calling client.
 | |
|  */
 | |
| 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 = dixLookupResourceOwner(&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 = calloc(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 = calloc(1, 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
 | |
| SProcSyncCreateCounter(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncCreateCounterReq);
 | |
|     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);
 | |
|     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);
 | |
|     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);
 | |
|     REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
 | |
|     swapl(&stuff->counter);
 | |
| 
 | |
|     return ProcSyncQueryCounter(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSyncDestroyCounter(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncDestroyCounterReq);
 | |
|     REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
 | |
|     swapl(&stuff->counter);
 | |
| 
 | |
|     return ProcSyncDestroyCounter(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSyncAwait(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncAwaitReq);
 | |
|     REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
 | |
|     SwapRestL(stuff);
 | |
| 
 | |
|     return ProcSyncAwait(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSyncCreateAlarm(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncCreateAlarmReq);
 | |
|     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);
 | |
|     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);
 | |
|     REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
 | |
|     swapl(&stuff->alarm);
 | |
| 
 | |
|     return ProcSyncQueryAlarm(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSyncDestroyAlarm(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncDestroyAlarmReq);
 | |
|     REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
 | |
|     swapl(&stuff->alarm);
 | |
| 
 | |
|     return ProcSyncDestroyAlarm(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSyncSetPriority(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncSetPriorityReq);
 | |
|     REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
 | |
|     swapl(&stuff->id);
 | |
|     swapl(&stuff->priority);
 | |
| 
 | |
|     return ProcSyncSetPriority(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSyncGetPriority(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncGetPriorityReq);
 | |
|     REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
 | |
|     swapl(&stuff->id);
 | |
| 
 | |
|     return ProcSyncGetPriority(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSyncCreateFence(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncCreateFenceReq);
 | |
|     REQUEST_SIZE_MATCH(xSyncCreateFenceReq);
 | |
|     swapl(&stuff->d);
 | |
|     swapl(&stuff->fid);
 | |
| 
 | |
|     return ProcSyncCreateFence(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSyncTriggerFence(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncTriggerFenceReq);
 | |
|     REQUEST_SIZE_MATCH(xSyncTriggerFenceReq);
 | |
|     swapl(&stuff->fid);
 | |
| 
 | |
|     return ProcSyncTriggerFence(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSyncResetFence(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncResetFenceReq);
 | |
|     REQUEST_SIZE_MATCH(xSyncResetFenceReq);
 | |
|     swapl(&stuff->fid);
 | |
| 
 | |
|     return ProcSyncResetFence(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSyncDestroyFence(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncDestroyFenceReq);
 | |
|     REQUEST_SIZE_MATCH(xSyncDestroyFenceReq);
 | |
|     swapl(&stuff->fid);
 | |
| 
 | |
|     return ProcSyncDestroyFence(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSyncQueryFence(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncQueryFenceReq);
 | |
|     REQUEST_SIZE_MATCH(xSyncQueryFenceReq);
 | |
|     swapl(&stuff->fid);
 | |
| 
 | |
|     return ProcSyncQueryFence(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| SProcSyncAwaitFence(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xSyncAwaitFenceReq);
 | |
|     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 ProcSyncInitialize(client);
 | |
|     case X_SyncListSystemCounters:
 | |
|         return ProcSyncListSystemCounters(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 = XIAllDevices;
 | |
|     CARD32 idle;
 | |
| 
 | |
|     if (pCounter) {
 | |
|         SyncCounter *counter = pCounter;
 | |
|         IdleCounterPriv *priv = SysCounterGetPrivate(counter);
 | |
|         if (priv)
 | |
|             deviceid = priv->deviceid;
 | |
|     }
 | |
|     idle = GetTimeInMillis() - LastEventTime(deviceid).milliseconds;
 | |
|     *pValue_return = idle;
 | |
| }
 | |
| 
 | |
| static void
 | |
| IdleTimeBlockHandler(void *pCounter, void *wt)
 | |
| {
 | |
|     SyncCounter *counter = pCounter;
 | |
|     IdleCounterPriv *priv = SysCounterGetPrivate(counter);
 | |
|     if (!priv)
 | |
|         return;
 | |
|     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);
 | |
|     if (!priv)
 | |
|         return;
 | |
|     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);
 | |
|     if (!priv)
 | |
|         return;
 | |
|     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);
 | |
| 
 | |
|     IdleCounterPriv *priv = calloc(1, sizeof(IdleCounterPriv));
 | |
|     if (!priv)
 | |
|         return NULL;
 | |
| 
 | |
|     idle_time_counter = SyncCreateSystemCounter(name, idle, resolution,
 | |
|                                                 XSyncCounterUnrestricted,
 | |
|                                                 IdleTimeQueryValue,
 | |
|                                                 IdleTimeBracketValues);
 | |
| 
 | |
|     if (!idle_time_counter) {
 | |
|         free(priv);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     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);
 | |
| }
 |