105b261ecSmrg/* 205b261ecSmrg 305b261ecSmrgCopyright 1991, 1993, 1998 The Open Group 405b261ecSmrg 505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that 705b261ecSmrgthe above copyright notice appear in all copies and that both that 805b261ecSmrgcopyright notice and this permission notice appear in supporting 905b261ecSmrgdocumentation. 1005b261ecSmrg 1105b261ecSmrgThe above copyright notice and this permission notice shall be included 1205b261ecSmrgin all copies or substantial portions of the Software. 1305b261ecSmrg 1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1505b261ecSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1605b261ecSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1705b261ecSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 1805b261ecSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1905b261ecSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2005b261ecSmrgOTHER DEALINGS IN THE SOFTWARE. 2105b261ecSmrg 2205b261ecSmrgExcept as contained in this notice, the name of The Open Group shall 2305b261ecSmrgnot be used in advertising or otherwise to promote the sale, use or 2405b261ecSmrgother dealings in this Software without prior written authorization 2505b261ecSmrgfrom The Open Group. 2605b261ecSmrg 2705b261ecSmrgCopyright 1991, 1993 by Digital Equipment Corporation, Maynard, Massachusetts, 2805b261ecSmrgand Olivetti Research Limited, Cambridge, England. 2905b261ecSmrg 3005b261ecSmrg All Rights Reserved 3105b261ecSmrg 3205b261ecSmrgPermission to use, copy, modify, and distribute this software and its 3305b261ecSmrgdocumentation for any purpose and without fee is hereby granted, 3405b261ecSmrgprovided that the above copyright notice appear in all copies and that 3505b261ecSmrgboth that copyright notice and this permission notice appear in 364202a189Smrgsupporting documentation, and that the names of Digital or Olivetti 3705b261ecSmrgnot be used in advertising or publicity pertaining to distribution of the 3805b261ecSmrgsoftware without specific, written prior permission. Digital and Olivetti 3905b261ecSmrgmake no representations about the suitability of this software 4005b261ecSmrgfor any purpose. It is provided "as is" without express or implied warranty. 4105b261ecSmrg 4205b261ecSmrgDIGITAL AND OLIVETTI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 4305b261ecSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 4405b261ecSmrgFITNESS, IN NO EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR 4505b261ecSmrgCONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 4605b261ecSmrgUSE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 4705b261ecSmrgOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 4805b261ecSmrgPERFORMANCE OF THIS SOFTWARE. 4905b261ecSmrg 5005b261ecSmrg*/ 5105b261ecSmrg 5205b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 5305b261ecSmrg#include <dix-config.h> 5405b261ecSmrg#endif 5505b261ecSmrg 5605b261ecSmrg#include <string.h> 5705b261ecSmrg 5805b261ecSmrg#include <X11/X.h> 5905b261ecSmrg#include <X11/Xproto.h> 6005b261ecSmrg#include <X11/Xmd.h> 6165b04b38Smrg#include "scrnintstr.h" 6205b261ecSmrg#include "os.h" 6305b261ecSmrg#include "extnsionst.h" 6405b261ecSmrg#include "dixstruct.h" 6565b04b38Smrg#include "pixmapstr.h" 6605b261ecSmrg#include "resource.h" 6705b261ecSmrg#include "opaque.h" 684202a189Smrg#include <X11/extensions/syncproto.h> 694202a189Smrg#include "syncsrv.h" 7065b04b38Smrg#include "syncsdk.h" 711b684552Smrg#include "protocol-versions.h" 72f7df2e56Smrg#include "inputstr.h" 7305b261ecSmrg 7405b261ecSmrg#include <stdio.h> 75637ac9abSmrg#if !defined(WIN32) 7605b261ecSmrg#include <sys/time.h> 7705b261ecSmrg#endif 7805b261ecSmrg 79f7df2e56Smrg#include "extinit.h" 8005b261ecSmrg 8105b261ecSmrg/* 8205b261ecSmrg * Local Global Variables 8305b261ecSmrg */ 84f7df2e56Smrgstatic int SyncEventBase; 85f7df2e56Smrgstatic int SyncErrorBase; 86f7df2e56Smrgstatic RESTYPE RTCounter = 0; 87f7df2e56Smrgstatic RESTYPE RTAwait; 88f7df2e56Smrgstatic RESTYPE RTAlarm; 89f7df2e56Smrgstatic RESTYPE RTAlarmClient; 90f7df2e56Smrgstatic RESTYPE RTFence; 91f7df2e56Smrgstatic struct xorg_list SysCounterList; 9265b04b38Smrgstatic int SyncNumInvalidCounterWarnings = 0; 93f7df2e56Smrg 9465b04b38Smrg#define MAX_INVALID_COUNTER_WARNINGS 5 9565b04b38Smrg 9665b04b38Smrgstatic const char *WARN_INVALID_COUNTER_COMPARE = 97f7df2e56Smrg "Warning: Non-counter XSync object using Counter-only\n" 98f7df2e56Smrg " comparison. Result will never be true.\n"; 9965b04b38Smrg 10065b04b38Smrgstatic const char *WARN_INVALID_COUNTER_ALARM = 101f7df2e56Smrg "Warning: Non-counter XSync object used in alarm. This is\n" 102f7df2e56Smrg " the result of a programming error in the X server.\n"; 10305b261ecSmrg 10405b261ecSmrg#define IsSystemCounter(pCounter) \ 10565b04b38Smrg (pCounter && (pCounter->sync.client == NULL)) 10605b261ecSmrg 10705b261ecSmrg/* these are all the alarm attributes that pertain to the alarm's trigger */ 10805b261ecSmrg#define XSyncCAAllTrigger \ 10905b261ecSmrg (XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType) 11005b261ecSmrg 1114202a189Smrgstatic void SyncComputeBracketValues(SyncCounter *); 11205b261ecSmrg 1134202a189Smrgstatic void SyncInitServerTime(void); 11405b261ecSmrg 1154202a189Smrgstatic void SyncInitIdleTime(void); 11605b261ecSmrg 117f7df2e56Smrgstatic inline void* 118f7df2e56SmrgSysCounterGetPrivate(SyncCounter *counter) 119f7df2e56Smrg{ 120f7df2e56Smrg BUG_WARN(!IsSystemCounter(counter)); 121f7df2e56Smrg 122f7df2e56Smrg return counter->pSysCounterInfo ? counter->pSysCounterInfo->private : NULL; 123f7df2e56Smrg} 124f7df2e56Smrg 12565b04b38Smrgstatic Bool 126f7df2e56SmrgSyncCheckWarnIsCounter(const SyncObject * pSync, const char *warning) 12765b04b38Smrg{ 128f7df2e56Smrg if (pSync && (SYNC_COUNTER != pSync->type)) { 129f7df2e56Smrg if (SyncNumInvalidCounterWarnings++ < MAX_INVALID_COUNTER_WARNINGS) { 130f7df2e56Smrg ErrorF("%s", warning); 131f7df2e56Smrg ErrorF(" Counter type: %d\n", pSync->type); 132f7df2e56Smrg } 13365b04b38Smrg 134f7df2e56Smrg return FALSE; 13565b04b38Smrg } 13665b04b38Smrg 13765b04b38Smrg return TRUE; 13865b04b38Smrg} 13905b261ecSmrg 14005b261ecSmrg/* Each counter maintains a simple linked list of triggers that are 14105b261ecSmrg * interested in the counter. The two functions below are used to 14205b261ecSmrg * delete and add triggers on this list. 14305b261ecSmrg */ 144f7df2e56Smrgvoid 145f7df2e56SmrgSyncDeleteTriggerFromSyncObject(SyncTrigger * pTrigger) 14605b261ecSmrg{ 14705b261ecSmrg SyncTriggerList *pCur; 14805b261ecSmrg SyncTriggerList *pPrev; 14965b04b38Smrg SyncCounter *pCounter; 15005b261ecSmrg 15165b04b38Smrg /* pSync needs to be stored in pTrigger before calling here. */ 15205b261ecSmrg 15365b04b38Smrg if (!pTrigger->pSync) 154f7df2e56Smrg return; 15505b261ecSmrg 15605b261ecSmrg pPrev = NULL; 15765b04b38Smrg pCur = pTrigger->pSync->pTriglist; 15805b261ecSmrg 159f7df2e56Smrg while (pCur) { 160f7df2e56Smrg if (pCur->pTrigger == pTrigger) { 161f7df2e56Smrg if (pPrev) 162f7df2e56Smrg pPrev->next = pCur->next; 163f7df2e56Smrg else 164f7df2e56Smrg pTrigger->pSync->pTriglist = pCur->next; 165f7df2e56Smrg 166f7df2e56Smrg free(pCur); 167f7df2e56Smrg break; 168f7df2e56Smrg } 1694202a189Smrg 170f7df2e56Smrg pPrev = pCur; 171f7df2e56Smrg pCur = pCur->next; 17205b261ecSmrg } 1734202a189Smrg 174f7df2e56Smrg if (SYNC_COUNTER == pTrigger->pSync->type) { 175f7df2e56Smrg pCounter = (SyncCounter *) pTrigger->pSync; 17665b04b38Smrg 177f7df2e56Smrg if (IsSystemCounter(pCounter)) 178f7df2e56Smrg SyncComputeBracketValues(pCounter); 17965b04b38Smrg } 180f7df2e56Smrg else if (SYNC_FENCE == pTrigger->pSync->type) { 181f7df2e56Smrg SyncFence *pFence = (SyncFence *) pTrigger->pSync; 18205b261ecSmrg 183f7df2e56Smrg pFence->funcs.DeleteTrigger(pTrigger); 184f7df2e56Smrg } 185f7df2e56Smrg} 18605b261ecSmrg 187f7df2e56Smrgint 188f7df2e56SmrgSyncAddTriggerToSyncObject(SyncTrigger * pTrigger) 18905b261ecSmrg{ 19005b261ecSmrg SyncTriggerList *pCur; 19165b04b38Smrg SyncCounter *pCounter; 19205b261ecSmrg 19365b04b38Smrg if (!pTrigger->pSync) 194f7df2e56Smrg return Success; 19505b261ecSmrg 19605b261ecSmrg /* don't do anything if it's already there */ 197f7df2e56Smrg for (pCur = pTrigger->pSync->pTriglist; pCur; pCur = pCur->next) { 198f7df2e56Smrg if (pCur->pTrigger == pTrigger) 199f7df2e56Smrg return Success; 20005b261ecSmrg } 20105b261ecSmrg 202d566a54bSmrg /* Failure is not an option, it's succeed or burst! */ 203d566a54bSmrg pCur = XNFalloc(sizeof(SyncTriggerList)); 20405b261ecSmrg 20505b261ecSmrg pCur->pTrigger = pTrigger; 20665b04b38Smrg pCur->next = pTrigger->pSync->pTriglist; 20765b04b38Smrg pTrigger->pSync->pTriglist = pCur; 20805b261ecSmrg 209f7df2e56Smrg if (SYNC_COUNTER == pTrigger->pSync->type) { 210f7df2e56Smrg pCounter = (SyncCounter *) pTrigger->pSync; 21165b04b38Smrg 212f7df2e56Smrg if (IsSystemCounter(pCounter)) 213f7df2e56Smrg SyncComputeBracketValues(pCounter); 214f7df2e56Smrg } 215f7df2e56Smrg else if (SYNC_FENCE == pTrigger->pSync->type) { 216f7df2e56Smrg SyncFence *pFence = (SyncFence *) pTrigger->pSync; 217f7df2e56Smrg 218f7df2e56Smrg pFence->funcs.AddTrigger(pTrigger); 21965b04b38Smrg } 22005b261ecSmrg 22105b261ecSmrg return Success; 22205b261ecSmrg} 22305b261ecSmrg 22465b04b38Smrg/* Below are five possible functions that can be plugged into 22565b04b38Smrg * pTrigger->CheckTrigger for counter sync objects, corresponding to 22665b04b38Smrg * the four possible test-types, and the one possible function that 22765b04b38Smrg * can be plugged into pTrigger->CheckTrigger for fence sync objects. 22865b04b38Smrg * These functions are called after the sync object's state changes 22965b04b38Smrg * but are also passed the old state so they can inspect both the old 23065b04b38Smrg * and new values. (PositiveTransition and NegativeTransition need to 23165b04b38Smrg * see both pieces of information.) These functions return the truth 23265b04b38Smrg * value of the trigger. 23305b261ecSmrg * 23465b04b38Smrg * All of them include the condition pTrigger->pSync == NULL. 23565b04b38Smrg * This is because the spec says that a trigger with a sync value 23605b261ecSmrg * of None is always TRUE. 23705b261ecSmrg */ 23805b261ecSmrg 23905b261ecSmrgstatic Bool 2407e31ba66SmrgSyncCheckTriggerPositiveComparison(SyncTrigger * pTrigger, int64_t oldval) 24105b261ecSmrg{ 24265b04b38Smrg SyncCounter *pCounter; 24365b04b38Smrg 24465b04b38Smrg /* Non-counter sync objects should never get here because they 24565b04b38Smrg * never trigger this comparison. */ 24665b04b38Smrg if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE)) 247f7df2e56Smrg return FALSE; 24865b04b38Smrg 249f7df2e56Smrg pCounter = (SyncCounter *) pTrigger->pSync; 25065b04b38Smrg 2517e31ba66Smrg return pCounter == NULL || pCounter->value >= pTrigger->test_value; 25205b261ecSmrg} 25305b261ecSmrg 25405b261ecSmrgstatic Bool 2557e31ba66SmrgSyncCheckTriggerNegativeComparison(SyncTrigger * pTrigger, int64_t oldval) 25605b261ecSmrg{ 25765b04b38Smrg SyncCounter *pCounter; 25865b04b38Smrg 25965b04b38Smrg /* Non-counter sync objects should never get here because they 26065b04b38Smrg * never trigger this comparison. */ 26165b04b38Smrg if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE)) 262f7df2e56Smrg return FALSE; 26365b04b38Smrg 264f7df2e56Smrg pCounter = (SyncCounter *) pTrigger->pSync; 26565b04b38Smrg 2667e31ba66Smrg return pCounter == NULL || pCounter->value <= pTrigger->test_value; 26705b261ecSmrg} 26805b261ecSmrg 26905b261ecSmrgstatic Bool 2707e31ba66SmrgSyncCheckTriggerPositiveTransition(SyncTrigger * pTrigger, int64_t oldval) 27105b261ecSmrg{ 27265b04b38Smrg SyncCounter *pCounter; 27365b04b38Smrg 27465b04b38Smrg /* Non-counter sync objects should never get here because they 27565b04b38Smrg * never trigger this comparison. */ 27665b04b38Smrg if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE)) 277f7df2e56Smrg return FALSE; 27865b04b38Smrg 279f7df2e56Smrg pCounter = (SyncCounter *) pTrigger->pSync; 28065b04b38Smrg 28165b04b38Smrg return (pCounter == NULL || 2827e31ba66Smrg (oldval < pTrigger->test_value && 2837e31ba66Smrg pCounter->value >= pTrigger->test_value)); 28405b261ecSmrg} 28505b261ecSmrg 28605b261ecSmrgstatic Bool 2877e31ba66SmrgSyncCheckTriggerNegativeTransition(SyncTrigger * pTrigger, int64_t oldval) 28805b261ecSmrg{ 28965b04b38Smrg SyncCounter *pCounter; 29065b04b38Smrg 29165b04b38Smrg /* Non-counter sync objects should never get here because they 29265b04b38Smrg * never trigger this comparison. */ 29365b04b38Smrg if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE)) 294f7df2e56Smrg return FALSE; 29565b04b38Smrg 296f7df2e56Smrg pCounter = (SyncCounter *) pTrigger->pSync; 29765b04b38Smrg 29865b04b38Smrg return (pCounter == NULL || 2997e31ba66Smrg (oldval > pTrigger->test_value && 3007e31ba66Smrg pCounter->value <= pTrigger->test_value)); 30165b04b38Smrg} 30265b04b38Smrg 30365b04b38Smrgstatic Bool 3047e31ba66SmrgSyncCheckTriggerFence(SyncTrigger * pTrigger, int64_t unused) 30565b04b38Smrg{ 306f7df2e56Smrg SyncFence *pFence = (SyncFence *) pTrigger->pSync; 307f7df2e56Smrg 308f7df2e56Smrg (void) unused; 30965b04b38Smrg 310f7df2e56Smrg return (pFence == NULL || pFence->funcs.CheckTriggered(pFence)); 31105b261ecSmrg} 31205b261ecSmrg 3134202a189Smrgstatic int 314f7df2e56SmrgSyncInitTrigger(ClientPtr client, SyncTrigger * pTrigger, XID syncObject, 315f7df2e56Smrg RESTYPE resType, Mask changes) 31605b261ecSmrg{ 31765b04b38Smrg SyncObject *pSync = pTrigger->pSync; 31865b04b38Smrg SyncCounter *pCounter = NULL; 319f7df2e56Smrg int rc; 320f7df2e56Smrg Bool newSyncObject = FALSE; 321f7df2e56Smrg 322f7df2e56Smrg if (changes & XSyncCACounter) { 323f7df2e56Smrg if (syncObject == None) 324f7df2e56Smrg pSync = NULL; 325f7df2e56Smrg else if (Success != (rc = dixLookupResourceByType((void **) &pSync, 326f7df2e56Smrg syncObject, resType, 327f7df2e56Smrg client, 328f7df2e56Smrg DixReadAccess))) { 329f7df2e56Smrg client->errorValue = syncObject; 330f7df2e56Smrg return rc; 331f7df2e56Smrg } 33205b261ecSmrg } 33305b261ecSmrg 33405b261ecSmrg /* if system counter, ask it what the current value is */ 33505b261ecSmrg 336f7df2e56Smrg if (pSync && SYNC_COUNTER == pSync->type) { 337f7df2e56Smrg pCounter = (SyncCounter *) pSync; 338f7df2e56Smrg 339f7df2e56Smrg if (IsSystemCounter(pCounter)) { 340f7df2e56Smrg (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter, 341f7df2e56Smrg &pCounter->value); 342f7df2e56Smrg } 343f7df2e56Smrg } 344f7df2e56Smrg 345f7df2e56Smrg if (changes & XSyncCAValueType) { 346f7df2e56Smrg if (pTrigger->value_type != XSyncRelative && 347f7df2e56Smrg pTrigger->value_type != XSyncAbsolute) { 348f7df2e56Smrg client->errorValue = pTrigger->value_type; 349f7df2e56Smrg return BadValue; 350f7df2e56Smrg } 351f7df2e56Smrg } 352f7df2e56Smrg 353d566a54bSmrg if (changes & (XSyncCAValueType | XSyncCAValue)) { 354d566a54bSmrg if (pTrigger->value_type == XSyncAbsolute) 355d566a54bSmrg pTrigger->test_value = pTrigger->wait_value; 356d566a54bSmrg else { /* relative */ 357d566a54bSmrg Bool overflow; 358d566a54bSmrg 359d566a54bSmrg if (pCounter == NULL) 360d566a54bSmrg return BadMatch; 361d566a54bSmrg 362d566a54bSmrg overflow = checked_int64_add(&pTrigger->test_value, 363d566a54bSmrg pCounter->value, pTrigger->wait_value); 364d566a54bSmrg if (overflow) { 365d566a54bSmrg client->errorValue = pTrigger->wait_value >> 32; 366d566a54bSmrg return BadValue; 367d566a54bSmrg } 368d566a54bSmrg } 369d566a54bSmrg } 370d566a54bSmrg 371f7df2e56Smrg if (changes & XSyncCATestType) { 372f7df2e56Smrg 373f7df2e56Smrg if (pSync && SYNC_FENCE == pSync->type) { 374f7df2e56Smrg pTrigger->CheckTrigger = SyncCheckTriggerFence; 375f7df2e56Smrg } 376f7df2e56Smrg else { 377f7df2e56Smrg /* select appropriate CheckTrigger function */ 378f7df2e56Smrg 379f7df2e56Smrg switch (pTrigger->test_type) { 380f7df2e56Smrg case XSyncPositiveTransition: 381f7df2e56Smrg pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition; 382f7df2e56Smrg break; 383f7df2e56Smrg case XSyncNegativeTransition: 384f7df2e56Smrg pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition; 385f7df2e56Smrg break; 386f7df2e56Smrg case XSyncPositiveComparison: 387f7df2e56Smrg pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison; 388f7df2e56Smrg break; 389f7df2e56Smrg case XSyncNegativeComparison: 390f7df2e56Smrg pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison; 391f7df2e56Smrg break; 392f7df2e56Smrg default: 393f7df2e56Smrg client->errorValue = pTrigger->test_type; 394f7df2e56Smrg return BadValue; 395f7df2e56Smrg } 396f7df2e56Smrg } 397f7df2e56Smrg } 398f7df2e56Smrg 399d566a54bSmrg if (changes & XSyncCACounter) { 400d566a54bSmrg if (pSync != pTrigger->pSync) { /* new counter for trigger */ 401d566a54bSmrg SyncDeleteTriggerFromSyncObject(pTrigger); 402d566a54bSmrg pTrigger->pSync = pSync; 403d566a54bSmrg newSyncObject = TRUE; 404f7df2e56Smrg } 40505b261ecSmrg } 40605b261ecSmrg 40705b261ecSmrg /* we wait until we're sure there are no errors before registering 40805b261ecSmrg * a new counter on a trigger 40905b261ecSmrg */ 410f7df2e56Smrg if (newSyncObject) { 411d566a54bSmrg SyncAddTriggerToSyncObject(pTrigger); 41205b261ecSmrg } 413f7df2e56Smrg else if (pCounter && IsSystemCounter(pCounter)) { 414f7df2e56Smrg SyncComputeBracketValues(pCounter); 41505b261ecSmrg } 4164202a189Smrg 41705b261ecSmrg return Success; 41805b261ecSmrg} 41905b261ecSmrg 42005b261ecSmrg/* AlarmNotify events happen in response to actions taken on an Alarm or 4214202a189Smrg * the counter used by the alarm. AlarmNotify may be sent to multiple 42205b261ecSmrg * clients. The alarm maintains a list of clients interested in events. 42305b261ecSmrg */ 42405b261ecSmrgstatic void 425f7df2e56SmrgSyncSendAlarmNotifyEvents(SyncAlarm * pAlarm) 42605b261ecSmrg{ 42705b261ecSmrg SyncAlarmClientList *pcl; 42805b261ecSmrg xSyncAlarmNotifyEvent ane; 42905b261ecSmrg SyncTrigger *pTrigger = &pAlarm->trigger; 43065b04b38Smrg SyncCounter *pCounter; 43165b04b38Smrg 43265b04b38Smrg if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM)) 433f7df2e56Smrg return; 43465b04b38Smrg 435f7df2e56Smrg pCounter = (SyncCounter *) pTrigger->pSync; 43605b261ecSmrg 43705b261ecSmrg UpdateCurrentTime(); 43805b261ecSmrg 439f7df2e56Smrg ane = (xSyncAlarmNotifyEvent) { 440f7df2e56Smrg .type = SyncEventBase + XSyncAlarmNotify, 441f7df2e56Smrg .kind = XSyncAlarmNotify, 442f7df2e56Smrg .alarm = pAlarm->alarm_id, 4437e31ba66Smrg .alarm_value_hi = pTrigger->test_value >> 32, 4447e31ba66Smrg .alarm_value_lo = pTrigger->test_value, 445f7df2e56Smrg .time = currentTime.milliseconds, 446f7df2e56Smrg .state = pAlarm->state 447f7df2e56Smrg }; 448f7df2e56Smrg 449f7df2e56Smrg if (pTrigger->pSync && SYNC_COUNTER == pTrigger->pSync->type) { 4507e31ba66Smrg ane.counter_value_hi = pCounter->value >> 32; 4517e31ba66Smrg ane.counter_value_lo = pCounter->value; 45205b261ecSmrg } 453f7df2e56Smrg else { 454f7df2e56Smrg /* XXX what else can we do if there's no counter? */ 455f7df2e56Smrg ane.counter_value_hi = ane.counter_value_lo = 0; 45605b261ecSmrg } 45705b261ecSmrg 45805b261ecSmrg /* send to owner */ 4594202a189Smrg if (pAlarm->events) 460f7df2e56Smrg WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane); 46105b261ecSmrg 46205b261ecSmrg /* send to other interested clients */ 46305b261ecSmrg for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next) 464f7df2e56Smrg WriteEventsToClient(pcl->client, 1, (xEvent *) &ane); 46505b261ecSmrg} 46605b261ecSmrg 4674202a189Smrg/* CounterNotify events only occur in response to an Await. The events 46805b261ecSmrg * go only to the Awaiting client. 46905b261ecSmrg */ 47005b261ecSmrgstatic void 471f7df2e56SmrgSyncSendCounterNotifyEvents(ClientPtr client, SyncAwait ** ppAwait, 472f7df2e56Smrg int num_events) 47305b261ecSmrg{ 47405b261ecSmrg xSyncCounterNotifyEvent *pEvents, *pev; 47505b261ecSmrg int i; 47605b261ecSmrg 47705b261ecSmrg if (client->clientGone) 478f7df2e56Smrg return; 479f7df2e56Smrg pev = pEvents = calloc(num_events, sizeof(xSyncCounterNotifyEvent)); 4804202a189Smrg if (!pEvents) 481f7df2e56Smrg return; 48205b261ecSmrg UpdateCurrentTime(); 483f7df2e56Smrg for (i = 0; i < num_events; i++, ppAwait++, pev++) { 484f7df2e56Smrg SyncTrigger *pTrigger = &(*ppAwait)->trigger; 485f7df2e56Smrg 486f7df2e56Smrg pev->type = SyncEventBase + XSyncCounterNotify; 487f7df2e56Smrg pev->kind = XSyncCounterNotify; 488f7df2e56Smrg pev->counter = pTrigger->pSync->id; 4897e31ba66Smrg pev->wait_value_lo = pTrigger->test_value; 4907e31ba66Smrg pev->wait_value_hi = pTrigger->test_value >> 32; 491f7df2e56Smrg if (SYNC_COUNTER == pTrigger->pSync->type) { 492f7df2e56Smrg SyncCounter *pCounter = (SyncCounter *) pTrigger->pSync; 493f7df2e56Smrg 4947e31ba66Smrg pev->counter_value_lo = pCounter->value; 4957e31ba66Smrg pev->counter_value_hi = pCounter->value >> 32; 496f7df2e56Smrg } 497f7df2e56Smrg else { 498f7df2e56Smrg pev->counter_value_lo = 0; 499f7df2e56Smrg pev->counter_value_hi = 0; 500f7df2e56Smrg } 501f7df2e56Smrg 502f7df2e56Smrg pev->time = currentTime.milliseconds; 503f7df2e56Smrg pev->count = num_events - i - 1; /* events remaining */ 504f7df2e56Smrg pev->destroyed = pTrigger->pSync->beingDestroyed; 50505b261ecSmrg } 50605b261ecSmrg /* swapping will be taken care of by this */ 507f7df2e56Smrg WriteEventsToClient(client, num_events, (xEvent *) pEvents); 5084202a189Smrg free(pEvents); 50905b261ecSmrg} 51005b261ecSmrg 51105b261ecSmrg/* This function is called when an alarm's counter is destroyed. 51205b261ecSmrg * It is plugged into pTrigger->CounterDestroyed (for alarm triggers). 51305b261ecSmrg */ 5144202a189Smrgstatic void 515f7df2e56SmrgSyncAlarmCounterDestroyed(SyncTrigger * pTrigger) 51605b261ecSmrg{ 517f7df2e56Smrg SyncAlarm *pAlarm = (SyncAlarm *) pTrigger; 51805b261ecSmrg 51905b261ecSmrg pAlarm->state = XSyncAlarmInactive; 52005b261ecSmrg SyncSendAlarmNotifyEvents(pAlarm); 52165b04b38Smrg pTrigger->pSync = NULL; 52205b261ecSmrg} 52305b261ecSmrg 5244202a189Smrg/* This function is called when an alarm "goes off." 52505b261ecSmrg * It is plugged into pTrigger->TriggerFired (for alarm triggers). 52605b261ecSmrg */ 52705b261ecSmrgstatic void 528f7df2e56SmrgSyncAlarmTriggerFired(SyncTrigger * pTrigger) 52905b261ecSmrg{ 530f7df2e56Smrg SyncAlarm *pAlarm = (SyncAlarm *) pTrigger; 53165b04b38Smrg SyncCounter *pCounter; 5327e31ba66Smrg int64_t new_test_value; 53305b261ecSmrg 53465b04b38Smrg if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM)) 535f7df2e56Smrg return; 53665b04b38Smrg 537f7df2e56Smrg pCounter = (SyncCounter *) pTrigger->pSync; 53865b04b38Smrg 53905b261ecSmrg /* no need to check alarm unless it's active */ 54005b261ecSmrg if (pAlarm->state != XSyncAlarmActive) 541f7df2e56Smrg return; 54205b261ecSmrg 54305b261ecSmrg /* " if the counter value is None, or if the delta is 0 and 54405b261ecSmrg * the test-type is PositiveComparison or NegativeComparison, 54505b261ecSmrg * no change is made to value (test-value) and the alarm 54605b261ecSmrg * state is changed to Inactive before the event is generated." 54705b261ecSmrg */ 5487e31ba66Smrg if (pCounter == NULL || (pAlarm->delta == 0 549f7df2e56Smrg && (pAlarm->trigger.test_type == 550f7df2e56Smrg XSyncPositiveComparison || 551f7df2e56Smrg pAlarm->trigger.test_type == 552f7df2e56Smrg XSyncNegativeComparison))) 553f7df2e56Smrg pAlarm->state = XSyncAlarmInactive; 55405b261ecSmrg 55505b261ecSmrg new_test_value = pAlarm->trigger.test_value; 55605b261ecSmrg 557f7df2e56Smrg if (pAlarm->state == XSyncAlarmActive) { 558f7df2e56Smrg Bool overflow; 5597e31ba66Smrg int64_t oldvalue; 560f7df2e56Smrg SyncTrigger *paTrigger = &pAlarm->trigger; 561f7df2e56Smrg SyncCounter *paCounter; 562f7df2e56Smrg 563f7df2e56Smrg if (!SyncCheckWarnIsCounter(paTrigger->pSync, 564f7df2e56Smrg WARN_INVALID_COUNTER_ALARM)) 565f7df2e56Smrg return; 566f7df2e56Smrg 567f7df2e56Smrg paCounter = (SyncCounter *) pTrigger->pSync; 568f7df2e56Smrg 569f7df2e56Smrg /* "The alarm is updated by repeatedly adding delta to the 570f7df2e56Smrg * value of the trigger and re-initializing it until it 571f7df2e56Smrg * becomes FALSE." 572f7df2e56Smrg */ 573f7df2e56Smrg oldvalue = paTrigger->test_value; 574f7df2e56Smrg 575f7df2e56Smrg /* XXX really should do something smarter here */ 576f7df2e56Smrg 577f7df2e56Smrg do { 5787e31ba66Smrg overflow = checked_int64_add(&paTrigger->test_value, 5797e31ba66Smrg paTrigger->test_value, pAlarm->delta); 580f7df2e56Smrg } while (!overflow && 581f7df2e56Smrg (*paTrigger->CheckTrigger) (paTrigger, paCounter->value)); 582f7df2e56Smrg 583f7df2e56Smrg new_test_value = paTrigger->test_value; 584f7df2e56Smrg paTrigger->test_value = oldvalue; 585f7df2e56Smrg 586f7df2e56Smrg /* "If this update would cause value to fall outside the range 587f7df2e56Smrg * for an INT64...no change is made to value (test-value) and 588f7df2e56Smrg * the alarm state is changed to Inactive before the event is 589f7df2e56Smrg * generated." 590f7df2e56Smrg */ 591f7df2e56Smrg if (overflow) { 592f7df2e56Smrg new_test_value = oldvalue; 593f7df2e56Smrg pAlarm->state = XSyncAlarmInactive; 594f7df2e56Smrg } 59505b261ecSmrg } 59605b261ecSmrg /* The AlarmNotify event has to have the "new state of the alarm" 59705b261ecSmrg * which we can't be sure of until this point. However, it has 59805b261ecSmrg * to have the "old" trigger test value. That's the reason for 59905b261ecSmrg * all the newvalue/oldvalue shuffling above. After we send the 60005b261ecSmrg * events, give the trigger its new test value. 60105b261ecSmrg */ 60205b261ecSmrg SyncSendAlarmNotifyEvents(pAlarm); 60305b261ecSmrg pTrigger->test_value = new_test_value; 60405b261ecSmrg} 60505b261ecSmrg 60605b261ecSmrg/* This function is called when an Await unblocks, either as a result 60705b261ecSmrg * of the trigger firing OR the counter being destroyed. 60805b261ecSmrg * It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed 60905b261ecSmrg * (for Await triggers). 61005b261ecSmrg */ 61105b261ecSmrgstatic void 612f7df2e56SmrgSyncAwaitTriggerFired(SyncTrigger * pTrigger) 61305b261ecSmrg{ 614f7df2e56Smrg SyncAwait *pAwait = (SyncAwait *) pTrigger; 61505b261ecSmrg int numwaits; 61605b261ecSmrg SyncAwaitUnion *pAwaitUnion; 61705b261ecSmrg SyncAwait **ppAwait; 61805b261ecSmrg int num_events = 0; 61905b261ecSmrg 620f7df2e56Smrg pAwaitUnion = (SyncAwaitUnion *) pAwait->pHeader; 62105b261ecSmrg numwaits = pAwaitUnion->header.num_waitconditions; 622f7df2e56Smrg ppAwait = xallocarray(numwaits, sizeof(SyncAwait *)); 62305b261ecSmrg if (!ppAwait) 624f7df2e56Smrg goto bail; 62505b261ecSmrg 626f7df2e56Smrg pAwait = &(pAwaitUnion + 1)->await; 62705b261ecSmrg 62805b261ecSmrg /* "When a client is unblocked, all the CounterNotify events for 62905b261ecSmrg * the Await request are generated contiguously. If count is 0 63005b261ecSmrg * there are no more events to follow for this request. If 63105b261ecSmrg * count is n, there are at least n more events to follow." 63205b261ecSmrg * 63305b261ecSmrg * Thus, it is best to find all the counters for which events 63405b261ecSmrg * need to be sent first, so that an accurate count field can 63505b261ecSmrg * be stored in the events. 63605b261ecSmrg */ 637f7df2e56Smrg for (; numwaits; numwaits--, pAwait++) { 6387e31ba66Smrg int64_t diff; 639f7df2e56Smrg Bool overflow, diffgreater, diffequal; 640f7df2e56Smrg 641f7df2e56Smrg /* "A CounterNotify event with the destroyed flag set to TRUE is 642f7df2e56Smrg * always generated if the counter for one of the triggers is 643f7df2e56Smrg * destroyed." 644f7df2e56Smrg */ 645f7df2e56Smrg if (pAwait->trigger.pSync->beingDestroyed) { 646f7df2e56Smrg ppAwait[num_events++] = pAwait; 647f7df2e56Smrg continue; 648f7df2e56Smrg } 649f7df2e56Smrg 650f7df2e56Smrg if (SYNC_COUNTER == pAwait->trigger.pSync->type) { 651f7df2e56Smrg SyncCounter *pCounter = (SyncCounter *) pAwait->trigger.pSync; 652f7df2e56Smrg 653f7df2e56Smrg /* "The difference between the counter and the test value is 654f7df2e56Smrg * calculated by subtracting the test value from the value of 655f7df2e56Smrg * the counter." 656f7df2e56Smrg */ 6577e31ba66Smrg overflow = checked_int64_subtract(&diff, pCounter->value, 6587e31ba66Smrg pAwait->trigger.test_value); 659f7df2e56Smrg 660f7df2e56Smrg /* "If the difference lies outside the range for an INT64, an 661f7df2e56Smrg * event is not generated." 662f7df2e56Smrg */ 663f7df2e56Smrg if (overflow) 664f7df2e56Smrg continue; 6657e31ba66Smrg diffgreater = diff > pAwait->event_threshold; 6667e31ba66Smrg diffequal = diff == pAwait->event_threshold; 667f7df2e56Smrg 668f7df2e56Smrg /* "If the test-type is PositiveTransition or 669f7df2e56Smrg * PositiveComparison, a CounterNotify event is generated if 670f7df2e56Smrg * the difference is at least event-threshold. If the test-type 671f7df2e56Smrg * is NegativeTransition or NegativeComparison, a CounterNotify 672f7df2e56Smrg * event is generated if the difference is at most 673f7df2e56Smrg * event-threshold." 674f7df2e56Smrg */ 675f7df2e56Smrg 676f7df2e56Smrg if (((pAwait->trigger.test_type == XSyncPositiveComparison || 677f7df2e56Smrg pAwait->trigger.test_type == XSyncPositiveTransition) 678f7df2e56Smrg && (diffgreater || diffequal)) 679f7df2e56Smrg || 680f7df2e56Smrg ((pAwait->trigger.test_type == XSyncNegativeComparison || 681f7df2e56Smrg pAwait->trigger.test_type == XSyncNegativeTransition) 682f7df2e56Smrg && (!diffgreater) /* less or equal */ 683f7df2e56Smrg ) 684f7df2e56Smrg ) { 685f7df2e56Smrg ppAwait[num_events++] = pAwait; 686f7df2e56Smrg } 687f7df2e56Smrg } 68805b261ecSmrg } 68905b261ecSmrg if (num_events) 690f7df2e56Smrg SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait, 691f7df2e56Smrg num_events); 6924202a189Smrg free(ppAwait); 69305b261ecSmrg 694f7df2e56Smrg bail: 69505b261ecSmrg /* unblock the client */ 69605b261ecSmrg AttendClient(pAwaitUnion->header.client); 69705b261ecSmrg /* delete the await */ 69805b261ecSmrg FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 69905b261ecSmrg} 70005b261ecSmrg 7017e31ba66Smrgstatic int64_t 7027e31ba66SmrgSyncUpdateCounter(SyncCounter *pCounter, int64_t newval) 703f7df2e56Smrg{ 7047e31ba66Smrg int64_t oldval = pCounter->value; 705f7df2e56Smrg pCounter->value = newval; 706f7df2e56Smrg return oldval; 707f7df2e56Smrg} 70805b261ecSmrg 70905b261ecSmrg/* This function should always be used to change a counter's value so that 71005b261ecSmrg * any triggers depending on the counter will be checked. 71105b261ecSmrg */ 71205b261ecSmrgvoid 7137e31ba66SmrgSyncChangeCounter(SyncCounter * pCounter, int64_t newval) 71405b261ecSmrg{ 715f7df2e56Smrg SyncTriggerList *ptl, *pnext; 7167e31ba66Smrg int64_t oldval; 71705b261ecSmrg 718f7df2e56Smrg oldval = SyncUpdateCounter(pCounter, newval); 71905b261ecSmrg 72005b261ecSmrg /* run through triggers to see if any become true */ 721f7df2e56Smrg for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) { 722f7df2e56Smrg pnext = ptl->next; 723f7df2e56Smrg if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, oldval)) 724f7df2e56Smrg (*ptl->pTrigger->TriggerFired) (ptl->pTrigger); 72505b261ecSmrg } 72605b261ecSmrg 727f7df2e56Smrg if (IsSystemCounter(pCounter)) { 728f7df2e56Smrg SyncComputeBracketValues(pCounter); 72905b261ecSmrg } 73005b261ecSmrg} 73105b261ecSmrg 73205b261ecSmrg/* loosely based on dix/events.c/EventSelectForWindow */ 73305b261ecSmrgstatic Bool 734f7df2e56SmrgSyncEventSelectForAlarm(SyncAlarm * pAlarm, ClientPtr client, Bool wantevents) 73505b261ecSmrg{ 73605b261ecSmrg SyncAlarmClientList *pClients; 73705b261ecSmrg 738f7df2e56Smrg if (client == pAlarm->client) { /* alarm owner */ 739f7df2e56Smrg pAlarm->events = wantevents; 740f7df2e56Smrg return Success; 74105b261ecSmrg } 74205b261ecSmrg 74305b261ecSmrg /* see if the client is already on the list (has events selected) */ 74405b261ecSmrg 745f7df2e56Smrg for (pClients = pAlarm->pEventClients; pClients; pClients = pClients->next) { 746f7df2e56Smrg if (pClients->client == client) { 747f7df2e56Smrg /* client's presence on the list indicates desire for 748f7df2e56Smrg * events. If the client doesn't want events, remove it 749f7df2e56Smrg * from the list. If the client does want events, do 750f7df2e56Smrg * nothing, since it's already got them. 751f7df2e56Smrg */ 752f7df2e56Smrg if (!wantevents) { 753f7df2e56Smrg FreeResource(pClients->delete_id, RT_NONE); 754f7df2e56Smrg } 755f7df2e56Smrg return Success; 756f7df2e56Smrg } 75705b261ecSmrg } 75805b261ecSmrg 75905b261ecSmrg /* if we get here, this client does not currently have 76005b261ecSmrg * events selected on the alarm 76105b261ecSmrg */ 76205b261ecSmrg 76305b261ecSmrg if (!wantevents) 764f7df2e56Smrg /* client doesn't want events, and we just discovered that it 765f7df2e56Smrg * doesn't have them, so there's nothing to do. 766f7df2e56Smrg */ 767f7df2e56Smrg return Success; 76805b261ecSmrg 76905b261ecSmrg /* add new client to pAlarm->pEventClients */ 77005b261ecSmrg 7714202a189Smrg pClients = malloc(sizeof(SyncAlarmClientList)); 77205b261ecSmrg if (!pClients) 773f7df2e56Smrg return BadAlloc; 77405b261ecSmrg 7754202a189Smrg /* register it as a resource so it will be cleaned up 77605b261ecSmrg * if the client dies 77705b261ecSmrg */ 77805b261ecSmrg 77905b261ecSmrg pClients->delete_id = FakeClientID(client->index); 78005b261ecSmrg 78105b261ecSmrg /* link it into list after we know all the allocations succeed */ 78205b261ecSmrg pClients->next = pAlarm->pEventClients; 78305b261ecSmrg pAlarm->pEventClients = pClients; 78405b261ecSmrg pClients->client = client; 78565b04b38Smrg 78665b04b38Smrg if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm)) 787f7df2e56Smrg return BadAlloc; 78865b04b38Smrg 78905b261ecSmrg return Success; 79005b261ecSmrg} 79105b261ecSmrg 79205b261ecSmrg/* 79305b261ecSmrg * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm 79405b261ecSmrg */ 7954202a189Smrgstatic int 796f7df2e56SmrgSyncChangeAlarmAttributes(ClientPtr client, SyncAlarm * pAlarm, Mask mask, 797f7df2e56Smrg CARD32 *values) 798f7df2e56Smrg{ 799f7df2e56Smrg int status; 800f7df2e56Smrg XSyncCounter counter; 801f7df2e56Smrg Mask origmask = mask; 802d566a54bSmrg SyncTrigger trigger; 803d566a54bSmrg Bool select_events_changed = FALSE; 804d566a54bSmrg Bool select_events_value = FALSE; 805d566a54bSmrg int64_t delta; 806f7df2e56Smrg 807d566a54bSmrg trigger = pAlarm->trigger; 808d566a54bSmrg delta = pAlarm->delta; 809d566a54bSmrg counter = trigger.pSync ? trigger.pSync->id : None; 810f7df2e56Smrg 811f7df2e56Smrg while (mask) { 812f7df2e56Smrg int index2 = lowbit(mask); 813f7df2e56Smrg 814f7df2e56Smrg mask &= ~index2; 815f7df2e56Smrg switch (index2) { 816f7df2e56Smrg case XSyncCACounter: 817f7df2e56Smrg mask &= ~XSyncCACounter; 818f7df2e56Smrg /* sanity check in SyncInitTrigger */ 819f7df2e56Smrg counter = *values++; 820f7df2e56Smrg break; 821f7df2e56Smrg 822f7df2e56Smrg case XSyncCAValueType: 823f7df2e56Smrg mask &= ~XSyncCAValueType; 824f7df2e56Smrg /* sanity check in SyncInitTrigger */ 825d566a54bSmrg trigger.value_type = *values++; 826f7df2e56Smrg break; 827f7df2e56Smrg 828f7df2e56Smrg case XSyncCAValue: 829f7df2e56Smrg mask &= ~XSyncCAValue; 830d566a54bSmrg trigger.wait_value = ((int64_t)values[0] << 32) | values[1]; 831f7df2e56Smrg values += 2; 832f7df2e56Smrg break; 833f7df2e56Smrg 834f7df2e56Smrg case XSyncCATestType: 835f7df2e56Smrg mask &= ~XSyncCATestType; 836f7df2e56Smrg /* sanity check in SyncInitTrigger */ 837d566a54bSmrg trigger.test_type = *values++; 838f7df2e56Smrg break; 839f7df2e56Smrg 840f7df2e56Smrg case XSyncCADelta: 841f7df2e56Smrg mask &= ~XSyncCADelta; 842d566a54bSmrg delta = ((int64_t)values[0] << 32) | values[1]; 843f7df2e56Smrg values += 2; 844f7df2e56Smrg break; 845f7df2e56Smrg 846f7df2e56Smrg case XSyncCAEvents: 847f7df2e56Smrg mask &= ~XSyncCAEvents; 848f7df2e56Smrg if ((*values != xTrue) && (*values != xFalse)) { 849f7df2e56Smrg client->errorValue = *values; 850f7df2e56Smrg return BadValue; 851f7df2e56Smrg } 852d566a54bSmrg select_events_value = (Bool) (*values++); 853d566a54bSmrg select_events_changed = TRUE; 854f7df2e56Smrg break; 855f7df2e56Smrg 856f7df2e56Smrg default: 857f7df2e56Smrg client->errorValue = mask; 858f7df2e56Smrg return BadValue; 859f7df2e56Smrg } 86005b261ecSmrg } 86105b261ecSmrg 862d566a54bSmrg if (select_events_changed) { 863d566a54bSmrg status = SyncEventSelectForAlarm(pAlarm, client, select_events_value); 864d566a54bSmrg if (status != Success) 865d566a54bSmrg return status; 866d566a54bSmrg } 867d566a54bSmrg 86805b261ecSmrg /* "If the test-type is PositiveComparison or PositiveTransition 86905b261ecSmrg * and delta is less than zero, or if the test-type is 87005b261ecSmrg * NegativeComparison or NegativeTransition and delta is 87105b261ecSmrg * greater than zero, a Match error is generated." 87205b261ecSmrg */ 873f7df2e56Smrg if (origmask & (XSyncCADelta | XSyncCATestType)) { 874d566a54bSmrg if ((((trigger.test_type == XSyncPositiveComparison) || 875d566a54bSmrg (trigger.test_type == XSyncPositiveTransition)) 876d566a54bSmrg && delta < 0) 877f7df2e56Smrg || 878d566a54bSmrg (((trigger.test_type == XSyncNegativeComparison) || 879d566a54bSmrg (trigger.test_type == XSyncNegativeTransition)) 880d566a54bSmrg && delta > 0) 881f7df2e56Smrg ) { 882f7df2e56Smrg return BadMatch; 883f7df2e56Smrg } 88405b261ecSmrg } 88505b261ecSmrg 88605b261ecSmrg /* postpone this until now, when we're sure nothing else can go wrong */ 887d566a54bSmrg pAlarm->delta = delta; 888d566a54bSmrg pAlarm->trigger = trigger; 88965b04b38Smrg if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter, 890f7df2e56Smrg origmask & XSyncCAAllTrigger)) != Success) 891f7df2e56Smrg return status; 89205b261ecSmrg 89305b261ecSmrg /* XXX spec does not really say to do this - needs clarification */ 89405b261ecSmrg pAlarm->state = XSyncAlarmActive; 89505b261ecSmrg return Success; 89605b261ecSmrg} 89705b261ecSmrg 8984e185dc0SmrgSyncObject * 89965b04b38SmrgSyncCreate(ClientPtr client, XID id, unsigned char type) 90065b04b38Smrg{ 90165b04b38Smrg SyncObject *pSync; 9024e185dc0Smrg RESTYPE resType; 90365b04b38Smrg 90465b04b38Smrg switch (type) { 90565b04b38Smrg case SYNC_COUNTER: 906f7df2e56Smrg pSync = malloc(sizeof(SyncCounter)); 9074e185dc0Smrg resType = RTCounter; 908f7df2e56Smrg break; 90965b04b38Smrg case SYNC_FENCE: 910f7df2e56Smrg pSync = (SyncObject *) dixAllocateObjectWithPrivates(SyncFence, 911f7df2e56Smrg PRIVATE_SYNC_FENCE); 9124e185dc0Smrg resType = RTFence; 913f7df2e56Smrg break; 91465b04b38Smrg default: 915f7df2e56Smrg return NULL; 91665b04b38Smrg } 91765b04b38Smrg 91865b04b38Smrg if (!pSync) 919f7df2e56Smrg return NULL; 92065b04b38Smrg 9214e185dc0Smrg pSync->initialized = FALSE; 9224e185dc0Smrg 9234e185dc0Smrg if (!AddResource(id, resType, (void *) pSync)) 9244e185dc0Smrg return NULL; 9254e185dc0Smrg 92665b04b38Smrg pSync->client = client; 92765b04b38Smrg pSync->id = id; 92865b04b38Smrg pSync->pTriglist = NULL; 92965b04b38Smrg pSync->beingDestroyed = FALSE; 93065b04b38Smrg pSync->type = type; 93165b04b38Smrg 93265b04b38Smrg return pSync; 93365b04b38Smrg} 93465b04b38Smrg 935f7df2e56Smrgint 936f7df2e56SmrgSyncCreateFenceFromFD(ClientPtr client, DrawablePtr pDraw, XID id, int fd, BOOL initially_triggered) 937f7df2e56Smrg{ 9387e31ba66Smrg#ifdef HAVE_XSHMFENCE 939f7df2e56Smrg SyncFence *pFence; 940f7df2e56Smrg int status; 941f7df2e56Smrg 942f7df2e56Smrg pFence = (SyncFence *) SyncCreate(client, id, SYNC_FENCE); 943f7df2e56Smrg if (!pFence) 944f7df2e56Smrg return BadAlloc; 945f7df2e56Smrg 946f7df2e56Smrg status = miSyncInitFenceFromFD(pDraw, pFence, fd, initially_triggered); 947f7df2e56Smrg if (status != Success) { 9484e185dc0Smrg FreeResource(pFence->sync.id, RT_NONE); 949f7df2e56Smrg return status; 950f7df2e56Smrg } 951f7df2e56Smrg 952f7df2e56Smrg return Success; 953f7df2e56Smrg#else 954f7df2e56Smrg return BadImplementation; 955f7df2e56Smrg#endif 956f7df2e56Smrg} 957f7df2e56Smrg 958f7df2e56Smrgint 959f7df2e56SmrgSyncFDFromFence(ClientPtr client, DrawablePtr pDraw, SyncFence *pFence) 960f7df2e56Smrg{ 9617e31ba66Smrg#ifdef HAVE_XSHMFENCE 962f7df2e56Smrg return miSyncFDFromFence(pDraw, pFence); 963f7df2e56Smrg#else 964f7df2e56Smrg return BadImplementation; 965f7df2e56Smrg#endif 966f7df2e56Smrg} 96705b261ecSmrg 96805b261ecSmrgstatic SyncCounter * 9697e31ba66SmrgSyncCreateCounter(ClientPtr client, XSyncCounter id, int64_t initialvalue) 97005b261ecSmrg{ 97105b261ecSmrg SyncCounter *pCounter; 97205b261ecSmrg 973f7df2e56Smrg if (!(pCounter = (SyncCounter *) SyncCreate(client, id, SYNC_COUNTER))) 974f7df2e56Smrg return NULL; 97505b261ecSmrg 97665b04b38Smrg pCounter->value = initialvalue; 97765b04b38Smrg pCounter->pSysCounterInfo = NULL; 97865b04b38Smrg 9794e185dc0Smrg pCounter->sync.initialized = TRUE; 98005b261ecSmrg 98105b261ecSmrg return pCounter; 98205b261ecSmrg} 98305b261ecSmrg 9844202a189Smrgstatic int FreeCounter(void *, XID); 98505b261ecSmrg 98605b261ecSmrg/* 98705b261ecSmrg * ***** System Counter utilities 98805b261ecSmrg */ 98905b261ecSmrg 990f7df2e56SmrgSyncCounter* 991f7df2e56SmrgSyncCreateSystemCounter(const char *name, 9927e31ba66Smrg int64_t initial, 9937e31ba66Smrg int64_t resolution, 994f7df2e56Smrg SyncCounterType counterType, 995f7df2e56Smrg SyncSystemCounterQueryValue QueryValue, 996f7df2e56Smrg SyncSystemCounterBracketValues BracketValues 997f7df2e56Smrg ) 998f7df2e56Smrg{ 9997e31ba66Smrg SyncCounter *pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial); 100005b261ecSmrg 1001f7df2e56Smrg if (pCounter) { 1002f7df2e56Smrg SysCounterInfo *psci; 1003f7df2e56Smrg 1004f7df2e56Smrg psci = malloc(sizeof(SysCounterInfo)); 1005f7df2e56Smrg if (!psci) { 1006f7df2e56Smrg FreeResource(pCounter->sync.id, RT_NONE); 1007f7df2e56Smrg return pCounter; 1008f7df2e56Smrg } 1009f7df2e56Smrg pCounter->pSysCounterInfo = psci; 1010f7df2e56Smrg psci->pCounter = pCounter; 1011f7df2e56Smrg psci->name = strdup(name); 1012f7df2e56Smrg psci->resolution = resolution; 1013f7df2e56Smrg psci->counterType = counterType; 1014f7df2e56Smrg psci->QueryValue = QueryValue; 1015f7df2e56Smrg psci->BracketValues = BracketValues; 1016f7df2e56Smrg psci->private = NULL; 10177e31ba66Smrg psci->bracket_greater = LLONG_MAX; 10187e31ba66Smrg psci->bracket_less = LLONG_MIN; 1019f7df2e56Smrg xorg_list_add(&psci->entry, &SysCounterList); 102005b261ecSmrg } 10214202a189Smrg return pCounter; 102205b261ecSmrg} 102305b261ecSmrg 102405b261ecSmrgvoid 1025f7df2e56SmrgSyncDestroySystemCounter(void *pSysCounter) 102605b261ecSmrg{ 1027f7df2e56Smrg SyncCounter *pCounter = (SyncCounter *) pSysCounter; 1028f7df2e56Smrg 102965b04b38Smrg FreeResource(pCounter->sync.id, RT_NONE); 103005b261ecSmrg} 103105b261ecSmrg 103205b261ecSmrgstatic void 1033f7df2e56SmrgSyncComputeBracketValues(SyncCounter * pCounter) 103405b261ecSmrg{ 103505b261ecSmrg SyncTriggerList *pCur; 103605b261ecSmrg SyncTrigger *pTrigger; 103705b261ecSmrg SysCounterInfo *psci; 10387e31ba66Smrg int64_t *pnewgtval = NULL; 10397e31ba66Smrg int64_t *pnewltval = NULL; 104005b261ecSmrg SyncCounterType ct; 104105b261ecSmrg 104205b261ecSmrg if (!pCounter) 1043f7df2e56Smrg return; 104405b261ecSmrg 104505b261ecSmrg psci = pCounter->pSysCounterInfo; 104605b261ecSmrg ct = pCounter->pSysCounterInfo->counterType; 104705b261ecSmrg if (ct == XSyncCounterNeverChanges) 1048f7df2e56Smrg return; 104905b261ecSmrg 10507e31ba66Smrg psci->bracket_greater = LLONG_MAX; 10517e31ba66Smrg psci->bracket_less = LLONG_MIN; 105205b261ecSmrg 1053f7df2e56Smrg for (pCur = pCounter->sync.pTriglist; pCur; pCur = pCur->next) { 1054f7df2e56Smrg pTrigger = pCur->pTrigger; 1055f7df2e56Smrg 105605b261ecSmrg if (pTrigger->test_type == XSyncPositiveComparison && 1057f7df2e56Smrg ct != XSyncCounterNeverIncreases) { 10587e31ba66Smrg if (pCounter->value < pTrigger->test_value && 10597e31ba66Smrg pTrigger->test_value < psci->bracket_greater) { 1060f7df2e56Smrg psci->bracket_greater = pTrigger->test_value; 1061f7df2e56Smrg pnewgtval = &psci->bracket_greater; 1062f7df2e56Smrg } 10637e31ba66Smrg else if (pCounter->value > pTrigger->test_value && 10647e31ba66Smrg pTrigger->test_value > psci->bracket_less) { 1065f7df2e56Smrg psci->bracket_less = pTrigger->test_value; 1066f7df2e56Smrg pnewltval = &psci->bracket_less; 1067f7df2e56Smrg } 1068f7df2e56Smrg } 1069f7df2e56Smrg else if (pTrigger->test_type == XSyncNegativeComparison && 1070f7df2e56Smrg ct != XSyncCounterNeverDecreases) { 10717e31ba66Smrg if (pCounter->value > pTrigger->test_value && 10727e31ba66Smrg pTrigger->test_value > psci->bracket_less) { 1073f7df2e56Smrg psci->bracket_less = pTrigger->test_value; 1074f7df2e56Smrg pnewltval = &psci->bracket_less; 1075f7df2e56Smrg } 10767e31ba66Smrg else if (pCounter->value < pTrigger->test_value && 10777e31ba66Smrg pTrigger->test_value < psci->bracket_greater) { 1078f7df2e56Smrg psci->bracket_greater = pTrigger->test_value; 1079f7df2e56Smrg pnewgtval = &psci->bracket_greater; 1080f7df2e56Smrg } 1081f7df2e56Smrg } 1082f7df2e56Smrg else if (pTrigger->test_type == XSyncNegativeTransition && 1083f7df2e56Smrg ct != XSyncCounterNeverIncreases) { 10847e31ba66Smrg if (pCounter->value >= pTrigger->test_value && 10857e31ba66Smrg pTrigger->test_value > psci->bracket_less) { 1086f7df2e56Smrg /* 1087f7df2e56Smrg * If the value is exactly equal to our threshold, we want one 1088f7df2e56Smrg * more event in the negative direction to ensure we pick up 1089f7df2e56Smrg * when the value is less than this threshold. 1090f7df2e56Smrg */ 1091f7df2e56Smrg psci->bracket_less = pTrigger->test_value; 1092f7df2e56Smrg pnewltval = &psci->bracket_less; 1093f7df2e56Smrg } 10947e31ba66Smrg else if (pCounter->value < pTrigger->test_value && 10957e31ba66Smrg pTrigger->test_value < psci->bracket_greater) { 1096f7df2e56Smrg psci->bracket_greater = pTrigger->test_value; 1097f7df2e56Smrg pnewgtval = &psci->bracket_greater; 1098f7df2e56Smrg } 1099f7df2e56Smrg } 1100a0d10bb6Smrg else if (pTrigger->test_type == XSyncPositiveTransition && 1101f7df2e56Smrg ct != XSyncCounterNeverDecreases) { 11027e31ba66Smrg if (pCounter->value <= pTrigger->test_value && 11037e31ba66Smrg pTrigger->test_value < psci->bracket_greater) { 1104f7df2e56Smrg /* 1105f7df2e56Smrg * If the value is exactly equal to our threshold, we 1106f7df2e56Smrg * want one more event in the positive direction to 1107f7df2e56Smrg * ensure we pick up when the value *exceeds* this 1108f7df2e56Smrg * threshold. 1109f7df2e56Smrg */ 1110f7df2e56Smrg psci->bracket_greater = pTrigger->test_value; 1111f7df2e56Smrg pnewgtval = &psci->bracket_greater; 1112f7df2e56Smrg } 11137e31ba66Smrg else if (pCounter->value > pTrigger->test_value && 11147e31ba66Smrg pTrigger->test_value > psci->bracket_less) { 1115f7df2e56Smrg psci->bracket_less = pTrigger->test_value; 1116f7df2e56Smrg pnewltval = &psci->bracket_less; 1117f7df2e56Smrg } 1118f7df2e56Smrg } 1119f7df2e56Smrg } /* end for each trigger */ 1120f7df2e56Smrg 1121f7df2e56Smrg (*psci->BracketValues) ((void *) pCounter, pnewltval, pnewgtval); 1122f7df2e56Smrg 112305b261ecSmrg} 112405b261ecSmrg 112505b261ecSmrg/* 112605b261ecSmrg * ***** Resource delete functions 112705b261ecSmrg */ 112805b261ecSmrg 112905b261ecSmrg/* ARGSUSED */ 113005b261ecSmrgstatic int 11314202a189SmrgFreeAlarm(void *addr, XID id) 113205b261ecSmrg{ 1133f7df2e56Smrg SyncAlarm *pAlarm = (SyncAlarm *) addr; 113405b261ecSmrg 113505b261ecSmrg pAlarm->state = XSyncAlarmDestroyed; 113605b261ecSmrg 113705b261ecSmrg SyncSendAlarmNotifyEvents(pAlarm); 113805b261ecSmrg 113905b261ecSmrg /* delete event selections */ 114005b261ecSmrg 114105b261ecSmrg while (pAlarm->pEventClients) 1142f7df2e56Smrg FreeResource(pAlarm->pEventClients->delete_id, RT_NONE); 114305b261ecSmrg 114465b04b38Smrg SyncDeleteTriggerFromSyncObject(&pAlarm->trigger); 114505b261ecSmrg 11464202a189Smrg free(pAlarm); 114705b261ecSmrg return Success; 114805b261ecSmrg} 114905b261ecSmrg 115005b261ecSmrg/* 115105b261ecSmrg * ** Cleanup after the destruction of a Counter 115205b261ecSmrg */ 115305b261ecSmrg/* ARGSUSED */ 115405b261ecSmrgstatic int 11554202a189SmrgFreeCounter(void *env, XID id) 115605b261ecSmrg{ 1157f7df2e56Smrg SyncCounter *pCounter = (SyncCounter *) env; 115805b261ecSmrg 115965b04b38Smrg pCounter->sync.beingDestroyed = TRUE; 11604e185dc0Smrg 11614e185dc0Smrg if (pCounter->sync.initialized) { 11624e185dc0Smrg SyncTriggerList *ptl, *pnext; 11634e185dc0Smrg 11644e185dc0Smrg /* tell all the counter's triggers that counter has been destroyed */ 11654e185dc0Smrg for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) { 11664e185dc0Smrg (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger); 11674e185dc0Smrg pnext = ptl->next; 11684e185dc0Smrg free(ptl); /* destroy the trigger list as we go */ 11694e185dc0Smrg } 11704e185dc0Smrg if (IsSystemCounter(pCounter)) { 11714e185dc0Smrg xorg_list_del(&pCounter->pSysCounterInfo->entry); 11724e185dc0Smrg free(pCounter->pSysCounterInfo->name); 11734e185dc0Smrg free(pCounter->pSysCounterInfo->private); 11744e185dc0Smrg free(pCounter->pSysCounterInfo); 11754e185dc0Smrg } 117605b261ecSmrg } 11774e185dc0Smrg 11784202a189Smrg free(pCounter); 117905b261ecSmrg return Success; 118005b261ecSmrg} 118105b261ecSmrg 118205b261ecSmrg/* 118305b261ecSmrg * ** Cleanup after Await 118405b261ecSmrg */ 118505b261ecSmrg/* ARGSUSED */ 118605b261ecSmrgstatic int 11874202a189SmrgFreeAwait(void *addr, XID id) 118805b261ecSmrg{ 118905b261ecSmrg SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr; 119005b261ecSmrg SyncAwait *pAwait; 119105b261ecSmrg int numwaits; 119205b261ecSmrg 1193f7df2e56Smrg pAwait = &(pAwaitUnion + 1)->await; /* first await on list */ 119405b261ecSmrg 119505b261ecSmrg /* remove triggers from counters */ 119605b261ecSmrg 119705b261ecSmrg for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits; 1198f7df2e56Smrg numwaits--, pAwait++) { 1199f7df2e56Smrg /* If the counter is being destroyed, FreeCounter will delete 1200f7df2e56Smrg * the trigger list itself, so don't do it here. 1201f7df2e56Smrg */ 1202f7df2e56Smrg SyncObject *pSync = pAwait->trigger.pSync; 1203f7df2e56Smrg 1204f7df2e56Smrg if (pSync && !pSync->beingDestroyed) 1205f7df2e56Smrg SyncDeleteTriggerFromSyncObject(&pAwait->trigger); 120605b261ecSmrg } 12074202a189Smrg free(pAwaitUnion); 120805b261ecSmrg return Success; 120905b261ecSmrg} 121005b261ecSmrg 121105b261ecSmrg/* loosely based on dix/events.c/OtherClientGone */ 121205b261ecSmrgstatic int 12134202a189SmrgFreeAlarmClient(void *value, XID id) 121405b261ecSmrg{ 1215f7df2e56Smrg SyncAlarm *pAlarm = (SyncAlarm *) value; 121605b261ecSmrg SyncAlarmClientList *pCur, *pPrev; 121705b261ecSmrg 121805b261ecSmrg for (pPrev = NULL, pCur = pAlarm->pEventClients; 1219f7df2e56Smrg pCur; pPrev = pCur, pCur = pCur->next) { 1220f7df2e56Smrg if (pCur->delete_id == id) { 1221f7df2e56Smrg if (pPrev) 1222f7df2e56Smrg pPrev->next = pCur->next; 1223f7df2e56Smrg else 1224f7df2e56Smrg pAlarm->pEventClients = pCur->next; 1225f7df2e56Smrg free(pCur); 1226f7df2e56Smrg return Success; 1227f7df2e56Smrg } 122805b261ecSmrg } 122905b261ecSmrg FatalError("alarm client not on event list"); 1230f7df2e56Smrg /*NOTREACHED*/} 123105b261ecSmrg 123205b261ecSmrg/* 123305b261ecSmrg * ***** Proc functions 123405b261ecSmrg */ 123505b261ecSmrg 123605b261ecSmrg/* 123705b261ecSmrg * ** Initialize the extension 123805b261ecSmrg */ 12394202a189Smrgstatic int 12404202a189SmrgProcSyncInitialize(ClientPtr client) 124105b261ecSmrg{ 1242f7df2e56Smrg xSyncInitializeReply rep = { 1243f7df2e56Smrg .type = X_Reply, 1244f7df2e56Smrg .sequenceNumber = client->sequence, 1245f7df2e56Smrg .length = 0, 1246f7df2e56Smrg .majorVersion = SERVER_SYNC_MAJOR_VERSION, 1247f7df2e56Smrg .minorVersion = SERVER_SYNC_MINOR_VERSION, 1248f7df2e56Smrg }; 124905b261ecSmrg 125005b261ecSmrg REQUEST_SIZE_MATCH(xSyncInitializeReq); 125105b261ecSmrg 1252f7df2e56Smrg if (client->swapped) { 1253f7df2e56Smrg swaps(&rep.sequenceNumber); 125405b261ecSmrg } 1255f7df2e56Smrg WriteToClient(client, sizeof(rep), &rep); 12564202a189Smrg return Success; 125705b261ecSmrg} 125805b261ecSmrg 125905b261ecSmrg/* 126005b261ecSmrg * ** Get list of system counters available through the extension 126105b261ecSmrg */ 12624202a189Smrgstatic int 12634202a189SmrgProcSyncListSystemCounters(ClientPtr client) 126405b261ecSmrg{ 1265f7df2e56Smrg xSyncListSystemCountersReply rep = { 1266f7df2e56Smrg .type = X_Reply, 1267f7df2e56Smrg .sequenceNumber = client->sequence, 1268f7df2e56Smrg .nCounters = 0, 1269f7df2e56Smrg }; 1270f7df2e56Smrg SysCounterInfo *psci; 1271f7df2e56Smrg int len = 0; 127205b261ecSmrg xSyncSystemCounter *list = NULL, *walklist = NULL; 12734202a189Smrg 127405b261ecSmrg REQUEST_SIZE_MATCH(xSyncListSystemCountersReq); 127505b261ecSmrg 1276f7df2e56Smrg xorg_list_for_each_entry(psci, &SysCounterList, entry) { 1277f7df2e56Smrg /* pad to 4 byte boundary */ 1278f7df2e56Smrg len += pad_to_int32(sz_xSyncSystemCounter + strlen(psci->name)); 1279f7df2e56Smrg ++rep.nCounters; 128005b261ecSmrg } 128105b261ecSmrg 1282f7df2e56Smrg if (len) { 1283f7df2e56Smrg walklist = list = malloc(len); 1284f7df2e56Smrg if (!list) 1285f7df2e56Smrg return BadAlloc; 128605b261ecSmrg } 128705b261ecSmrg 12884202a189Smrg rep.length = bytes_to_int32(len); 128905b261ecSmrg 1290f7df2e56Smrg if (client->swapped) { 1291f7df2e56Smrg swaps(&rep.sequenceNumber); 1292f7df2e56Smrg swapl(&rep.length); 1293f7df2e56Smrg swapl(&rep.nCounters); 129405b261ecSmrg } 129505b261ecSmrg 1296f7df2e56Smrg xorg_list_for_each_entry(psci, &SysCounterList, entry) { 1297f7df2e56Smrg int namelen; 1298f7df2e56Smrg char *pname_in_reply; 129905b261ecSmrg 1300f7df2e56Smrg walklist->counter = psci->pCounter->sync.id; 13017e31ba66Smrg walklist->resolution_hi = psci->resolution >> 32; 13027e31ba66Smrg walklist->resolution_lo = psci->resolution; 1303f7df2e56Smrg namelen = strlen(psci->name); 1304f7df2e56Smrg walklist->name_length = namelen; 130505b261ecSmrg 1306f7df2e56Smrg if (client->swapped) { 1307f7df2e56Smrg swapl(&walklist->counter); 1308f7df2e56Smrg swapl(&walklist->resolution_hi); 1309f7df2e56Smrg swapl(&walklist->resolution_lo); 1310f7df2e56Smrg swaps(&walklist->name_length); 1311f7df2e56Smrg } 131205b261ecSmrg 1313f7df2e56Smrg pname_in_reply = ((char *) walklist) + sz_xSyncSystemCounter; 1314f7df2e56Smrg strncpy(pname_in_reply, psci->name, namelen); 1315f7df2e56Smrg walklist = (xSyncSystemCounter *) (((char *) walklist) + 1316f7df2e56Smrg pad_to_int32(sz_xSyncSystemCounter + 1317f7df2e56Smrg namelen)); 131805b261ecSmrg } 131905b261ecSmrg 1320f7df2e56Smrg WriteToClient(client, sizeof(rep), &rep); 1321f7df2e56Smrg if (len) { 1322f7df2e56Smrg WriteToClient(client, len, list); 1323f7df2e56Smrg free(list); 132405b261ecSmrg } 132505b261ecSmrg 13264202a189Smrg return Success; 132705b261ecSmrg} 132805b261ecSmrg 132905b261ecSmrg/* 133005b261ecSmrg * ** Set client Priority 133105b261ecSmrg */ 13324202a189Smrgstatic int 13334202a189SmrgProcSyncSetPriority(ClientPtr client) 133405b261ecSmrg{ 133505b261ecSmrg REQUEST(xSyncSetPriorityReq); 133605b261ecSmrg ClientPtr priorityclient; 133705b261ecSmrg int rc; 133805b261ecSmrg 133905b261ecSmrg REQUEST_SIZE_MATCH(xSyncSetPriorityReq); 134005b261ecSmrg 134105b261ecSmrg if (stuff->id == None) 1342f7df2e56Smrg priorityclient = client; 134305b261ecSmrg else { 1344f7df2e56Smrg rc = dixLookupClient(&priorityclient, stuff->id, client, 1345f7df2e56Smrg DixSetAttrAccess); 1346f7df2e56Smrg if (rc != Success) 1347f7df2e56Smrg return rc; 134805b261ecSmrg } 134905b261ecSmrg 1350f7df2e56Smrg if (priorityclient->priority != stuff->priority) { 1351f7df2e56Smrg priorityclient->priority = stuff->priority; 135205b261ecSmrg 1353f7df2e56Smrg /* The following will force the server back into WaitForSomething 1354f7df2e56Smrg * so that the change in this client's priority is immediately 1355f7df2e56Smrg * reflected. 1356f7df2e56Smrg */ 1357f7df2e56Smrg isItTimeToYield = TRUE; 1358f7df2e56Smrg dispatchException |= DE_PRIORITYCHANGE; 135905b261ecSmrg } 136005b261ecSmrg return Success; 136105b261ecSmrg} 136205b261ecSmrg 136305b261ecSmrg/* 136405b261ecSmrg * ** Get client Priority 136505b261ecSmrg */ 13664202a189Smrgstatic int 13674202a189SmrgProcSyncGetPriority(ClientPtr client) 136805b261ecSmrg{ 136905b261ecSmrg REQUEST(xSyncGetPriorityReq); 137005b261ecSmrg xSyncGetPriorityReply rep; 137105b261ecSmrg ClientPtr priorityclient; 137205b261ecSmrg int rc; 137305b261ecSmrg 137405b261ecSmrg REQUEST_SIZE_MATCH(xSyncGetPriorityReq); 137505b261ecSmrg 137605b261ecSmrg if (stuff->id == None) 1377f7df2e56Smrg priorityclient = client; 137805b261ecSmrg else { 1379f7df2e56Smrg rc = dixLookupClient(&priorityclient, stuff->id, client, 1380f7df2e56Smrg DixGetAttrAccess); 1381f7df2e56Smrg if (rc != Success) 1382f7df2e56Smrg return rc; 138305b261ecSmrg } 138405b261ecSmrg 1385f7df2e56Smrg rep = (xSyncGetPriorityReply) { 1386f7df2e56Smrg .type = X_Reply, 1387f7df2e56Smrg .sequenceNumber = client->sequence, 1388f7df2e56Smrg .length = 0, 1389f7df2e56Smrg .priority = priorityclient->priority 1390f7df2e56Smrg }; 139105b261ecSmrg 1392f7df2e56Smrg if (client->swapped) { 1393f7df2e56Smrg swaps(&rep.sequenceNumber); 1394f7df2e56Smrg swapl(&rep.priority); 139505b261ecSmrg } 139605b261ecSmrg 1397f7df2e56Smrg WriteToClient(client, sizeof(xSyncGetPriorityReply), &rep); 139805b261ecSmrg 13994202a189Smrg return Success; 140005b261ecSmrg} 140105b261ecSmrg 140205b261ecSmrg/* 140305b261ecSmrg * ** Create a new counter 140405b261ecSmrg */ 14054202a189Smrgstatic int 14064202a189SmrgProcSyncCreateCounter(ClientPtr client) 140705b261ecSmrg{ 140805b261ecSmrg REQUEST(xSyncCreateCounterReq); 14097e31ba66Smrg int64_t initial; 141005b261ecSmrg 141105b261ecSmrg REQUEST_SIZE_MATCH(xSyncCreateCounterReq); 141205b261ecSmrg 141305b261ecSmrg LEGAL_NEW_RESOURCE(stuff->cid, client); 141405b261ecSmrg 14157e31ba66Smrg initial = ((int64_t)stuff->initial_value_hi << 32) | stuff->initial_value_lo; 14167e31ba66Smrg 141705b261ecSmrg if (!SyncCreateCounter(client, stuff->cid, initial)) 1418f7df2e56Smrg return BadAlloc; 141905b261ecSmrg 14204202a189Smrg return Success; 142105b261ecSmrg} 142205b261ecSmrg 142305b261ecSmrg/* 142405b261ecSmrg * ** Set Counter value 142505b261ecSmrg */ 14264202a189Smrgstatic int 14274202a189SmrgProcSyncSetCounter(ClientPtr client) 142805b261ecSmrg{ 142905b261ecSmrg REQUEST(xSyncSetCounterReq); 1430f7df2e56Smrg SyncCounter *pCounter; 14317e31ba66Smrg int64_t newvalue; 1432f7df2e56Smrg int rc; 143305b261ecSmrg 143405b261ecSmrg REQUEST_SIZE_MATCH(xSyncSetCounterReq); 143505b261ecSmrg 1436f7df2e56Smrg rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter, 1437f7df2e56Smrg client, DixWriteAccess); 14384202a189Smrg if (rc != Success) 1439f7df2e56Smrg return rc; 144005b261ecSmrg 1441f7df2e56Smrg if (IsSystemCounter(pCounter)) { 1442f7df2e56Smrg client->errorValue = stuff->cid; 1443f7df2e56Smrg return BadAccess; 144405b261ecSmrg } 144505b261ecSmrg 14467e31ba66Smrg newvalue = ((int64_t)stuff->value_hi << 32) | stuff->value_lo; 144705b261ecSmrg SyncChangeCounter(pCounter, newvalue); 144805b261ecSmrg return Success; 144905b261ecSmrg} 145005b261ecSmrg 145105b261ecSmrg/* 145205b261ecSmrg * ** Change Counter value 145305b261ecSmrg */ 14544202a189Smrgstatic int 14554202a189SmrgProcSyncChangeCounter(ClientPtr client) 145605b261ecSmrg{ 145705b261ecSmrg REQUEST(xSyncChangeCounterReq); 1458f7df2e56Smrg SyncCounter *pCounter; 14597e31ba66Smrg int64_t newvalue; 1460f7df2e56Smrg Bool overflow; 1461f7df2e56Smrg int rc; 146205b261ecSmrg 146305b261ecSmrg REQUEST_SIZE_MATCH(xSyncChangeCounterReq); 146405b261ecSmrg 1465f7df2e56Smrg rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter, 1466f7df2e56Smrg client, DixWriteAccess); 14674202a189Smrg if (rc != Success) 1468f7df2e56Smrg return rc; 146905b261ecSmrg 1470f7df2e56Smrg if (IsSystemCounter(pCounter)) { 1471f7df2e56Smrg client->errorValue = stuff->cid; 1472f7df2e56Smrg return BadAccess; 147305b261ecSmrg } 147405b261ecSmrg 14757e31ba66Smrg newvalue = (int64_t)stuff->value_hi << 32 | stuff->value_lo; 14767e31ba66Smrg overflow = checked_int64_add(&newvalue, newvalue, pCounter->value); 1477f7df2e56Smrg if (overflow) { 1478f7df2e56Smrg /* XXX 64 bit value can't fit in 32 bits; do the best we can */ 1479f7df2e56Smrg client->errorValue = stuff->value_hi; 1480f7df2e56Smrg return BadValue; 148105b261ecSmrg } 148205b261ecSmrg SyncChangeCounter(pCounter, newvalue); 148305b261ecSmrg return Success; 148405b261ecSmrg} 148505b261ecSmrg 148605b261ecSmrg/* 148705b261ecSmrg * ** Destroy a counter 148805b261ecSmrg */ 14894202a189Smrgstatic int 14904202a189SmrgProcSyncDestroyCounter(ClientPtr client) 149105b261ecSmrg{ 149205b261ecSmrg REQUEST(xSyncDestroyCounterReq); 1493f7df2e56Smrg SyncCounter *pCounter; 14944202a189Smrg int rc; 149505b261ecSmrg 149605b261ecSmrg REQUEST_SIZE_MATCH(xSyncDestroyCounterReq); 149705b261ecSmrg 1498f7df2e56Smrg rc = dixLookupResourceByType((void **) &pCounter, stuff->counter, 1499f7df2e56Smrg RTCounter, client, DixDestroyAccess); 15004202a189Smrg if (rc != Success) 1501f7df2e56Smrg return rc; 15024202a189Smrg 1503f7df2e56Smrg if (IsSystemCounter(pCounter)) { 1504f7df2e56Smrg client->errorValue = stuff->counter; 1505f7df2e56Smrg return BadAccess; 150605b261ecSmrg } 150765b04b38Smrg FreeResource(pCounter->sync.id, RT_NONE); 150805b261ecSmrg return Success; 150905b261ecSmrg} 151005b261ecSmrg 1511f7df2e56Smrgstatic SyncAwaitUnion * 151265b04b38SmrgSyncAwaitPrologue(ClientPtr client, int items) 151365b04b38Smrg{ 151465b04b38Smrg SyncAwaitUnion *pAwaitUnion; 151565b04b38Smrg 151665b04b38Smrg /* all the memory for the entire await list is allocated 151765b04b38Smrg * here in one chunk 151865b04b38Smrg */ 1519f7df2e56Smrg pAwaitUnion = xallocarray(items + 1, sizeof(SyncAwaitUnion)); 152065b04b38Smrg if (!pAwaitUnion) 1521f7df2e56Smrg return NULL; 152265b04b38Smrg 152365b04b38Smrg /* first item is the header, remainder are real wait conditions */ 152465b04b38Smrg 152565b04b38Smrg pAwaitUnion->header.delete_id = FakeClientID(client->index); 152665b04b38Smrg pAwaitUnion->header.client = client; 152765b04b38Smrg pAwaitUnion->header.num_waitconditions = 0; 152865b04b38Smrg 152965b04b38Smrg if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion)) 1530f7df2e56Smrg return NULL; 153165b04b38Smrg 153265b04b38Smrg return pAwaitUnion; 153365b04b38Smrg} 153465b04b38Smrg 153565b04b38Smrgstatic void 1536f7df2e56SmrgSyncAwaitEpilogue(ClientPtr client, int items, SyncAwaitUnion * pAwaitUnion) 153765b04b38Smrg{ 153865b04b38Smrg SyncAwait *pAwait; 153965b04b38Smrg int i; 154065b04b38Smrg 154165b04b38Smrg IgnoreClient(client); 154265b04b38Smrg 154365b04b38Smrg /* see if any of the triggers are already true */ 154465b04b38Smrg 1545f7df2e56Smrg pAwait = &(pAwaitUnion + 1)->await; /* skip over header */ 1546f7df2e56Smrg for (i = 0; i < items; i++, pAwait++) { 15477e31ba66Smrg int64_t value; 1548f7df2e56Smrg 1549f7df2e56Smrg /* don't have to worry about NULL counters because the request 1550f7df2e56Smrg * errors before we get here out if they occur 1551f7df2e56Smrg */ 1552f7df2e56Smrg switch (pAwait->trigger.pSync->type) { 1553f7df2e56Smrg case SYNC_COUNTER: 1554f7df2e56Smrg value = ((SyncCounter *) pAwait->trigger.pSync)->value; 1555f7df2e56Smrg break; 1556f7df2e56Smrg default: 15577e31ba66Smrg value = 0; 1558f7df2e56Smrg } 155965b04b38Smrg 1560f7df2e56Smrg if ((*pAwait->trigger.CheckTrigger) (&pAwait->trigger, value)) { 1561f7df2e56Smrg (*pAwait->trigger.TriggerFired) (&pAwait->trigger); 1562f7df2e56Smrg break; /* once is enough */ 1563f7df2e56Smrg } 156465b04b38Smrg } 156565b04b38Smrg} 156605b261ecSmrg 156705b261ecSmrg/* 156805b261ecSmrg * ** Await 156905b261ecSmrg */ 15704202a189Smrgstatic int 15714202a189SmrgProcSyncAwait(ClientPtr client) 157205b261ecSmrg{ 157305b261ecSmrg REQUEST(xSyncAwaitReq); 1574f7df2e56Smrg int len, items; 1575f7df2e56Smrg int i; 157605b261ecSmrg xSyncWaitCondition *pProtocolWaitConds; 157705b261ecSmrg SyncAwaitUnion *pAwaitUnion; 1578f7df2e56Smrg SyncAwait *pAwait; 1579f7df2e56Smrg int status; 158005b261ecSmrg 158105b261ecSmrg REQUEST_AT_LEAST_SIZE(xSyncAwaitReq); 158205b261ecSmrg 158305b261ecSmrg len = client->req_len << 2; 158405b261ecSmrg len -= sz_xSyncAwaitReq; 158505b261ecSmrg items = len / sz_xSyncWaitCondition; 158605b261ecSmrg 1587f7df2e56Smrg if (items * sz_xSyncWaitCondition != len) { 1588f7df2e56Smrg return BadLength; 158905b261ecSmrg } 1590f7df2e56Smrg if (items == 0) { 1591f7df2e56Smrg client->errorValue = items; /* XXX protocol change */ 1592f7df2e56Smrg return BadValue; 159305b261ecSmrg } 159405b261ecSmrg 159565b04b38Smrg if (!(pAwaitUnion = SyncAwaitPrologue(client, items))) 1596f7df2e56Smrg return BadAlloc; 159705b261ecSmrg 159805b261ecSmrg /* don't need to do any more memory allocation for this request! */ 159905b261ecSmrg 1600f7df2e56Smrg pProtocolWaitConds = (xSyncWaitCondition *) &stuff[1]; 1601f7df2e56Smrg 1602f7df2e56Smrg pAwait = &(pAwaitUnion + 1)->await; /* skip over header */ 1603f7df2e56Smrg for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++) { 1604f7df2e56Smrg if (pProtocolWaitConds->counter == None) { /* XXX protocol change */ 1605f7df2e56Smrg /* this should take care of removing any triggers created by 1606f7df2e56Smrg * this request that have already been registered on sync objects 1607f7df2e56Smrg */ 1608f7df2e56Smrg FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 1609f7df2e56Smrg client->errorValue = pProtocolWaitConds->counter; 1610f7df2e56Smrg return SyncErrorBase + XSyncBadCounter; 1611f7df2e56Smrg } 1612f7df2e56Smrg 1613f7df2e56Smrg /* sanity checks are in SyncInitTrigger */ 1614f7df2e56Smrg pAwait->trigger.pSync = NULL; 1615f7df2e56Smrg pAwait->trigger.value_type = pProtocolWaitConds->value_type; 16167e31ba66Smrg pAwait->trigger.wait_value = 16177e31ba66Smrg ((int64_t)pProtocolWaitConds->wait_value_hi << 32) | 16187e31ba66Smrg pProtocolWaitConds->wait_value_lo; 1619f7df2e56Smrg pAwait->trigger.test_type = pProtocolWaitConds->test_type; 1620f7df2e56Smrg 1621f7df2e56Smrg status = SyncInitTrigger(client, &pAwait->trigger, 1622f7df2e56Smrg pProtocolWaitConds->counter, RTCounter, 1623f7df2e56Smrg XSyncCAAllTrigger); 1624f7df2e56Smrg if (status != Success) { 1625f7df2e56Smrg /* this should take care of removing any triggers created by 1626f7df2e56Smrg * this request that have already been registered on sync objects 1627f7df2e56Smrg */ 1628f7df2e56Smrg FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 1629f7df2e56Smrg return status; 1630f7df2e56Smrg } 1631f7df2e56Smrg /* this is not a mistake -- same function works for both cases */ 1632f7df2e56Smrg pAwait->trigger.TriggerFired = SyncAwaitTriggerFired; 1633f7df2e56Smrg pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired; 16347e31ba66Smrg pAwait->event_threshold = 16357e31ba66Smrg ((int64_t) pProtocolWaitConds->event_threshold_hi << 32) | 16367e31ba66Smrg pProtocolWaitConds->event_threshold_lo; 16377e31ba66Smrg 1638f7df2e56Smrg pAwait->pHeader = &pAwaitUnion->header; 1639f7df2e56Smrg pAwaitUnion->header.num_waitconditions++; 164005b261ecSmrg } 164105b261ecSmrg 164265b04b38Smrg SyncAwaitEpilogue(client, items, pAwaitUnion); 164305b261ecSmrg 164405b261ecSmrg return Success; 164505b261ecSmrg} 164605b261ecSmrg 164705b261ecSmrg/* 164805b261ecSmrg * ** Query a counter 164905b261ecSmrg */ 16504202a189Smrgstatic int 16514202a189SmrgProcSyncQueryCounter(ClientPtr client) 165205b261ecSmrg{ 165305b261ecSmrg REQUEST(xSyncQueryCounterReq); 165405b261ecSmrg xSyncQueryCounterReply rep; 1655f7df2e56Smrg SyncCounter *pCounter; 16564202a189Smrg int rc; 165705b261ecSmrg 165805b261ecSmrg REQUEST_SIZE_MATCH(xSyncQueryCounterReq); 165905b261ecSmrg 1660f7df2e56Smrg rc = dixLookupResourceByType((void **) &pCounter, stuff->counter, 1661f7df2e56Smrg RTCounter, client, DixReadAccess); 16624202a189Smrg if (rc != Success) 1663f7df2e56Smrg return rc; 166405b261ecSmrg 166505b261ecSmrg /* if system counter, ask it what the current value is */ 1666f7df2e56Smrg if (IsSystemCounter(pCounter)) { 1667f7df2e56Smrg (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter, 1668f7df2e56Smrg &pCounter->value); 1669f7df2e56Smrg } 1670f7df2e56Smrg 1671f7df2e56Smrg rep = (xSyncQueryCounterReply) { 1672f7df2e56Smrg .type = X_Reply, 1673f7df2e56Smrg .sequenceNumber = client->sequence, 1674f7df2e56Smrg .length = 0, 16757e31ba66Smrg .value_hi = pCounter->value >> 32, 16767e31ba66Smrg .value_lo = pCounter->value 1677f7df2e56Smrg }; 1678f7df2e56Smrg 1679f7df2e56Smrg if (client->swapped) { 1680f7df2e56Smrg swaps(&rep.sequenceNumber); 1681f7df2e56Smrg swapl(&rep.length); 1682f7df2e56Smrg swapl(&rep.value_hi); 1683f7df2e56Smrg swapl(&rep.value_lo); 1684f7df2e56Smrg } 1685f7df2e56Smrg WriteToClient(client, sizeof(xSyncQueryCounterReply), &rep); 16864202a189Smrg return Success; 168705b261ecSmrg} 168805b261ecSmrg 168905b261ecSmrg/* 169005b261ecSmrg * ** Create Alarm 169105b261ecSmrg */ 16924202a189Smrgstatic int 16934202a189SmrgProcSyncCreateAlarm(ClientPtr client) 169405b261ecSmrg{ 169505b261ecSmrg REQUEST(xSyncCreateAlarmReq); 1696f7df2e56Smrg SyncAlarm *pAlarm; 1697f7df2e56Smrg int status; 1698f7df2e56Smrg unsigned long len, vmask; 1699f7df2e56Smrg SyncTrigger *pTrigger; 170005b261ecSmrg 170105b261ecSmrg REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq); 170205b261ecSmrg 170305b261ecSmrg LEGAL_NEW_RESOURCE(stuff->id, client); 170405b261ecSmrg 170505b261ecSmrg vmask = stuff->valueMask; 17064202a189Smrg len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq)); 170705b261ecSmrg /* the "extra" call to Ones accounts for the presence of 64 bit values */ 1708f7df2e56Smrg if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta)))) 1709f7df2e56Smrg return BadLength; 171005b261ecSmrg 1711f7df2e56Smrg if (!(pAlarm = malloc(sizeof(SyncAlarm)))) { 1712f7df2e56Smrg return BadAlloc; 171305b261ecSmrg } 171405b261ecSmrg 171505b261ecSmrg /* set up defaults */ 171605b261ecSmrg 171705b261ecSmrg pTrigger = &pAlarm->trigger; 171865b04b38Smrg pTrigger->pSync = NULL; 171905b261ecSmrg pTrigger->value_type = XSyncAbsolute; 17207e31ba66Smrg pTrigger->wait_value = 0; 172105b261ecSmrg pTrigger->test_type = XSyncPositiveComparison; 172205b261ecSmrg pTrigger->TriggerFired = SyncAlarmTriggerFired; 172305b261ecSmrg pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed; 172465b04b38Smrg status = SyncInitTrigger(client, pTrigger, None, RTCounter, 1725f7df2e56Smrg XSyncCAAllTrigger); 1726f7df2e56Smrg if (status != Success) { 1727f7df2e56Smrg free(pAlarm); 1728f7df2e56Smrg return status; 172905b261ecSmrg } 173005b261ecSmrg 173105b261ecSmrg pAlarm->client = client; 173205b261ecSmrg pAlarm->alarm_id = stuff->id; 17337e31ba66Smrg pAlarm->delta = 1; 173405b261ecSmrg pAlarm->events = TRUE; 173505b261ecSmrg pAlarm->state = XSyncAlarmInactive; 173605b261ecSmrg pAlarm->pEventClients = NULL; 173705b261ecSmrg status = SyncChangeAlarmAttributes(client, pAlarm, vmask, 1738f7df2e56Smrg (CARD32 *) &stuff[1]); 1739f7df2e56Smrg if (status != Success) { 1740f7df2e56Smrg free(pAlarm); 1741f7df2e56Smrg return status; 174205b261ecSmrg } 174305b261ecSmrg 174405b261ecSmrg if (!AddResource(stuff->id, RTAlarm, pAlarm)) 1745f7df2e56Smrg return BadAlloc; 174605b261ecSmrg 174705b261ecSmrg /* see if alarm already triggered. NULL counter will not trigger 174805b261ecSmrg * in CreateAlarm and sets alarm state to Inactive. 174905b261ecSmrg */ 175005b261ecSmrg 1751f7df2e56Smrg if (!pTrigger->pSync) { 1752f7df2e56Smrg pAlarm->state = XSyncAlarmInactive; /* XXX protocol change */ 175305b261ecSmrg } 1754f7df2e56Smrg else { 1755f7df2e56Smrg SyncCounter *pCounter; 175665b04b38Smrg 1757f7df2e56Smrg if (!SyncCheckWarnIsCounter(pTrigger->pSync, 1758f7df2e56Smrg WARN_INVALID_COUNTER_ALARM)) { 1759f7df2e56Smrg FreeResource(stuff->id, RT_NONE); 1760f7df2e56Smrg return BadAlloc; 1761f7df2e56Smrg } 176265b04b38Smrg 1763f7df2e56Smrg pCounter = (SyncCounter *) pTrigger->pSync; 176465b04b38Smrg 1765f7df2e56Smrg if ((*pTrigger->CheckTrigger) (pTrigger, pCounter->value)) 1766f7df2e56Smrg (*pTrigger->TriggerFired) (pTrigger); 176705b261ecSmrg } 176805b261ecSmrg 176905b261ecSmrg return Success; 177005b261ecSmrg} 177105b261ecSmrg 177205b261ecSmrg/* 177305b261ecSmrg * ** Change Alarm 177405b261ecSmrg */ 17754202a189Smrgstatic int 17764202a189SmrgProcSyncChangeAlarm(ClientPtr client) 177705b261ecSmrg{ 177805b261ecSmrg REQUEST(xSyncChangeAlarmReq); 1779f7df2e56Smrg SyncAlarm *pAlarm; 178065b04b38Smrg SyncCounter *pCounter = NULL; 1781f7df2e56Smrg long vmask; 1782f7df2e56Smrg int len, status; 178305b261ecSmrg 178405b261ecSmrg REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq); 178505b261ecSmrg 1786f7df2e56Smrg status = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm, 1787f7df2e56Smrg client, DixWriteAccess); 17884202a189Smrg if (status != Success) 1789f7df2e56Smrg return status; 179005b261ecSmrg 179105b261ecSmrg vmask = stuff->valueMask; 17924202a189Smrg len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq)); 179305b261ecSmrg /* the "extra" call to Ones accounts for the presence of 64 bit values */ 1794f7df2e56Smrg if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta)))) 1795f7df2e56Smrg return BadLength; 179605b261ecSmrg 17974202a189Smrg if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask, 1798f7df2e56Smrg (CARD32 *) &stuff[1])) != Success) 1799f7df2e56Smrg return status; 180005b261ecSmrg 180165b04b38Smrg if (SyncCheckWarnIsCounter(pAlarm->trigger.pSync, 1802f7df2e56Smrg WARN_INVALID_COUNTER_ALARM)) 1803f7df2e56Smrg pCounter = (SyncCounter *) pAlarm->trigger.pSync; 180465b04b38Smrg 180505b261ecSmrg /* see if alarm already triggered. NULL counter WILL trigger 180605b261ecSmrg * in ChangeAlarm. 180705b261ecSmrg */ 180805b261ecSmrg 180965b04b38Smrg if (!pCounter || 1810f7df2e56Smrg (*pAlarm->trigger.CheckTrigger) (&pAlarm->trigger, pCounter->value)) { 1811f7df2e56Smrg (*pAlarm->trigger.TriggerFired) (&pAlarm->trigger); 181205b261ecSmrg } 181305b261ecSmrg return Success; 181405b261ecSmrg} 181505b261ecSmrg 18164202a189Smrgstatic int 18174202a189SmrgProcSyncQueryAlarm(ClientPtr client) 181805b261ecSmrg{ 181905b261ecSmrg REQUEST(xSyncQueryAlarmReq); 1820f7df2e56Smrg SyncAlarm *pAlarm; 182105b261ecSmrg xSyncQueryAlarmReply rep; 1822f7df2e56Smrg SyncTrigger *pTrigger; 18234202a189Smrg int rc; 182405b261ecSmrg 182505b261ecSmrg REQUEST_SIZE_MATCH(xSyncQueryAlarmReq); 182605b261ecSmrg 1827f7df2e56Smrg rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm, 1828f7df2e56Smrg client, DixReadAccess); 18294202a189Smrg if (rc != Success) 1830f7df2e56Smrg return rc; 183105b261ecSmrg 183205b261ecSmrg pTrigger = &pAlarm->trigger; 1833f7df2e56Smrg rep = (xSyncQueryAlarmReply) { 1834f7df2e56Smrg .type = X_Reply, 1835f7df2e56Smrg .sequenceNumber = client->sequence, 1836f7df2e56Smrg .length = 1837f7df2e56Smrg bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply)), 1838f7df2e56Smrg .counter = (pTrigger->pSync) ? pTrigger->pSync->id : None, 1839f7df2e56Smrg 1840f7df2e56Smrg#if 0 /* XXX unclear what to do, depends on whether relative value-types 1841f7df2e56Smrg * are "consumed" immediately and are considered absolute from then 1842f7df2e56Smrg * on. 1843f7df2e56Smrg */ 1844f7df2e56Smrg .value_type = pTrigger->value_type, 18457e31ba66Smrg .wait_value_hi = pTrigger->wait_value >> 32, 18467e31ba66Smrg .wait_value_lo = pTrigger->wait_value, 184705b261ecSmrg#else 1848f7df2e56Smrg .value_type = XSyncAbsolute, 18497e31ba66Smrg .wait_value_hi = pTrigger->test_value >> 32, 18507e31ba66Smrg .wait_value_lo = pTrigger->test_value, 185105b261ecSmrg#endif 185205b261ecSmrg 1853f7df2e56Smrg .test_type = pTrigger->test_type, 18547e31ba66Smrg .delta_hi = pAlarm->delta >> 32, 18557e31ba66Smrg .delta_lo = pAlarm->delta, 1856f7df2e56Smrg .events = pAlarm->events, 1857f7df2e56Smrg .state = pAlarm->state 1858f7df2e56Smrg }; 1859f7df2e56Smrg 1860f7df2e56Smrg if (client->swapped) { 1861f7df2e56Smrg swaps(&rep.sequenceNumber); 1862f7df2e56Smrg swapl(&rep.length); 1863f7df2e56Smrg swapl(&rep.counter); 1864f7df2e56Smrg swapl(&rep.wait_value_hi); 1865f7df2e56Smrg swapl(&rep.wait_value_lo); 1866f7df2e56Smrg swapl(&rep.test_type); 1867f7df2e56Smrg swapl(&rep.delta_hi); 1868f7df2e56Smrg swapl(&rep.delta_lo); 1869f7df2e56Smrg } 1870f7df2e56Smrg 1871f7df2e56Smrg WriteToClient(client, sizeof(xSyncQueryAlarmReply), &rep); 18724202a189Smrg return Success; 187305b261ecSmrg} 187405b261ecSmrg 18754202a189Smrgstatic int 18764202a189SmrgProcSyncDestroyAlarm(ClientPtr client) 187705b261ecSmrg{ 18784202a189Smrg SyncAlarm *pAlarm; 18794202a189Smrg int rc; 1880f7df2e56Smrg 188105b261ecSmrg REQUEST(xSyncDestroyAlarmReq); 188205b261ecSmrg 188305b261ecSmrg REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq); 188405b261ecSmrg 1885f7df2e56Smrg rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm, 1886f7df2e56Smrg client, DixDestroyAccess); 18874202a189Smrg if (rc != Success) 1888f7df2e56Smrg return rc; 188905b261ecSmrg 189005b261ecSmrg FreeResource(stuff->alarm, RT_NONE); 18914202a189Smrg return Success; 189205b261ecSmrg} 189305b261ecSmrg 189465b04b38Smrgstatic int 189565b04b38SmrgProcSyncCreateFence(ClientPtr client) 189665b04b38Smrg{ 189765b04b38Smrg REQUEST(xSyncCreateFenceReq); 189865b04b38Smrg DrawablePtr pDraw; 189965b04b38Smrg SyncFence *pFence; 190065b04b38Smrg int rc; 190165b04b38Smrg 190265b04b38Smrg REQUEST_SIZE_MATCH(xSyncCreateFenceReq); 190365b04b38Smrg 190465b04b38Smrg rc = dixLookupDrawable(&pDraw, stuff->d, client, M_ANY, DixGetAttrAccess); 190565b04b38Smrg if (rc != Success) 1906f7df2e56Smrg return rc; 190765b04b38Smrg 190865b04b38Smrg LEGAL_NEW_RESOURCE(stuff->fid, client); 190965b04b38Smrg 1910f7df2e56Smrg if (!(pFence = (SyncFence *) SyncCreate(client, stuff->fid, SYNC_FENCE))) 1911f7df2e56Smrg return BadAlloc; 191265b04b38Smrg 191365b04b38Smrg miSyncInitFence(pDraw->pScreen, pFence, stuff->initially_triggered); 191465b04b38Smrg 19157e31ba66Smrg return Success; 191665b04b38Smrg} 191765b04b38Smrg 191865b04b38Smrgstatic int 191965b04b38SmrgFreeFence(void *obj, XID id) 192065b04b38Smrg{ 192165b04b38Smrg SyncFence *pFence = (SyncFence *) obj; 192265b04b38Smrg 192365b04b38Smrg miSyncDestroyFence(pFence); 192465b04b38Smrg 192565b04b38Smrg return Success; 192665b04b38Smrg} 192765b04b38Smrg 1928f7df2e56Smrgint 1929f7df2e56SmrgSyncVerifyFence(SyncFence ** ppSyncFence, XID fid, ClientPtr client, Mask mode) 193065b04b38Smrg{ 1931f7df2e56Smrg int rc = dixLookupResourceByType((void **) ppSyncFence, fid, RTFence, 1932f7df2e56Smrg client, mode); 193365b04b38Smrg 193465b04b38Smrg if (rc != Success) 1935f7df2e56Smrg client->errorValue = fid; 193665b04b38Smrg 193765b04b38Smrg return rc; 193865b04b38Smrg} 193965b04b38Smrg 194065b04b38Smrgstatic int 194165b04b38SmrgProcSyncTriggerFence(ClientPtr client) 194265b04b38Smrg{ 194365b04b38Smrg REQUEST(xSyncTriggerFenceReq); 194465b04b38Smrg SyncFence *pFence; 194565b04b38Smrg int rc; 194665b04b38Smrg 194765b04b38Smrg REQUEST_SIZE_MATCH(xSyncTriggerFenceReq); 194865b04b38Smrg 1949f7df2e56Smrg rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence, 1950f7df2e56Smrg client, DixWriteAccess); 195165b04b38Smrg if (rc != Success) 1952f7df2e56Smrg return rc; 195365b04b38Smrg 195465b04b38Smrg miSyncTriggerFence(pFence); 195565b04b38Smrg 19567e31ba66Smrg return Success; 195765b04b38Smrg} 195865b04b38Smrg 195965b04b38Smrgstatic int 196065b04b38SmrgProcSyncResetFence(ClientPtr client) 196165b04b38Smrg{ 196265b04b38Smrg REQUEST(xSyncResetFenceReq); 196365b04b38Smrg SyncFence *pFence; 196465b04b38Smrg int rc; 196565b04b38Smrg 196665b04b38Smrg REQUEST_SIZE_MATCH(xSyncResetFenceReq); 196765b04b38Smrg 1968f7df2e56Smrg rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence, 1969f7df2e56Smrg client, DixWriteAccess); 197065b04b38Smrg if (rc != Success) 1971f7df2e56Smrg return rc; 197265b04b38Smrg 197365b04b38Smrg if (pFence->funcs.CheckTriggered(pFence) != TRUE) 1974f7df2e56Smrg return BadMatch; 197565b04b38Smrg 197665b04b38Smrg pFence->funcs.Reset(pFence); 197765b04b38Smrg 19787e31ba66Smrg return Success; 197965b04b38Smrg} 198065b04b38Smrg 198165b04b38Smrgstatic int 198265b04b38SmrgProcSyncDestroyFence(ClientPtr client) 198365b04b38Smrg{ 198465b04b38Smrg REQUEST(xSyncDestroyFenceReq); 198565b04b38Smrg SyncFence *pFence; 198665b04b38Smrg int rc; 198765b04b38Smrg 198865b04b38Smrg REQUEST_SIZE_MATCH(xSyncDestroyFenceReq); 198965b04b38Smrg 1990f7df2e56Smrg rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence, 1991f7df2e56Smrg client, DixDestroyAccess); 199265b04b38Smrg if (rc != Success) 1993f7df2e56Smrg return rc; 199465b04b38Smrg 199565b04b38Smrg FreeResource(stuff->fid, RT_NONE); 19967e31ba66Smrg return Success; 199765b04b38Smrg} 199865b04b38Smrg 199965b04b38Smrgstatic int 200065b04b38SmrgProcSyncQueryFence(ClientPtr client) 200165b04b38Smrg{ 200265b04b38Smrg REQUEST(xSyncQueryFenceReq); 200365b04b38Smrg xSyncQueryFenceReply rep; 200465b04b38Smrg SyncFence *pFence; 200565b04b38Smrg int rc; 200665b04b38Smrg 200765b04b38Smrg REQUEST_SIZE_MATCH(xSyncQueryFenceReq); 200865b04b38Smrg 2009f7df2e56Smrg rc = dixLookupResourceByType((void **) &pFence, stuff->fid, 2010f7df2e56Smrg RTFence, client, DixReadAccess); 201165b04b38Smrg if (rc != Success) 2012f7df2e56Smrg return rc; 201365b04b38Smrg 2014f7df2e56Smrg rep = (xSyncQueryFenceReply) { 2015f7df2e56Smrg .type = X_Reply, 2016f7df2e56Smrg .sequenceNumber = client->sequence, 2017f7df2e56Smrg .length = 0, 201865b04b38Smrg 2019f7df2e56Smrg .triggered = pFence->funcs.CheckTriggered(pFence) 2020f7df2e56Smrg }; 202165b04b38Smrg 2022f7df2e56Smrg if (client->swapped) { 2023f7df2e56Smrg swaps(&rep.sequenceNumber); 2024f7df2e56Smrg swapl(&rep.length); 202565b04b38Smrg } 202665b04b38Smrg 2027f7df2e56Smrg WriteToClient(client, sizeof(xSyncQueryFenceReply), &rep); 20287e31ba66Smrg return Success; 202965b04b38Smrg} 203065b04b38Smrg 203165b04b38Smrgstatic int 203265b04b38SmrgProcSyncAwaitFence(ClientPtr client) 203365b04b38Smrg{ 203465b04b38Smrg REQUEST(xSyncAwaitFenceReq); 203565b04b38Smrg SyncAwaitUnion *pAwaitUnion; 203665b04b38Smrg SyncAwait *pAwait; 2037f7df2e56Smrg 203865b04b38Smrg /* Use CARD32 rather than XSyncFence because XIDs are hard-coded to 203965b04b38Smrg * CARD32 in protocol definitions */ 204065b04b38Smrg CARD32 *pProtocolFences; 204165b04b38Smrg int status; 204265b04b38Smrg int len; 204365b04b38Smrg int items; 204465b04b38Smrg int i; 204565b04b38Smrg 204665b04b38Smrg REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq); 204765b04b38Smrg 204865b04b38Smrg len = client->req_len << 2; 204965b04b38Smrg len -= sz_xSyncAwaitFenceReq; 205065b04b38Smrg items = len / sizeof(CARD32); 205165b04b38Smrg 2052f7df2e56Smrg if (items * sizeof(CARD32) != len) { 2053f7df2e56Smrg return BadLength; 205465b04b38Smrg } 2055f7df2e56Smrg if (items == 0) { 2056f7df2e56Smrg client->errorValue = items; 2057f7df2e56Smrg return BadValue; 205865b04b38Smrg } 205965b04b38Smrg 206065b04b38Smrg if (!(pAwaitUnion = SyncAwaitPrologue(client, items))) 2061f7df2e56Smrg return BadAlloc; 206265b04b38Smrg 206365b04b38Smrg /* don't need to do any more memory allocation for this request! */ 206465b04b38Smrg 2065f7df2e56Smrg pProtocolFences = (CARD32 *) &stuff[1]; 2066f7df2e56Smrg 2067f7df2e56Smrg pAwait = &(pAwaitUnion + 1)->await; /* skip over header */ 2068f7df2e56Smrg for (i = 0; i < items; i++, pProtocolFences++, pAwait++) { 2069f7df2e56Smrg if (*pProtocolFences == None) { 2070f7df2e56Smrg /* this should take care of removing any triggers created by 2071f7df2e56Smrg * this request that have already been registered on sync objects 2072f7df2e56Smrg */ 2073f7df2e56Smrg FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 2074f7df2e56Smrg client->errorValue = *pProtocolFences; 2075f7df2e56Smrg return SyncErrorBase + XSyncBadFence; 2076f7df2e56Smrg } 2077f7df2e56Smrg 2078f7df2e56Smrg pAwait->trigger.pSync = NULL; 2079f7df2e56Smrg /* Provide acceptable values for these unused fields to 2080f7df2e56Smrg * satisfy SyncInitTrigger's validation logic 2081f7df2e56Smrg */ 2082f7df2e56Smrg pAwait->trigger.value_type = XSyncAbsolute; 20837e31ba66Smrg pAwait->trigger.wait_value = 0; 2084f7df2e56Smrg pAwait->trigger.test_type = 0; 2085f7df2e56Smrg 2086f7df2e56Smrg status = SyncInitTrigger(client, &pAwait->trigger, 2087f7df2e56Smrg *pProtocolFences, RTFence, XSyncCAAllTrigger); 2088f7df2e56Smrg if (status != Success) { 2089f7df2e56Smrg /* this should take care of removing any triggers created by 2090f7df2e56Smrg * this request that have already been registered on sync objects 2091f7df2e56Smrg */ 2092f7df2e56Smrg FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 2093f7df2e56Smrg return status; 2094f7df2e56Smrg } 2095f7df2e56Smrg /* this is not a mistake -- same function works for both cases */ 2096f7df2e56Smrg pAwait->trigger.TriggerFired = SyncAwaitTriggerFired; 2097f7df2e56Smrg pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired; 2098f7df2e56Smrg /* event_threshold is unused for fence syncs */ 20997e31ba66Smrg pAwait->event_threshold = 0; 2100f7df2e56Smrg pAwait->pHeader = &pAwaitUnion->header; 2101f7df2e56Smrg pAwaitUnion->header.num_waitconditions++; 210265b04b38Smrg } 210365b04b38Smrg 210465b04b38Smrg SyncAwaitEpilogue(client, items, pAwaitUnion); 210565b04b38Smrg 21067e31ba66Smrg return Success; 210765b04b38Smrg} 210865b04b38Smrg 210905b261ecSmrg/* 211005b261ecSmrg * ** Given an extension request, call the appropriate request procedure 211105b261ecSmrg */ 21124202a189Smrgstatic int 21134202a189SmrgProcSyncDispatch(ClientPtr client) 211405b261ecSmrg{ 211505b261ecSmrg REQUEST(xReq); 211605b261ecSmrg 2117f7df2e56Smrg switch (stuff->data) { 2118f7df2e56Smrg case X_SyncInitialize: 2119f7df2e56Smrg return ProcSyncInitialize(client); 2120f7df2e56Smrg case X_SyncListSystemCounters: 2121f7df2e56Smrg return ProcSyncListSystemCounters(client); 2122f7df2e56Smrg case X_SyncCreateCounter: 2123f7df2e56Smrg return ProcSyncCreateCounter(client); 2124f7df2e56Smrg case X_SyncSetCounter: 2125f7df2e56Smrg return ProcSyncSetCounter(client); 2126f7df2e56Smrg case X_SyncChangeCounter: 2127f7df2e56Smrg return ProcSyncChangeCounter(client); 2128f7df2e56Smrg case X_SyncQueryCounter: 2129f7df2e56Smrg return ProcSyncQueryCounter(client); 2130f7df2e56Smrg case X_SyncDestroyCounter: 2131f7df2e56Smrg return ProcSyncDestroyCounter(client); 2132f7df2e56Smrg case X_SyncAwait: 2133f7df2e56Smrg return ProcSyncAwait(client); 2134f7df2e56Smrg case X_SyncCreateAlarm: 2135f7df2e56Smrg return ProcSyncCreateAlarm(client); 2136f7df2e56Smrg case X_SyncChangeAlarm: 2137f7df2e56Smrg return ProcSyncChangeAlarm(client); 2138f7df2e56Smrg case X_SyncQueryAlarm: 2139f7df2e56Smrg return ProcSyncQueryAlarm(client); 2140f7df2e56Smrg case X_SyncDestroyAlarm: 2141f7df2e56Smrg return ProcSyncDestroyAlarm(client); 2142f7df2e56Smrg case X_SyncSetPriority: 2143f7df2e56Smrg return ProcSyncSetPriority(client); 2144f7df2e56Smrg case X_SyncGetPriority: 2145f7df2e56Smrg return ProcSyncGetPriority(client); 2146f7df2e56Smrg case X_SyncCreateFence: 2147f7df2e56Smrg return ProcSyncCreateFence(client); 2148f7df2e56Smrg case X_SyncTriggerFence: 2149f7df2e56Smrg return ProcSyncTriggerFence(client); 2150f7df2e56Smrg case X_SyncResetFence: 2151f7df2e56Smrg return ProcSyncResetFence(client); 2152f7df2e56Smrg case X_SyncDestroyFence: 2153f7df2e56Smrg return ProcSyncDestroyFence(client); 2154f7df2e56Smrg case X_SyncQueryFence: 2155f7df2e56Smrg return ProcSyncQueryFence(client); 2156f7df2e56Smrg case X_SyncAwaitFence: 2157f7df2e56Smrg return ProcSyncAwaitFence(client); 2158f7df2e56Smrg default: 2159f7df2e56Smrg return BadRequest; 216005b261ecSmrg } 216105b261ecSmrg} 216205b261ecSmrg 216305b261ecSmrg/* 216405b261ecSmrg * Boring Swapping stuff ... 216505b261ecSmrg */ 216605b261ecSmrg 21677e31ba66Smrgstatic int _X_COLD 21684202a189SmrgSProcSyncInitialize(ClientPtr client) 216905b261ecSmrg{ 217005b261ecSmrg REQUEST(xSyncInitializeReq); 2171f7df2e56Smrg swaps(&stuff->length); 2172f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncInitializeReq); 217305b261ecSmrg 217405b261ecSmrg return ProcSyncInitialize(client); 217505b261ecSmrg} 217605b261ecSmrg 21777e31ba66Smrgstatic int _X_COLD 21784202a189SmrgSProcSyncListSystemCounters(ClientPtr client) 217905b261ecSmrg{ 218005b261ecSmrg REQUEST(xSyncListSystemCountersReq); 2181f7df2e56Smrg swaps(&stuff->length); 2182f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncListSystemCountersReq); 218305b261ecSmrg 218405b261ecSmrg return ProcSyncListSystemCounters(client); 218505b261ecSmrg} 218605b261ecSmrg 21877e31ba66Smrgstatic int _X_COLD 21884202a189SmrgSProcSyncCreateCounter(ClientPtr client) 218905b261ecSmrg{ 219005b261ecSmrg REQUEST(xSyncCreateCounterReq); 2191f7df2e56Smrg swaps(&stuff->length); 2192f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncCreateCounterReq); 2193f7df2e56Smrg swapl(&stuff->cid); 2194f7df2e56Smrg swapl(&stuff->initial_value_lo); 2195f7df2e56Smrg swapl(&stuff->initial_value_hi); 219605b261ecSmrg 219705b261ecSmrg return ProcSyncCreateCounter(client); 219805b261ecSmrg} 219905b261ecSmrg 22007e31ba66Smrgstatic int _X_COLD 22014202a189SmrgSProcSyncSetCounter(ClientPtr client) 220205b261ecSmrg{ 220305b261ecSmrg REQUEST(xSyncSetCounterReq); 2204f7df2e56Smrg swaps(&stuff->length); 2205f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncSetCounterReq); 2206f7df2e56Smrg swapl(&stuff->cid); 2207f7df2e56Smrg swapl(&stuff->value_lo); 2208f7df2e56Smrg swapl(&stuff->value_hi); 220905b261ecSmrg 221005b261ecSmrg return ProcSyncSetCounter(client); 221105b261ecSmrg} 221205b261ecSmrg 22137e31ba66Smrgstatic int _X_COLD 22144202a189SmrgSProcSyncChangeCounter(ClientPtr client) 221505b261ecSmrg{ 221605b261ecSmrg REQUEST(xSyncChangeCounterReq); 2217f7df2e56Smrg swaps(&stuff->length); 2218f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncChangeCounterReq); 2219f7df2e56Smrg swapl(&stuff->cid); 2220f7df2e56Smrg swapl(&stuff->value_lo); 2221f7df2e56Smrg swapl(&stuff->value_hi); 222205b261ecSmrg 222305b261ecSmrg return ProcSyncChangeCounter(client); 222405b261ecSmrg} 222505b261ecSmrg 22267e31ba66Smrgstatic int _X_COLD 22274202a189SmrgSProcSyncQueryCounter(ClientPtr client) 222805b261ecSmrg{ 222905b261ecSmrg REQUEST(xSyncQueryCounterReq); 2230f7df2e56Smrg swaps(&stuff->length); 2231f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncQueryCounterReq); 2232f7df2e56Smrg swapl(&stuff->counter); 223305b261ecSmrg 223405b261ecSmrg return ProcSyncQueryCounter(client); 223505b261ecSmrg} 223605b261ecSmrg 22377e31ba66Smrgstatic int _X_COLD 22384202a189SmrgSProcSyncDestroyCounter(ClientPtr client) 223905b261ecSmrg{ 224005b261ecSmrg REQUEST(xSyncDestroyCounterReq); 2241f7df2e56Smrg swaps(&stuff->length); 2242f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncDestroyCounterReq); 2243f7df2e56Smrg swapl(&stuff->counter); 224405b261ecSmrg 224505b261ecSmrg return ProcSyncDestroyCounter(client); 224605b261ecSmrg} 224705b261ecSmrg 22487e31ba66Smrgstatic int _X_COLD 22494202a189SmrgSProcSyncAwait(ClientPtr client) 225005b261ecSmrg{ 225105b261ecSmrg REQUEST(xSyncAwaitReq); 2252f7df2e56Smrg swaps(&stuff->length); 225305b261ecSmrg REQUEST_AT_LEAST_SIZE(xSyncAwaitReq); 225405b261ecSmrg SwapRestL(stuff); 225505b261ecSmrg 225605b261ecSmrg return ProcSyncAwait(client); 225705b261ecSmrg} 225805b261ecSmrg 22597e31ba66Smrgstatic int _X_COLD 22604202a189SmrgSProcSyncCreateAlarm(ClientPtr client) 226105b261ecSmrg{ 226205b261ecSmrg REQUEST(xSyncCreateAlarmReq); 2263f7df2e56Smrg swaps(&stuff->length); 226405b261ecSmrg REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq); 2265f7df2e56Smrg swapl(&stuff->id); 2266f7df2e56Smrg swapl(&stuff->valueMask); 226705b261ecSmrg SwapRestL(stuff); 226805b261ecSmrg 226905b261ecSmrg return ProcSyncCreateAlarm(client); 227005b261ecSmrg} 227105b261ecSmrg 22727e31ba66Smrgstatic int _X_COLD 22734202a189SmrgSProcSyncChangeAlarm(ClientPtr client) 227405b261ecSmrg{ 227505b261ecSmrg REQUEST(xSyncChangeAlarmReq); 2276f7df2e56Smrg swaps(&stuff->length); 227705b261ecSmrg REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq); 2278f7df2e56Smrg swapl(&stuff->alarm); 2279f7df2e56Smrg swapl(&stuff->valueMask); 228005b261ecSmrg SwapRestL(stuff); 228105b261ecSmrg return ProcSyncChangeAlarm(client); 228205b261ecSmrg} 228305b261ecSmrg 22847e31ba66Smrgstatic int _X_COLD 22854202a189SmrgSProcSyncQueryAlarm(ClientPtr client) 228605b261ecSmrg{ 228705b261ecSmrg REQUEST(xSyncQueryAlarmReq); 2288f7df2e56Smrg swaps(&stuff->length); 2289f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncQueryAlarmReq); 2290f7df2e56Smrg swapl(&stuff->alarm); 229105b261ecSmrg 229205b261ecSmrg return ProcSyncQueryAlarm(client); 229305b261ecSmrg} 229405b261ecSmrg 22957e31ba66Smrgstatic int _X_COLD 22964202a189SmrgSProcSyncDestroyAlarm(ClientPtr client) 229705b261ecSmrg{ 229805b261ecSmrg REQUEST(xSyncDestroyAlarmReq); 2299f7df2e56Smrg swaps(&stuff->length); 2300f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq); 2301f7df2e56Smrg swapl(&stuff->alarm); 230205b261ecSmrg 230305b261ecSmrg return ProcSyncDestroyAlarm(client); 230405b261ecSmrg} 230505b261ecSmrg 23067e31ba66Smrgstatic int _X_COLD 23074202a189SmrgSProcSyncSetPriority(ClientPtr client) 230805b261ecSmrg{ 230905b261ecSmrg REQUEST(xSyncSetPriorityReq); 2310f7df2e56Smrg swaps(&stuff->length); 2311f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncSetPriorityReq); 2312f7df2e56Smrg swapl(&stuff->id); 2313f7df2e56Smrg swapl(&stuff->priority); 231405b261ecSmrg 231505b261ecSmrg return ProcSyncSetPriority(client); 231605b261ecSmrg} 231705b261ecSmrg 23187e31ba66Smrgstatic int _X_COLD 23194202a189SmrgSProcSyncGetPriority(ClientPtr client) 232005b261ecSmrg{ 232105b261ecSmrg REQUEST(xSyncGetPriorityReq); 2322f7df2e56Smrg swaps(&stuff->length); 2323f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncGetPriorityReq); 2324f7df2e56Smrg swapl(&stuff->id); 232505b261ecSmrg 232605b261ecSmrg return ProcSyncGetPriority(client); 232705b261ecSmrg} 232805b261ecSmrg 23297e31ba66Smrgstatic int _X_COLD 233065b04b38SmrgSProcSyncCreateFence(ClientPtr client) 233165b04b38Smrg{ 233265b04b38Smrg REQUEST(xSyncCreateFenceReq); 2333f7df2e56Smrg swaps(&stuff->length); 2334f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncCreateFenceReq); 2335875c6e4fSmrg swapl(&stuff->d); 2336f7df2e56Smrg swapl(&stuff->fid); 233765b04b38Smrg 233865b04b38Smrg return ProcSyncCreateFence(client); 233965b04b38Smrg} 234065b04b38Smrg 23417e31ba66Smrgstatic int _X_COLD 234265b04b38SmrgSProcSyncTriggerFence(ClientPtr client) 234365b04b38Smrg{ 234465b04b38Smrg REQUEST(xSyncTriggerFenceReq); 2345f7df2e56Smrg swaps(&stuff->length); 2346f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncTriggerFenceReq); 2347f7df2e56Smrg swapl(&stuff->fid); 234865b04b38Smrg 234965b04b38Smrg return ProcSyncTriggerFence(client); 235065b04b38Smrg} 235165b04b38Smrg 23527e31ba66Smrgstatic int _X_COLD 235365b04b38SmrgSProcSyncResetFence(ClientPtr client) 235465b04b38Smrg{ 235565b04b38Smrg REQUEST(xSyncResetFenceReq); 2356f7df2e56Smrg swaps(&stuff->length); 2357f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncResetFenceReq); 2358f7df2e56Smrg swapl(&stuff->fid); 235965b04b38Smrg 236065b04b38Smrg return ProcSyncResetFence(client); 236165b04b38Smrg} 236265b04b38Smrg 23637e31ba66Smrgstatic int _X_COLD 236465b04b38SmrgSProcSyncDestroyFence(ClientPtr client) 236565b04b38Smrg{ 236665b04b38Smrg REQUEST(xSyncDestroyFenceReq); 2367f7df2e56Smrg swaps(&stuff->length); 2368f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncDestroyFenceReq); 2369f7df2e56Smrg swapl(&stuff->fid); 237065b04b38Smrg 237165b04b38Smrg return ProcSyncDestroyFence(client); 237265b04b38Smrg} 237365b04b38Smrg 23747e31ba66Smrgstatic int _X_COLD 237565b04b38SmrgSProcSyncQueryFence(ClientPtr client) 237665b04b38Smrg{ 237765b04b38Smrg REQUEST(xSyncQueryFenceReq); 2378f7df2e56Smrg swaps(&stuff->length); 2379f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncQueryFenceReq); 2380f7df2e56Smrg swapl(&stuff->fid); 238165b04b38Smrg 238265b04b38Smrg return ProcSyncQueryFence(client); 238365b04b38Smrg} 238465b04b38Smrg 23857e31ba66Smrgstatic int _X_COLD 238665b04b38SmrgSProcSyncAwaitFence(ClientPtr client) 238765b04b38Smrg{ 238865b04b38Smrg REQUEST(xSyncAwaitFenceReq); 2389f7df2e56Smrg swaps(&stuff->length); 239065b04b38Smrg REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq); 239165b04b38Smrg SwapRestL(stuff); 239265b04b38Smrg 239365b04b38Smrg return ProcSyncAwaitFence(client); 239465b04b38Smrg} 239505b261ecSmrg 23967e31ba66Smrgstatic int _X_COLD 23974202a189SmrgSProcSyncDispatch(ClientPtr client) 239805b261ecSmrg{ 239905b261ecSmrg REQUEST(xReq); 240005b261ecSmrg 2401f7df2e56Smrg switch (stuff->data) { 2402f7df2e56Smrg case X_SyncInitialize: 2403f7df2e56Smrg return SProcSyncInitialize(client); 2404f7df2e56Smrg case X_SyncListSystemCounters: 2405f7df2e56Smrg return SProcSyncListSystemCounters(client); 2406f7df2e56Smrg case X_SyncCreateCounter: 2407f7df2e56Smrg return SProcSyncCreateCounter(client); 2408f7df2e56Smrg case X_SyncSetCounter: 2409f7df2e56Smrg return SProcSyncSetCounter(client); 2410f7df2e56Smrg case X_SyncChangeCounter: 2411f7df2e56Smrg return SProcSyncChangeCounter(client); 2412f7df2e56Smrg case X_SyncQueryCounter: 2413f7df2e56Smrg return SProcSyncQueryCounter(client); 2414f7df2e56Smrg case X_SyncDestroyCounter: 2415f7df2e56Smrg return SProcSyncDestroyCounter(client); 2416f7df2e56Smrg case X_SyncAwait: 2417f7df2e56Smrg return SProcSyncAwait(client); 2418f7df2e56Smrg case X_SyncCreateAlarm: 2419f7df2e56Smrg return SProcSyncCreateAlarm(client); 2420f7df2e56Smrg case X_SyncChangeAlarm: 2421f7df2e56Smrg return SProcSyncChangeAlarm(client); 2422f7df2e56Smrg case X_SyncQueryAlarm: 2423f7df2e56Smrg return SProcSyncQueryAlarm(client); 2424f7df2e56Smrg case X_SyncDestroyAlarm: 2425f7df2e56Smrg return SProcSyncDestroyAlarm(client); 2426f7df2e56Smrg case X_SyncSetPriority: 2427f7df2e56Smrg return SProcSyncSetPriority(client); 2428f7df2e56Smrg case X_SyncGetPriority: 2429f7df2e56Smrg return SProcSyncGetPriority(client); 2430f7df2e56Smrg case X_SyncCreateFence: 2431f7df2e56Smrg return SProcSyncCreateFence(client); 2432f7df2e56Smrg case X_SyncTriggerFence: 2433f7df2e56Smrg return SProcSyncTriggerFence(client); 2434f7df2e56Smrg case X_SyncResetFence: 2435f7df2e56Smrg return SProcSyncResetFence(client); 2436f7df2e56Smrg case X_SyncDestroyFence: 2437f7df2e56Smrg return SProcSyncDestroyFence(client); 2438f7df2e56Smrg case X_SyncQueryFence: 2439f7df2e56Smrg return SProcSyncQueryFence(client); 2440f7df2e56Smrg case X_SyncAwaitFence: 2441f7df2e56Smrg return SProcSyncAwaitFence(client); 2442f7df2e56Smrg default: 2443f7df2e56Smrg return BadRequest; 244405b261ecSmrg } 244505b261ecSmrg} 244605b261ecSmrg 244705b261ecSmrg/* 244805b261ecSmrg * Event Swapping 244905b261ecSmrg */ 245005b261ecSmrg 24517e31ba66Smrgstatic void _X_COLD 2452f7df2e56SmrgSCounterNotifyEvent(xSyncCounterNotifyEvent * from, 2453f7df2e56Smrg xSyncCounterNotifyEvent * to) 245405b261ecSmrg{ 245505b261ecSmrg to->type = from->type; 245605b261ecSmrg to->kind = from->kind; 245705b261ecSmrg cpswaps(from->sequenceNumber, to->sequenceNumber); 245805b261ecSmrg cpswapl(from->counter, to->counter); 245905b261ecSmrg cpswapl(from->wait_value_lo, to->wait_value_lo); 246005b261ecSmrg cpswapl(from->wait_value_hi, to->wait_value_hi); 246105b261ecSmrg cpswapl(from->counter_value_lo, to->counter_value_lo); 246205b261ecSmrg cpswapl(from->counter_value_hi, to->counter_value_hi); 246305b261ecSmrg cpswapl(from->time, to->time); 246405b261ecSmrg cpswaps(from->count, to->count); 246505b261ecSmrg to->destroyed = from->destroyed; 246605b261ecSmrg} 246705b261ecSmrg 24687e31ba66Smrgstatic void _X_COLD 2469f7df2e56SmrgSAlarmNotifyEvent(xSyncAlarmNotifyEvent * from, xSyncAlarmNotifyEvent * to) 247005b261ecSmrg{ 247105b261ecSmrg to->type = from->type; 247205b261ecSmrg to->kind = from->kind; 247305b261ecSmrg cpswaps(from->sequenceNumber, to->sequenceNumber); 247405b261ecSmrg cpswapl(from->alarm, to->alarm); 247505b261ecSmrg cpswapl(from->counter_value_lo, to->counter_value_lo); 247605b261ecSmrg cpswapl(from->counter_value_hi, to->counter_value_hi); 247705b261ecSmrg cpswapl(from->alarm_value_lo, to->alarm_value_lo); 247805b261ecSmrg cpswapl(from->alarm_value_hi, to->alarm_value_hi); 247905b261ecSmrg cpswapl(from->time, to->time); 248005b261ecSmrg to->state = from->state; 248105b261ecSmrg} 248205b261ecSmrg 248305b261ecSmrg/* 248405b261ecSmrg * ** Close everything down. ** This is fairly simple for now. 248505b261ecSmrg */ 248605b261ecSmrg/* ARGSUSED */ 24874202a189Smrgstatic void 2488f7df2e56SmrgSyncResetProc(ExtensionEntry * extEntry) 248905b261ecSmrg{ 249005b261ecSmrg RTCounter = 0; 249105b261ecSmrg} 249205b261ecSmrg 249305b261ecSmrg/* 249405b261ecSmrg * ** Initialise the extension. 249505b261ecSmrg */ 24964202a189Smrgvoid 24974202a189SmrgSyncExtensionInit(void) 249805b261ecSmrg{ 249905b261ecSmrg ExtensionEntry *extEntry; 2500f7df2e56Smrg int s; 250165b04b38Smrg 250265b04b38Smrg for (s = 0; s < screenInfo.numScreens; s++) 2503f7df2e56Smrg miSyncSetup(screenInfo.screens[s]); 250405b261ecSmrg 25057e31ba66Smrg RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter"); 25067e31ba66Smrg xorg_list_init(&SysCounterList); 25074202a189Smrg RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm"); 25084202a189Smrg RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait"); 250965b04b38Smrg RTFence = CreateNewResourceType(FreeFence, "SyncFence"); 25104202a189Smrg if (RTAwait) 2511f7df2e56Smrg RTAwait |= RC_NEVERRETAIN; 25124202a189Smrg RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient"); 25134202a189Smrg if (RTAlarmClient) 2514f7df2e56Smrg RTAlarmClient |= RC_NEVERRETAIN; 251505b261ecSmrg 251605b261ecSmrg if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 || 2517f7df2e56Smrg RTAlarmClient == 0 || 2518f7df2e56Smrg (extEntry = AddExtension(SYNC_NAME, 2519f7df2e56Smrg XSyncNumberEvents, XSyncNumberErrors, 2520f7df2e56Smrg ProcSyncDispatch, SProcSyncDispatch, 2521f7df2e56Smrg SyncResetProc, StandardMinorOpcode)) == NULL) { 2522f7df2e56Smrg ErrorF("Sync Extension %d.%d failed to Initialise\n", 2523f7df2e56Smrg SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION); 2524f7df2e56Smrg return; 252505b261ecSmrg } 252605b261ecSmrg 252705b261ecSmrg SyncEventBase = extEntry->eventBase; 252805b261ecSmrg SyncErrorBase = extEntry->errorBase; 2529f7df2e56Smrg EventSwapVector[SyncEventBase + XSyncCounterNotify] = 2530f7df2e56Smrg (EventSwapPtr) SCounterNotifyEvent; 2531f7df2e56Smrg EventSwapVector[SyncEventBase + XSyncAlarmNotify] = 2532f7df2e56Smrg (EventSwapPtr) SAlarmNotifyEvent; 253305b261ecSmrg 25344202a189Smrg SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter); 25354202a189Smrg SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm); 253665b04b38Smrg SetResourceTypeErrorValue(RTFence, SyncErrorBase + XSyncBadFence); 25374202a189Smrg 253805b261ecSmrg /* 253905b261ecSmrg * Although SERVERTIME is implemented by the OS layer, we initialise it 254005b261ecSmrg * here because doing it in OsInit() is too early. The resource database 254105b261ecSmrg * is not initialised when OsInit() is called. This is just about OK 254205b261ecSmrg * because there is always a servertime counter. 254305b261ecSmrg */ 254405b261ecSmrg SyncInitServerTime(); 254505b261ecSmrg SyncInitIdleTime(); 254605b261ecSmrg 254705b261ecSmrg#ifdef DEBUG 254805b261ecSmrg fprintf(stderr, "Sync Extension %d.%d\n", 2549f7df2e56Smrg SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION); 255005b261ecSmrg#endif 255105b261ecSmrg} 255205b261ecSmrg 255305b261ecSmrg/* 255405b261ecSmrg * ***** SERVERTIME implementation - should go in its own file in OS directory? 255505b261ecSmrg */ 255605b261ecSmrg 2557f7df2e56Smrgstatic void *ServertimeCounter; 25587e31ba66Smrgstatic int64_t Now; 25597e31ba66Smrgstatic int64_t *pnext_time; 25607e31ba66Smrg 25617e31ba66Smrgstatic void GetTime(void) 25627e31ba66Smrg{ 25637e31ba66Smrg unsigned long millis = GetTimeInMillis(); 25647e31ba66Smrg unsigned long maxis = Now >> 32; 25657e31ba66Smrg 25667e31ba66Smrg if (millis < (Now & 0xffffffff)) 25677e31ba66Smrg maxis++; 256805b261ecSmrg 25697e31ba66Smrg Now = ((int64_t)maxis << 32) | millis; 257005b261ecSmrg} 257105b261ecSmrg 257205b261ecSmrg/* 257305b261ecSmrg*** Server Block Handler 25744202a189Smrg*** code inspired by multibuffer extension (now deprecated) 257505b261ecSmrg */ 25767e31ba66Smrg/*ARGSUSED*/ static void 25777e31ba66SmrgServertimeBlockHandler(void *env, void *wt) 257805b261ecSmrg{ 257905b261ecSmrg unsigned long timeout; 258005b261ecSmrg 2581f7df2e56Smrg if (pnext_time) { 258205b261ecSmrg GetTime(); 258305b261ecSmrg 25847e31ba66Smrg if (Now >= *pnext_time) { 258505b261ecSmrg timeout = 0; 25864202a189Smrg } 2587f7df2e56Smrg else { 25887e31ba66Smrg timeout = *pnext_time - Now; 258905b261ecSmrg } 2590f7df2e56Smrg AdjustWaitForDelay(wt, timeout); /* os/utils.c */ 259105b261ecSmrg } 259205b261ecSmrg} 259305b261ecSmrg 259405b261ecSmrg/* 259505b261ecSmrg*** Wakeup Handler 259605b261ecSmrg */ 25977e31ba66Smrg/*ARGSUSED*/ static void 25987e31ba66SmrgServertimeWakeupHandler(void *env, int rc) 259905b261ecSmrg{ 2600f7df2e56Smrg if (pnext_time) { 260105b261ecSmrg GetTime(); 260205b261ecSmrg 26037e31ba66Smrg if (Now >= *pnext_time) { 260405b261ecSmrg SyncChangeCounter(ServertimeCounter, Now); 260505b261ecSmrg } 260605b261ecSmrg } 260705b261ecSmrg} 260805b261ecSmrg 260905b261ecSmrgstatic void 26107e31ba66SmrgServertimeQueryValue(void *pCounter, int64_t *pValue_return) 261105b261ecSmrg{ 261205b261ecSmrg GetTime(); 261305b261ecSmrg *pValue_return = Now; 261405b261ecSmrg} 261505b261ecSmrg 261605b261ecSmrgstatic void 26177e31ba66SmrgServertimeBracketValues(void *pCounter, int64_t *pbracket_less, 26187e31ba66Smrg int64_t *pbracket_greater) 261905b261ecSmrg{ 2620f7df2e56Smrg if (!pnext_time && pbracket_greater) { 2621f7df2e56Smrg RegisterBlockAndWakeupHandlers(ServertimeBlockHandler, 2622f7df2e56Smrg ServertimeWakeupHandler, NULL); 262305b261ecSmrg } 2624f7df2e56Smrg else if (pnext_time && !pbracket_greater) { 2625f7df2e56Smrg RemoveBlockAndWakeupHandlers(ServertimeBlockHandler, 2626f7df2e56Smrg ServertimeWakeupHandler, NULL); 262705b261ecSmrg } 262805b261ecSmrg pnext_time = pbracket_greater; 262905b261ecSmrg} 263005b261ecSmrg 263105b261ecSmrgstatic void 263205b261ecSmrgSyncInitServerTime(void) 263305b261ecSmrg{ 26347e31ba66Smrg int64_t resolution = 4; 263505b261ecSmrg 26367e31ba66Smrg Now = GetTimeInMillis(); 263705b261ecSmrg ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution, 2638f7df2e56Smrg XSyncCounterNeverDecreases, 2639f7df2e56Smrg ServertimeQueryValue, 2640f7df2e56Smrg ServertimeBracketValues); 264105b261ecSmrg pnext_time = NULL; 264205b261ecSmrg} 264305b261ecSmrg 264405b261ecSmrg/* 264505b261ecSmrg * IDLETIME implementation 264605b261ecSmrg */ 264705b261ecSmrg 2648f7df2e56Smrgtypedef struct { 26497e31ba66Smrg int64_t *value_less; 26507e31ba66Smrg int64_t *value_greater; 2651f7df2e56Smrg int deviceid; 2652f7df2e56Smrg} IdleCounterPriv; 265305b261ecSmrg 265405b261ecSmrgstatic void 26557e31ba66SmrgIdleTimeQueryValue(void *pCounter, int64_t *pValue_return) 265605b261ecSmrg{ 2657f7df2e56Smrg int deviceid; 2658f7df2e56Smrg CARD32 idle; 2659f7df2e56Smrg 2660f7df2e56Smrg if (pCounter) { 2661f7df2e56Smrg SyncCounter *counter = pCounter; 2662f7df2e56Smrg IdleCounterPriv *priv = SysCounterGetPrivate(counter); 2663f7df2e56Smrg deviceid = priv->deviceid; 2664f7df2e56Smrg } 2665f7df2e56Smrg else 2666f7df2e56Smrg deviceid = XIAllDevices; 2667f7df2e56Smrg idle = GetTimeInMillis() - LastEventTime(deviceid).milliseconds; 26687e31ba66Smrg *pValue_return = idle; 266905b261ecSmrg} 267005b261ecSmrg 267105b261ecSmrgstatic void 26727e31ba66SmrgIdleTimeBlockHandler(void *pCounter, void *wt) 267305b261ecSmrg{ 2674f7df2e56Smrg SyncCounter *counter = pCounter; 2675f7df2e56Smrg IdleCounterPriv *priv = SysCounterGetPrivate(counter); 26767e31ba66Smrg int64_t *less = priv->value_less; 26777e31ba66Smrg int64_t *greater = priv->value_greater; 26787e31ba66Smrg int64_t idle, old_idle; 2679f7df2e56Smrg SyncTriggerList *list = counter->sync.pTriglist; 268045801275Sjmcneill SyncTrigger *trig; 268105b261ecSmrg 2682f7df2e56Smrg if (!less && !greater) 2683f7df2e56Smrg return; 2684f7df2e56Smrg 2685f7df2e56Smrg old_idle = counter->value; 2686f7df2e56Smrg IdleTimeQueryValue(counter, &idle); 2687f7df2e56Smrg counter->value = idle; /* push, so CheckTrigger works */ 2688f7df2e56Smrg 2689f7df2e56Smrg /** 2690f7df2e56Smrg * There's an indefinite amount of time between ProcessInputEvents() 2691f7df2e56Smrg * where the idle time is reset and the time we actually get here. idle 2692f7df2e56Smrg * may be past the lower bracket if we dawdled with the events, so 2693f7df2e56Smrg * check for whether we did reset and bomb out of select immediately. 2694f7df2e56Smrg */ 26957e31ba66Smrg if (less && idle > *less && 2696f7df2e56Smrg LastEventTimeWasReset(priv->deviceid)) { 2697f7df2e56Smrg AdjustWaitForDelay(wt, 0); 26987e31ba66Smrg } else if (less && idle <= *less) { 2699f7df2e56Smrg /* 2700f7df2e56Smrg * We've been idle for less than the threshold value, and someone 2701f7df2e56Smrg * wants to know about that, but now we need to know whether they 2702f7df2e56Smrg * want level or edge trigger. Check the trigger list against the 2703f7df2e56Smrg * current idle time, and if any succeed, bomb out of select() 2704f7df2e56Smrg * immediately so we can reschedule. 2705f7df2e56Smrg */ 2706f7df2e56Smrg 2707f7df2e56Smrg for (list = counter->sync.pTriglist; list; list = list->next) { 2708f7df2e56Smrg trig = list->pTrigger; 2709f7df2e56Smrg if (trig->CheckTrigger(trig, old_idle)) { 2710f7df2e56Smrg AdjustWaitForDelay(wt, 0); 2711f7df2e56Smrg break; 2712f7df2e56Smrg } 2713f7df2e56Smrg } 2714f7df2e56Smrg /* 2715f7df2e56Smrg * We've been called exactly on the idle time, but we have a 2716f7df2e56Smrg * NegativeTransition trigger which requires a transition from an 2717f7df2e56Smrg * idle time greater than this. Schedule a wakeup for the next 2718f7df2e56Smrg * millisecond so we won't miss a transition. 2719f7df2e56Smrg */ 27207e31ba66Smrg if (idle == *less) 2721f7df2e56Smrg AdjustWaitForDelay(wt, 1); 2722f7df2e56Smrg } 2723f7df2e56Smrg else if (greater) { 2724f7df2e56Smrg /* 2725f7df2e56Smrg * There's a threshold in the positive direction. If we've been 2726f7df2e56Smrg * idle less than it, schedule a wakeup for sometime in the future. 2727f7df2e56Smrg * If we've been idle more than it, and someone wants to know about 2728f7df2e56Smrg * that level-triggered, schedule an immediate wakeup. 2729f7df2e56Smrg */ 2730f7df2e56Smrg 27317e31ba66Smrg if (idle < *greater) { 27327e31ba66Smrg AdjustWaitForDelay(wt, *greater - idle); 2733f7df2e56Smrg } 2734f7df2e56Smrg else { 2735f7df2e56Smrg for (list = counter->sync.pTriglist; list; 2736f7df2e56Smrg list = list->next) { 2737f7df2e56Smrg trig = list->pTrigger; 2738f7df2e56Smrg if (trig->CheckTrigger(trig, old_idle)) { 2739f7df2e56Smrg AdjustWaitForDelay(wt, 0); 2740f7df2e56Smrg break; 2741f7df2e56Smrg } 2742f7df2e56Smrg } 2743f7df2e56Smrg } 2744f7df2e56Smrg } 2745f7df2e56Smrg 2746f7df2e56Smrg counter->value = old_idle; /* pop */ 2747f7df2e56Smrg} 2748f7df2e56Smrg 2749f7df2e56Smrgstatic void 27507e31ba66SmrgIdleTimeCheckBrackets(SyncCounter *counter, int64_t idle, 27517e31ba66Smrg int64_t *less, int64_t *greater) 2752f7df2e56Smrg{ 27537e31ba66Smrg if ((greater && idle >= *greater) || 27547e31ba66Smrg (less && idle <= *less)) { 2755f7df2e56Smrg SyncChangeCounter(counter, idle); 2756f7df2e56Smrg } 2757f7df2e56Smrg else 2758f7df2e56Smrg SyncUpdateCounter(counter, idle); 275905b261ecSmrg} 276005b261ecSmrg 276105b261ecSmrgstatic void 27627e31ba66SmrgIdleTimeWakeupHandler(void *pCounter, int rc) 276305b261ecSmrg{ 2764f7df2e56Smrg SyncCounter *counter = pCounter; 2765f7df2e56Smrg IdleCounterPriv *priv = SysCounterGetPrivate(counter); 27667e31ba66Smrg int64_t *less = priv->value_less; 27677e31ba66Smrg int64_t *greater = priv->value_greater; 27687e31ba66Smrg int64_t idle; 276905b261ecSmrg 2770f7df2e56Smrg if (!less && !greater) 2771f7df2e56Smrg return; 277205b261ecSmrg 2773f7df2e56Smrg IdleTimeQueryValue(pCounter, &idle); 277405b261ecSmrg 2775f7df2e56Smrg /* 2776f7df2e56Smrg There is no guarantee for the WakeupHandler to be called within a specific 2777f7df2e56Smrg timeframe. Idletime may go to 0, but by the time we get here, it may be 2778f7df2e56Smrg non-zero and alarms for a pos. transition on 0 won't get triggered. 2779f7df2e56Smrg https://bugs.freedesktop.org/show_bug.cgi?id=70476 2780f7df2e56Smrg */ 2781f7df2e56Smrg if (LastEventTimeWasReset(priv->deviceid)) { 2782f7df2e56Smrg LastEventTimeToggleResetFlag(priv->deviceid, FALSE); 27837e31ba66Smrg if (idle != 0) { 27847e31ba66Smrg IdleTimeCheckBrackets(counter, 0, less, greater); 2785f7df2e56Smrg less = priv->value_less; 2786f7df2e56Smrg greater = priv->value_greater; 2787f7df2e56Smrg } 278805b261ecSmrg } 2789f7df2e56Smrg 2790f7df2e56Smrg IdleTimeCheckBrackets(counter, idle, less, greater); 279105b261ecSmrg} 279205b261ecSmrg 279305b261ecSmrgstatic void 27947e31ba66SmrgIdleTimeBracketValues(void *pCounter, int64_t *pbracket_less, 27957e31ba66Smrg int64_t *pbracket_greater) 279605b261ecSmrg{ 2797f7df2e56Smrg SyncCounter *counter = pCounter; 2798f7df2e56Smrg IdleCounterPriv *priv = SysCounterGetPrivate(counter); 27997e31ba66Smrg int64_t *less = priv->value_less; 28007e31ba66Smrg int64_t *greater = priv->value_greater; 2801f7df2e56Smrg Bool registered = (less || greater); 280205b261ecSmrg 2803f7df2e56Smrg if (registered && !pbracket_less && !pbracket_greater) { 2804f7df2e56Smrg RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler, 2805f7df2e56Smrg IdleTimeWakeupHandler, pCounter); 280605b261ecSmrg } 2807f7df2e56Smrg else if (!registered && (pbracket_less || pbracket_greater)) { 2808f7df2e56Smrg /* Reset flag must be zero so we don't force a idle timer reset on 2809f7df2e56Smrg the first wakeup */ 2810f7df2e56Smrg LastEventTimeToggleResetAll(FALSE); 2811f7df2e56Smrg RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler, 2812f7df2e56Smrg IdleTimeWakeupHandler, pCounter); 281305b261ecSmrg } 281405b261ecSmrg 2815f7df2e56Smrg priv->value_greater = pbracket_greater; 2816f7df2e56Smrg priv->value_less = pbracket_less; 281705b261ecSmrg} 281805b261ecSmrg 2819f7df2e56Smrgstatic SyncCounter* 2820f7df2e56Smrginit_system_idle_counter(const char *name, int deviceid) 282105b261ecSmrg{ 28227e31ba66Smrg int64_t resolution = 4; 28237e31ba66Smrg int64_t idle; 2824f7df2e56Smrg SyncCounter *idle_time_counter; 2825f7df2e56Smrg 2826f7df2e56Smrg IdleTimeQueryValue(NULL, &idle); 282705b261ecSmrg 2828f7df2e56Smrg idle_time_counter = SyncCreateSystemCounter(name, idle, resolution, 2829f7df2e56Smrg XSyncCounterUnrestricted, 2830f7df2e56Smrg IdleTimeQueryValue, 2831f7df2e56Smrg IdleTimeBracketValues); 283205b261ecSmrg 2833f7df2e56Smrg if (idle_time_counter != NULL) { 2834f7df2e56Smrg IdleCounterPriv *priv = malloc(sizeof(IdleCounterPriv)); 283505b261ecSmrg 2836f7df2e56Smrg priv->value_less = priv->value_greater = NULL; 2837f7df2e56Smrg priv->deviceid = deviceid; 2838f7df2e56Smrg 2839f7df2e56Smrg idle_time_counter->pSysCounterInfo->private = priv; 2840f7df2e56Smrg } 2841f7df2e56Smrg 2842f7df2e56Smrg return idle_time_counter; 2843f7df2e56Smrg} 2844f7df2e56Smrg 2845f7df2e56Smrgstatic void 2846f7df2e56SmrgSyncInitIdleTime(void) 2847f7df2e56Smrg{ 2848f7df2e56Smrg init_system_idle_counter("IDLETIME", XIAllDevices); 2849f7df2e56Smrg} 2850f7df2e56Smrg 2851f7df2e56SmrgSyncCounter* 2852f7df2e56SmrgSyncInitDeviceIdleTime(DeviceIntPtr dev) 2853f7df2e56Smrg{ 2854f7df2e56Smrg char timer_name[64]; 2855f7df2e56Smrg sprintf(timer_name, "DEVICEIDLETIME %d", dev->id); 2856f7df2e56Smrg 2857f7df2e56Smrg return init_system_idle_counter(timer_name, dev->id); 2858f7df2e56Smrg} 2859f7df2e56Smrg 2860f7df2e56Smrgvoid SyncRemoveDeviceIdleTime(SyncCounter *counter) 2861f7df2e56Smrg{ 2862f7df2e56Smrg /* FreeAllResources() frees all system counters before the devices are 2863f7df2e56Smrg shut down, check if there are any left before freeing the device's 2864f7df2e56Smrg counter */ 2865f7df2e56Smrg if (counter && !xorg_list_is_empty(&SysCounterList)) 2866f7df2e56Smrg xorg_list_del(&counter->pSysCounterInfo->entry); 286705b261ecSmrg} 2868