sync.c revision 875c6e4f
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 2024202a189Smrg if (!(pCur = malloc(sizeof(SyncTriggerList)))) 203f7df2e56Smrg return BadAlloc; 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 } 332f7df2e56Smrg if (pSync != pTrigger->pSync) { /* new counter for trigger */ 333f7df2e56Smrg SyncDeleteTriggerFromSyncObject(pTrigger); 334f7df2e56Smrg pTrigger->pSync = pSync; 335f7df2e56Smrg newSyncObject = TRUE; 336f7df2e56Smrg } 33705b261ecSmrg } 33805b261ecSmrg 33905b261ecSmrg /* if system counter, ask it what the current value is */ 34005b261ecSmrg 341f7df2e56Smrg if (pSync && SYNC_COUNTER == pSync->type) { 342f7df2e56Smrg pCounter = (SyncCounter *) pSync; 343f7df2e56Smrg 344f7df2e56Smrg if (IsSystemCounter(pCounter)) { 345f7df2e56Smrg (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter, 346f7df2e56Smrg &pCounter->value); 347f7df2e56Smrg } 348f7df2e56Smrg } 349f7df2e56Smrg 350f7df2e56Smrg if (changes & XSyncCAValueType) { 351f7df2e56Smrg if (pTrigger->value_type != XSyncRelative && 352f7df2e56Smrg pTrigger->value_type != XSyncAbsolute) { 353f7df2e56Smrg client->errorValue = pTrigger->value_type; 354f7df2e56Smrg return BadValue; 355f7df2e56Smrg } 356f7df2e56Smrg } 357f7df2e56Smrg 358f7df2e56Smrg if (changes & XSyncCATestType) { 359f7df2e56Smrg 360f7df2e56Smrg if (pSync && SYNC_FENCE == pSync->type) { 361f7df2e56Smrg pTrigger->CheckTrigger = SyncCheckTriggerFence; 362f7df2e56Smrg } 363f7df2e56Smrg else { 364f7df2e56Smrg /* select appropriate CheckTrigger function */ 365f7df2e56Smrg 366f7df2e56Smrg switch (pTrigger->test_type) { 367f7df2e56Smrg case XSyncPositiveTransition: 368f7df2e56Smrg pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition; 369f7df2e56Smrg break; 370f7df2e56Smrg case XSyncNegativeTransition: 371f7df2e56Smrg pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition; 372f7df2e56Smrg break; 373f7df2e56Smrg case XSyncPositiveComparison: 374f7df2e56Smrg pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison; 375f7df2e56Smrg break; 376f7df2e56Smrg case XSyncNegativeComparison: 377f7df2e56Smrg pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison; 378f7df2e56Smrg break; 379f7df2e56Smrg default: 380f7df2e56Smrg client->errorValue = pTrigger->test_type; 381f7df2e56Smrg return BadValue; 382f7df2e56Smrg } 383f7df2e56Smrg } 384f7df2e56Smrg } 385f7df2e56Smrg 386f7df2e56Smrg if (changes & (XSyncCAValueType | XSyncCAValue)) { 387f7df2e56Smrg if (pTrigger->value_type == XSyncAbsolute) 388f7df2e56Smrg pTrigger->test_value = pTrigger->wait_value; 389f7df2e56Smrg else { /* relative */ 390f7df2e56Smrg Bool overflow; 391f7df2e56Smrg 392f7df2e56Smrg if (pCounter == NULL) 393f7df2e56Smrg return BadMatch; 394f7df2e56Smrg 3957e31ba66Smrg overflow = checked_int64_add(&pTrigger->test_value, 3967e31ba66Smrg pCounter->value, pTrigger->wait_value); 397f7df2e56Smrg if (overflow) { 3987e31ba66Smrg client->errorValue = pTrigger->wait_value >> 32; 399f7df2e56Smrg return BadValue; 400f7df2e56Smrg } 401f7df2e56Smrg } 40205b261ecSmrg } 40305b261ecSmrg 40405b261ecSmrg /* we wait until we're sure there are no errors before registering 40505b261ecSmrg * a new counter on a trigger 40605b261ecSmrg */ 407f7df2e56Smrg if (newSyncObject) { 408f7df2e56Smrg if ((rc = SyncAddTriggerToSyncObject(pTrigger)) != Success) 409f7df2e56Smrg return rc; 41005b261ecSmrg } 411f7df2e56Smrg else if (pCounter && IsSystemCounter(pCounter)) { 412f7df2e56Smrg SyncComputeBracketValues(pCounter); 41305b261ecSmrg } 4144202a189Smrg 41505b261ecSmrg return Success; 41605b261ecSmrg} 41705b261ecSmrg 41805b261ecSmrg/* AlarmNotify events happen in response to actions taken on an Alarm or 4194202a189Smrg * the counter used by the alarm. AlarmNotify may be sent to multiple 42005b261ecSmrg * clients. The alarm maintains a list of clients interested in events. 42105b261ecSmrg */ 42205b261ecSmrgstatic void 423f7df2e56SmrgSyncSendAlarmNotifyEvents(SyncAlarm * pAlarm) 42405b261ecSmrg{ 42505b261ecSmrg SyncAlarmClientList *pcl; 42605b261ecSmrg xSyncAlarmNotifyEvent ane; 42705b261ecSmrg SyncTrigger *pTrigger = &pAlarm->trigger; 42865b04b38Smrg SyncCounter *pCounter; 42965b04b38Smrg 43065b04b38Smrg if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM)) 431f7df2e56Smrg return; 43265b04b38Smrg 433f7df2e56Smrg pCounter = (SyncCounter *) pTrigger->pSync; 43405b261ecSmrg 43505b261ecSmrg UpdateCurrentTime(); 43605b261ecSmrg 437f7df2e56Smrg ane = (xSyncAlarmNotifyEvent) { 438f7df2e56Smrg .type = SyncEventBase + XSyncAlarmNotify, 439f7df2e56Smrg .kind = XSyncAlarmNotify, 440f7df2e56Smrg .alarm = pAlarm->alarm_id, 4417e31ba66Smrg .alarm_value_hi = pTrigger->test_value >> 32, 4427e31ba66Smrg .alarm_value_lo = pTrigger->test_value, 443f7df2e56Smrg .time = currentTime.milliseconds, 444f7df2e56Smrg .state = pAlarm->state 445f7df2e56Smrg }; 446f7df2e56Smrg 447f7df2e56Smrg if (pTrigger->pSync && SYNC_COUNTER == pTrigger->pSync->type) { 4487e31ba66Smrg ane.counter_value_hi = pCounter->value >> 32; 4497e31ba66Smrg ane.counter_value_lo = pCounter->value; 45005b261ecSmrg } 451f7df2e56Smrg else { 452f7df2e56Smrg /* XXX what else can we do if there's no counter? */ 453f7df2e56Smrg ane.counter_value_hi = ane.counter_value_lo = 0; 45405b261ecSmrg } 45505b261ecSmrg 45605b261ecSmrg /* send to owner */ 4574202a189Smrg if (pAlarm->events) 458f7df2e56Smrg WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane); 45905b261ecSmrg 46005b261ecSmrg /* send to other interested clients */ 46105b261ecSmrg for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next) 462f7df2e56Smrg WriteEventsToClient(pcl->client, 1, (xEvent *) &ane); 46305b261ecSmrg} 46405b261ecSmrg 4654202a189Smrg/* CounterNotify events only occur in response to an Await. The events 46605b261ecSmrg * go only to the Awaiting client. 46705b261ecSmrg */ 46805b261ecSmrgstatic void 469f7df2e56SmrgSyncSendCounterNotifyEvents(ClientPtr client, SyncAwait ** ppAwait, 470f7df2e56Smrg int num_events) 47105b261ecSmrg{ 47205b261ecSmrg xSyncCounterNotifyEvent *pEvents, *pev; 47305b261ecSmrg int i; 47405b261ecSmrg 47505b261ecSmrg if (client->clientGone) 476f7df2e56Smrg return; 477f7df2e56Smrg pev = pEvents = calloc(num_events, sizeof(xSyncCounterNotifyEvent)); 4784202a189Smrg if (!pEvents) 479f7df2e56Smrg return; 48005b261ecSmrg UpdateCurrentTime(); 481f7df2e56Smrg for (i = 0; i < num_events; i++, ppAwait++, pev++) { 482f7df2e56Smrg SyncTrigger *pTrigger = &(*ppAwait)->trigger; 483f7df2e56Smrg 484f7df2e56Smrg pev->type = SyncEventBase + XSyncCounterNotify; 485f7df2e56Smrg pev->kind = XSyncCounterNotify; 486f7df2e56Smrg pev->counter = pTrigger->pSync->id; 4877e31ba66Smrg pev->wait_value_lo = pTrigger->test_value; 4887e31ba66Smrg pev->wait_value_hi = pTrigger->test_value >> 32; 489f7df2e56Smrg if (SYNC_COUNTER == pTrigger->pSync->type) { 490f7df2e56Smrg SyncCounter *pCounter = (SyncCounter *) pTrigger->pSync; 491f7df2e56Smrg 4927e31ba66Smrg pev->counter_value_lo = pCounter->value; 4937e31ba66Smrg pev->counter_value_hi = pCounter->value >> 32; 494f7df2e56Smrg } 495f7df2e56Smrg else { 496f7df2e56Smrg pev->counter_value_lo = 0; 497f7df2e56Smrg pev->counter_value_hi = 0; 498f7df2e56Smrg } 499f7df2e56Smrg 500f7df2e56Smrg pev->time = currentTime.milliseconds; 501f7df2e56Smrg pev->count = num_events - i - 1; /* events remaining */ 502f7df2e56Smrg pev->destroyed = pTrigger->pSync->beingDestroyed; 50305b261ecSmrg } 50405b261ecSmrg /* swapping will be taken care of by this */ 505f7df2e56Smrg WriteEventsToClient(client, num_events, (xEvent *) pEvents); 5064202a189Smrg free(pEvents); 50705b261ecSmrg} 50805b261ecSmrg 50905b261ecSmrg/* This function is called when an alarm's counter is destroyed. 51005b261ecSmrg * It is plugged into pTrigger->CounterDestroyed (for alarm triggers). 51105b261ecSmrg */ 5124202a189Smrgstatic void 513f7df2e56SmrgSyncAlarmCounterDestroyed(SyncTrigger * pTrigger) 51405b261ecSmrg{ 515f7df2e56Smrg SyncAlarm *pAlarm = (SyncAlarm *) pTrigger; 51605b261ecSmrg 51705b261ecSmrg pAlarm->state = XSyncAlarmInactive; 51805b261ecSmrg SyncSendAlarmNotifyEvents(pAlarm); 51965b04b38Smrg pTrigger->pSync = NULL; 52005b261ecSmrg} 52105b261ecSmrg 5224202a189Smrg/* This function is called when an alarm "goes off." 52305b261ecSmrg * It is plugged into pTrigger->TriggerFired (for alarm triggers). 52405b261ecSmrg */ 52505b261ecSmrgstatic void 526f7df2e56SmrgSyncAlarmTriggerFired(SyncTrigger * pTrigger) 52705b261ecSmrg{ 528f7df2e56Smrg SyncAlarm *pAlarm = (SyncAlarm *) pTrigger; 52965b04b38Smrg SyncCounter *pCounter; 5307e31ba66Smrg int64_t new_test_value; 53105b261ecSmrg 53265b04b38Smrg if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM)) 533f7df2e56Smrg return; 53465b04b38Smrg 535f7df2e56Smrg pCounter = (SyncCounter *) pTrigger->pSync; 53665b04b38Smrg 53705b261ecSmrg /* no need to check alarm unless it's active */ 53805b261ecSmrg if (pAlarm->state != XSyncAlarmActive) 539f7df2e56Smrg return; 54005b261ecSmrg 54105b261ecSmrg /* " if the counter value is None, or if the delta is 0 and 54205b261ecSmrg * the test-type is PositiveComparison or NegativeComparison, 54305b261ecSmrg * no change is made to value (test-value) and the alarm 54405b261ecSmrg * state is changed to Inactive before the event is generated." 54505b261ecSmrg */ 5467e31ba66Smrg if (pCounter == NULL || (pAlarm->delta == 0 547f7df2e56Smrg && (pAlarm->trigger.test_type == 548f7df2e56Smrg XSyncPositiveComparison || 549f7df2e56Smrg pAlarm->trigger.test_type == 550f7df2e56Smrg XSyncNegativeComparison))) 551f7df2e56Smrg pAlarm->state = XSyncAlarmInactive; 55205b261ecSmrg 55305b261ecSmrg new_test_value = pAlarm->trigger.test_value; 55405b261ecSmrg 555f7df2e56Smrg if (pAlarm->state == XSyncAlarmActive) { 556f7df2e56Smrg Bool overflow; 5577e31ba66Smrg int64_t oldvalue; 558f7df2e56Smrg SyncTrigger *paTrigger = &pAlarm->trigger; 559f7df2e56Smrg SyncCounter *paCounter; 560f7df2e56Smrg 561f7df2e56Smrg if (!SyncCheckWarnIsCounter(paTrigger->pSync, 562f7df2e56Smrg WARN_INVALID_COUNTER_ALARM)) 563f7df2e56Smrg return; 564f7df2e56Smrg 565f7df2e56Smrg paCounter = (SyncCounter *) pTrigger->pSync; 566f7df2e56Smrg 567f7df2e56Smrg /* "The alarm is updated by repeatedly adding delta to the 568f7df2e56Smrg * value of the trigger and re-initializing it until it 569f7df2e56Smrg * becomes FALSE." 570f7df2e56Smrg */ 571f7df2e56Smrg oldvalue = paTrigger->test_value; 572f7df2e56Smrg 573f7df2e56Smrg /* XXX really should do something smarter here */ 574f7df2e56Smrg 575f7df2e56Smrg do { 5767e31ba66Smrg overflow = checked_int64_add(&paTrigger->test_value, 5777e31ba66Smrg paTrigger->test_value, pAlarm->delta); 578f7df2e56Smrg } while (!overflow && 579f7df2e56Smrg (*paTrigger->CheckTrigger) (paTrigger, paCounter->value)); 580f7df2e56Smrg 581f7df2e56Smrg new_test_value = paTrigger->test_value; 582f7df2e56Smrg paTrigger->test_value = oldvalue; 583f7df2e56Smrg 584f7df2e56Smrg /* "If this update would cause value to fall outside the range 585f7df2e56Smrg * for an INT64...no change is made to value (test-value) and 586f7df2e56Smrg * the alarm state is changed to Inactive before the event is 587f7df2e56Smrg * generated." 588f7df2e56Smrg */ 589f7df2e56Smrg if (overflow) { 590f7df2e56Smrg new_test_value = oldvalue; 591f7df2e56Smrg pAlarm->state = XSyncAlarmInactive; 592f7df2e56Smrg } 59305b261ecSmrg } 59405b261ecSmrg /* The AlarmNotify event has to have the "new state of the alarm" 59505b261ecSmrg * which we can't be sure of until this point. However, it has 59605b261ecSmrg * to have the "old" trigger test value. That's the reason for 59705b261ecSmrg * all the newvalue/oldvalue shuffling above. After we send the 59805b261ecSmrg * events, give the trigger its new test value. 59905b261ecSmrg */ 60005b261ecSmrg SyncSendAlarmNotifyEvents(pAlarm); 60105b261ecSmrg pTrigger->test_value = new_test_value; 60205b261ecSmrg} 60305b261ecSmrg 60405b261ecSmrg/* This function is called when an Await unblocks, either as a result 60505b261ecSmrg * of the trigger firing OR the counter being destroyed. 60605b261ecSmrg * It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed 60705b261ecSmrg * (for Await triggers). 60805b261ecSmrg */ 60905b261ecSmrgstatic void 610f7df2e56SmrgSyncAwaitTriggerFired(SyncTrigger * pTrigger) 61105b261ecSmrg{ 612f7df2e56Smrg SyncAwait *pAwait = (SyncAwait *) pTrigger; 61305b261ecSmrg int numwaits; 61405b261ecSmrg SyncAwaitUnion *pAwaitUnion; 61505b261ecSmrg SyncAwait **ppAwait; 61605b261ecSmrg int num_events = 0; 61705b261ecSmrg 618f7df2e56Smrg pAwaitUnion = (SyncAwaitUnion *) pAwait->pHeader; 61905b261ecSmrg numwaits = pAwaitUnion->header.num_waitconditions; 620f7df2e56Smrg ppAwait = xallocarray(numwaits, sizeof(SyncAwait *)); 62105b261ecSmrg if (!ppAwait) 622f7df2e56Smrg goto bail; 62305b261ecSmrg 624f7df2e56Smrg pAwait = &(pAwaitUnion + 1)->await; 62505b261ecSmrg 62605b261ecSmrg /* "When a client is unblocked, all the CounterNotify events for 62705b261ecSmrg * the Await request are generated contiguously. If count is 0 62805b261ecSmrg * there are no more events to follow for this request. If 62905b261ecSmrg * count is n, there are at least n more events to follow." 63005b261ecSmrg * 63105b261ecSmrg * Thus, it is best to find all the counters for which events 63205b261ecSmrg * need to be sent first, so that an accurate count field can 63305b261ecSmrg * be stored in the events. 63405b261ecSmrg */ 635f7df2e56Smrg for (; numwaits; numwaits--, pAwait++) { 6367e31ba66Smrg int64_t diff; 637f7df2e56Smrg Bool overflow, diffgreater, diffequal; 638f7df2e56Smrg 639f7df2e56Smrg /* "A CounterNotify event with the destroyed flag set to TRUE is 640f7df2e56Smrg * always generated if the counter for one of the triggers is 641f7df2e56Smrg * destroyed." 642f7df2e56Smrg */ 643f7df2e56Smrg if (pAwait->trigger.pSync->beingDestroyed) { 644f7df2e56Smrg ppAwait[num_events++] = pAwait; 645f7df2e56Smrg continue; 646f7df2e56Smrg } 647f7df2e56Smrg 648f7df2e56Smrg if (SYNC_COUNTER == pAwait->trigger.pSync->type) { 649f7df2e56Smrg SyncCounter *pCounter = (SyncCounter *) pAwait->trigger.pSync; 650f7df2e56Smrg 651f7df2e56Smrg /* "The difference between the counter and the test value is 652f7df2e56Smrg * calculated by subtracting the test value from the value of 653f7df2e56Smrg * the counter." 654f7df2e56Smrg */ 6557e31ba66Smrg overflow = checked_int64_subtract(&diff, pCounter->value, 6567e31ba66Smrg pAwait->trigger.test_value); 657f7df2e56Smrg 658f7df2e56Smrg /* "If the difference lies outside the range for an INT64, an 659f7df2e56Smrg * event is not generated." 660f7df2e56Smrg */ 661f7df2e56Smrg if (overflow) 662f7df2e56Smrg continue; 6637e31ba66Smrg diffgreater = diff > pAwait->event_threshold; 6647e31ba66Smrg diffequal = diff == pAwait->event_threshold; 665f7df2e56Smrg 666f7df2e56Smrg /* "If the test-type is PositiveTransition or 667f7df2e56Smrg * PositiveComparison, a CounterNotify event is generated if 668f7df2e56Smrg * the difference is at least event-threshold. If the test-type 669f7df2e56Smrg * is NegativeTransition or NegativeComparison, a CounterNotify 670f7df2e56Smrg * event is generated if the difference is at most 671f7df2e56Smrg * event-threshold." 672f7df2e56Smrg */ 673f7df2e56Smrg 674f7df2e56Smrg if (((pAwait->trigger.test_type == XSyncPositiveComparison || 675f7df2e56Smrg pAwait->trigger.test_type == XSyncPositiveTransition) 676f7df2e56Smrg && (diffgreater || diffequal)) 677f7df2e56Smrg || 678f7df2e56Smrg ((pAwait->trigger.test_type == XSyncNegativeComparison || 679f7df2e56Smrg pAwait->trigger.test_type == XSyncNegativeTransition) 680f7df2e56Smrg && (!diffgreater) /* less or equal */ 681f7df2e56Smrg ) 682f7df2e56Smrg ) { 683f7df2e56Smrg ppAwait[num_events++] = pAwait; 684f7df2e56Smrg } 685f7df2e56Smrg } 68605b261ecSmrg } 68705b261ecSmrg if (num_events) 688f7df2e56Smrg SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait, 689f7df2e56Smrg num_events); 6904202a189Smrg free(ppAwait); 69105b261ecSmrg 692f7df2e56Smrg bail: 69305b261ecSmrg /* unblock the client */ 69405b261ecSmrg AttendClient(pAwaitUnion->header.client); 69505b261ecSmrg /* delete the await */ 69605b261ecSmrg FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 69705b261ecSmrg} 69805b261ecSmrg 6997e31ba66Smrgstatic int64_t 7007e31ba66SmrgSyncUpdateCounter(SyncCounter *pCounter, int64_t newval) 701f7df2e56Smrg{ 7027e31ba66Smrg int64_t oldval = pCounter->value; 703f7df2e56Smrg pCounter->value = newval; 704f7df2e56Smrg return oldval; 705f7df2e56Smrg} 70605b261ecSmrg 70705b261ecSmrg/* This function should always be used to change a counter's value so that 70805b261ecSmrg * any triggers depending on the counter will be checked. 70905b261ecSmrg */ 71005b261ecSmrgvoid 7117e31ba66SmrgSyncChangeCounter(SyncCounter * pCounter, int64_t newval) 71205b261ecSmrg{ 713f7df2e56Smrg SyncTriggerList *ptl, *pnext; 7147e31ba66Smrg int64_t oldval; 71505b261ecSmrg 716f7df2e56Smrg oldval = SyncUpdateCounter(pCounter, newval); 71705b261ecSmrg 71805b261ecSmrg /* run through triggers to see if any become true */ 719f7df2e56Smrg for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) { 720f7df2e56Smrg pnext = ptl->next; 721f7df2e56Smrg if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, oldval)) 722f7df2e56Smrg (*ptl->pTrigger->TriggerFired) (ptl->pTrigger); 72305b261ecSmrg } 72405b261ecSmrg 725f7df2e56Smrg if (IsSystemCounter(pCounter)) { 726f7df2e56Smrg SyncComputeBracketValues(pCounter); 72705b261ecSmrg } 72805b261ecSmrg} 72905b261ecSmrg 73005b261ecSmrg/* loosely based on dix/events.c/EventSelectForWindow */ 73105b261ecSmrgstatic Bool 732f7df2e56SmrgSyncEventSelectForAlarm(SyncAlarm * pAlarm, ClientPtr client, Bool wantevents) 73305b261ecSmrg{ 73405b261ecSmrg SyncAlarmClientList *pClients; 73505b261ecSmrg 736f7df2e56Smrg if (client == pAlarm->client) { /* alarm owner */ 737f7df2e56Smrg pAlarm->events = wantevents; 738f7df2e56Smrg return Success; 73905b261ecSmrg } 74005b261ecSmrg 74105b261ecSmrg /* see if the client is already on the list (has events selected) */ 74205b261ecSmrg 743f7df2e56Smrg for (pClients = pAlarm->pEventClients; pClients; pClients = pClients->next) { 744f7df2e56Smrg if (pClients->client == client) { 745f7df2e56Smrg /* client's presence on the list indicates desire for 746f7df2e56Smrg * events. If the client doesn't want events, remove it 747f7df2e56Smrg * from the list. If the client does want events, do 748f7df2e56Smrg * nothing, since it's already got them. 749f7df2e56Smrg */ 750f7df2e56Smrg if (!wantevents) { 751f7df2e56Smrg FreeResource(pClients->delete_id, RT_NONE); 752f7df2e56Smrg } 753f7df2e56Smrg return Success; 754f7df2e56Smrg } 75505b261ecSmrg } 75605b261ecSmrg 75705b261ecSmrg /* if we get here, this client does not currently have 75805b261ecSmrg * events selected on the alarm 75905b261ecSmrg */ 76005b261ecSmrg 76105b261ecSmrg if (!wantevents) 762f7df2e56Smrg /* client doesn't want events, and we just discovered that it 763f7df2e56Smrg * doesn't have them, so there's nothing to do. 764f7df2e56Smrg */ 765f7df2e56Smrg return Success; 76605b261ecSmrg 76705b261ecSmrg /* add new client to pAlarm->pEventClients */ 76805b261ecSmrg 7694202a189Smrg pClients = malloc(sizeof(SyncAlarmClientList)); 77005b261ecSmrg if (!pClients) 771f7df2e56Smrg return BadAlloc; 77205b261ecSmrg 7734202a189Smrg /* register it as a resource so it will be cleaned up 77405b261ecSmrg * if the client dies 77505b261ecSmrg */ 77605b261ecSmrg 77705b261ecSmrg pClients->delete_id = FakeClientID(client->index); 77805b261ecSmrg 77905b261ecSmrg /* link it into list after we know all the allocations succeed */ 78005b261ecSmrg pClients->next = pAlarm->pEventClients; 78105b261ecSmrg pAlarm->pEventClients = pClients; 78205b261ecSmrg pClients->client = client; 78365b04b38Smrg 78465b04b38Smrg if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm)) 785f7df2e56Smrg return BadAlloc; 78665b04b38Smrg 78705b261ecSmrg return Success; 78805b261ecSmrg} 78905b261ecSmrg 79005b261ecSmrg/* 79105b261ecSmrg * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm 79205b261ecSmrg */ 7934202a189Smrgstatic int 794f7df2e56SmrgSyncChangeAlarmAttributes(ClientPtr client, SyncAlarm * pAlarm, Mask mask, 795f7df2e56Smrg CARD32 *values) 796f7df2e56Smrg{ 797f7df2e56Smrg int status; 798f7df2e56Smrg XSyncCounter counter; 799f7df2e56Smrg Mask origmask = mask; 800f7df2e56Smrg 801f7df2e56Smrg counter = pAlarm->trigger.pSync ? pAlarm->trigger.pSync->id : None; 802f7df2e56Smrg 803f7df2e56Smrg while (mask) { 804f7df2e56Smrg int index2 = lowbit(mask); 805f7df2e56Smrg 806f7df2e56Smrg mask &= ~index2; 807f7df2e56Smrg switch (index2) { 808f7df2e56Smrg case XSyncCACounter: 809f7df2e56Smrg mask &= ~XSyncCACounter; 810f7df2e56Smrg /* sanity check in SyncInitTrigger */ 811f7df2e56Smrg counter = *values++; 812f7df2e56Smrg break; 813f7df2e56Smrg 814f7df2e56Smrg case XSyncCAValueType: 815f7df2e56Smrg mask &= ~XSyncCAValueType; 816f7df2e56Smrg /* sanity check in SyncInitTrigger */ 817f7df2e56Smrg pAlarm->trigger.value_type = *values++; 818f7df2e56Smrg break; 819f7df2e56Smrg 820f7df2e56Smrg case XSyncCAValue: 821f7df2e56Smrg mask &= ~XSyncCAValue; 8227e31ba66Smrg pAlarm->trigger.wait_value = ((int64_t)values[0] << 32) | values[1]; 823f7df2e56Smrg values += 2; 824f7df2e56Smrg break; 825f7df2e56Smrg 826f7df2e56Smrg case XSyncCATestType: 827f7df2e56Smrg mask &= ~XSyncCATestType; 828f7df2e56Smrg /* sanity check in SyncInitTrigger */ 829f7df2e56Smrg pAlarm->trigger.test_type = *values++; 830f7df2e56Smrg break; 831f7df2e56Smrg 832f7df2e56Smrg case XSyncCADelta: 833f7df2e56Smrg mask &= ~XSyncCADelta; 8347e31ba66Smrg pAlarm->delta = ((int64_t)values[0] << 32) | values[1]; 835f7df2e56Smrg values += 2; 836f7df2e56Smrg break; 837f7df2e56Smrg 838f7df2e56Smrg case XSyncCAEvents: 839f7df2e56Smrg mask &= ~XSyncCAEvents; 840f7df2e56Smrg if ((*values != xTrue) && (*values != xFalse)) { 841f7df2e56Smrg client->errorValue = *values; 842f7df2e56Smrg return BadValue; 843f7df2e56Smrg } 844f7df2e56Smrg status = SyncEventSelectForAlarm(pAlarm, client, 845f7df2e56Smrg (Bool) (*values++)); 846f7df2e56Smrg if (status != Success) 847f7df2e56Smrg return status; 848f7df2e56Smrg break; 849f7df2e56Smrg 850f7df2e56Smrg default: 851f7df2e56Smrg client->errorValue = mask; 852f7df2e56Smrg return BadValue; 853f7df2e56Smrg } 85405b261ecSmrg } 85505b261ecSmrg 85605b261ecSmrg /* "If the test-type is PositiveComparison or PositiveTransition 85705b261ecSmrg * and delta is less than zero, or if the test-type is 85805b261ecSmrg * NegativeComparison or NegativeTransition and delta is 85905b261ecSmrg * greater than zero, a Match error is generated." 86005b261ecSmrg */ 861f7df2e56Smrg if (origmask & (XSyncCADelta | XSyncCATestType)) { 862f7df2e56Smrg if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) || 863f7df2e56Smrg (pAlarm->trigger.test_type == XSyncPositiveTransition)) 8647e31ba66Smrg && pAlarm->delta < 0) 865f7df2e56Smrg || 866f7df2e56Smrg (((pAlarm->trigger.test_type == XSyncNegativeComparison) || 867f7df2e56Smrg (pAlarm->trigger.test_type == XSyncNegativeTransition)) 8687e31ba66Smrg && pAlarm->delta > 0) 869f7df2e56Smrg ) { 870f7df2e56Smrg return BadMatch; 871f7df2e56Smrg } 87205b261ecSmrg } 87305b261ecSmrg 87405b261ecSmrg /* postpone this until now, when we're sure nothing else can go wrong */ 87565b04b38Smrg if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter, 876f7df2e56Smrg origmask & XSyncCAAllTrigger)) != Success) 877f7df2e56Smrg return status; 87805b261ecSmrg 87905b261ecSmrg /* XXX spec does not really say to do this - needs clarification */ 88005b261ecSmrg pAlarm->state = XSyncAlarmActive; 88105b261ecSmrg return Success; 88205b261ecSmrg} 88305b261ecSmrg 8844e185dc0SmrgSyncObject * 88565b04b38SmrgSyncCreate(ClientPtr client, XID id, unsigned char type) 88665b04b38Smrg{ 88765b04b38Smrg SyncObject *pSync; 8884e185dc0Smrg RESTYPE resType; 88965b04b38Smrg 89065b04b38Smrg switch (type) { 89165b04b38Smrg case SYNC_COUNTER: 892f7df2e56Smrg pSync = malloc(sizeof(SyncCounter)); 8934e185dc0Smrg resType = RTCounter; 894f7df2e56Smrg break; 89565b04b38Smrg case SYNC_FENCE: 896f7df2e56Smrg pSync = (SyncObject *) dixAllocateObjectWithPrivates(SyncFence, 897f7df2e56Smrg PRIVATE_SYNC_FENCE); 8984e185dc0Smrg resType = RTFence; 899f7df2e56Smrg break; 90065b04b38Smrg default: 901f7df2e56Smrg return NULL; 90265b04b38Smrg } 90365b04b38Smrg 90465b04b38Smrg if (!pSync) 905f7df2e56Smrg return NULL; 90665b04b38Smrg 9074e185dc0Smrg pSync->initialized = FALSE; 9084e185dc0Smrg 9094e185dc0Smrg if (!AddResource(id, resType, (void *) pSync)) 9104e185dc0Smrg return NULL; 9114e185dc0Smrg 91265b04b38Smrg pSync->client = client; 91365b04b38Smrg pSync->id = id; 91465b04b38Smrg pSync->pTriglist = NULL; 91565b04b38Smrg pSync->beingDestroyed = FALSE; 91665b04b38Smrg pSync->type = type; 91765b04b38Smrg 91865b04b38Smrg return pSync; 91965b04b38Smrg} 92065b04b38Smrg 921f7df2e56Smrgint 922f7df2e56SmrgSyncCreateFenceFromFD(ClientPtr client, DrawablePtr pDraw, XID id, int fd, BOOL initially_triggered) 923f7df2e56Smrg{ 9247e31ba66Smrg#ifdef HAVE_XSHMFENCE 925f7df2e56Smrg SyncFence *pFence; 926f7df2e56Smrg int status; 927f7df2e56Smrg 928f7df2e56Smrg pFence = (SyncFence *) SyncCreate(client, id, SYNC_FENCE); 929f7df2e56Smrg if (!pFence) 930f7df2e56Smrg return BadAlloc; 931f7df2e56Smrg 932f7df2e56Smrg status = miSyncInitFenceFromFD(pDraw, pFence, fd, initially_triggered); 933f7df2e56Smrg if (status != Success) { 9344e185dc0Smrg FreeResource(pFence->sync.id, RT_NONE); 935f7df2e56Smrg return status; 936f7df2e56Smrg } 937f7df2e56Smrg 938f7df2e56Smrg return Success; 939f7df2e56Smrg#else 940f7df2e56Smrg return BadImplementation; 941f7df2e56Smrg#endif 942f7df2e56Smrg} 943f7df2e56Smrg 944f7df2e56Smrgint 945f7df2e56SmrgSyncFDFromFence(ClientPtr client, DrawablePtr pDraw, SyncFence *pFence) 946f7df2e56Smrg{ 9477e31ba66Smrg#ifdef HAVE_XSHMFENCE 948f7df2e56Smrg return miSyncFDFromFence(pDraw, pFence); 949f7df2e56Smrg#else 950f7df2e56Smrg return BadImplementation; 951f7df2e56Smrg#endif 952f7df2e56Smrg} 95305b261ecSmrg 95405b261ecSmrgstatic SyncCounter * 9557e31ba66SmrgSyncCreateCounter(ClientPtr client, XSyncCounter id, int64_t initialvalue) 95605b261ecSmrg{ 95705b261ecSmrg SyncCounter *pCounter; 95805b261ecSmrg 959f7df2e56Smrg if (!(pCounter = (SyncCounter *) SyncCreate(client, id, SYNC_COUNTER))) 960f7df2e56Smrg return NULL; 96105b261ecSmrg 96265b04b38Smrg pCounter->value = initialvalue; 96365b04b38Smrg pCounter->pSysCounterInfo = NULL; 96465b04b38Smrg 9654e185dc0Smrg pCounter->sync.initialized = TRUE; 96605b261ecSmrg 96705b261ecSmrg return pCounter; 96805b261ecSmrg} 96905b261ecSmrg 9704202a189Smrgstatic int FreeCounter(void *, XID); 97105b261ecSmrg 97205b261ecSmrg/* 97305b261ecSmrg * ***** System Counter utilities 97405b261ecSmrg */ 97505b261ecSmrg 976f7df2e56SmrgSyncCounter* 977f7df2e56SmrgSyncCreateSystemCounter(const char *name, 9787e31ba66Smrg int64_t initial, 9797e31ba66Smrg int64_t resolution, 980f7df2e56Smrg SyncCounterType counterType, 981f7df2e56Smrg SyncSystemCounterQueryValue QueryValue, 982f7df2e56Smrg SyncSystemCounterBracketValues BracketValues 983f7df2e56Smrg ) 984f7df2e56Smrg{ 9857e31ba66Smrg SyncCounter *pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial); 98605b261ecSmrg 987f7df2e56Smrg if (pCounter) { 988f7df2e56Smrg SysCounterInfo *psci; 989f7df2e56Smrg 990f7df2e56Smrg psci = malloc(sizeof(SysCounterInfo)); 991f7df2e56Smrg if (!psci) { 992f7df2e56Smrg FreeResource(pCounter->sync.id, RT_NONE); 993f7df2e56Smrg return pCounter; 994f7df2e56Smrg } 995f7df2e56Smrg pCounter->pSysCounterInfo = psci; 996f7df2e56Smrg psci->pCounter = pCounter; 997f7df2e56Smrg psci->name = strdup(name); 998f7df2e56Smrg psci->resolution = resolution; 999f7df2e56Smrg psci->counterType = counterType; 1000f7df2e56Smrg psci->QueryValue = QueryValue; 1001f7df2e56Smrg psci->BracketValues = BracketValues; 1002f7df2e56Smrg psci->private = NULL; 10037e31ba66Smrg psci->bracket_greater = LLONG_MAX; 10047e31ba66Smrg psci->bracket_less = LLONG_MIN; 1005f7df2e56Smrg xorg_list_add(&psci->entry, &SysCounterList); 100605b261ecSmrg } 10074202a189Smrg return pCounter; 100805b261ecSmrg} 100905b261ecSmrg 101005b261ecSmrgvoid 1011f7df2e56SmrgSyncDestroySystemCounter(void *pSysCounter) 101205b261ecSmrg{ 1013f7df2e56Smrg SyncCounter *pCounter = (SyncCounter *) pSysCounter; 1014f7df2e56Smrg 101565b04b38Smrg FreeResource(pCounter->sync.id, RT_NONE); 101605b261ecSmrg} 101705b261ecSmrg 101805b261ecSmrgstatic void 1019f7df2e56SmrgSyncComputeBracketValues(SyncCounter * pCounter) 102005b261ecSmrg{ 102105b261ecSmrg SyncTriggerList *pCur; 102205b261ecSmrg SyncTrigger *pTrigger; 102305b261ecSmrg SysCounterInfo *psci; 10247e31ba66Smrg int64_t *pnewgtval = NULL; 10257e31ba66Smrg int64_t *pnewltval = NULL; 102605b261ecSmrg SyncCounterType ct; 102705b261ecSmrg 102805b261ecSmrg if (!pCounter) 1029f7df2e56Smrg return; 103005b261ecSmrg 103105b261ecSmrg psci = pCounter->pSysCounterInfo; 103205b261ecSmrg ct = pCounter->pSysCounterInfo->counterType; 103305b261ecSmrg if (ct == XSyncCounterNeverChanges) 1034f7df2e56Smrg return; 103505b261ecSmrg 10367e31ba66Smrg psci->bracket_greater = LLONG_MAX; 10377e31ba66Smrg psci->bracket_less = LLONG_MIN; 103805b261ecSmrg 1039f7df2e56Smrg for (pCur = pCounter->sync.pTriglist; pCur; pCur = pCur->next) { 1040f7df2e56Smrg pTrigger = pCur->pTrigger; 1041f7df2e56Smrg 104205b261ecSmrg if (pTrigger->test_type == XSyncPositiveComparison && 1043f7df2e56Smrg ct != XSyncCounterNeverIncreases) { 10447e31ba66Smrg if (pCounter->value < pTrigger->test_value && 10457e31ba66Smrg pTrigger->test_value < psci->bracket_greater) { 1046f7df2e56Smrg psci->bracket_greater = pTrigger->test_value; 1047f7df2e56Smrg pnewgtval = &psci->bracket_greater; 1048f7df2e56Smrg } 10497e31ba66Smrg else if (pCounter->value > pTrigger->test_value && 10507e31ba66Smrg pTrigger->test_value > psci->bracket_less) { 1051f7df2e56Smrg psci->bracket_less = pTrigger->test_value; 1052f7df2e56Smrg pnewltval = &psci->bracket_less; 1053f7df2e56Smrg } 1054f7df2e56Smrg } 1055f7df2e56Smrg else if (pTrigger->test_type == XSyncNegativeComparison && 1056f7df2e56Smrg ct != XSyncCounterNeverDecreases) { 10577e31ba66Smrg if (pCounter->value > pTrigger->test_value && 10587e31ba66Smrg pTrigger->test_value > psci->bracket_less) { 1059f7df2e56Smrg psci->bracket_less = pTrigger->test_value; 1060f7df2e56Smrg pnewltval = &psci->bracket_less; 1061f7df2e56Smrg } 10627e31ba66Smrg else if (pCounter->value < pTrigger->test_value && 10637e31ba66Smrg pTrigger->test_value < psci->bracket_greater) { 1064f7df2e56Smrg psci->bracket_greater = pTrigger->test_value; 1065f7df2e56Smrg pnewgtval = &psci->bracket_greater; 1066f7df2e56Smrg } 1067f7df2e56Smrg } 1068f7df2e56Smrg else if (pTrigger->test_type == XSyncNegativeTransition && 1069f7df2e56Smrg ct != XSyncCounterNeverIncreases) { 10707e31ba66Smrg if (pCounter->value >= pTrigger->test_value && 10717e31ba66Smrg pTrigger->test_value > psci->bracket_less) { 1072f7df2e56Smrg /* 1073f7df2e56Smrg * If the value is exactly equal to our threshold, we want one 1074f7df2e56Smrg * more event in the negative direction to ensure we pick up 1075f7df2e56Smrg * when the value is less than this threshold. 1076f7df2e56Smrg */ 1077f7df2e56Smrg psci->bracket_less = pTrigger->test_value; 1078f7df2e56Smrg pnewltval = &psci->bracket_less; 1079f7df2e56Smrg } 10807e31ba66Smrg else if (pCounter->value < pTrigger->test_value && 10817e31ba66Smrg pTrigger->test_value < psci->bracket_greater) { 1082f7df2e56Smrg psci->bracket_greater = pTrigger->test_value; 1083f7df2e56Smrg pnewgtval = &psci->bracket_greater; 1084f7df2e56Smrg } 1085f7df2e56Smrg } 1086a0d10bb6Smrg else if (pTrigger->test_type == XSyncPositiveTransition && 1087f7df2e56Smrg ct != XSyncCounterNeverDecreases) { 10887e31ba66Smrg if (pCounter->value <= pTrigger->test_value && 10897e31ba66Smrg pTrigger->test_value < psci->bracket_greater) { 1090f7df2e56Smrg /* 1091f7df2e56Smrg * If the value is exactly equal to our threshold, we 1092f7df2e56Smrg * want one more event in the positive direction to 1093f7df2e56Smrg * ensure we pick up when the value *exceeds* this 1094f7df2e56Smrg * threshold. 1095f7df2e56Smrg */ 1096f7df2e56Smrg psci->bracket_greater = pTrigger->test_value; 1097f7df2e56Smrg pnewgtval = &psci->bracket_greater; 1098f7df2e56Smrg } 10997e31ba66Smrg else if (pCounter->value > pTrigger->test_value && 11007e31ba66Smrg pTrigger->test_value > psci->bracket_less) { 1101f7df2e56Smrg psci->bracket_less = pTrigger->test_value; 1102f7df2e56Smrg pnewltval = &psci->bracket_less; 1103f7df2e56Smrg } 1104f7df2e56Smrg } 1105f7df2e56Smrg } /* end for each trigger */ 1106f7df2e56Smrg 1107f7df2e56Smrg (*psci->BracketValues) ((void *) pCounter, pnewltval, pnewgtval); 1108f7df2e56Smrg 110905b261ecSmrg} 111005b261ecSmrg 111105b261ecSmrg/* 111205b261ecSmrg * ***** Resource delete functions 111305b261ecSmrg */ 111405b261ecSmrg 111505b261ecSmrg/* ARGSUSED */ 111605b261ecSmrgstatic int 11174202a189SmrgFreeAlarm(void *addr, XID id) 111805b261ecSmrg{ 1119f7df2e56Smrg SyncAlarm *pAlarm = (SyncAlarm *) addr; 112005b261ecSmrg 112105b261ecSmrg pAlarm->state = XSyncAlarmDestroyed; 112205b261ecSmrg 112305b261ecSmrg SyncSendAlarmNotifyEvents(pAlarm); 112405b261ecSmrg 112505b261ecSmrg /* delete event selections */ 112605b261ecSmrg 112705b261ecSmrg while (pAlarm->pEventClients) 1128f7df2e56Smrg FreeResource(pAlarm->pEventClients->delete_id, RT_NONE); 112905b261ecSmrg 113065b04b38Smrg SyncDeleteTriggerFromSyncObject(&pAlarm->trigger); 113105b261ecSmrg 11324202a189Smrg free(pAlarm); 113305b261ecSmrg return Success; 113405b261ecSmrg} 113505b261ecSmrg 113605b261ecSmrg/* 113705b261ecSmrg * ** Cleanup after the destruction of a Counter 113805b261ecSmrg */ 113905b261ecSmrg/* ARGSUSED */ 114005b261ecSmrgstatic int 11414202a189SmrgFreeCounter(void *env, XID id) 114205b261ecSmrg{ 1143f7df2e56Smrg SyncCounter *pCounter = (SyncCounter *) env; 114405b261ecSmrg 114565b04b38Smrg pCounter->sync.beingDestroyed = TRUE; 11464e185dc0Smrg 11474e185dc0Smrg if (pCounter->sync.initialized) { 11484e185dc0Smrg SyncTriggerList *ptl, *pnext; 11494e185dc0Smrg 11504e185dc0Smrg /* tell all the counter's triggers that counter has been destroyed */ 11514e185dc0Smrg for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) { 11524e185dc0Smrg (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger); 11534e185dc0Smrg pnext = ptl->next; 11544e185dc0Smrg free(ptl); /* destroy the trigger list as we go */ 11554e185dc0Smrg } 11564e185dc0Smrg if (IsSystemCounter(pCounter)) { 11574e185dc0Smrg xorg_list_del(&pCounter->pSysCounterInfo->entry); 11584e185dc0Smrg free(pCounter->pSysCounterInfo->name); 11594e185dc0Smrg free(pCounter->pSysCounterInfo->private); 11604e185dc0Smrg free(pCounter->pSysCounterInfo); 11614e185dc0Smrg } 116205b261ecSmrg } 11634e185dc0Smrg 11644202a189Smrg free(pCounter); 116505b261ecSmrg return Success; 116605b261ecSmrg} 116705b261ecSmrg 116805b261ecSmrg/* 116905b261ecSmrg * ** Cleanup after Await 117005b261ecSmrg */ 117105b261ecSmrg/* ARGSUSED */ 117205b261ecSmrgstatic int 11734202a189SmrgFreeAwait(void *addr, XID id) 117405b261ecSmrg{ 117505b261ecSmrg SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr; 117605b261ecSmrg SyncAwait *pAwait; 117705b261ecSmrg int numwaits; 117805b261ecSmrg 1179f7df2e56Smrg pAwait = &(pAwaitUnion + 1)->await; /* first await on list */ 118005b261ecSmrg 118105b261ecSmrg /* remove triggers from counters */ 118205b261ecSmrg 118305b261ecSmrg for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits; 1184f7df2e56Smrg numwaits--, pAwait++) { 1185f7df2e56Smrg /* If the counter is being destroyed, FreeCounter will delete 1186f7df2e56Smrg * the trigger list itself, so don't do it here. 1187f7df2e56Smrg */ 1188f7df2e56Smrg SyncObject *pSync = pAwait->trigger.pSync; 1189f7df2e56Smrg 1190f7df2e56Smrg if (pSync && !pSync->beingDestroyed) 1191f7df2e56Smrg SyncDeleteTriggerFromSyncObject(&pAwait->trigger); 119205b261ecSmrg } 11934202a189Smrg free(pAwaitUnion); 119405b261ecSmrg return Success; 119505b261ecSmrg} 119605b261ecSmrg 119705b261ecSmrg/* loosely based on dix/events.c/OtherClientGone */ 119805b261ecSmrgstatic int 11994202a189SmrgFreeAlarmClient(void *value, XID id) 120005b261ecSmrg{ 1201f7df2e56Smrg SyncAlarm *pAlarm = (SyncAlarm *) value; 120205b261ecSmrg SyncAlarmClientList *pCur, *pPrev; 120305b261ecSmrg 120405b261ecSmrg for (pPrev = NULL, pCur = pAlarm->pEventClients; 1205f7df2e56Smrg pCur; pPrev = pCur, pCur = pCur->next) { 1206f7df2e56Smrg if (pCur->delete_id == id) { 1207f7df2e56Smrg if (pPrev) 1208f7df2e56Smrg pPrev->next = pCur->next; 1209f7df2e56Smrg else 1210f7df2e56Smrg pAlarm->pEventClients = pCur->next; 1211f7df2e56Smrg free(pCur); 1212f7df2e56Smrg return Success; 1213f7df2e56Smrg } 121405b261ecSmrg } 121505b261ecSmrg FatalError("alarm client not on event list"); 1216f7df2e56Smrg /*NOTREACHED*/} 121705b261ecSmrg 121805b261ecSmrg/* 121905b261ecSmrg * ***** Proc functions 122005b261ecSmrg */ 122105b261ecSmrg 122205b261ecSmrg/* 122305b261ecSmrg * ** Initialize the extension 122405b261ecSmrg */ 12254202a189Smrgstatic int 12264202a189SmrgProcSyncInitialize(ClientPtr client) 122705b261ecSmrg{ 1228f7df2e56Smrg xSyncInitializeReply rep = { 1229f7df2e56Smrg .type = X_Reply, 1230f7df2e56Smrg .sequenceNumber = client->sequence, 1231f7df2e56Smrg .length = 0, 1232f7df2e56Smrg .majorVersion = SERVER_SYNC_MAJOR_VERSION, 1233f7df2e56Smrg .minorVersion = SERVER_SYNC_MINOR_VERSION, 1234f7df2e56Smrg }; 123505b261ecSmrg 123605b261ecSmrg REQUEST_SIZE_MATCH(xSyncInitializeReq); 123705b261ecSmrg 1238f7df2e56Smrg if (client->swapped) { 1239f7df2e56Smrg swaps(&rep.sequenceNumber); 124005b261ecSmrg } 1241f7df2e56Smrg WriteToClient(client, sizeof(rep), &rep); 12424202a189Smrg return Success; 124305b261ecSmrg} 124405b261ecSmrg 124505b261ecSmrg/* 124605b261ecSmrg * ** Get list of system counters available through the extension 124705b261ecSmrg */ 12484202a189Smrgstatic int 12494202a189SmrgProcSyncListSystemCounters(ClientPtr client) 125005b261ecSmrg{ 1251f7df2e56Smrg xSyncListSystemCountersReply rep = { 1252f7df2e56Smrg .type = X_Reply, 1253f7df2e56Smrg .sequenceNumber = client->sequence, 1254f7df2e56Smrg .nCounters = 0, 1255f7df2e56Smrg }; 1256f7df2e56Smrg SysCounterInfo *psci; 1257f7df2e56Smrg int len = 0; 125805b261ecSmrg xSyncSystemCounter *list = NULL, *walklist = NULL; 12594202a189Smrg 126005b261ecSmrg REQUEST_SIZE_MATCH(xSyncListSystemCountersReq); 126105b261ecSmrg 1262f7df2e56Smrg xorg_list_for_each_entry(psci, &SysCounterList, entry) { 1263f7df2e56Smrg /* pad to 4 byte boundary */ 1264f7df2e56Smrg len += pad_to_int32(sz_xSyncSystemCounter + strlen(psci->name)); 1265f7df2e56Smrg ++rep.nCounters; 126605b261ecSmrg } 126705b261ecSmrg 1268f7df2e56Smrg if (len) { 1269f7df2e56Smrg walklist = list = malloc(len); 1270f7df2e56Smrg if (!list) 1271f7df2e56Smrg return BadAlloc; 127205b261ecSmrg } 127305b261ecSmrg 12744202a189Smrg rep.length = bytes_to_int32(len); 127505b261ecSmrg 1276f7df2e56Smrg if (client->swapped) { 1277f7df2e56Smrg swaps(&rep.sequenceNumber); 1278f7df2e56Smrg swapl(&rep.length); 1279f7df2e56Smrg swapl(&rep.nCounters); 128005b261ecSmrg } 128105b261ecSmrg 1282f7df2e56Smrg xorg_list_for_each_entry(psci, &SysCounterList, entry) { 1283f7df2e56Smrg int namelen; 1284f7df2e56Smrg char *pname_in_reply; 128505b261ecSmrg 1286f7df2e56Smrg walklist->counter = psci->pCounter->sync.id; 12877e31ba66Smrg walklist->resolution_hi = psci->resolution >> 32; 12887e31ba66Smrg walklist->resolution_lo = psci->resolution; 1289f7df2e56Smrg namelen = strlen(psci->name); 1290f7df2e56Smrg walklist->name_length = namelen; 129105b261ecSmrg 1292f7df2e56Smrg if (client->swapped) { 1293f7df2e56Smrg swapl(&walklist->counter); 1294f7df2e56Smrg swapl(&walklist->resolution_hi); 1295f7df2e56Smrg swapl(&walklist->resolution_lo); 1296f7df2e56Smrg swaps(&walklist->name_length); 1297f7df2e56Smrg } 129805b261ecSmrg 1299f7df2e56Smrg pname_in_reply = ((char *) walklist) + sz_xSyncSystemCounter; 1300f7df2e56Smrg strncpy(pname_in_reply, psci->name, namelen); 1301f7df2e56Smrg walklist = (xSyncSystemCounter *) (((char *) walklist) + 1302f7df2e56Smrg pad_to_int32(sz_xSyncSystemCounter + 1303f7df2e56Smrg namelen)); 130405b261ecSmrg } 130505b261ecSmrg 1306f7df2e56Smrg WriteToClient(client, sizeof(rep), &rep); 1307f7df2e56Smrg if (len) { 1308f7df2e56Smrg WriteToClient(client, len, list); 1309f7df2e56Smrg free(list); 131005b261ecSmrg } 131105b261ecSmrg 13124202a189Smrg return Success; 131305b261ecSmrg} 131405b261ecSmrg 131505b261ecSmrg/* 131605b261ecSmrg * ** Set client Priority 131705b261ecSmrg */ 13184202a189Smrgstatic int 13194202a189SmrgProcSyncSetPriority(ClientPtr client) 132005b261ecSmrg{ 132105b261ecSmrg REQUEST(xSyncSetPriorityReq); 132205b261ecSmrg ClientPtr priorityclient; 132305b261ecSmrg int rc; 132405b261ecSmrg 132505b261ecSmrg REQUEST_SIZE_MATCH(xSyncSetPriorityReq); 132605b261ecSmrg 132705b261ecSmrg if (stuff->id == None) 1328f7df2e56Smrg priorityclient = client; 132905b261ecSmrg else { 1330f7df2e56Smrg rc = dixLookupClient(&priorityclient, stuff->id, client, 1331f7df2e56Smrg DixSetAttrAccess); 1332f7df2e56Smrg if (rc != Success) 1333f7df2e56Smrg return rc; 133405b261ecSmrg } 133505b261ecSmrg 1336f7df2e56Smrg if (priorityclient->priority != stuff->priority) { 1337f7df2e56Smrg priorityclient->priority = stuff->priority; 133805b261ecSmrg 1339f7df2e56Smrg /* The following will force the server back into WaitForSomething 1340f7df2e56Smrg * so that the change in this client's priority is immediately 1341f7df2e56Smrg * reflected. 1342f7df2e56Smrg */ 1343f7df2e56Smrg isItTimeToYield = TRUE; 1344f7df2e56Smrg dispatchException |= DE_PRIORITYCHANGE; 134505b261ecSmrg } 134605b261ecSmrg return Success; 134705b261ecSmrg} 134805b261ecSmrg 134905b261ecSmrg/* 135005b261ecSmrg * ** Get client Priority 135105b261ecSmrg */ 13524202a189Smrgstatic int 13534202a189SmrgProcSyncGetPriority(ClientPtr client) 135405b261ecSmrg{ 135505b261ecSmrg REQUEST(xSyncGetPriorityReq); 135605b261ecSmrg xSyncGetPriorityReply rep; 135705b261ecSmrg ClientPtr priorityclient; 135805b261ecSmrg int rc; 135905b261ecSmrg 136005b261ecSmrg REQUEST_SIZE_MATCH(xSyncGetPriorityReq); 136105b261ecSmrg 136205b261ecSmrg if (stuff->id == None) 1363f7df2e56Smrg priorityclient = client; 136405b261ecSmrg else { 1365f7df2e56Smrg rc = dixLookupClient(&priorityclient, stuff->id, client, 1366f7df2e56Smrg DixGetAttrAccess); 1367f7df2e56Smrg if (rc != Success) 1368f7df2e56Smrg return rc; 136905b261ecSmrg } 137005b261ecSmrg 1371f7df2e56Smrg rep = (xSyncGetPriorityReply) { 1372f7df2e56Smrg .type = X_Reply, 1373f7df2e56Smrg .sequenceNumber = client->sequence, 1374f7df2e56Smrg .length = 0, 1375f7df2e56Smrg .priority = priorityclient->priority 1376f7df2e56Smrg }; 137705b261ecSmrg 1378f7df2e56Smrg if (client->swapped) { 1379f7df2e56Smrg swaps(&rep.sequenceNumber); 1380f7df2e56Smrg swapl(&rep.priority); 138105b261ecSmrg } 138205b261ecSmrg 1383f7df2e56Smrg WriteToClient(client, sizeof(xSyncGetPriorityReply), &rep); 138405b261ecSmrg 13854202a189Smrg return Success; 138605b261ecSmrg} 138705b261ecSmrg 138805b261ecSmrg/* 138905b261ecSmrg * ** Create a new counter 139005b261ecSmrg */ 13914202a189Smrgstatic int 13924202a189SmrgProcSyncCreateCounter(ClientPtr client) 139305b261ecSmrg{ 139405b261ecSmrg REQUEST(xSyncCreateCounterReq); 13957e31ba66Smrg int64_t initial; 139605b261ecSmrg 139705b261ecSmrg REQUEST_SIZE_MATCH(xSyncCreateCounterReq); 139805b261ecSmrg 139905b261ecSmrg LEGAL_NEW_RESOURCE(stuff->cid, client); 140005b261ecSmrg 14017e31ba66Smrg initial = ((int64_t)stuff->initial_value_hi << 32) | stuff->initial_value_lo; 14027e31ba66Smrg 140305b261ecSmrg if (!SyncCreateCounter(client, stuff->cid, initial)) 1404f7df2e56Smrg return BadAlloc; 140505b261ecSmrg 14064202a189Smrg return Success; 140705b261ecSmrg} 140805b261ecSmrg 140905b261ecSmrg/* 141005b261ecSmrg * ** Set Counter value 141105b261ecSmrg */ 14124202a189Smrgstatic int 14134202a189SmrgProcSyncSetCounter(ClientPtr client) 141405b261ecSmrg{ 141505b261ecSmrg REQUEST(xSyncSetCounterReq); 1416f7df2e56Smrg SyncCounter *pCounter; 14177e31ba66Smrg int64_t newvalue; 1418f7df2e56Smrg int rc; 141905b261ecSmrg 142005b261ecSmrg REQUEST_SIZE_MATCH(xSyncSetCounterReq); 142105b261ecSmrg 1422f7df2e56Smrg rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter, 1423f7df2e56Smrg client, DixWriteAccess); 14244202a189Smrg if (rc != Success) 1425f7df2e56Smrg return rc; 142605b261ecSmrg 1427f7df2e56Smrg if (IsSystemCounter(pCounter)) { 1428f7df2e56Smrg client->errorValue = stuff->cid; 1429f7df2e56Smrg return BadAccess; 143005b261ecSmrg } 143105b261ecSmrg 14327e31ba66Smrg newvalue = ((int64_t)stuff->value_hi << 32) | stuff->value_lo; 143305b261ecSmrg SyncChangeCounter(pCounter, newvalue); 143405b261ecSmrg return Success; 143505b261ecSmrg} 143605b261ecSmrg 143705b261ecSmrg/* 143805b261ecSmrg * ** Change Counter value 143905b261ecSmrg */ 14404202a189Smrgstatic int 14414202a189SmrgProcSyncChangeCounter(ClientPtr client) 144205b261ecSmrg{ 144305b261ecSmrg REQUEST(xSyncChangeCounterReq); 1444f7df2e56Smrg SyncCounter *pCounter; 14457e31ba66Smrg int64_t newvalue; 1446f7df2e56Smrg Bool overflow; 1447f7df2e56Smrg int rc; 144805b261ecSmrg 144905b261ecSmrg REQUEST_SIZE_MATCH(xSyncChangeCounterReq); 145005b261ecSmrg 1451f7df2e56Smrg rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter, 1452f7df2e56Smrg client, DixWriteAccess); 14534202a189Smrg if (rc != Success) 1454f7df2e56Smrg return rc; 145505b261ecSmrg 1456f7df2e56Smrg if (IsSystemCounter(pCounter)) { 1457f7df2e56Smrg client->errorValue = stuff->cid; 1458f7df2e56Smrg return BadAccess; 145905b261ecSmrg } 146005b261ecSmrg 14617e31ba66Smrg newvalue = (int64_t)stuff->value_hi << 32 | stuff->value_lo; 14627e31ba66Smrg overflow = checked_int64_add(&newvalue, newvalue, pCounter->value); 1463f7df2e56Smrg if (overflow) { 1464f7df2e56Smrg /* XXX 64 bit value can't fit in 32 bits; do the best we can */ 1465f7df2e56Smrg client->errorValue = stuff->value_hi; 1466f7df2e56Smrg return BadValue; 146705b261ecSmrg } 146805b261ecSmrg SyncChangeCounter(pCounter, newvalue); 146905b261ecSmrg return Success; 147005b261ecSmrg} 147105b261ecSmrg 147205b261ecSmrg/* 147305b261ecSmrg * ** Destroy a counter 147405b261ecSmrg */ 14754202a189Smrgstatic int 14764202a189SmrgProcSyncDestroyCounter(ClientPtr client) 147705b261ecSmrg{ 147805b261ecSmrg REQUEST(xSyncDestroyCounterReq); 1479f7df2e56Smrg SyncCounter *pCounter; 14804202a189Smrg int rc; 148105b261ecSmrg 148205b261ecSmrg REQUEST_SIZE_MATCH(xSyncDestroyCounterReq); 148305b261ecSmrg 1484f7df2e56Smrg rc = dixLookupResourceByType((void **) &pCounter, stuff->counter, 1485f7df2e56Smrg RTCounter, client, DixDestroyAccess); 14864202a189Smrg if (rc != Success) 1487f7df2e56Smrg return rc; 14884202a189Smrg 1489f7df2e56Smrg if (IsSystemCounter(pCounter)) { 1490f7df2e56Smrg client->errorValue = stuff->counter; 1491f7df2e56Smrg return BadAccess; 149205b261ecSmrg } 149365b04b38Smrg FreeResource(pCounter->sync.id, RT_NONE); 149405b261ecSmrg return Success; 149505b261ecSmrg} 149605b261ecSmrg 1497f7df2e56Smrgstatic SyncAwaitUnion * 149865b04b38SmrgSyncAwaitPrologue(ClientPtr client, int items) 149965b04b38Smrg{ 150065b04b38Smrg SyncAwaitUnion *pAwaitUnion; 150165b04b38Smrg 150265b04b38Smrg /* all the memory for the entire await list is allocated 150365b04b38Smrg * here in one chunk 150465b04b38Smrg */ 1505f7df2e56Smrg pAwaitUnion = xallocarray(items + 1, sizeof(SyncAwaitUnion)); 150665b04b38Smrg if (!pAwaitUnion) 1507f7df2e56Smrg return NULL; 150865b04b38Smrg 150965b04b38Smrg /* first item is the header, remainder are real wait conditions */ 151065b04b38Smrg 151165b04b38Smrg pAwaitUnion->header.delete_id = FakeClientID(client->index); 151265b04b38Smrg pAwaitUnion->header.client = client; 151365b04b38Smrg pAwaitUnion->header.num_waitconditions = 0; 151465b04b38Smrg 151565b04b38Smrg if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion)) 1516f7df2e56Smrg return NULL; 151765b04b38Smrg 151865b04b38Smrg return pAwaitUnion; 151965b04b38Smrg} 152065b04b38Smrg 152165b04b38Smrgstatic void 1522f7df2e56SmrgSyncAwaitEpilogue(ClientPtr client, int items, SyncAwaitUnion * pAwaitUnion) 152365b04b38Smrg{ 152465b04b38Smrg SyncAwait *pAwait; 152565b04b38Smrg int i; 152665b04b38Smrg 152765b04b38Smrg IgnoreClient(client); 152865b04b38Smrg 152965b04b38Smrg /* see if any of the triggers are already true */ 153065b04b38Smrg 1531f7df2e56Smrg pAwait = &(pAwaitUnion + 1)->await; /* skip over header */ 1532f7df2e56Smrg for (i = 0; i < items; i++, pAwait++) { 15337e31ba66Smrg int64_t value; 1534f7df2e56Smrg 1535f7df2e56Smrg /* don't have to worry about NULL counters because the request 1536f7df2e56Smrg * errors before we get here out if they occur 1537f7df2e56Smrg */ 1538f7df2e56Smrg switch (pAwait->trigger.pSync->type) { 1539f7df2e56Smrg case SYNC_COUNTER: 1540f7df2e56Smrg value = ((SyncCounter *) pAwait->trigger.pSync)->value; 1541f7df2e56Smrg break; 1542f7df2e56Smrg default: 15437e31ba66Smrg value = 0; 1544f7df2e56Smrg } 154565b04b38Smrg 1546f7df2e56Smrg if ((*pAwait->trigger.CheckTrigger) (&pAwait->trigger, value)) { 1547f7df2e56Smrg (*pAwait->trigger.TriggerFired) (&pAwait->trigger); 1548f7df2e56Smrg break; /* once is enough */ 1549f7df2e56Smrg } 155065b04b38Smrg } 155165b04b38Smrg} 155205b261ecSmrg 155305b261ecSmrg/* 155405b261ecSmrg * ** Await 155505b261ecSmrg */ 15564202a189Smrgstatic int 15574202a189SmrgProcSyncAwait(ClientPtr client) 155805b261ecSmrg{ 155905b261ecSmrg REQUEST(xSyncAwaitReq); 1560f7df2e56Smrg int len, items; 1561f7df2e56Smrg int i; 156205b261ecSmrg xSyncWaitCondition *pProtocolWaitConds; 156305b261ecSmrg SyncAwaitUnion *pAwaitUnion; 1564f7df2e56Smrg SyncAwait *pAwait; 1565f7df2e56Smrg int status; 156605b261ecSmrg 156705b261ecSmrg REQUEST_AT_LEAST_SIZE(xSyncAwaitReq); 156805b261ecSmrg 156905b261ecSmrg len = client->req_len << 2; 157005b261ecSmrg len -= sz_xSyncAwaitReq; 157105b261ecSmrg items = len / sz_xSyncWaitCondition; 157205b261ecSmrg 1573f7df2e56Smrg if (items * sz_xSyncWaitCondition != len) { 1574f7df2e56Smrg return BadLength; 157505b261ecSmrg } 1576f7df2e56Smrg if (items == 0) { 1577f7df2e56Smrg client->errorValue = items; /* XXX protocol change */ 1578f7df2e56Smrg return BadValue; 157905b261ecSmrg } 158005b261ecSmrg 158165b04b38Smrg if (!(pAwaitUnion = SyncAwaitPrologue(client, items))) 1582f7df2e56Smrg return BadAlloc; 158305b261ecSmrg 158405b261ecSmrg /* don't need to do any more memory allocation for this request! */ 158505b261ecSmrg 1586f7df2e56Smrg pProtocolWaitConds = (xSyncWaitCondition *) &stuff[1]; 1587f7df2e56Smrg 1588f7df2e56Smrg pAwait = &(pAwaitUnion + 1)->await; /* skip over header */ 1589f7df2e56Smrg for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++) { 1590f7df2e56Smrg if (pProtocolWaitConds->counter == None) { /* XXX protocol change */ 1591f7df2e56Smrg /* this should take care of removing any triggers created by 1592f7df2e56Smrg * this request that have already been registered on sync objects 1593f7df2e56Smrg */ 1594f7df2e56Smrg FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 1595f7df2e56Smrg client->errorValue = pProtocolWaitConds->counter; 1596f7df2e56Smrg return SyncErrorBase + XSyncBadCounter; 1597f7df2e56Smrg } 1598f7df2e56Smrg 1599f7df2e56Smrg /* sanity checks are in SyncInitTrigger */ 1600f7df2e56Smrg pAwait->trigger.pSync = NULL; 1601f7df2e56Smrg pAwait->trigger.value_type = pProtocolWaitConds->value_type; 16027e31ba66Smrg pAwait->trigger.wait_value = 16037e31ba66Smrg ((int64_t)pProtocolWaitConds->wait_value_hi << 32) | 16047e31ba66Smrg pProtocolWaitConds->wait_value_lo; 1605f7df2e56Smrg pAwait->trigger.test_type = pProtocolWaitConds->test_type; 1606f7df2e56Smrg 1607f7df2e56Smrg status = SyncInitTrigger(client, &pAwait->trigger, 1608f7df2e56Smrg pProtocolWaitConds->counter, RTCounter, 1609f7df2e56Smrg XSyncCAAllTrigger); 1610f7df2e56Smrg if (status != Success) { 1611f7df2e56Smrg /* this should take care of removing any triggers created by 1612f7df2e56Smrg * this request that have already been registered on sync objects 1613f7df2e56Smrg */ 1614f7df2e56Smrg FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 1615f7df2e56Smrg return status; 1616f7df2e56Smrg } 1617f7df2e56Smrg /* this is not a mistake -- same function works for both cases */ 1618f7df2e56Smrg pAwait->trigger.TriggerFired = SyncAwaitTriggerFired; 1619f7df2e56Smrg pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired; 16207e31ba66Smrg pAwait->event_threshold = 16217e31ba66Smrg ((int64_t) pProtocolWaitConds->event_threshold_hi << 32) | 16227e31ba66Smrg pProtocolWaitConds->event_threshold_lo; 16237e31ba66Smrg 1624f7df2e56Smrg pAwait->pHeader = &pAwaitUnion->header; 1625f7df2e56Smrg pAwaitUnion->header.num_waitconditions++; 162605b261ecSmrg } 162705b261ecSmrg 162865b04b38Smrg SyncAwaitEpilogue(client, items, pAwaitUnion); 162905b261ecSmrg 163005b261ecSmrg return Success; 163105b261ecSmrg} 163205b261ecSmrg 163305b261ecSmrg/* 163405b261ecSmrg * ** Query a counter 163505b261ecSmrg */ 16364202a189Smrgstatic int 16374202a189SmrgProcSyncQueryCounter(ClientPtr client) 163805b261ecSmrg{ 163905b261ecSmrg REQUEST(xSyncQueryCounterReq); 164005b261ecSmrg xSyncQueryCounterReply rep; 1641f7df2e56Smrg SyncCounter *pCounter; 16424202a189Smrg int rc; 164305b261ecSmrg 164405b261ecSmrg REQUEST_SIZE_MATCH(xSyncQueryCounterReq); 164505b261ecSmrg 1646f7df2e56Smrg rc = dixLookupResourceByType((void **) &pCounter, stuff->counter, 1647f7df2e56Smrg RTCounter, client, DixReadAccess); 16484202a189Smrg if (rc != Success) 1649f7df2e56Smrg return rc; 165005b261ecSmrg 165105b261ecSmrg /* if system counter, ask it what the current value is */ 1652f7df2e56Smrg if (IsSystemCounter(pCounter)) { 1653f7df2e56Smrg (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter, 1654f7df2e56Smrg &pCounter->value); 1655f7df2e56Smrg } 1656f7df2e56Smrg 1657f7df2e56Smrg rep = (xSyncQueryCounterReply) { 1658f7df2e56Smrg .type = X_Reply, 1659f7df2e56Smrg .sequenceNumber = client->sequence, 1660f7df2e56Smrg .length = 0, 16617e31ba66Smrg .value_hi = pCounter->value >> 32, 16627e31ba66Smrg .value_lo = pCounter->value 1663f7df2e56Smrg }; 1664f7df2e56Smrg 1665f7df2e56Smrg if (client->swapped) { 1666f7df2e56Smrg swaps(&rep.sequenceNumber); 1667f7df2e56Smrg swapl(&rep.length); 1668f7df2e56Smrg swapl(&rep.value_hi); 1669f7df2e56Smrg swapl(&rep.value_lo); 1670f7df2e56Smrg } 1671f7df2e56Smrg WriteToClient(client, sizeof(xSyncQueryCounterReply), &rep); 16724202a189Smrg return Success; 167305b261ecSmrg} 167405b261ecSmrg 167505b261ecSmrg/* 167605b261ecSmrg * ** Create Alarm 167705b261ecSmrg */ 16784202a189Smrgstatic int 16794202a189SmrgProcSyncCreateAlarm(ClientPtr client) 168005b261ecSmrg{ 168105b261ecSmrg REQUEST(xSyncCreateAlarmReq); 1682f7df2e56Smrg SyncAlarm *pAlarm; 1683f7df2e56Smrg int status; 1684f7df2e56Smrg unsigned long len, vmask; 1685f7df2e56Smrg SyncTrigger *pTrigger; 168605b261ecSmrg 168705b261ecSmrg REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq); 168805b261ecSmrg 168905b261ecSmrg LEGAL_NEW_RESOURCE(stuff->id, client); 169005b261ecSmrg 169105b261ecSmrg vmask = stuff->valueMask; 16924202a189Smrg len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq)); 169305b261ecSmrg /* the "extra" call to Ones accounts for the presence of 64 bit values */ 1694f7df2e56Smrg if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta)))) 1695f7df2e56Smrg return BadLength; 169605b261ecSmrg 1697f7df2e56Smrg if (!(pAlarm = malloc(sizeof(SyncAlarm)))) { 1698f7df2e56Smrg return BadAlloc; 169905b261ecSmrg } 170005b261ecSmrg 170105b261ecSmrg /* set up defaults */ 170205b261ecSmrg 170305b261ecSmrg pTrigger = &pAlarm->trigger; 170465b04b38Smrg pTrigger->pSync = NULL; 170505b261ecSmrg pTrigger->value_type = XSyncAbsolute; 17067e31ba66Smrg pTrigger->wait_value = 0; 170705b261ecSmrg pTrigger->test_type = XSyncPositiveComparison; 170805b261ecSmrg pTrigger->TriggerFired = SyncAlarmTriggerFired; 170905b261ecSmrg pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed; 171065b04b38Smrg status = SyncInitTrigger(client, pTrigger, None, RTCounter, 1711f7df2e56Smrg XSyncCAAllTrigger); 1712f7df2e56Smrg if (status != Success) { 1713f7df2e56Smrg free(pAlarm); 1714f7df2e56Smrg return status; 171505b261ecSmrg } 171605b261ecSmrg 171705b261ecSmrg pAlarm->client = client; 171805b261ecSmrg pAlarm->alarm_id = stuff->id; 17197e31ba66Smrg pAlarm->delta = 1; 172005b261ecSmrg pAlarm->events = TRUE; 172105b261ecSmrg pAlarm->state = XSyncAlarmInactive; 172205b261ecSmrg pAlarm->pEventClients = NULL; 172305b261ecSmrg status = SyncChangeAlarmAttributes(client, pAlarm, vmask, 1724f7df2e56Smrg (CARD32 *) &stuff[1]); 1725f7df2e56Smrg if (status != Success) { 1726f7df2e56Smrg free(pAlarm); 1727f7df2e56Smrg return status; 172805b261ecSmrg } 172905b261ecSmrg 173005b261ecSmrg if (!AddResource(stuff->id, RTAlarm, pAlarm)) 1731f7df2e56Smrg return BadAlloc; 173205b261ecSmrg 173305b261ecSmrg /* see if alarm already triggered. NULL counter will not trigger 173405b261ecSmrg * in CreateAlarm and sets alarm state to Inactive. 173505b261ecSmrg */ 173605b261ecSmrg 1737f7df2e56Smrg if (!pTrigger->pSync) { 1738f7df2e56Smrg pAlarm->state = XSyncAlarmInactive; /* XXX protocol change */ 173905b261ecSmrg } 1740f7df2e56Smrg else { 1741f7df2e56Smrg SyncCounter *pCounter; 174265b04b38Smrg 1743f7df2e56Smrg if (!SyncCheckWarnIsCounter(pTrigger->pSync, 1744f7df2e56Smrg WARN_INVALID_COUNTER_ALARM)) { 1745f7df2e56Smrg FreeResource(stuff->id, RT_NONE); 1746f7df2e56Smrg return BadAlloc; 1747f7df2e56Smrg } 174865b04b38Smrg 1749f7df2e56Smrg pCounter = (SyncCounter *) pTrigger->pSync; 175065b04b38Smrg 1751f7df2e56Smrg if ((*pTrigger->CheckTrigger) (pTrigger, pCounter->value)) 1752f7df2e56Smrg (*pTrigger->TriggerFired) (pTrigger); 175305b261ecSmrg } 175405b261ecSmrg 175505b261ecSmrg return Success; 175605b261ecSmrg} 175705b261ecSmrg 175805b261ecSmrg/* 175905b261ecSmrg * ** Change Alarm 176005b261ecSmrg */ 17614202a189Smrgstatic int 17624202a189SmrgProcSyncChangeAlarm(ClientPtr client) 176305b261ecSmrg{ 176405b261ecSmrg REQUEST(xSyncChangeAlarmReq); 1765f7df2e56Smrg SyncAlarm *pAlarm; 176665b04b38Smrg SyncCounter *pCounter = NULL; 1767f7df2e56Smrg long vmask; 1768f7df2e56Smrg int len, status; 176905b261ecSmrg 177005b261ecSmrg REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq); 177105b261ecSmrg 1772f7df2e56Smrg status = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm, 1773f7df2e56Smrg client, DixWriteAccess); 17744202a189Smrg if (status != Success) 1775f7df2e56Smrg return status; 177605b261ecSmrg 177705b261ecSmrg vmask = stuff->valueMask; 17784202a189Smrg len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq)); 177905b261ecSmrg /* the "extra" call to Ones accounts for the presence of 64 bit values */ 1780f7df2e56Smrg if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta)))) 1781f7df2e56Smrg return BadLength; 178205b261ecSmrg 17834202a189Smrg if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask, 1784f7df2e56Smrg (CARD32 *) &stuff[1])) != Success) 1785f7df2e56Smrg return status; 178605b261ecSmrg 178765b04b38Smrg if (SyncCheckWarnIsCounter(pAlarm->trigger.pSync, 1788f7df2e56Smrg WARN_INVALID_COUNTER_ALARM)) 1789f7df2e56Smrg pCounter = (SyncCounter *) pAlarm->trigger.pSync; 179065b04b38Smrg 179105b261ecSmrg /* see if alarm already triggered. NULL counter WILL trigger 179205b261ecSmrg * in ChangeAlarm. 179305b261ecSmrg */ 179405b261ecSmrg 179565b04b38Smrg if (!pCounter || 1796f7df2e56Smrg (*pAlarm->trigger.CheckTrigger) (&pAlarm->trigger, pCounter->value)) { 1797f7df2e56Smrg (*pAlarm->trigger.TriggerFired) (&pAlarm->trigger); 179805b261ecSmrg } 179905b261ecSmrg return Success; 180005b261ecSmrg} 180105b261ecSmrg 18024202a189Smrgstatic int 18034202a189SmrgProcSyncQueryAlarm(ClientPtr client) 180405b261ecSmrg{ 180505b261ecSmrg REQUEST(xSyncQueryAlarmReq); 1806f7df2e56Smrg SyncAlarm *pAlarm; 180705b261ecSmrg xSyncQueryAlarmReply rep; 1808f7df2e56Smrg SyncTrigger *pTrigger; 18094202a189Smrg int rc; 181005b261ecSmrg 181105b261ecSmrg REQUEST_SIZE_MATCH(xSyncQueryAlarmReq); 181205b261ecSmrg 1813f7df2e56Smrg rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm, 1814f7df2e56Smrg client, DixReadAccess); 18154202a189Smrg if (rc != Success) 1816f7df2e56Smrg return rc; 181705b261ecSmrg 181805b261ecSmrg pTrigger = &pAlarm->trigger; 1819f7df2e56Smrg rep = (xSyncQueryAlarmReply) { 1820f7df2e56Smrg .type = X_Reply, 1821f7df2e56Smrg .sequenceNumber = client->sequence, 1822f7df2e56Smrg .length = 1823f7df2e56Smrg bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply)), 1824f7df2e56Smrg .counter = (pTrigger->pSync) ? pTrigger->pSync->id : None, 1825f7df2e56Smrg 1826f7df2e56Smrg#if 0 /* XXX unclear what to do, depends on whether relative value-types 1827f7df2e56Smrg * are "consumed" immediately and are considered absolute from then 1828f7df2e56Smrg * on. 1829f7df2e56Smrg */ 1830f7df2e56Smrg .value_type = pTrigger->value_type, 18317e31ba66Smrg .wait_value_hi = pTrigger->wait_value >> 32, 18327e31ba66Smrg .wait_value_lo = pTrigger->wait_value, 183305b261ecSmrg#else 1834f7df2e56Smrg .value_type = XSyncAbsolute, 18357e31ba66Smrg .wait_value_hi = pTrigger->test_value >> 32, 18367e31ba66Smrg .wait_value_lo = pTrigger->test_value, 183705b261ecSmrg#endif 183805b261ecSmrg 1839f7df2e56Smrg .test_type = pTrigger->test_type, 18407e31ba66Smrg .delta_hi = pAlarm->delta >> 32, 18417e31ba66Smrg .delta_lo = pAlarm->delta, 1842f7df2e56Smrg .events = pAlarm->events, 1843f7df2e56Smrg .state = pAlarm->state 1844f7df2e56Smrg }; 1845f7df2e56Smrg 1846f7df2e56Smrg if (client->swapped) { 1847f7df2e56Smrg swaps(&rep.sequenceNumber); 1848f7df2e56Smrg swapl(&rep.length); 1849f7df2e56Smrg swapl(&rep.counter); 1850f7df2e56Smrg swapl(&rep.wait_value_hi); 1851f7df2e56Smrg swapl(&rep.wait_value_lo); 1852f7df2e56Smrg swapl(&rep.test_type); 1853f7df2e56Smrg swapl(&rep.delta_hi); 1854f7df2e56Smrg swapl(&rep.delta_lo); 1855f7df2e56Smrg } 1856f7df2e56Smrg 1857f7df2e56Smrg WriteToClient(client, sizeof(xSyncQueryAlarmReply), &rep); 18584202a189Smrg return Success; 185905b261ecSmrg} 186005b261ecSmrg 18614202a189Smrgstatic int 18624202a189SmrgProcSyncDestroyAlarm(ClientPtr client) 186305b261ecSmrg{ 18644202a189Smrg SyncAlarm *pAlarm; 18654202a189Smrg int rc; 1866f7df2e56Smrg 186705b261ecSmrg REQUEST(xSyncDestroyAlarmReq); 186805b261ecSmrg 186905b261ecSmrg REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq); 187005b261ecSmrg 1871f7df2e56Smrg rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm, 1872f7df2e56Smrg client, DixDestroyAccess); 18734202a189Smrg if (rc != Success) 1874f7df2e56Smrg return rc; 187505b261ecSmrg 187605b261ecSmrg FreeResource(stuff->alarm, RT_NONE); 18774202a189Smrg return Success; 187805b261ecSmrg} 187905b261ecSmrg 188065b04b38Smrgstatic int 188165b04b38SmrgProcSyncCreateFence(ClientPtr client) 188265b04b38Smrg{ 188365b04b38Smrg REQUEST(xSyncCreateFenceReq); 188465b04b38Smrg DrawablePtr pDraw; 188565b04b38Smrg SyncFence *pFence; 188665b04b38Smrg int rc; 188765b04b38Smrg 188865b04b38Smrg REQUEST_SIZE_MATCH(xSyncCreateFenceReq); 188965b04b38Smrg 189065b04b38Smrg rc = dixLookupDrawable(&pDraw, stuff->d, client, M_ANY, DixGetAttrAccess); 189165b04b38Smrg if (rc != Success) 1892f7df2e56Smrg return rc; 189365b04b38Smrg 189465b04b38Smrg LEGAL_NEW_RESOURCE(stuff->fid, client); 189565b04b38Smrg 1896f7df2e56Smrg if (!(pFence = (SyncFence *) SyncCreate(client, stuff->fid, SYNC_FENCE))) 1897f7df2e56Smrg return BadAlloc; 189865b04b38Smrg 189965b04b38Smrg miSyncInitFence(pDraw->pScreen, pFence, stuff->initially_triggered); 190065b04b38Smrg 19017e31ba66Smrg return Success; 190265b04b38Smrg} 190365b04b38Smrg 190465b04b38Smrgstatic int 190565b04b38SmrgFreeFence(void *obj, XID id) 190665b04b38Smrg{ 190765b04b38Smrg SyncFence *pFence = (SyncFence *) obj; 190865b04b38Smrg 190965b04b38Smrg miSyncDestroyFence(pFence); 191065b04b38Smrg 191165b04b38Smrg return Success; 191265b04b38Smrg} 191365b04b38Smrg 1914f7df2e56Smrgint 1915f7df2e56SmrgSyncVerifyFence(SyncFence ** ppSyncFence, XID fid, ClientPtr client, Mask mode) 191665b04b38Smrg{ 1917f7df2e56Smrg int rc = dixLookupResourceByType((void **) ppSyncFence, fid, RTFence, 1918f7df2e56Smrg client, mode); 191965b04b38Smrg 192065b04b38Smrg if (rc != Success) 1921f7df2e56Smrg client->errorValue = fid; 192265b04b38Smrg 192365b04b38Smrg return rc; 192465b04b38Smrg} 192565b04b38Smrg 192665b04b38Smrgstatic int 192765b04b38SmrgProcSyncTriggerFence(ClientPtr client) 192865b04b38Smrg{ 192965b04b38Smrg REQUEST(xSyncTriggerFenceReq); 193065b04b38Smrg SyncFence *pFence; 193165b04b38Smrg int rc; 193265b04b38Smrg 193365b04b38Smrg REQUEST_SIZE_MATCH(xSyncTriggerFenceReq); 193465b04b38Smrg 1935f7df2e56Smrg rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence, 1936f7df2e56Smrg client, DixWriteAccess); 193765b04b38Smrg if (rc != Success) 1938f7df2e56Smrg return rc; 193965b04b38Smrg 194065b04b38Smrg miSyncTriggerFence(pFence); 194165b04b38Smrg 19427e31ba66Smrg return Success; 194365b04b38Smrg} 194465b04b38Smrg 194565b04b38Smrgstatic int 194665b04b38SmrgProcSyncResetFence(ClientPtr client) 194765b04b38Smrg{ 194865b04b38Smrg REQUEST(xSyncResetFenceReq); 194965b04b38Smrg SyncFence *pFence; 195065b04b38Smrg int rc; 195165b04b38Smrg 195265b04b38Smrg REQUEST_SIZE_MATCH(xSyncResetFenceReq); 195365b04b38Smrg 1954f7df2e56Smrg rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence, 1955f7df2e56Smrg client, DixWriteAccess); 195665b04b38Smrg if (rc != Success) 1957f7df2e56Smrg return rc; 195865b04b38Smrg 195965b04b38Smrg if (pFence->funcs.CheckTriggered(pFence) != TRUE) 1960f7df2e56Smrg return BadMatch; 196165b04b38Smrg 196265b04b38Smrg pFence->funcs.Reset(pFence); 196365b04b38Smrg 19647e31ba66Smrg return Success; 196565b04b38Smrg} 196665b04b38Smrg 196765b04b38Smrgstatic int 196865b04b38SmrgProcSyncDestroyFence(ClientPtr client) 196965b04b38Smrg{ 197065b04b38Smrg REQUEST(xSyncDestroyFenceReq); 197165b04b38Smrg SyncFence *pFence; 197265b04b38Smrg int rc; 197365b04b38Smrg 197465b04b38Smrg REQUEST_SIZE_MATCH(xSyncDestroyFenceReq); 197565b04b38Smrg 1976f7df2e56Smrg rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence, 1977f7df2e56Smrg client, DixDestroyAccess); 197865b04b38Smrg if (rc != Success) 1979f7df2e56Smrg return rc; 198065b04b38Smrg 198165b04b38Smrg FreeResource(stuff->fid, RT_NONE); 19827e31ba66Smrg return Success; 198365b04b38Smrg} 198465b04b38Smrg 198565b04b38Smrgstatic int 198665b04b38SmrgProcSyncQueryFence(ClientPtr client) 198765b04b38Smrg{ 198865b04b38Smrg REQUEST(xSyncQueryFenceReq); 198965b04b38Smrg xSyncQueryFenceReply rep; 199065b04b38Smrg SyncFence *pFence; 199165b04b38Smrg int rc; 199265b04b38Smrg 199365b04b38Smrg REQUEST_SIZE_MATCH(xSyncQueryFenceReq); 199465b04b38Smrg 1995f7df2e56Smrg rc = dixLookupResourceByType((void **) &pFence, stuff->fid, 1996f7df2e56Smrg RTFence, client, DixReadAccess); 199765b04b38Smrg if (rc != Success) 1998f7df2e56Smrg return rc; 199965b04b38Smrg 2000f7df2e56Smrg rep = (xSyncQueryFenceReply) { 2001f7df2e56Smrg .type = X_Reply, 2002f7df2e56Smrg .sequenceNumber = client->sequence, 2003f7df2e56Smrg .length = 0, 200465b04b38Smrg 2005f7df2e56Smrg .triggered = pFence->funcs.CheckTriggered(pFence) 2006f7df2e56Smrg }; 200765b04b38Smrg 2008f7df2e56Smrg if (client->swapped) { 2009f7df2e56Smrg swaps(&rep.sequenceNumber); 2010f7df2e56Smrg swapl(&rep.length); 201165b04b38Smrg } 201265b04b38Smrg 2013f7df2e56Smrg WriteToClient(client, sizeof(xSyncQueryFenceReply), &rep); 20147e31ba66Smrg return Success; 201565b04b38Smrg} 201665b04b38Smrg 201765b04b38Smrgstatic int 201865b04b38SmrgProcSyncAwaitFence(ClientPtr client) 201965b04b38Smrg{ 202065b04b38Smrg REQUEST(xSyncAwaitFenceReq); 202165b04b38Smrg SyncAwaitUnion *pAwaitUnion; 202265b04b38Smrg SyncAwait *pAwait; 2023f7df2e56Smrg 202465b04b38Smrg /* Use CARD32 rather than XSyncFence because XIDs are hard-coded to 202565b04b38Smrg * CARD32 in protocol definitions */ 202665b04b38Smrg CARD32 *pProtocolFences; 202765b04b38Smrg int status; 202865b04b38Smrg int len; 202965b04b38Smrg int items; 203065b04b38Smrg int i; 203165b04b38Smrg 203265b04b38Smrg REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq); 203365b04b38Smrg 203465b04b38Smrg len = client->req_len << 2; 203565b04b38Smrg len -= sz_xSyncAwaitFenceReq; 203665b04b38Smrg items = len / sizeof(CARD32); 203765b04b38Smrg 2038f7df2e56Smrg if (items * sizeof(CARD32) != len) { 2039f7df2e56Smrg return BadLength; 204065b04b38Smrg } 2041f7df2e56Smrg if (items == 0) { 2042f7df2e56Smrg client->errorValue = items; 2043f7df2e56Smrg return BadValue; 204465b04b38Smrg } 204565b04b38Smrg 204665b04b38Smrg if (!(pAwaitUnion = SyncAwaitPrologue(client, items))) 2047f7df2e56Smrg return BadAlloc; 204865b04b38Smrg 204965b04b38Smrg /* don't need to do any more memory allocation for this request! */ 205065b04b38Smrg 2051f7df2e56Smrg pProtocolFences = (CARD32 *) &stuff[1]; 2052f7df2e56Smrg 2053f7df2e56Smrg pAwait = &(pAwaitUnion + 1)->await; /* skip over header */ 2054f7df2e56Smrg for (i = 0; i < items; i++, pProtocolFences++, pAwait++) { 2055f7df2e56Smrg if (*pProtocolFences == None) { 2056f7df2e56Smrg /* this should take care of removing any triggers created by 2057f7df2e56Smrg * this request that have already been registered on sync objects 2058f7df2e56Smrg */ 2059f7df2e56Smrg FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 2060f7df2e56Smrg client->errorValue = *pProtocolFences; 2061f7df2e56Smrg return SyncErrorBase + XSyncBadFence; 2062f7df2e56Smrg } 2063f7df2e56Smrg 2064f7df2e56Smrg pAwait->trigger.pSync = NULL; 2065f7df2e56Smrg /* Provide acceptable values for these unused fields to 2066f7df2e56Smrg * satisfy SyncInitTrigger's validation logic 2067f7df2e56Smrg */ 2068f7df2e56Smrg pAwait->trigger.value_type = XSyncAbsolute; 20697e31ba66Smrg pAwait->trigger.wait_value = 0; 2070f7df2e56Smrg pAwait->trigger.test_type = 0; 2071f7df2e56Smrg 2072f7df2e56Smrg status = SyncInitTrigger(client, &pAwait->trigger, 2073f7df2e56Smrg *pProtocolFences, RTFence, XSyncCAAllTrigger); 2074f7df2e56Smrg if (status != Success) { 2075f7df2e56Smrg /* this should take care of removing any triggers created by 2076f7df2e56Smrg * this request that have already been registered on sync objects 2077f7df2e56Smrg */ 2078f7df2e56Smrg FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 2079f7df2e56Smrg return status; 2080f7df2e56Smrg } 2081f7df2e56Smrg /* this is not a mistake -- same function works for both cases */ 2082f7df2e56Smrg pAwait->trigger.TriggerFired = SyncAwaitTriggerFired; 2083f7df2e56Smrg pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired; 2084f7df2e56Smrg /* event_threshold is unused for fence syncs */ 20857e31ba66Smrg pAwait->event_threshold = 0; 2086f7df2e56Smrg pAwait->pHeader = &pAwaitUnion->header; 2087f7df2e56Smrg pAwaitUnion->header.num_waitconditions++; 208865b04b38Smrg } 208965b04b38Smrg 209065b04b38Smrg SyncAwaitEpilogue(client, items, pAwaitUnion); 209165b04b38Smrg 20927e31ba66Smrg return Success; 209365b04b38Smrg} 209465b04b38Smrg 209505b261ecSmrg/* 209605b261ecSmrg * ** Given an extension request, call the appropriate request procedure 209705b261ecSmrg */ 20984202a189Smrgstatic int 20994202a189SmrgProcSyncDispatch(ClientPtr client) 210005b261ecSmrg{ 210105b261ecSmrg REQUEST(xReq); 210205b261ecSmrg 2103f7df2e56Smrg switch (stuff->data) { 2104f7df2e56Smrg case X_SyncInitialize: 2105f7df2e56Smrg return ProcSyncInitialize(client); 2106f7df2e56Smrg case X_SyncListSystemCounters: 2107f7df2e56Smrg return ProcSyncListSystemCounters(client); 2108f7df2e56Smrg case X_SyncCreateCounter: 2109f7df2e56Smrg return ProcSyncCreateCounter(client); 2110f7df2e56Smrg case X_SyncSetCounter: 2111f7df2e56Smrg return ProcSyncSetCounter(client); 2112f7df2e56Smrg case X_SyncChangeCounter: 2113f7df2e56Smrg return ProcSyncChangeCounter(client); 2114f7df2e56Smrg case X_SyncQueryCounter: 2115f7df2e56Smrg return ProcSyncQueryCounter(client); 2116f7df2e56Smrg case X_SyncDestroyCounter: 2117f7df2e56Smrg return ProcSyncDestroyCounter(client); 2118f7df2e56Smrg case X_SyncAwait: 2119f7df2e56Smrg return ProcSyncAwait(client); 2120f7df2e56Smrg case X_SyncCreateAlarm: 2121f7df2e56Smrg return ProcSyncCreateAlarm(client); 2122f7df2e56Smrg case X_SyncChangeAlarm: 2123f7df2e56Smrg return ProcSyncChangeAlarm(client); 2124f7df2e56Smrg case X_SyncQueryAlarm: 2125f7df2e56Smrg return ProcSyncQueryAlarm(client); 2126f7df2e56Smrg case X_SyncDestroyAlarm: 2127f7df2e56Smrg return ProcSyncDestroyAlarm(client); 2128f7df2e56Smrg case X_SyncSetPriority: 2129f7df2e56Smrg return ProcSyncSetPriority(client); 2130f7df2e56Smrg case X_SyncGetPriority: 2131f7df2e56Smrg return ProcSyncGetPriority(client); 2132f7df2e56Smrg case X_SyncCreateFence: 2133f7df2e56Smrg return ProcSyncCreateFence(client); 2134f7df2e56Smrg case X_SyncTriggerFence: 2135f7df2e56Smrg return ProcSyncTriggerFence(client); 2136f7df2e56Smrg case X_SyncResetFence: 2137f7df2e56Smrg return ProcSyncResetFence(client); 2138f7df2e56Smrg case X_SyncDestroyFence: 2139f7df2e56Smrg return ProcSyncDestroyFence(client); 2140f7df2e56Smrg case X_SyncQueryFence: 2141f7df2e56Smrg return ProcSyncQueryFence(client); 2142f7df2e56Smrg case X_SyncAwaitFence: 2143f7df2e56Smrg return ProcSyncAwaitFence(client); 2144f7df2e56Smrg default: 2145f7df2e56Smrg return BadRequest; 214605b261ecSmrg } 214705b261ecSmrg} 214805b261ecSmrg 214905b261ecSmrg/* 215005b261ecSmrg * Boring Swapping stuff ... 215105b261ecSmrg */ 215205b261ecSmrg 21537e31ba66Smrgstatic int _X_COLD 21544202a189SmrgSProcSyncInitialize(ClientPtr client) 215505b261ecSmrg{ 215605b261ecSmrg REQUEST(xSyncInitializeReq); 2157f7df2e56Smrg swaps(&stuff->length); 2158f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncInitializeReq); 215905b261ecSmrg 216005b261ecSmrg return ProcSyncInitialize(client); 216105b261ecSmrg} 216205b261ecSmrg 21637e31ba66Smrgstatic int _X_COLD 21644202a189SmrgSProcSyncListSystemCounters(ClientPtr client) 216505b261ecSmrg{ 216605b261ecSmrg REQUEST(xSyncListSystemCountersReq); 2167f7df2e56Smrg swaps(&stuff->length); 2168f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncListSystemCountersReq); 216905b261ecSmrg 217005b261ecSmrg return ProcSyncListSystemCounters(client); 217105b261ecSmrg} 217205b261ecSmrg 21737e31ba66Smrgstatic int _X_COLD 21744202a189SmrgSProcSyncCreateCounter(ClientPtr client) 217505b261ecSmrg{ 217605b261ecSmrg REQUEST(xSyncCreateCounterReq); 2177f7df2e56Smrg swaps(&stuff->length); 2178f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncCreateCounterReq); 2179f7df2e56Smrg swapl(&stuff->cid); 2180f7df2e56Smrg swapl(&stuff->initial_value_lo); 2181f7df2e56Smrg swapl(&stuff->initial_value_hi); 218205b261ecSmrg 218305b261ecSmrg return ProcSyncCreateCounter(client); 218405b261ecSmrg} 218505b261ecSmrg 21867e31ba66Smrgstatic int _X_COLD 21874202a189SmrgSProcSyncSetCounter(ClientPtr client) 218805b261ecSmrg{ 218905b261ecSmrg REQUEST(xSyncSetCounterReq); 2190f7df2e56Smrg swaps(&stuff->length); 2191f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncSetCounterReq); 2192f7df2e56Smrg swapl(&stuff->cid); 2193f7df2e56Smrg swapl(&stuff->value_lo); 2194f7df2e56Smrg swapl(&stuff->value_hi); 219505b261ecSmrg 219605b261ecSmrg return ProcSyncSetCounter(client); 219705b261ecSmrg} 219805b261ecSmrg 21997e31ba66Smrgstatic int _X_COLD 22004202a189SmrgSProcSyncChangeCounter(ClientPtr client) 220105b261ecSmrg{ 220205b261ecSmrg REQUEST(xSyncChangeCounterReq); 2203f7df2e56Smrg swaps(&stuff->length); 2204f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncChangeCounterReq); 2205f7df2e56Smrg swapl(&stuff->cid); 2206f7df2e56Smrg swapl(&stuff->value_lo); 2207f7df2e56Smrg swapl(&stuff->value_hi); 220805b261ecSmrg 220905b261ecSmrg return ProcSyncChangeCounter(client); 221005b261ecSmrg} 221105b261ecSmrg 22127e31ba66Smrgstatic int _X_COLD 22134202a189SmrgSProcSyncQueryCounter(ClientPtr client) 221405b261ecSmrg{ 221505b261ecSmrg REQUEST(xSyncQueryCounterReq); 2216f7df2e56Smrg swaps(&stuff->length); 2217f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncQueryCounterReq); 2218f7df2e56Smrg swapl(&stuff->counter); 221905b261ecSmrg 222005b261ecSmrg return ProcSyncQueryCounter(client); 222105b261ecSmrg} 222205b261ecSmrg 22237e31ba66Smrgstatic int _X_COLD 22244202a189SmrgSProcSyncDestroyCounter(ClientPtr client) 222505b261ecSmrg{ 222605b261ecSmrg REQUEST(xSyncDestroyCounterReq); 2227f7df2e56Smrg swaps(&stuff->length); 2228f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncDestroyCounterReq); 2229f7df2e56Smrg swapl(&stuff->counter); 223005b261ecSmrg 223105b261ecSmrg return ProcSyncDestroyCounter(client); 223205b261ecSmrg} 223305b261ecSmrg 22347e31ba66Smrgstatic int _X_COLD 22354202a189SmrgSProcSyncAwait(ClientPtr client) 223605b261ecSmrg{ 223705b261ecSmrg REQUEST(xSyncAwaitReq); 2238f7df2e56Smrg swaps(&stuff->length); 223905b261ecSmrg REQUEST_AT_LEAST_SIZE(xSyncAwaitReq); 224005b261ecSmrg SwapRestL(stuff); 224105b261ecSmrg 224205b261ecSmrg return ProcSyncAwait(client); 224305b261ecSmrg} 224405b261ecSmrg 22457e31ba66Smrgstatic int _X_COLD 22464202a189SmrgSProcSyncCreateAlarm(ClientPtr client) 224705b261ecSmrg{ 224805b261ecSmrg REQUEST(xSyncCreateAlarmReq); 2249f7df2e56Smrg swaps(&stuff->length); 225005b261ecSmrg REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq); 2251f7df2e56Smrg swapl(&stuff->id); 2252f7df2e56Smrg swapl(&stuff->valueMask); 225305b261ecSmrg SwapRestL(stuff); 225405b261ecSmrg 225505b261ecSmrg return ProcSyncCreateAlarm(client); 225605b261ecSmrg} 225705b261ecSmrg 22587e31ba66Smrgstatic int _X_COLD 22594202a189SmrgSProcSyncChangeAlarm(ClientPtr client) 226005b261ecSmrg{ 226105b261ecSmrg REQUEST(xSyncChangeAlarmReq); 2262f7df2e56Smrg swaps(&stuff->length); 226305b261ecSmrg REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq); 2264f7df2e56Smrg swapl(&stuff->alarm); 2265f7df2e56Smrg swapl(&stuff->valueMask); 226605b261ecSmrg SwapRestL(stuff); 226705b261ecSmrg return ProcSyncChangeAlarm(client); 226805b261ecSmrg} 226905b261ecSmrg 22707e31ba66Smrgstatic int _X_COLD 22714202a189SmrgSProcSyncQueryAlarm(ClientPtr client) 227205b261ecSmrg{ 227305b261ecSmrg REQUEST(xSyncQueryAlarmReq); 2274f7df2e56Smrg swaps(&stuff->length); 2275f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncQueryAlarmReq); 2276f7df2e56Smrg swapl(&stuff->alarm); 227705b261ecSmrg 227805b261ecSmrg return ProcSyncQueryAlarm(client); 227905b261ecSmrg} 228005b261ecSmrg 22817e31ba66Smrgstatic int _X_COLD 22824202a189SmrgSProcSyncDestroyAlarm(ClientPtr client) 228305b261ecSmrg{ 228405b261ecSmrg REQUEST(xSyncDestroyAlarmReq); 2285f7df2e56Smrg swaps(&stuff->length); 2286f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq); 2287f7df2e56Smrg swapl(&stuff->alarm); 228805b261ecSmrg 228905b261ecSmrg return ProcSyncDestroyAlarm(client); 229005b261ecSmrg} 229105b261ecSmrg 22927e31ba66Smrgstatic int _X_COLD 22934202a189SmrgSProcSyncSetPriority(ClientPtr client) 229405b261ecSmrg{ 229505b261ecSmrg REQUEST(xSyncSetPriorityReq); 2296f7df2e56Smrg swaps(&stuff->length); 2297f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncSetPriorityReq); 2298f7df2e56Smrg swapl(&stuff->id); 2299f7df2e56Smrg swapl(&stuff->priority); 230005b261ecSmrg 230105b261ecSmrg return ProcSyncSetPriority(client); 230205b261ecSmrg} 230305b261ecSmrg 23047e31ba66Smrgstatic int _X_COLD 23054202a189SmrgSProcSyncGetPriority(ClientPtr client) 230605b261ecSmrg{ 230705b261ecSmrg REQUEST(xSyncGetPriorityReq); 2308f7df2e56Smrg swaps(&stuff->length); 2309f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncGetPriorityReq); 2310f7df2e56Smrg swapl(&stuff->id); 231105b261ecSmrg 231205b261ecSmrg return ProcSyncGetPriority(client); 231305b261ecSmrg} 231405b261ecSmrg 23157e31ba66Smrgstatic int _X_COLD 231665b04b38SmrgSProcSyncCreateFence(ClientPtr client) 231765b04b38Smrg{ 231865b04b38Smrg REQUEST(xSyncCreateFenceReq); 2319f7df2e56Smrg swaps(&stuff->length); 2320f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncCreateFenceReq); 2321875c6e4fSmrg swapl(&stuff->d); 2322f7df2e56Smrg swapl(&stuff->fid); 232365b04b38Smrg 232465b04b38Smrg return ProcSyncCreateFence(client); 232565b04b38Smrg} 232665b04b38Smrg 23277e31ba66Smrgstatic int _X_COLD 232865b04b38SmrgSProcSyncTriggerFence(ClientPtr client) 232965b04b38Smrg{ 233065b04b38Smrg REQUEST(xSyncTriggerFenceReq); 2331f7df2e56Smrg swaps(&stuff->length); 2332f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncTriggerFenceReq); 2333f7df2e56Smrg swapl(&stuff->fid); 233465b04b38Smrg 233565b04b38Smrg return ProcSyncTriggerFence(client); 233665b04b38Smrg} 233765b04b38Smrg 23387e31ba66Smrgstatic int _X_COLD 233965b04b38SmrgSProcSyncResetFence(ClientPtr client) 234065b04b38Smrg{ 234165b04b38Smrg REQUEST(xSyncResetFenceReq); 2342f7df2e56Smrg swaps(&stuff->length); 2343f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncResetFenceReq); 2344f7df2e56Smrg swapl(&stuff->fid); 234565b04b38Smrg 234665b04b38Smrg return ProcSyncResetFence(client); 234765b04b38Smrg} 234865b04b38Smrg 23497e31ba66Smrgstatic int _X_COLD 235065b04b38SmrgSProcSyncDestroyFence(ClientPtr client) 235165b04b38Smrg{ 235265b04b38Smrg REQUEST(xSyncDestroyFenceReq); 2353f7df2e56Smrg swaps(&stuff->length); 2354f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncDestroyFenceReq); 2355f7df2e56Smrg swapl(&stuff->fid); 235665b04b38Smrg 235765b04b38Smrg return ProcSyncDestroyFence(client); 235865b04b38Smrg} 235965b04b38Smrg 23607e31ba66Smrgstatic int _X_COLD 236165b04b38SmrgSProcSyncQueryFence(ClientPtr client) 236265b04b38Smrg{ 236365b04b38Smrg REQUEST(xSyncQueryFenceReq); 2364f7df2e56Smrg swaps(&stuff->length); 2365f7df2e56Smrg REQUEST_SIZE_MATCH(xSyncQueryFenceReq); 2366f7df2e56Smrg swapl(&stuff->fid); 236765b04b38Smrg 236865b04b38Smrg return ProcSyncQueryFence(client); 236965b04b38Smrg} 237065b04b38Smrg 23717e31ba66Smrgstatic int _X_COLD 237265b04b38SmrgSProcSyncAwaitFence(ClientPtr client) 237365b04b38Smrg{ 237465b04b38Smrg REQUEST(xSyncAwaitFenceReq); 2375f7df2e56Smrg swaps(&stuff->length); 237665b04b38Smrg REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq); 237765b04b38Smrg SwapRestL(stuff); 237865b04b38Smrg 237965b04b38Smrg return ProcSyncAwaitFence(client); 238065b04b38Smrg} 238105b261ecSmrg 23827e31ba66Smrgstatic int _X_COLD 23834202a189SmrgSProcSyncDispatch(ClientPtr client) 238405b261ecSmrg{ 238505b261ecSmrg REQUEST(xReq); 238605b261ecSmrg 2387f7df2e56Smrg switch (stuff->data) { 2388f7df2e56Smrg case X_SyncInitialize: 2389f7df2e56Smrg return SProcSyncInitialize(client); 2390f7df2e56Smrg case X_SyncListSystemCounters: 2391f7df2e56Smrg return SProcSyncListSystemCounters(client); 2392f7df2e56Smrg case X_SyncCreateCounter: 2393f7df2e56Smrg return SProcSyncCreateCounter(client); 2394f7df2e56Smrg case X_SyncSetCounter: 2395f7df2e56Smrg return SProcSyncSetCounter(client); 2396f7df2e56Smrg case X_SyncChangeCounter: 2397f7df2e56Smrg return SProcSyncChangeCounter(client); 2398f7df2e56Smrg case X_SyncQueryCounter: 2399f7df2e56Smrg return SProcSyncQueryCounter(client); 2400f7df2e56Smrg case X_SyncDestroyCounter: 2401f7df2e56Smrg return SProcSyncDestroyCounter(client); 2402f7df2e56Smrg case X_SyncAwait: 2403f7df2e56Smrg return SProcSyncAwait(client); 2404f7df2e56Smrg case X_SyncCreateAlarm: 2405f7df2e56Smrg return SProcSyncCreateAlarm(client); 2406f7df2e56Smrg case X_SyncChangeAlarm: 2407f7df2e56Smrg return SProcSyncChangeAlarm(client); 2408f7df2e56Smrg case X_SyncQueryAlarm: 2409f7df2e56Smrg return SProcSyncQueryAlarm(client); 2410f7df2e56Smrg case X_SyncDestroyAlarm: 2411f7df2e56Smrg return SProcSyncDestroyAlarm(client); 2412f7df2e56Smrg case X_SyncSetPriority: 2413f7df2e56Smrg return SProcSyncSetPriority(client); 2414f7df2e56Smrg case X_SyncGetPriority: 2415f7df2e56Smrg return SProcSyncGetPriority(client); 2416f7df2e56Smrg case X_SyncCreateFence: 2417f7df2e56Smrg return SProcSyncCreateFence(client); 2418f7df2e56Smrg case X_SyncTriggerFence: 2419f7df2e56Smrg return SProcSyncTriggerFence(client); 2420f7df2e56Smrg case X_SyncResetFence: 2421f7df2e56Smrg return SProcSyncResetFence(client); 2422f7df2e56Smrg case X_SyncDestroyFence: 2423f7df2e56Smrg return SProcSyncDestroyFence(client); 2424f7df2e56Smrg case X_SyncQueryFence: 2425f7df2e56Smrg return SProcSyncQueryFence(client); 2426f7df2e56Smrg case X_SyncAwaitFence: 2427f7df2e56Smrg return SProcSyncAwaitFence(client); 2428f7df2e56Smrg default: 2429f7df2e56Smrg return BadRequest; 243005b261ecSmrg } 243105b261ecSmrg} 243205b261ecSmrg 243305b261ecSmrg/* 243405b261ecSmrg * Event Swapping 243505b261ecSmrg */ 243605b261ecSmrg 24377e31ba66Smrgstatic void _X_COLD 2438f7df2e56SmrgSCounterNotifyEvent(xSyncCounterNotifyEvent * from, 2439f7df2e56Smrg xSyncCounterNotifyEvent * to) 244005b261ecSmrg{ 244105b261ecSmrg to->type = from->type; 244205b261ecSmrg to->kind = from->kind; 244305b261ecSmrg cpswaps(from->sequenceNumber, to->sequenceNumber); 244405b261ecSmrg cpswapl(from->counter, to->counter); 244505b261ecSmrg cpswapl(from->wait_value_lo, to->wait_value_lo); 244605b261ecSmrg cpswapl(from->wait_value_hi, to->wait_value_hi); 244705b261ecSmrg cpswapl(from->counter_value_lo, to->counter_value_lo); 244805b261ecSmrg cpswapl(from->counter_value_hi, to->counter_value_hi); 244905b261ecSmrg cpswapl(from->time, to->time); 245005b261ecSmrg cpswaps(from->count, to->count); 245105b261ecSmrg to->destroyed = from->destroyed; 245205b261ecSmrg} 245305b261ecSmrg 24547e31ba66Smrgstatic void _X_COLD 2455f7df2e56SmrgSAlarmNotifyEvent(xSyncAlarmNotifyEvent * from, xSyncAlarmNotifyEvent * to) 245605b261ecSmrg{ 245705b261ecSmrg to->type = from->type; 245805b261ecSmrg to->kind = from->kind; 245905b261ecSmrg cpswaps(from->sequenceNumber, to->sequenceNumber); 246005b261ecSmrg cpswapl(from->alarm, to->alarm); 246105b261ecSmrg cpswapl(from->counter_value_lo, to->counter_value_lo); 246205b261ecSmrg cpswapl(from->counter_value_hi, to->counter_value_hi); 246305b261ecSmrg cpswapl(from->alarm_value_lo, to->alarm_value_lo); 246405b261ecSmrg cpswapl(from->alarm_value_hi, to->alarm_value_hi); 246505b261ecSmrg cpswapl(from->time, to->time); 246605b261ecSmrg to->state = from->state; 246705b261ecSmrg} 246805b261ecSmrg 246905b261ecSmrg/* 247005b261ecSmrg * ** Close everything down. ** This is fairly simple for now. 247105b261ecSmrg */ 247205b261ecSmrg/* ARGSUSED */ 24734202a189Smrgstatic void 2474f7df2e56SmrgSyncResetProc(ExtensionEntry * extEntry) 247505b261ecSmrg{ 247605b261ecSmrg RTCounter = 0; 247705b261ecSmrg} 247805b261ecSmrg 247905b261ecSmrg/* 248005b261ecSmrg * ** Initialise the extension. 248105b261ecSmrg */ 24824202a189Smrgvoid 24834202a189SmrgSyncExtensionInit(void) 248405b261ecSmrg{ 248505b261ecSmrg ExtensionEntry *extEntry; 2486f7df2e56Smrg int s; 248765b04b38Smrg 248865b04b38Smrg for (s = 0; s < screenInfo.numScreens; s++) 2489f7df2e56Smrg miSyncSetup(screenInfo.screens[s]); 249005b261ecSmrg 24917e31ba66Smrg RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter"); 24927e31ba66Smrg xorg_list_init(&SysCounterList); 24934202a189Smrg RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm"); 24944202a189Smrg RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait"); 249565b04b38Smrg RTFence = CreateNewResourceType(FreeFence, "SyncFence"); 24964202a189Smrg if (RTAwait) 2497f7df2e56Smrg RTAwait |= RC_NEVERRETAIN; 24984202a189Smrg RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient"); 24994202a189Smrg if (RTAlarmClient) 2500f7df2e56Smrg RTAlarmClient |= RC_NEVERRETAIN; 250105b261ecSmrg 250205b261ecSmrg if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 || 2503f7df2e56Smrg RTAlarmClient == 0 || 2504f7df2e56Smrg (extEntry = AddExtension(SYNC_NAME, 2505f7df2e56Smrg XSyncNumberEvents, XSyncNumberErrors, 2506f7df2e56Smrg ProcSyncDispatch, SProcSyncDispatch, 2507f7df2e56Smrg SyncResetProc, StandardMinorOpcode)) == NULL) { 2508f7df2e56Smrg ErrorF("Sync Extension %d.%d failed to Initialise\n", 2509f7df2e56Smrg SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION); 2510f7df2e56Smrg return; 251105b261ecSmrg } 251205b261ecSmrg 251305b261ecSmrg SyncEventBase = extEntry->eventBase; 251405b261ecSmrg SyncErrorBase = extEntry->errorBase; 2515f7df2e56Smrg EventSwapVector[SyncEventBase + XSyncCounterNotify] = 2516f7df2e56Smrg (EventSwapPtr) SCounterNotifyEvent; 2517f7df2e56Smrg EventSwapVector[SyncEventBase + XSyncAlarmNotify] = 2518f7df2e56Smrg (EventSwapPtr) SAlarmNotifyEvent; 251905b261ecSmrg 25204202a189Smrg SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter); 25214202a189Smrg SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm); 252265b04b38Smrg SetResourceTypeErrorValue(RTFence, SyncErrorBase + XSyncBadFence); 25234202a189Smrg 252405b261ecSmrg /* 252505b261ecSmrg * Although SERVERTIME is implemented by the OS layer, we initialise it 252605b261ecSmrg * here because doing it in OsInit() is too early. The resource database 252705b261ecSmrg * is not initialised when OsInit() is called. This is just about OK 252805b261ecSmrg * because there is always a servertime counter. 252905b261ecSmrg */ 253005b261ecSmrg SyncInitServerTime(); 253105b261ecSmrg SyncInitIdleTime(); 253205b261ecSmrg 253305b261ecSmrg#ifdef DEBUG 253405b261ecSmrg fprintf(stderr, "Sync Extension %d.%d\n", 2535f7df2e56Smrg SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION); 253605b261ecSmrg#endif 253705b261ecSmrg} 253805b261ecSmrg 253905b261ecSmrg/* 254005b261ecSmrg * ***** SERVERTIME implementation - should go in its own file in OS directory? 254105b261ecSmrg */ 254205b261ecSmrg 2543f7df2e56Smrgstatic void *ServertimeCounter; 25447e31ba66Smrgstatic int64_t Now; 25457e31ba66Smrgstatic int64_t *pnext_time; 25467e31ba66Smrg 25477e31ba66Smrgstatic void GetTime(void) 25487e31ba66Smrg{ 25497e31ba66Smrg unsigned long millis = GetTimeInMillis(); 25507e31ba66Smrg unsigned long maxis = Now >> 32; 25517e31ba66Smrg 25527e31ba66Smrg if (millis < (Now & 0xffffffff)) 25537e31ba66Smrg maxis++; 255405b261ecSmrg 25557e31ba66Smrg Now = ((int64_t)maxis << 32) | millis; 255605b261ecSmrg} 255705b261ecSmrg 255805b261ecSmrg/* 255905b261ecSmrg*** Server Block Handler 25604202a189Smrg*** code inspired by multibuffer extension (now deprecated) 256105b261ecSmrg */ 25627e31ba66Smrg/*ARGSUSED*/ static void 25637e31ba66SmrgServertimeBlockHandler(void *env, void *wt) 256405b261ecSmrg{ 256505b261ecSmrg unsigned long timeout; 256605b261ecSmrg 2567f7df2e56Smrg if (pnext_time) { 256805b261ecSmrg GetTime(); 256905b261ecSmrg 25707e31ba66Smrg if (Now >= *pnext_time) { 257105b261ecSmrg timeout = 0; 25724202a189Smrg } 2573f7df2e56Smrg else { 25747e31ba66Smrg timeout = *pnext_time - Now; 257505b261ecSmrg } 2576f7df2e56Smrg AdjustWaitForDelay(wt, timeout); /* os/utils.c */ 257705b261ecSmrg } 257805b261ecSmrg} 257905b261ecSmrg 258005b261ecSmrg/* 258105b261ecSmrg*** Wakeup Handler 258205b261ecSmrg */ 25837e31ba66Smrg/*ARGSUSED*/ static void 25847e31ba66SmrgServertimeWakeupHandler(void *env, int rc) 258505b261ecSmrg{ 2586f7df2e56Smrg if (pnext_time) { 258705b261ecSmrg GetTime(); 258805b261ecSmrg 25897e31ba66Smrg if (Now >= *pnext_time) { 259005b261ecSmrg SyncChangeCounter(ServertimeCounter, Now); 259105b261ecSmrg } 259205b261ecSmrg } 259305b261ecSmrg} 259405b261ecSmrg 259505b261ecSmrgstatic void 25967e31ba66SmrgServertimeQueryValue(void *pCounter, int64_t *pValue_return) 259705b261ecSmrg{ 259805b261ecSmrg GetTime(); 259905b261ecSmrg *pValue_return = Now; 260005b261ecSmrg} 260105b261ecSmrg 260205b261ecSmrgstatic void 26037e31ba66SmrgServertimeBracketValues(void *pCounter, int64_t *pbracket_less, 26047e31ba66Smrg int64_t *pbracket_greater) 260505b261ecSmrg{ 2606f7df2e56Smrg if (!pnext_time && pbracket_greater) { 2607f7df2e56Smrg RegisterBlockAndWakeupHandlers(ServertimeBlockHandler, 2608f7df2e56Smrg ServertimeWakeupHandler, NULL); 260905b261ecSmrg } 2610f7df2e56Smrg else if (pnext_time && !pbracket_greater) { 2611f7df2e56Smrg RemoveBlockAndWakeupHandlers(ServertimeBlockHandler, 2612f7df2e56Smrg ServertimeWakeupHandler, NULL); 261305b261ecSmrg } 261405b261ecSmrg pnext_time = pbracket_greater; 261505b261ecSmrg} 261605b261ecSmrg 261705b261ecSmrgstatic void 261805b261ecSmrgSyncInitServerTime(void) 261905b261ecSmrg{ 26207e31ba66Smrg int64_t resolution = 4; 262105b261ecSmrg 26227e31ba66Smrg Now = GetTimeInMillis(); 262305b261ecSmrg ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution, 2624f7df2e56Smrg XSyncCounterNeverDecreases, 2625f7df2e56Smrg ServertimeQueryValue, 2626f7df2e56Smrg ServertimeBracketValues); 262705b261ecSmrg pnext_time = NULL; 262805b261ecSmrg} 262905b261ecSmrg 263005b261ecSmrg/* 263105b261ecSmrg * IDLETIME implementation 263205b261ecSmrg */ 263305b261ecSmrg 2634f7df2e56Smrgtypedef struct { 26357e31ba66Smrg int64_t *value_less; 26367e31ba66Smrg int64_t *value_greater; 2637f7df2e56Smrg int deviceid; 2638f7df2e56Smrg} IdleCounterPriv; 263905b261ecSmrg 264005b261ecSmrgstatic void 26417e31ba66SmrgIdleTimeQueryValue(void *pCounter, int64_t *pValue_return) 264205b261ecSmrg{ 2643f7df2e56Smrg int deviceid; 2644f7df2e56Smrg CARD32 idle; 2645f7df2e56Smrg 2646f7df2e56Smrg if (pCounter) { 2647f7df2e56Smrg SyncCounter *counter = pCounter; 2648f7df2e56Smrg IdleCounterPriv *priv = SysCounterGetPrivate(counter); 2649f7df2e56Smrg deviceid = priv->deviceid; 2650f7df2e56Smrg } 2651f7df2e56Smrg else 2652f7df2e56Smrg deviceid = XIAllDevices; 2653f7df2e56Smrg idle = GetTimeInMillis() - LastEventTime(deviceid).milliseconds; 26547e31ba66Smrg *pValue_return = idle; 265505b261ecSmrg} 265605b261ecSmrg 265705b261ecSmrgstatic void 26587e31ba66SmrgIdleTimeBlockHandler(void *pCounter, void *wt) 265905b261ecSmrg{ 2660f7df2e56Smrg SyncCounter *counter = pCounter; 2661f7df2e56Smrg IdleCounterPriv *priv = SysCounterGetPrivate(counter); 26627e31ba66Smrg int64_t *less = priv->value_less; 26637e31ba66Smrg int64_t *greater = priv->value_greater; 26647e31ba66Smrg int64_t idle, old_idle; 2665f7df2e56Smrg SyncTriggerList *list = counter->sync.pTriglist; 266645801275Sjmcneill SyncTrigger *trig; 266705b261ecSmrg 2668f7df2e56Smrg if (!less && !greater) 2669f7df2e56Smrg return; 2670f7df2e56Smrg 2671f7df2e56Smrg old_idle = counter->value; 2672f7df2e56Smrg IdleTimeQueryValue(counter, &idle); 2673f7df2e56Smrg counter->value = idle; /* push, so CheckTrigger works */ 2674f7df2e56Smrg 2675f7df2e56Smrg /** 2676f7df2e56Smrg * There's an indefinite amount of time between ProcessInputEvents() 2677f7df2e56Smrg * where the idle time is reset and the time we actually get here. idle 2678f7df2e56Smrg * may be past the lower bracket if we dawdled with the events, so 2679f7df2e56Smrg * check for whether we did reset and bomb out of select immediately. 2680f7df2e56Smrg */ 26817e31ba66Smrg if (less && idle > *less && 2682f7df2e56Smrg LastEventTimeWasReset(priv->deviceid)) { 2683f7df2e56Smrg AdjustWaitForDelay(wt, 0); 26847e31ba66Smrg } else if (less && idle <= *less) { 2685f7df2e56Smrg /* 2686f7df2e56Smrg * We've been idle for less than the threshold value, and someone 2687f7df2e56Smrg * wants to know about that, but now we need to know whether they 2688f7df2e56Smrg * want level or edge trigger. Check the trigger list against the 2689f7df2e56Smrg * current idle time, and if any succeed, bomb out of select() 2690f7df2e56Smrg * immediately so we can reschedule. 2691f7df2e56Smrg */ 2692f7df2e56Smrg 2693f7df2e56Smrg for (list = counter->sync.pTriglist; list; list = list->next) { 2694f7df2e56Smrg trig = list->pTrigger; 2695f7df2e56Smrg if (trig->CheckTrigger(trig, old_idle)) { 2696f7df2e56Smrg AdjustWaitForDelay(wt, 0); 2697f7df2e56Smrg break; 2698f7df2e56Smrg } 2699f7df2e56Smrg } 2700f7df2e56Smrg /* 2701f7df2e56Smrg * We've been called exactly on the idle time, but we have a 2702f7df2e56Smrg * NegativeTransition trigger which requires a transition from an 2703f7df2e56Smrg * idle time greater than this. Schedule a wakeup for the next 2704f7df2e56Smrg * millisecond so we won't miss a transition. 2705f7df2e56Smrg */ 27067e31ba66Smrg if (idle == *less) 2707f7df2e56Smrg AdjustWaitForDelay(wt, 1); 2708f7df2e56Smrg } 2709f7df2e56Smrg else if (greater) { 2710f7df2e56Smrg /* 2711f7df2e56Smrg * There's a threshold in the positive direction. If we've been 2712f7df2e56Smrg * idle less than it, schedule a wakeup for sometime in the future. 2713f7df2e56Smrg * If we've been idle more than it, and someone wants to know about 2714f7df2e56Smrg * that level-triggered, schedule an immediate wakeup. 2715f7df2e56Smrg */ 2716f7df2e56Smrg 27177e31ba66Smrg if (idle < *greater) { 27187e31ba66Smrg AdjustWaitForDelay(wt, *greater - idle); 2719f7df2e56Smrg } 2720f7df2e56Smrg else { 2721f7df2e56Smrg for (list = counter->sync.pTriglist; list; 2722f7df2e56Smrg list = list->next) { 2723f7df2e56Smrg trig = list->pTrigger; 2724f7df2e56Smrg if (trig->CheckTrigger(trig, old_idle)) { 2725f7df2e56Smrg AdjustWaitForDelay(wt, 0); 2726f7df2e56Smrg break; 2727f7df2e56Smrg } 2728f7df2e56Smrg } 2729f7df2e56Smrg } 2730f7df2e56Smrg } 2731f7df2e56Smrg 2732f7df2e56Smrg counter->value = old_idle; /* pop */ 2733f7df2e56Smrg} 2734f7df2e56Smrg 2735f7df2e56Smrgstatic void 27367e31ba66SmrgIdleTimeCheckBrackets(SyncCounter *counter, int64_t idle, 27377e31ba66Smrg int64_t *less, int64_t *greater) 2738f7df2e56Smrg{ 27397e31ba66Smrg if ((greater && idle >= *greater) || 27407e31ba66Smrg (less && idle <= *less)) { 2741f7df2e56Smrg SyncChangeCounter(counter, idle); 2742f7df2e56Smrg } 2743f7df2e56Smrg else 2744f7df2e56Smrg SyncUpdateCounter(counter, idle); 274505b261ecSmrg} 274605b261ecSmrg 274705b261ecSmrgstatic void 27487e31ba66SmrgIdleTimeWakeupHandler(void *pCounter, int rc) 274905b261ecSmrg{ 2750f7df2e56Smrg SyncCounter *counter = pCounter; 2751f7df2e56Smrg IdleCounterPriv *priv = SysCounterGetPrivate(counter); 27527e31ba66Smrg int64_t *less = priv->value_less; 27537e31ba66Smrg int64_t *greater = priv->value_greater; 27547e31ba66Smrg int64_t idle; 275505b261ecSmrg 2756f7df2e56Smrg if (!less && !greater) 2757f7df2e56Smrg return; 275805b261ecSmrg 2759f7df2e56Smrg IdleTimeQueryValue(pCounter, &idle); 276005b261ecSmrg 2761f7df2e56Smrg /* 2762f7df2e56Smrg There is no guarantee for the WakeupHandler to be called within a specific 2763f7df2e56Smrg timeframe. Idletime may go to 0, but by the time we get here, it may be 2764f7df2e56Smrg non-zero and alarms for a pos. transition on 0 won't get triggered. 2765f7df2e56Smrg https://bugs.freedesktop.org/show_bug.cgi?id=70476 2766f7df2e56Smrg */ 2767f7df2e56Smrg if (LastEventTimeWasReset(priv->deviceid)) { 2768f7df2e56Smrg LastEventTimeToggleResetFlag(priv->deviceid, FALSE); 27697e31ba66Smrg if (idle != 0) { 27707e31ba66Smrg IdleTimeCheckBrackets(counter, 0, less, greater); 2771f7df2e56Smrg less = priv->value_less; 2772f7df2e56Smrg greater = priv->value_greater; 2773f7df2e56Smrg } 277405b261ecSmrg } 2775f7df2e56Smrg 2776f7df2e56Smrg IdleTimeCheckBrackets(counter, idle, less, greater); 277705b261ecSmrg} 277805b261ecSmrg 277905b261ecSmrgstatic void 27807e31ba66SmrgIdleTimeBracketValues(void *pCounter, int64_t *pbracket_less, 27817e31ba66Smrg int64_t *pbracket_greater) 278205b261ecSmrg{ 2783f7df2e56Smrg SyncCounter *counter = pCounter; 2784f7df2e56Smrg IdleCounterPriv *priv = SysCounterGetPrivate(counter); 27857e31ba66Smrg int64_t *less = priv->value_less; 27867e31ba66Smrg int64_t *greater = priv->value_greater; 2787f7df2e56Smrg Bool registered = (less || greater); 278805b261ecSmrg 2789f7df2e56Smrg if (registered && !pbracket_less && !pbracket_greater) { 2790f7df2e56Smrg RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler, 2791f7df2e56Smrg IdleTimeWakeupHandler, pCounter); 279205b261ecSmrg } 2793f7df2e56Smrg else if (!registered && (pbracket_less || pbracket_greater)) { 2794f7df2e56Smrg /* Reset flag must be zero so we don't force a idle timer reset on 2795f7df2e56Smrg the first wakeup */ 2796f7df2e56Smrg LastEventTimeToggleResetAll(FALSE); 2797f7df2e56Smrg RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler, 2798f7df2e56Smrg IdleTimeWakeupHandler, pCounter); 279905b261ecSmrg } 280005b261ecSmrg 2801f7df2e56Smrg priv->value_greater = pbracket_greater; 2802f7df2e56Smrg priv->value_less = pbracket_less; 280305b261ecSmrg} 280405b261ecSmrg 2805f7df2e56Smrgstatic SyncCounter* 2806f7df2e56Smrginit_system_idle_counter(const char *name, int deviceid) 280705b261ecSmrg{ 28087e31ba66Smrg int64_t resolution = 4; 28097e31ba66Smrg int64_t idle; 2810f7df2e56Smrg SyncCounter *idle_time_counter; 2811f7df2e56Smrg 2812f7df2e56Smrg IdleTimeQueryValue(NULL, &idle); 281305b261ecSmrg 2814f7df2e56Smrg idle_time_counter = SyncCreateSystemCounter(name, idle, resolution, 2815f7df2e56Smrg XSyncCounterUnrestricted, 2816f7df2e56Smrg IdleTimeQueryValue, 2817f7df2e56Smrg IdleTimeBracketValues); 281805b261ecSmrg 2819f7df2e56Smrg if (idle_time_counter != NULL) { 2820f7df2e56Smrg IdleCounterPriv *priv = malloc(sizeof(IdleCounterPriv)); 282105b261ecSmrg 2822f7df2e56Smrg priv->value_less = priv->value_greater = NULL; 2823f7df2e56Smrg priv->deviceid = deviceid; 2824f7df2e56Smrg 2825f7df2e56Smrg idle_time_counter->pSysCounterInfo->private = priv; 2826f7df2e56Smrg } 2827f7df2e56Smrg 2828f7df2e56Smrg return idle_time_counter; 2829f7df2e56Smrg} 2830f7df2e56Smrg 2831f7df2e56Smrgstatic void 2832f7df2e56SmrgSyncInitIdleTime(void) 2833f7df2e56Smrg{ 2834f7df2e56Smrg init_system_idle_counter("IDLETIME", XIAllDevices); 2835f7df2e56Smrg} 2836f7df2e56Smrg 2837f7df2e56SmrgSyncCounter* 2838f7df2e56SmrgSyncInitDeviceIdleTime(DeviceIntPtr dev) 2839f7df2e56Smrg{ 2840f7df2e56Smrg char timer_name[64]; 2841f7df2e56Smrg sprintf(timer_name, "DEVICEIDLETIME %d", dev->id); 2842f7df2e56Smrg 2843f7df2e56Smrg return init_system_idle_counter(timer_name, dev->id); 2844f7df2e56Smrg} 2845f7df2e56Smrg 2846f7df2e56Smrgvoid SyncRemoveDeviceIdleTime(SyncCounter *counter) 2847f7df2e56Smrg{ 2848f7df2e56Smrg /* FreeAllResources() frees all system counters before the devices are 2849f7df2e56Smrg shut down, check if there are any left before freeing the device's 2850f7df2e56Smrg counter */ 2851f7df2e56Smrg if (counter && !xorg_list_is_empty(&SysCounterList)) 2852f7df2e56Smrg xorg_list_del(&counter->pSysCounterInfo->entry); 285305b261ecSmrg} 2854