1/* 2 3Copyright 1991, 1993, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27Copyright 1991, 1993 by Digital Equipment Corporation, Maynard, Massachusetts, 28and Olivetti Research Limited, Cambridge, England. 29 30 All Rights Reserved 31 32Permission to use, copy, modify, and distribute this software and its 33documentation for any purpose and without fee is hereby granted, 34provided that the above copyright notice appear in all copies and that 35both that copyright notice and this permission notice appear in 36supporting documentation, and that the names of Digital or Olivetti 37not be used in advertising or publicity pertaining to distribution of the 38software without specific, written prior permission. Digital and Olivetti 39make no representations about the suitability of this software 40for any purpose. It is provided "as is" without express or implied warranty. 41 42DIGITAL AND OLIVETTI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 43SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 44FITNESS, IN NO EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR 45CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 46USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 47OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 48PERFORMANCE OF THIS SOFTWARE. 49 50*/ 51 52#ifdef HAVE_DIX_CONFIG_H 53#include <dix-config.h> 54#endif 55 56#include <string.h> 57 58#include <X11/X.h> 59#include <X11/Xproto.h> 60#include <X11/Xmd.h> 61#include "scrnintstr.h" 62#include "os.h" 63#include "extnsionst.h" 64#include "dixstruct.h" 65#include "pixmapstr.h" 66#include "resource.h" 67#include "opaque.h" 68#include <X11/extensions/syncproto.h> 69#include "syncsrv.h" 70#include "syncsdk.h" 71#include "protocol-versions.h" 72#include "inputstr.h" 73 74#include <stdio.h> 75#if !defined(WIN32) 76#include <sys/time.h> 77#endif 78 79#include "extinit.h" 80 81/* 82 * Local Global Variables 83 */ 84static int SyncEventBase; 85static int SyncErrorBase; 86static RESTYPE RTCounter = 0; 87static RESTYPE RTAwait; 88static RESTYPE RTAlarm; 89static RESTYPE RTAlarmClient; 90static RESTYPE RTFence; 91static struct xorg_list SysCounterList; 92static int SyncNumInvalidCounterWarnings = 0; 93 94#define MAX_INVALID_COUNTER_WARNINGS 5 95 96static const char *WARN_INVALID_COUNTER_COMPARE = 97 "Warning: Non-counter XSync object using Counter-only\n" 98 " comparison. Result will never be true.\n"; 99 100static const char *WARN_INVALID_COUNTER_ALARM = 101 "Warning: Non-counter XSync object used in alarm. This is\n" 102 " the result of a programming error in the X server.\n"; 103 104#define IsSystemCounter(pCounter) \ 105 (pCounter && (pCounter->sync.client == NULL)) 106 107/* these are all the alarm attributes that pertain to the alarm's trigger */ 108#define XSyncCAAllTrigger \ 109 (XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType) 110 111static void SyncComputeBracketValues(SyncCounter *); 112 113static void SyncInitServerTime(void); 114 115static void SyncInitIdleTime(void); 116 117static inline void* 118SysCounterGetPrivate(SyncCounter *counter) 119{ 120 BUG_WARN(!IsSystemCounter(counter)); 121 122 return counter->pSysCounterInfo ? counter->pSysCounterInfo->private : NULL; 123} 124 125static Bool 126SyncCheckWarnIsCounter(const SyncObject * pSync, const char *warning) 127{ 128 if (pSync && (SYNC_COUNTER != pSync->type)) { 129 if (SyncNumInvalidCounterWarnings++ < MAX_INVALID_COUNTER_WARNINGS) { 130 ErrorF("%s", warning); 131 ErrorF(" Counter type: %d\n", pSync->type); 132 } 133 134 return FALSE; 135 } 136 137 return TRUE; 138} 139 140/* Each counter maintains a simple linked list of triggers that are 141 * interested in the counter. The two functions below are used to 142 * delete and add triggers on this list. 143 */ 144void 145SyncDeleteTriggerFromSyncObject(SyncTrigger * pTrigger) 146{ 147 SyncTriggerList *pCur; 148 SyncTriggerList *pPrev; 149 SyncCounter *pCounter; 150 151 /* pSync needs to be stored in pTrigger before calling here. */ 152 153 if (!pTrigger->pSync) 154 return; 155 156 pPrev = NULL; 157 pCur = pTrigger->pSync->pTriglist; 158 159 while (pCur) { 160 if (pCur->pTrigger == pTrigger) { 161 if (pPrev) 162 pPrev->next = pCur->next; 163 else 164 pTrigger->pSync->pTriglist = pCur->next; 165 166 free(pCur); 167 break; 168 } 169 170 pPrev = pCur; 171 pCur = pCur->next; 172 } 173 174 if (SYNC_COUNTER == pTrigger->pSync->type) { 175 pCounter = (SyncCounter *) pTrigger->pSync; 176 177 if (IsSystemCounter(pCounter)) 178 SyncComputeBracketValues(pCounter); 179 } 180 else if (SYNC_FENCE == pTrigger->pSync->type) { 181 SyncFence *pFence = (SyncFence *) pTrigger->pSync; 182 183 pFence->funcs.DeleteTrigger(pTrigger); 184 } 185} 186 187int 188SyncAddTriggerToSyncObject(SyncTrigger * pTrigger) 189{ 190 SyncTriggerList *pCur; 191 SyncCounter *pCounter; 192 193 if (!pTrigger->pSync) 194 return Success; 195 196 /* don't do anything if it's already there */ 197 for (pCur = pTrigger->pSync->pTriglist; pCur; pCur = pCur->next) { 198 if (pCur->pTrigger == pTrigger) 199 return Success; 200 } 201 202 /* Failure is not an option, it's succeed or burst! */ 203 pCur = XNFalloc(sizeof(SyncTriggerList)); 204 205 pCur->pTrigger = pTrigger; 206 pCur->next = pTrigger->pSync->pTriglist; 207 pTrigger->pSync->pTriglist = pCur; 208 209 if (SYNC_COUNTER == pTrigger->pSync->type) { 210 pCounter = (SyncCounter *) pTrigger->pSync; 211 212 if (IsSystemCounter(pCounter)) 213 SyncComputeBracketValues(pCounter); 214 } 215 else if (SYNC_FENCE == pTrigger->pSync->type) { 216 SyncFence *pFence = (SyncFence *) pTrigger->pSync; 217 218 pFence->funcs.AddTrigger(pTrigger); 219 } 220 221 return Success; 222} 223 224/* Below are five possible functions that can be plugged into 225 * pTrigger->CheckTrigger for counter sync objects, corresponding to 226 * the four possible test-types, and the one possible function that 227 * can be plugged into pTrigger->CheckTrigger for fence sync objects. 228 * These functions are called after the sync object's state changes 229 * but are also passed the old state so they can inspect both the old 230 * and new values. (PositiveTransition and NegativeTransition need to 231 * see both pieces of information.) These functions return the truth 232 * value of the trigger. 233 * 234 * All of them include the condition pTrigger->pSync == NULL. 235 * This is because the spec says that a trigger with a sync value 236 * of None is always TRUE. 237 */ 238 239static Bool 240SyncCheckTriggerPositiveComparison(SyncTrigger * pTrigger, int64_t oldval) 241{ 242 SyncCounter *pCounter; 243 244 /* Non-counter sync objects should never get here because they 245 * never trigger this comparison. */ 246 if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE)) 247 return FALSE; 248 249 pCounter = (SyncCounter *) pTrigger->pSync; 250 251 return pCounter == NULL || pCounter->value >= pTrigger->test_value; 252} 253 254static Bool 255SyncCheckTriggerNegativeComparison(SyncTrigger * pTrigger, int64_t oldval) 256{ 257 SyncCounter *pCounter; 258 259 /* Non-counter sync objects should never get here because they 260 * never trigger this comparison. */ 261 if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE)) 262 return FALSE; 263 264 pCounter = (SyncCounter *) pTrigger->pSync; 265 266 return pCounter == NULL || pCounter->value <= pTrigger->test_value; 267} 268 269static Bool 270SyncCheckTriggerPositiveTransition(SyncTrigger * pTrigger, int64_t oldval) 271{ 272 SyncCounter *pCounter; 273 274 /* Non-counter sync objects should never get here because they 275 * never trigger this comparison. */ 276 if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE)) 277 return FALSE; 278 279 pCounter = (SyncCounter *) pTrigger->pSync; 280 281 return (pCounter == NULL || 282 (oldval < pTrigger->test_value && 283 pCounter->value >= pTrigger->test_value)); 284} 285 286static Bool 287SyncCheckTriggerNegativeTransition(SyncTrigger * pTrigger, int64_t oldval) 288{ 289 SyncCounter *pCounter; 290 291 /* Non-counter sync objects should never get here because they 292 * never trigger this comparison. */ 293 if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE)) 294 return FALSE; 295 296 pCounter = (SyncCounter *) pTrigger->pSync; 297 298 return (pCounter == NULL || 299 (oldval > pTrigger->test_value && 300 pCounter->value <= pTrigger->test_value)); 301} 302 303static Bool 304SyncCheckTriggerFence(SyncTrigger * pTrigger, int64_t unused) 305{ 306 SyncFence *pFence = (SyncFence *) pTrigger->pSync; 307 308 (void) unused; 309 310 return (pFence == NULL || pFence->funcs.CheckTriggered(pFence)); 311} 312 313static int 314SyncInitTrigger(ClientPtr client, SyncTrigger * pTrigger, XID syncObject, 315 RESTYPE resType, Mask changes) 316{ 317 SyncObject *pSync = pTrigger->pSync; 318 SyncCounter *pCounter = NULL; 319 int rc; 320 Bool newSyncObject = FALSE; 321 322 if (changes & XSyncCACounter) { 323 if (syncObject == None) 324 pSync = NULL; 325 else if (Success != (rc = dixLookupResourceByType((void **) &pSync, 326 syncObject, resType, 327 client, 328 DixReadAccess))) { 329 client->errorValue = syncObject; 330 return rc; 331 } 332 } 333 334 /* if system counter, ask it what the current value is */ 335 336 if (pSync && SYNC_COUNTER == pSync->type) { 337 pCounter = (SyncCounter *) pSync; 338 339 if (IsSystemCounter(pCounter)) { 340 (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter, 341 &pCounter->value); 342 } 343 } 344 345 if (changes & XSyncCAValueType) { 346 if (pTrigger->value_type != XSyncRelative && 347 pTrigger->value_type != XSyncAbsolute) { 348 client->errorValue = pTrigger->value_type; 349 return BadValue; 350 } 351 } 352 353 if (changes & (XSyncCAValueType | XSyncCAValue)) { 354 if (pTrigger->value_type == XSyncAbsolute) 355 pTrigger->test_value = pTrigger->wait_value; 356 else { /* relative */ 357 Bool overflow; 358 359 if (pCounter == NULL) 360 return BadMatch; 361 362 overflow = checked_int64_add(&pTrigger->test_value, 363 pCounter->value, pTrigger->wait_value); 364 if (overflow) { 365 client->errorValue = pTrigger->wait_value >> 32; 366 return BadValue; 367 } 368 } 369 } 370 371 if (changes & XSyncCATestType) { 372 373 if (pSync && SYNC_FENCE == pSync->type) { 374 pTrigger->CheckTrigger = SyncCheckTriggerFence; 375 } 376 else { 377 /* select appropriate CheckTrigger function */ 378 379 switch (pTrigger->test_type) { 380 case XSyncPositiveTransition: 381 pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition; 382 break; 383 case XSyncNegativeTransition: 384 pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition; 385 break; 386 case XSyncPositiveComparison: 387 pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison; 388 break; 389 case XSyncNegativeComparison: 390 pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison; 391 break; 392 default: 393 client->errorValue = pTrigger->test_type; 394 return BadValue; 395 } 396 } 397 } 398 399 if (changes & XSyncCACounter) { 400 if (pSync != pTrigger->pSync) { /* new counter for trigger */ 401 SyncDeleteTriggerFromSyncObject(pTrigger); 402 pTrigger->pSync = pSync; 403 newSyncObject = TRUE; 404 } 405 } 406 407 /* we wait until we're sure there are no errors before registering 408 * a new counter on a trigger 409 */ 410 if (newSyncObject) { 411 SyncAddTriggerToSyncObject(pTrigger); 412 } 413 else if (pCounter && IsSystemCounter(pCounter)) { 414 SyncComputeBracketValues(pCounter); 415 } 416 417 return Success; 418} 419 420/* AlarmNotify events happen in response to actions taken on an Alarm or 421 * the counter used by the alarm. AlarmNotify may be sent to multiple 422 * clients. The alarm maintains a list of clients interested in events. 423 */ 424static void 425SyncSendAlarmNotifyEvents(SyncAlarm * pAlarm) 426{ 427 SyncAlarmClientList *pcl; 428 xSyncAlarmNotifyEvent ane; 429 SyncTrigger *pTrigger = &pAlarm->trigger; 430 SyncCounter *pCounter; 431 432 if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM)) 433 return; 434 435 pCounter = (SyncCounter *) pTrigger->pSync; 436 437 UpdateCurrentTime(); 438 439 ane = (xSyncAlarmNotifyEvent) { 440 .type = SyncEventBase + XSyncAlarmNotify, 441 .kind = XSyncAlarmNotify, 442 .alarm = pAlarm->alarm_id, 443 .alarm_value_hi = pTrigger->test_value >> 32, 444 .alarm_value_lo = pTrigger->test_value, 445 .time = currentTime.milliseconds, 446 .state = pAlarm->state 447 }; 448 449 if (pTrigger->pSync && SYNC_COUNTER == pTrigger->pSync->type) { 450 ane.counter_value_hi = pCounter->value >> 32; 451 ane.counter_value_lo = pCounter->value; 452 } 453 else { 454 /* XXX what else can we do if there's no counter? */ 455 ane.counter_value_hi = ane.counter_value_lo = 0; 456 } 457 458 /* send to owner */ 459 if (pAlarm->events) 460 WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane); 461 462 /* send to other interested clients */ 463 for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next) 464 WriteEventsToClient(pcl->client, 1, (xEvent *) &ane); 465} 466 467/* CounterNotify events only occur in response to an Await. The events 468 * go only to the Awaiting client. 469 */ 470static void 471SyncSendCounterNotifyEvents(ClientPtr client, SyncAwait ** ppAwait, 472 int num_events) 473{ 474 xSyncCounterNotifyEvent *pEvents, *pev; 475 int i; 476 477 if (client->clientGone) 478 return; 479 pev = pEvents = calloc(num_events, sizeof(xSyncCounterNotifyEvent)); 480 if (!pEvents) 481 return; 482 UpdateCurrentTime(); 483 for (i = 0; i < num_events; i++, ppAwait++, pev++) { 484 SyncTrigger *pTrigger = &(*ppAwait)->trigger; 485 486 pev->type = SyncEventBase + XSyncCounterNotify; 487 pev->kind = XSyncCounterNotify; 488 pev->counter = pTrigger->pSync->id; 489 pev->wait_value_lo = pTrigger->test_value; 490 pev->wait_value_hi = pTrigger->test_value >> 32; 491 if (SYNC_COUNTER == pTrigger->pSync->type) { 492 SyncCounter *pCounter = (SyncCounter *) pTrigger->pSync; 493 494 pev->counter_value_lo = pCounter->value; 495 pev->counter_value_hi = pCounter->value >> 32; 496 } 497 else { 498 pev->counter_value_lo = 0; 499 pev->counter_value_hi = 0; 500 } 501 502 pev->time = currentTime.milliseconds; 503 pev->count = num_events - i - 1; /* events remaining */ 504 pev->destroyed = pTrigger->pSync->beingDestroyed; 505 } 506 /* swapping will be taken care of by this */ 507 WriteEventsToClient(client, num_events, (xEvent *) pEvents); 508 free(pEvents); 509} 510 511/* This function is called when an alarm's counter is destroyed. 512 * It is plugged into pTrigger->CounterDestroyed (for alarm triggers). 513 */ 514static void 515SyncAlarmCounterDestroyed(SyncTrigger * pTrigger) 516{ 517 SyncAlarm *pAlarm = (SyncAlarm *) pTrigger; 518 519 pAlarm->state = XSyncAlarmInactive; 520 SyncSendAlarmNotifyEvents(pAlarm); 521 pTrigger->pSync = NULL; 522} 523 524/* This function is called when an alarm "goes off." 525 * It is plugged into pTrigger->TriggerFired (for alarm triggers). 526 */ 527static void 528SyncAlarmTriggerFired(SyncTrigger * pTrigger) 529{ 530 SyncAlarm *pAlarm = (SyncAlarm *) pTrigger; 531 SyncCounter *pCounter; 532 int64_t new_test_value; 533 534 if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM)) 535 return; 536 537 pCounter = (SyncCounter *) pTrigger->pSync; 538 539 /* no need to check alarm unless it's active */ 540 if (pAlarm->state != XSyncAlarmActive) 541 return; 542 543 /* " if the counter value is None, or if the delta is 0 and 544 * the test-type is PositiveComparison or NegativeComparison, 545 * no change is made to value (test-value) and the alarm 546 * state is changed to Inactive before the event is generated." 547 */ 548 if (pCounter == NULL || (pAlarm->delta == 0 549 && (pAlarm->trigger.test_type == 550 XSyncPositiveComparison || 551 pAlarm->trigger.test_type == 552 XSyncNegativeComparison))) 553 pAlarm->state = XSyncAlarmInactive; 554 555 new_test_value = pAlarm->trigger.test_value; 556 557 if (pAlarm->state == XSyncAlarmActive) { 558 Bool overflow; 559 int64_t oldvalue; 560 SyncTrigger *paTrigger = &pAlarm->trigger; 561 SyncCounter *paCounter; 562 563 if (!SyncCheckWarnIsCounter(paTrigger->pSync, 564 WARN_INVALID_COUNTER_ALARM)) 565 return; 566 567 paCounter = (SyncCounter *) pTrigger->pSync; 568 569 /* "The alarm is updated by repeatedly adding delta to the 570 * value of the trigger and re-initializing it until it 571 * becomes FALSE." 572 */ 573 oldvalue = paTrigger->test_value; 574 575 /* XXX really should do something smarter here */ 576 577 do { 578 overflow = checked_int64_add(&paTrigger->test_value, 579 paTrigger->test_value, pAlarm->delta); 580 } while (!overflow && 581 (*paTrigger->CheckTrigger) (paTrigger, paCounter->value)); 582 583 new_test_value = paTrigger->test_value; 584 paTrigger->test_value = oldvalue; 585 586 /* "If this update would cause value to fall outside the range 587 * for an INT64...no change is made to value (test-value) and 588 * the alarm state is changed to Inactive before the event is 589 * generated." 590 */ 591 if (overflow) { 592 new_test_value = oldvalue; 593 pAlarm->state = XSyncAlarmInactive; 594 } 595 } 596 /* The AlarmNotify event has to have the "new state of the alarm" 597 * which we can't be sure of until this point. However, it has 598 * to have the "old" trigger test value. That's the reason for 599 * all the newvalue/oldvalue shuffling above. After we send the 600 * events, give the trigger its new test value. 601 */ 602 SyncSendAlarmNotifyEvents(pAlarm); 603 pTrigger->test_value = new_test_value; 604} 605 606/* This function is called when an Await unblocks, either as a result 607 * of the trigger firing OR the counter being destroyed. 608 * It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed 609 * (for Await triggers). 610 */ 611static void 612SyncAwaitTriggerFired(SyncTrigger * pTrigger) 613{ 614 SyncAwait *pAwait = (SyncAwait *) pTrigger; 615 int numwaits; 616 SyncAwaitUnion *pAwaitUnion; 617 SyncAwait **ppAwait; 618 int num_events = 0; 619 620 pAwaitUnion = (SyncAwaitUnion *) pAwait->pHeader; 621 numwaits = pAwaitUnion->header.num_waitconditions; 622 ppAwait = xallocarray(numwaits, sizeof(SyncAwait *)); 623 if (!ppAwait) 624 goto bail; 625 626 pAwait = &(pAwaitUnion + 1)->await; 627 628 /* "When a client is unblocked, all the CounterNotify events for 629 * the Await request are generated contiguously. If count is 0 630 * there are no more events to follow for this request. If 631 * count is n, there are at least n more events to follow." 632 * 633 * Thus, it is best to find all the counters for which events 634 * need to be sent first, so that an accurate count field can 635 * be stored in the events. 636 */ 637 for (; numwaits; numwaits--, pAwait++) { 638 int64_t diff; 639 Bool overflow, diffgreater, diffequal; 640 641 /* "A CounterNotify event with the destroyed flag set to TRUE is 642 * always generated if the counter for one of the triggers is 643 * destroyed." 644 */ 645 if (pAwait->trigger.pSync->beingDestroyed) { 646 ppAwait[num_events++] = pAwait; 647 continue; 648 } 649 650 if (SYNC_COUNTER == pAwait->trigger.pSync->type) { 651 SyncCounter *pCounter = (SyncCounter *) pAwait->trigger.pSync; 652 653 /* "The difference between the counter and the test value is 654 * calculated by subtracting the test value from the value of 655 * the counter." 656 */ 657 overflow = checked_int64_subtract(&diff, pCounter->value, 658 pAwait->trigger.test_value); 659 660 /* "If the difference lies outside the range for an INT64, an 661 * event is not generated." 662 */ 663 if (overflow) 664 continue; 665 diffgreater = diff > pAwait->event_threshold; 666 diffequal = diff == pAwait->event_threshold; 667 668 /* "If the test-type is PositiveTransition or 669 * PositiveComparison, a CounterNotify event is generated if 670 * the difference is at least event-threshold. If the test-type 671 * is NegativeTransition or NegativeComparison, a CounterNotify 672 * event is generated if the difference is at most 673 * event-threshold." 674 */ 675 676 if (((pAwait->trigger.test_type == XSyncPositiveComparison || 677 pAwait->trigger.test_type == XSyncPositiveTransition) 678 && (diffgreater || diffequal)) 679 || 680 ((pAwait->trigger.test_type == XSyncNegativeComparison || 681 pAwait->trigger.test_type == XSyncNegativeTransition) 682 && (!diffgreater) /* less or equal */ 683 ) 684 ) { 685 ppAwait[num_events++] = pAwait; 686 } 687 } 688 } 689 if (num_events) 690 SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait, 691 num_events); 692 free(ppAwait); 693 694 bail: 695 /* unblock the client */ 696 AttendClient(pAwaitUnion->header.client); 697 /* delete the await */ 698 FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 699} 700 701static int64_t 702SyncUpdateCounter(SyncCounter *pCounter, int64_t newval) 703{ 704 int64_t oldval = pCounter->value; 705 pCounter->value = newval; 706 return oldval; 707} 708 709/* This function should always be used to change a counter's value so that 710 * any triggers depending on the counter will be checked. 711 */ 712void 713SyncChangeCounter(SyncCounter * pCounter, int64_t newval) 714{ 715 SyncTriggerList *ptl, *pnext; 716 int64_t oldval; 717 718 oldval = SyncUpdateCounter(pCounter, newval); 719 720 /* run through triggers to see if any become true */ 721 for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) { 722 pnext = ptl->next; 723 if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, oldval)) 724 (*ptl->pTrigger->TriggerFired) (ptl->pTrigger); 725 } 726 727 if (IsSystemCounter(pCounter)) { 728 SyncComputeBracketValues(pCounter); 729 } 730} 731 732/* loosely based on dix/events.c/EventSelectForWindow */ 733static Bool 734SyncEventSelectForAlarm(SyncAlarm * pAlarm, ClientPtr client, Bool wantevents) 735{ 736 SyncAlarmClientList *pClients; 737 738 if (client == pAlarm->client) { /* alarm owner */ 739 pAlarm->events = wantevents; 740 return Success; 741 } 742 743 /* see if the client is already on the list (has events selected) */ 744 745 for (pClients = pAlarm->pEventClients; pClients; pClients = pClients->next) { 746 if (pClients->client == client) { 747 /* client's presence on the list indicates desire for 748 * events. If the client doesn't want events, remove it 749 * from the list. If the client does want events, do 750 * nothing, since it's already got them. 751 */ 752 if (!wantevents) { 753 FreeResource(pClients->delete_id, RT_NONE); 754 } 755 return Success; 756 } 757 } 758 759 /* if we get here, this client does not currently have 760 * events selected on the alarm 761 */ 762 763 if (!wantevents) 764 /* client doesn't want events, and we just discovered that it 765 * doesn't have them, so there's nothing to do. 766 */ 767 return Success; 768 769 /* add new client to pAlarm->pEventClients */ 770 771 pClients = malloc(sizeof(SyncAlarmClientList)); 772 if (!pClients) 773 return BadAlloc; 774 775 /* register it as a resource so it will be cleaned up 776 * if the client dies 777 */ 778 779 pClients->delete_id = FakeClientID(client->index); 780 781 /* link it into list after we know all the allocations succeed */ 782 pClients->next = pAlarm->pEventClients; 783 pAlarm->pEventClients = pClients; 784 pClients->client = client; 785 786 if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm)) 787 return BadAlloc; 788 789 return Success; 790} 791 792/* 793 * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm 794 */ 795static int 796SyncChangeAlarmAttributes(ClientPtr client, SyncAlarm * pAlarm, Mask mask, 797 CARD32 *values) 798{ 799 int status; 800 XSyncCounter counter; 801 Mask origmask = mask; 802 SyncTrigger trigger; 803 Bool select_events_changed = FALSE; 804 Bool select_events_value = FALSE; 805 int64_t delta; 806 807 trigger = pAlarm->trigger; 808 delta = pAlarm->delta; 809 counter = trigger.pSync ? trigger.pSync->id : None; 810 811 while (mask) { 812 int index2 = lowbit(mask); 813 814 mask &= ~index2; 815 switch (index2) { 816 case XSyncCACounter: 817 mask &= ~XSyncCACounter; 818 /* sanity check in SyncInitTrigger */ 819 counter = *values++; 820 break; 821 822 case XSyncCAValueType: 823 mask &= ~XSyncCAValueType; 824 /* sanity check in SyncInitTrigger */ 825 trigger.value_type = *values++; 826 break; 827 828 case XSyncCAValue: 829 mask &= ~XSyncCAValue; 830 trigger.wait_value = ((int64_t)values[0] << 32) | values[1]; 831 values += 2; 832 break; 833 834 case XSyncCATestType: 835 mask &= ~XSyncCATestType; 836 /* sanity check in SyncInitTrigger */ 837 trigger.test_type = *values++; 838 break; 839 840 case XSyncCADelta: 841 mask &= ~XSyncCADelta; 842 delta = ((int64_t)values[0] << 32) | values[1]; 843 values += 2; 844 break; 845 846 case XSyncCAEvents: 847 mask &= ~XSyncCAEvents; 848 if ((*values != xTrue) && (*values != xFalse)) { 849 client->errorValue = *values; 850 return BadValue; 851 } 852 select_events_value = (Bool) (*values++); 853 select_events_changed = TRUE; 854 break; 855 856 default: 857 client->errorValue = mask; 858 return BadValue; 859 } 860 } 861 862 if (select_events_changed) { 863 status = SyncEventSelectForAlarm(pAlarm, client, select_events_value); 864 if (status != Success) 865 return status; 866 } 867 868 /* "If the test-type is PositiveComparison or PositiveTransition 869 * and delta is less than zero, or if the test-type is 870 * NegativeComparison or NegativeTransition and delta is 871 * greater than zero, a Match error is generated." 872 */ 873 if (origmask & (XSyncCADelta | XSyncCATestType)) { 874 if ((((trigger.test_type == XSyncPositiveComparison) || 875 (trigger.test_type == XSyncPositiveTransition)) 876 && delta < 0) 877 || 878 (((trigger.test_type == XSyncNegativeComparison) || 879 (trigger.test_type == XSyncNegativeTransition)) 880 && delta > 0) 881 ) { 882 return BadMatch; 883 } 884 } 885 886 /* postpone this until now, when we're sure nothing else can go wrong */ 887 pAlarm->delta = delta; 888 pAlarm->trigger = trigger; 889 if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter, 890 origmask & XSyncCAAllTrigger)) != Success) 891 return status; 892 893 /* XXX spec does not really say to do this - needs clarification */ 894 pAlarm->state = XSyncAlarmActive; 895 return Success; 896} 897 898SyncObject * 899SyncCreate(ClientPtr client, XID id, unsigned char type) 900{ 901 SyncObject *pSync; 902 RESTYPE resType; 903 904 switch (type) { 905 case SYNC_COUNTER: 906 pSync = malloc(sizeof(SyncCounter)); 907 resType = RTCounter; 908 break; 909 case SYNC_FENCE: 910 pSync = (SyncObject *) dixAllocateObjectWithPrivates(SyncFence, 911 PRIVATE_SYNC_FENCE); 912 resType = RTFence; 913 break; 914 default: 915 return NULL; 916 } 917 918 if (!pSync) 919 return NULL; 920 921 pSync->initialized = FALSE; 922 923 if (!AddResource(id, resType, (void *) pSync)) 924 return NULL; 925 926 pSync->client = client; 927 pSync->id = id; 928 pSync->pTriglist = NULL; 929 pSync->beingDestroyed = FALSE; 930 pSync->type = type; 931 932 return pSync; 933} 934 935int 936SyncCreateFenceFromFD(ClientPtr client, DrawablePtr pDraw, XID id, int fd, BOOL initially_triggered) 937{ 938#ifdef HAVE_XSHMFENCE 939 SyncFence *pFence; 940 int status; 941 942 pFence = (SyncFence *) SyncCreate(client, id, SYNC_FENCE); 943 if (!pFence) 944 return BadAlloc; 945 946 status = miSyncInitFenceFromFD(pDraw, pFence, fd, initially_triggered); 947 if (status != Success) { 948 FreeResource(pFence->sync.id, RT_NONE); 949 return status; 950 } 951 952 return Success; 953#else 954 return BadImplementation; 955#endif 956} 957 958int 959SyncFDFromFence(ClientPtr client, DrawablePtr pDraw, SyncFence *pFence) 960{ 961#ifdef HAVE_XSHMFENCE 962 return miSyncFDFromFence(pDraw, pFence); 963#else 964 return BadImplementation; 965#endif 966} 967 968static SyncCounter * 969SyncCreateCounter(ClientPtr client, XSyncCounter id, int64_t initialvalue) 970{ 971 SyncCounter *pCounter; 972 973 if (!(pCounter = (SyncCounter *) SyncCreate(client, id, SYNC_COUNTER))) 974 return NULL; 975 976 pCounter->value = initialvalue; 977 pCounter->pSysCounterInfo = NULL; 978 979 pCounter->sync.initialized = TRUE; 980 981 return pCounter; 982} 983 984static int FreeCounter(void *, XID); 985 986/* 987 * ***** System Counter utilities 988 */ 989 990SyncCounter* 991SyncCreateSystemCounter(const char *name, 992 int64_t initial, 993 int64_t resolution, 994 SyncCounterType counterType, 995 SyncSystemCounterQueryValue QueryValue, 996 SyncSystemCounterBracketValues BracketValues 997 ) 998{ 999 SyncCounter *pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial); 1000 1001 if (pCounter) { 1002 SysCounterInfo *psci; 1003 1004 psci = malloc(sizeof(SysCounterInfo)); 1005 if (!psci) { 1006 FreeResource(pCounter->sync.id, RT_NONE); 1007 return pCounter; 1008 } 1009 pCounter->pSysCounterInfo = psci; 1010 psci->pCounter = pCounter; 1011 psci->name = strdup(name); 1012 psci->resolution = resolution; 1013 psci->counterType = counterType; 1014 psci->QueryValue = QueryValue; 1015 psci->BracketValues = BracketValues; 1016 psci->private = NULL; 1017 psci->bracket_greater = LLONG_MAX; 1018 psci->bracket_less = LLONG_MIN; 1019 xorg_list_add(&psci->entry, &SysCounterList); 1020 } 1021 return pCounter; 1022} 1023 1024void 1025SyncDestroySystemCounter(void *pSysCounter) 1026{ 1027 SyncCounter *pCounter = (SyncCounter *) pSysCounter; 1028 1029 FreeResource(pCounter->sync.id, RT_NONE); 1030} 1031 1032static void 1033SyncComputeBracketValues(SyncCounter * pCounter) 1034{ 1035 SyncTriggerList *pCur; 1036 SyncTrigger *pTrigger; 1037 SysCounterInfo *psci; 1038 int64_t *pnewgtval = NULL; 1039 int64_t *pnewltval = NULL; 1040 SyncCounterType ct; 1041 1042 if (!pCounter) 1043 return; 1044 1045 psci = pCounter->pSysCounterInfo; 1046 ct = pCounter->pSysCounterInfo->counterType; 1047 if (ct == XSyncCounterNeverChanges) 1048 return; 1049 1050 psci->bracket_greater = LLONG_MAX; 1051 psci->bracket_less = LLONG_MIN; 1052 1053 for (pCur = pCounter->sync.pTriglist; pCur; pCur = pCur->next) { 1054 pTrigger = pCur->pTrigger; 1055 1056 if (pTrigger->test_type == XSyncPositiveComparison && 1057 ct != XSyncCounterNeverIncreases) { 1058 if (pCounter->value < pTrigger->test_value && 1059 pTrigger->test_value < psci->bracket_greater) { 1060 psci->bracket_greater = pTrigger->test_value; 1061 pnewgtval = &psci->bracket_greater; 1062 } 1063 else if (pCounter->value > pTrigger->test_value && 1064 pTrigger->test_value > psci->bracket_less) { 1065 psci->bracket_less = pTrigger->test_value; 1066 pnewltval = &psci->bracket_less; 1067 } 1068 } 1069 else if (pTrigger->test_type == XSyncNegativeComparison && 1070 ct != XSyncCounterNeverDecreases) { 1071 if (pCounter->value > pTrigger->test_value && 1072 pTrigger->test_value > psci->bracket_less) { 1073 psci->bracket_less = pTrigger->test_value; 1074 pnewltval = &psci->bracket_less; 1075 } 1076 else if (pCounter->value < pTrigger->test_value && 1077 pTrigger->test_value < psci->bracket_greater) { 1078 psci->bracket_greater = pTrigger->test_value; 1079 pnewgtval = &psci->bracket_greater; 1080 } 1081 } 1082 else if (pTrigger->test_type == XSyncNegativeTransition && 1083 ct != XSyncCounterNeverIncreases) { 1084 if (pCounter->value >= pTrigger->test_value && 1085 pTrigger->test_value > psci->bracket_less) { 1086 /* 1087 * If the value is exactly equal to our threshold, we want one 1088 * more event in the negative direction to ensure we pick up 1089 * when the value is less than this threshold. 1090 */ 1091 psci->bracket_less = pTrigger->test_value; 1092 pnewltval = &psci->bracket_less; 1093 } 1094 else if (pCounter->value < pTrigger->test_value && 1095 pTrigger->test_value < psci->bracket_greater) { 1096 psci->bracket_greater = pTrigger->test_value; 1097 pnewgtval = &psci->bracket_greater; 1098 } 1099 } 1100 else if (pTrigger->test_type == XSyncPositiveTransition && 1101 ct != XSyncCounterNeverDecreases) { 1102 if (pCounter->value <= pTrigger->test_value && 1103 pTrigger->test_value < psci->bracket_greater) { 1104 /* 1105 * If the value is exactly equal to our threshold, we 1106 * want one more event in the positive direction to 1107 * ensure we pick up when the value *exceeds* this 1108 * threshold. 1109 */ 1110 psci->bracket_greater = pTrigger->test_value; 1111 pnewgtval = &psci->bracket_greater; 1112 } 1113 else if (pCounter->value > pTrigger->test_value && 1114 pTrigger->test_value > psci->bracket_less) { 1115 psci->bracket_less = pTrigger->test_value; 1116 pnewltval = &psci->bracket_less; 1117 } 1118 } 1119 } /* end for each trigger */ 1120 1121 (*psci->BracketValues) ((void *) pCounter, pnewltval, pnewgtval); 1122 1123} 1124 1125/* 1126 * ***** Resource delete functions 1127 */ 1128 1129/* ARGSUSED */ 1130static int 1131FreeAlarm(void *addr, XID id) 1132{ 1133 SyncAlarm *pAlarm = (SyncAlarm *) addr; 1134 1135 pAlarm->state = XSyncAlarmDestroyed; 1136 1137 SyncSendAlarmNotifyEvents(pAlarm); 1138 1139 /* delete event selections */ 1140 1141 while (pAlarm->pEventClients) 1142 FreeResource(pAlarm->pEventClients->delete_id, RT_NONE); 1143 1144 SyncDeleteTriggerFromSyncObject(&pAlarm->trigger); 1145 1146 free(pAlarm); 1147 return Success; 1148} 1149 1150/* 1151 * ** Cleanup after the destruction of a Counter 1152 */ 1153/* ARGSUSED */ 1154static int 1155FreeCounter(void *env, XID id) 1156{ 1157 SyncCounter *pCounter = (SyncCounter *) env; 1158 1159 pCounter->sync.beingDestroyed = TRUE; 1160 1161 if (pCounter->sync.initialized) { 1162 SyncTriggerList *ptl, *pnext; 1163 1164 /* tell all the counter's triggers that counter has been destroyed */ 1165 for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) { 1166 (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger); 1167 pnext = ptl->next; 1168 free(ptl); /* destroy the trigger list as we go */ 1169 } 1170 if (IsSystemCounter(pCounter)) { 1171 xorg_list_del(&pCounter->pSysCounterInfo->entry); 1172 free(pCounter->pSysCounterInfo->name); 1173 free(pCounter->pSysCounterInfo->private); 1174 free(pCounter->pSysCounterInfo); 1175 } 1176 } 1177 1178 free(pCounter); 1179 return Success; 1180} 1181 1182/* 1183 * ** Cleanup after Await 1184 */ 1185/* ARGSUSED */ 1186static int 1187FreeAwait(void *addr, XID id) 1188{ 1189 SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr; 1190 SyncAwait *pAwait; 1191 int numwaits; 1192 1193 pAwait = &(pAwaitUnion + 1)->await; /* first await on list */ 1194 1195 /* remove triggers from counters */ 1196 1197 for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits; 1198 numwaits--, pAwait++) { 1199 /* If the counter is being destroyed, FreeCounter will delete 1200 * the trigger list itself, so don't do it here. 1201 */ 1202 SyncObject *pSync = pAwait->trigger.pSync; 1203 1204 if (pSync && !pSync->beingDestroyed) 1205 SyncDeleteTriggerFromSyncObject(&pAwait->trigger); 1206 } 1207 free(pAwaitUnion); 1208 return Success; 1209} 1210 1211/* loosely based on dix/events.c/OtherClientGone */ 1212static int 1213FreeAlarmClient(void *value, XID id) 1214{ 1215 SyncAlarm *pAlarm = (SyncAlarm *) value; 1216 SyncAlarmClientList *pCur, *pPrev; 1217 1218 for (pPrev = NULL, pCur = pAlarm->pEventClients; 1219 pCur; pPrev = pCur, pCur = pCur->next) { 1220 if (pCur->delete_id == id) { 1221 if (pPrev) 1222 pPrev->next = pCur->next; 1223 else 1224 pAlarm->pEventClients = pCur->next; 1225 free(pCur); 1226 return Success; 1227 } 1228 } 1229 FatalError("alarm client not on event list"); 1230 /*NOTREACHED*/} 1231 1232/* 1233 * ***** Proc functions 1234 */ 1235 1236/* 1237 * ** Initialize the extension 1238 */ 1239static int 1240ProcSyncInitialize(ClientPtr client) 1241{ 1242 xSyncInitializeReply rep = { 1243 .type = X_Reply, 1244 .sequenceNumber = client->sequence, 1245 .length = 0, 1246 .majorVersion = SERVER_SYNC_MAJOR_VERSION, 1247 .minorVersion = SERVER_SYNC_MINOR_VERSION, 1248 }; 1249 1250 REQUEST_SIZE_MATCH(xSyncInitializeReq); 1251 1252 if (client->swapped) { 1253 swaps(&rep.sequenceNumber); 1254 } 1255 WriteToClient(client, sizeof(rep), &rep); 1256 return Success; 1257} 1258 1259/* 1260 * ** Get list of system counters available through the extension 1261 */ 1262static int 1263ProcSyncListSystemCounters(ClientPtr client) 1264{ 1265 xSyncListSystemCountersReply rep = { 1266 .type = X_Reply, 1267 .sequenceNumber = client->sequence, 1268 .nCounters = 0, 1269 }; 1270 SysCounterInfo *psci; 1271 int len = 0; 1272 xSyncSystemCounter *list = NULL, *walklist = NULL; 1273 1274 REQUEST_SIZE_MATCH(xSyncListSystemCountersReq); 1275 1276 xorg_list_for_each_entry(psci, &SysCounterList, entry) { 1277 /* pad to 4 byte boundary */ 1278 len += pad_to_int32(sz_xSyncSystemCounter + strlen(psci->name)); 1279 ++rep.nCounters; 1280 } 1281 1282 if (len) { 1283 walklist = list = malloc(len); 1284 if (!list) 1285 return BadAlloc; 1286 } 1287 1288 rep.length = bytes_to_int32(len); 1289 1290 if (client->swapped) { 1291 swaps(&rep.sequenceNumber); 1292 swapl(&rep.length); 1293 swapl(&rep.nCounters); 1294 } 1295 1296 xorg_list_for_each_entry(psci, &SysCounterList, entry) { 1297 int namelen; 1298 char *pname_in_reply; 1299 1300 walklist->counter = psci->pCounter->sync.id; 1301 walklist->resolution_hi = psci->resolution >> 32; 1302 walklist->resolution_lo = psci->resolution; 1303 namelen = strlen(psci->name); 1304 walklist->name_length = namelen; 1305 1306 if (client->swapped) { 1307 swapl(&walklist->counter); 1308 swapl(&walklist->resolution_hi); 1309 swapl(&walklist->resolution_lo); 1310 swaps(&walklist->name_length); 1311 } 1312 1313 pname_in_reply = ((char *) walklist) + sz_xSyncSystemCounter; 1314 strncpy(pname_in_reply, psci->name, namelen); 1315 walklist = (xSyncSystemCounter *) (((char *) walklist) + 1316 pad_to_int32(sz_xSyncSystemCounter + 1317 namelen)); 1318 } 1319 1320 WriteToClient(client, sizeof(rep), &rep); 1321 if (len) { 1322 WriteToClient(client, len, list); 1323 free(list); 1324 } 1325 1326 return Success; 1327} 1328 1329/* 1330 * ** Set client Priority 1331 */ 1332static int 1333ProcSyncSetPriority(ClientPtr client) 1334{ 1335 REQUEST(xSyncSetPriorityReq); 1336 ClientPtr priorityclient; 1337 int rc; 1338 1339 REQUEST_SIZE_MATCH(xSyncSetPriorityReq); 1340 1341 if (stuff->id == None) 1342 priorityclient = client; 1343 else { 1344 rc = dixLookupClient(&priorityclient, stuff->id, client, 1345 DixSetAttrAccess); 1346 if (rc != Success) 1347 return rc; 1348 } 1349 1350 if (priorityclient->priority != stuff->priority) { 1351 priorityclient->priority = stuff->priority; 1352 1353 /* The following will force the server back into WaitForSomething 1354 * so that the change in this client's priority is immediately 1355 * reflected. 1356 */ 1357 isItTimeToYield = TRUE; 1358 dispatchException |= DE_PRIORITYCHANGE; 1359 } 1360 return Success; 1361} 1362 1363/* 1364 * ** Get client Priority 1365 */ 1366static int 1367ProcSyncGetPriority(ClientPtr client) 1368{ 1369 REQUEST(xSyncGetPriorityReq); 1370 xSyncGetPriorityReply rep; 1371 ClientPtr priorityclient; 1372 int rc; 1373 1374 REQUEST_SIZE_MATCH(xSyncGetPriorityReq); 1375 1376 if (stuff->id == None) 1377 priorityclient = client; 1378 else { 1379 rc = dixLookupClient(&priorityclient, stuff->id, client, 1380 DixGetAttrAccess); 1381 if (rc != Success) 1382 return rc; 1383 } 1384 1385 rep = (xSyncGetPriorityReply) { 1386 .type = X_Reply, 1387 .sequenceNumber = client->sequence, 1388 .length = 0, 1389 .priority = priorityclient->priority 1390 }; 1391 1392 if (client->swapped) { 1393 swaps(&rep.sequenceNumber); 1394 swapl(&rep.priority); 1395 } 1396 1397 WriteToClient(client, sizeof(xSyncGetPriorityReply), &rep); 1398 1399 return Success; 1400} 1401 1402/* 1403 * ** Create a new counter 1404 */ 1405static int 1406ProcSyncCreateCounter(ClientPtr client) 1407{ 1408 REQUEST(xSyncCreateCounterReq); 1409 int64_t initial; 1410 1411 REQUEST_SIZE_MATCH(xSyncCreateCounterReq); 1412 1413 LEGAL_NEW_RESOURCE(stuff->cid, client); 1414 1415 initial = ((int64_t)stuff->initial_value_hi << 32) | stuff->initial_value_lo; 1416 1417 if (!SyncCreateCounter(client, stuff->cid, initial)) 1418 return BadAlloc; 1419 1420 return Success; 1421} 1422 1423/* 1424 * ** Set Counter value 1425 */ 1426static int 1427ProcSyncSetCounter(ClientPtr client) 1428{ 1429 REQUEST(xSyncSetCounterReq); 1430 SyncCounter *pCounter; 1431 int64_t newvalue; 1432 int rc; 1433 1434 REQUEST_SIZE_MATCH(xSyncSetCounterReq); 1435 1436 rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter, 1437 client, DixWriteAccess); 1438 if (rc != Success) 1439 return rc; 1440 1441 if (IsSystemCounter(pCounter)) { 1442 client->errorValue = stuff->cid; 1443 return BadAccess; 1444 } 1445 1446 newvalue = ((int64_t)stuff->value_hi << 32) | stuff->value_lo; 1447 SyncChangeCounter(pCounter, newvalue); 1448 return Success; 1449} 1450 1451/* 1452 * ** Change Counter value 1453 */ 1454static int 1455ProcSyncChangeCounter(ClientPtr client) 1456{ 1457 REQUEST(xSyncChangeCounterReq); 1458 SyncCounter *pCounter; 1459 int64_t newvalue; 1460 Bool overflow; 1461 int rc; 1462 1463 REQUEST_SIZE_MATCH(xSyncChangeCounterReq); 1464 1465 rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter, 1466 client, DixWriteAccess); 1467 if (rc != Success) 1468 return rc; 1469 1470 if (IsSystemCounter(pCounter)) { 1471 client->errorValue = stuff->cid; 1472 return BadAccess; 1473 } 1474 1475 newvalue = (int64_t)stuff->value_hi << 32 | stuff->value_lo; 1476 overflow = checked_int64_add(&newvalue, newvalue, pCounter->value); 1477 if (overflow) { 1478 /* XXX 64 bit value can't fit in 32 bits; do the best we can */ 1479 client->errorValue = stuff->value_hi; 1480 return BadValue; 1481 } 1482 SyncChangeCounter(pCounter, newvalue); 1483 return Success; 1484} 1485 1486/* 1487 * ** Destroy a counter 1488 */ 1489static int 1490ProcSyncDestroyCounter(ClientPtr client) 1491{ 1492 REQUEST(xSyncDestroyCounterReq); 1493 SyncCounter *pCounter; 1494 int rc; 1495 1496 REQUEST_SIZE_MATCH(xSyncDestroyCounterReq); 1497 1498 rc = dixLookupResourceByType((void **) &pCounter, stuff->counter, 1499 RTCounter, client, DixDestroyAccess); 1500 if (rc != Success) 1501 return rc; 1502 1503 if (IsSystemCounter(pCounter)) { 1504 client->errorValue = stuff->counter; 1505 return BadAccess; 1506 } 1507 FreeResource(pCounter->sync.id, RT_NONE); 1508 return Success; 1509} 1510 1511static SyncAwaitUnion * 1512SyncAwaitPrologue(ClientPtr client, int items) 1513{ 1514 SyncAwaitUnion *pAwaitUnion; 1515 1516 /* all the memory for the entire await list is allocated 1517 * here in one chunk 1518 */ 1519 pAwaitUnion = xallocarray(items + 1, sizeof(SyncAwaitUnion)); 1520 if (!pAwaitUnion) 1521 return NULL; 1522 1523 /* first item is the header, remainder are real wait conditions */ 1524 1525 pAwaitUnion->header.delete_id = FakeClientID(client->index); 1526 pAwaitUnion->header.client = client; 1527 pAwaitUnion->header.num_waitconditions = 0; 1528 1529 if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion)) 1530 return NULL; 1531 1532 return pAwaitUnion; 1533} 1534 1535static void 1536SyncAwaitEpilogue(ClientPtr client, int items, SyncAwaitUnion * pAwaitUnion) 1537{ 1538 SyncAwait *pAwait; 1539 int i; 1540 1541 IgnoreClient(client); 1542 1543 /* see if any of the triggers are already true */ 1544 1545 pAwait = &(pAwaitUnion + 1)->await; /* skip over header */ 1546 for (i = 0; i < items; i++, pAwait++) { 1547 int64_t value; 1548 1549 /* don't have to worry about NULL counters because the request 1550 * errors before we get here out if they occur 1551 */ 1552 switch (pAwait->trigger.pSync->type) { 1553 case SYNC_COUNTER: 1554 value = ((SyncCounter *) pAwait->trigger.pSync)->value; 1555 break; 1556 default: 1557 value = 0; 1558 } 1559 1560 if ((*pAwait->trigger.CheckTrigger) (&pAwait->trigger, value)) { 1561 (*pAwait->trigger.TriggerFired) (&pAwait->trigger); 1562 break; /* once is enough */ 1563 } 1564 } 1565} 1566 1567/* 1568 * ** Await 1569 */ 1570static int 1571ProcSyncAwait(ClientPtr client) 1572{ 1573 REQUEST(xSyncAwaitReq); 1574 int len, items; 1575 int i; 1576 xSyncWaitCondition *pProtocolWaitConds; 1577 SyncAwaitUnion *pAwaitUnion; 1578 SyncAwait *pAwait; 1579 int status; 1580 1581 REQUEST_AT_LEAST_SIZE(xSyncAwaitReq); 1582 1583 len = client->req_len << 2; 1584 len -= sz_xSyncAwaitReq; 1585 items = len / sz_xSyncWaitCondition; 1586 1587 if (items * sz_xSyncWaitCondition != len) { 1588 return BadLength; 1589 } 1590 if (items == 0) { 1591 client->errorValue = items; /* XXX protocol change */ 1592 return BadValue; 1593 } 1594 1595 if (!(pAwaitUnion = SyncAwaitPrologue(client, items))) 1596 return BadAlloc; 1597 1598 /* don't need to do any more memory allocation for this request! */ 1599 1600 pProtocolWaitConds = (xSyncWaitCondition *) &stuff[1]; 1601 1602 pAwait = &(pAwaitUnion + 1)->await; /* skip over header */ 1603 for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++) { 1604 if (pProtocolWaitConds->counter == None) { /* XXX protocol change */ 1605 /* this should take care of removing any triggers created by 1606 * this request that have already been registered on sync objects 1607 */ 1608 FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 1609 client->errorValue = pProtocolWaitConds->counter; 1610 return SyncErrorBase + XSyncBadCounter; 1611 } 1612 1613 /* sanity checks are in SyncInitTrigger */ 1614 pAwait->trigger.pSync = NULL; 1615 pAwait->trigger.value_type = pProtocolWaitConds->value_type; 1616 pAwait->trigger.wait_value = 1617 ((int64_t)pProtocolWaitConds->wait_value_hi << 32) | 1618 pProtocolWaitConds->wait_value_lo; 1619 pAwait->trigger.test_type = pProtocolWaitConds->test_type; 1620 1621 status = SyncInitTrigger(client, &pAwait->trigger, 1622 pProtocolWaitConds->counter, RTCounter, 1623 XSyncCAAllTrigger); 1624 if (status != Success) { 1625 /* this should take care of removing any triggers created by 1626 * this request that have already been registered on sync objects 1627 */ 1628 FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 1629 return status; 1630 } 1631 /* this is not a mistake -- same function works for both cases */ 1632 pAwait->trigger.TriggerFired = SyncAwaitTriggerFired; 1633 pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired; 1634 pAwait->event_threshold = 1635 ((int64_t) pProtocolWaitConds->event_threshold_hi << 32) | 1636 pProtocolWaitConds->event_threshold_lo; 1637 1638 pAwait->pHeader = &pAwaitUnion->header; 1639 pAwaitUnion->header.num_waitconditions++; 1640 } 1641 1642 SyncAwaitEpilogue(client, items, pAwaitUnion); 1643 1644 return Success; 1645} 1646 1647/* 1648 * ** Query a counter 1649 */ 1650static int 1651ProcSyncQueryCounter(ClientPtr client) 1652{ 1653 REQUEST(xSyncQueryCounterReq); 1654 xSyncQueryCounterReply rep; 1655 SyncCounter *pCounter; 1656 int rc; 1657 1658 REQUEST_SIZE_MATCH(xSyncQueryCounterReq); 1659 1660 rc = dixLookupResourceByType((void **) &pCounter, stuff->counter, 1661 RTCounter, client, DixReadAccess); 1662 if (rc != Success) 1663 return rc; 1664 1665 /* if system counter, ask it what the current value is */ 1666 if (IsSystemCounter(pCounter)) { 1667 (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter, 1668 &pCounter->value); 1669 } 1670 1671 rep = (xSyncQueryCounterReply) { 1672 .type = X_Reply, 1673 .sequenceNumber = client->sequence, 1674 .length = 0, 1675 .value_hi = pCounter->value >> 32, 1676 .value_lo = pCounter->value 1677 }; 1678 1679 if (client->swapped) { 1680 swaps(&rep.sequenceNumber); 1681 swapl(&rep.length); 1682 swapl(&rep.value_hi); 1683 swapl(&rep.value_lo); 1684 } 1685 WriteToClient(client, sizeof(xSyncQueryCounterReply), &rep); 1686 return Success; 1687} 1688 1689/* 1690 * ** Create Alarm 1691 */ 1692static int 1693ProcSyncCreateAlarm(ClientPtr client) 1694{ 1695 REQUEST(xSyncCreateAlarmReq); 1696 SyncAlarm *pAlarm; 1697 int status; 1698 unsigned long len, vmask; 1699 SyncTrigger *pTrigger; 1700 1701 REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq); 1702 1703 LEGAL_NEW_RESOURCE(stuff->id, client); 1704 1705 vmask = stuff->valueMask; 1706 len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq)); 1707 /* the "extra" call to Ones accounts for the presence of 64 bit values */ 1708 if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta)))) 1709 return BadLength; 1710 1711 if (!(pAlarm = malloc(sizeof(SyncAlarm)))) { 1712 return BadAlloc; 1713 } 1714 1715 /* set up defaults */ 1716 1717 pTrigger = &pAlarm->trigger; 1718 pTrigger->pSync = NULL; 1719 pTrigger->value_type = XSyncAbsolute; 1720 pTrigger->wait_value = 0; 1721 pTrigger->test_type = XSyncPositiveComparison; 1722 pTrigger->TriggerFired = SyncAlarmTriggerFired; 1723 pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed; 1724 status = SyncInitTrigger(client, pTrigger, None, RTCounter, 1725 XSyncCAAllTrigger); 1726 if (status != Success) { 1727 free(pAlarm); 1728 return status; 1729 } 1730 1731 pAlarm->client = client; 1732 pAlarm->alarm_id = stuff->id; 1733 pAlarm->delta = 1; 1734 pAlarm->events = TRUE; 1735 pAlarm->state = XSyncAlarmInactive; 1736 pAlarm->pEventClients = NULL; 1737 status = SyncChangeAlarmAttributes(client, pAlarm, vmask, 1738 (CARD32 *) &stuff[1]); 1739 if (status != Success) { 1740 free(pAlarm); 1741 return status; 1742 } 1743 1744 if (!AddResource(stuff->id, RTAlarm, pAlarm)) 1745 return BadAlloc; 1746 1747 /* see if alarm already triggered. NULL counter will not trigger 1748 * in CreateAlarm and sets alarm state to Inactive. 1749 */ 1750 1751 if (!pTrigger->pSync) { 1752 pAlarm->state = XSyncAlarmInactive; /* XXX protocol change */ 1753 } 1754 else { 1755 SyncCounter *pCounter; 1756 1757 if (!SyncCheckWarnIsCounter(pTrigger->pSync, 1758 WARN_INVALID_COUNTER_ALARM)) { 1759 FreeResource(stuff->id, RT_NONE); 1760 return BadAlloc; 1761 } 1762 1763 pCounter = (SyncCounter *) pTrigger->pSync; 1764 1765 if ((*pTrigger->CheckTrigger) (pTrigger, pCounter->value)) 1766 (*pTrigger->TriggerFired) (pTrigger); 1767 } 1768 1769 return Success; 1770} 1771 1772/* 1773 * ** Change Alarm 1774 */ 1775static int 1776ProcSyncChangeAlarm(ClientPtr client) 1777{ 1778 REQUEST(xSyncChangeAlarmReq); 1779 SyncAlarm *pAlarm; 1780 SyncCounter *pCounter = NULL; 1781 long vmask; 1782 int len, status; 1783 1784 REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq); 1785 1786 status = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm, 1787 client, DixWriteAccess); 1788 if (status != Success) 1789 return status; 1790 1791 vmask = stuff->valueMask; 1792 len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq)); 1793 /* the "extra" call to Ones accounts for the presence of 64 bit values */ 1794 if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta)))) 1795 return BadLength; 1796 1797 if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask, 1798 (CARD32 *) &stuff[1])) != Success) 1799 return status; 1800 1801 if (SyncCheckWarnIsCounter(pAlarm->trigger.pSync, 1802 WARN_INVALID_COUNTER_ALARM)) 1803 pCounter = (SyncCounter *) pAlarm->trigger.pSync; 1804 1805 /* see if alarm already triggered. NULL counter WILL trigger 1806 * in ChangeAlarm. 1807 */ 1808 1809 if (!pCounter || 1810 (*pAlarm->trigger.CheckTrigger) (&pAlarm->trigger, pCounter->value)) { 1811 (*pAlarm->trigger.TriggerFired) (&pAlarm->trigger); 1812 } 1813 return Success; 1814} 1815 1816static int 1817ProcSyncQueryAlarm(ClientPtr client) 1818{ 1819 REQUEST(xSyncQueryAlarmReq); 1820 SyncAlarm *pAlarm; 1821 xSyncQueryAlarmReply rep; 1822 SyncTrigger *pTrigger; 1823 int rc; 1824 1825 REQUEST_SIZE_MATCH(xSyncQueryAlarmReq); 1826 1827 rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm, 1828 client, DixReadAccess); 1829 if (rc != Success) 1830 return rc; 1831 1832 pTrigger = &pAlarm->trigger; 1833 rep = (xSyncQueryAlarmReply) { 1834 .type = X_Reply, 1835 .sequenceNumber = client->sequence, 1836 .length = 1837 bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply)), 1838 .counter = (pTrigger->pSync) ? pTrigger->pSync->id : None, 1839 1840#if 0 /* XXX unclear what to do, depends on whether relative value-types 1841 * are "consumed" immediately and are considered absolute from then 1842 * on. 1843 */ 1844 .value_type = pTrigger->value_type, 1845 .wait_value_hi = pTrigger->wait_value >> 32, 1846 .wait_value_lo = pTrigger->wait_value, 1847#else 1848 .value_type = XSyncAbsolute, 1849 .wait_value_hi = pTrigger->test_value >> 32, 1850 .wait_value_lo = pTrigger->test_value, 1851#endif 1852 1853 .test_type = pTrigger->test_type, 1854 .delta_hi = pAlarm->delta >> 32, 1855 .delta_lo = pAlarm->delta, 1856 .events = pAlarm->events, 1857 .state = pAlarm->state 1858 }; 1859 1860 if (client->swapped) { 1861 swaps(&rep.sequenceNumber); 1862 swapl(&rep.length); 1863 swapl(&rep.counter); 1864 swapl(&rep.wait_value_hi); 1865 swapl(&rep.wait_value_lo); 1866 swapl(&rep.test_type); 1867 swapl(&rep.delta_hi); 1868 swapl(&rep.delta_lo); 1869 } 1870 1871 WriteToClient(client, sizeof(xSyncQueryAlarmReply), &rep); 1872 return Success; 1873} 1874 1875static int 1876ProcSyncDestroyAlarm(ClientPtr client) 1877{ 1878 SyncAlarm *pAlarm; 1879 int rc; 1880 1881 REQUEST(xSyncDestroyAlarmReq); 1882 1883 REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq); 1884 1885 rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm, 1886 client, DixDestroyAccess); 1887 if (rc != Success) 1888 return rc; 1889 1890 FreeResource(stuff->alarm, RT_NONE); 1891 return Success; 1892} 1893 1894static int 1895ProcSyncCreateFence(ClientPtr client) 1896{ 1897 REQUEST(xSyncCreateFenceReq); 1898 DrawablePtr pDraw; 1899 SyncFence *pFence; 1900 int rc; 1901 1902 REQUEST_SIZE_MATCH(xSyncCreateFenceReq); 1903 1904 rc = dixLookupDrawable(&pDraw, stuff->d, client, M_ANY, DixGetAttrAccess); 1905 if (rc != Success) 1906 return rc; 1907 1908 LEGAL_NEW_RESOURCE(stuff->fid, client); 1909 1910 if (!(pFence = (SyncFence *) SyncCreate(client, stuff->fid, SYNC_FENCE))) 1911 return BadAlloc; 1912 1913 miSyncInitFence(pDraw->pScreen, pFence, stuff->initially_triggered); 1914 1915 return Success; 1916} 1917 1918static int 1919FreeFence(void *obj, XID id) 1920{ 1921 SyncFence *pFence = (SyncFence *) obj; 1922 1923 miSyncDestroyFence(pFence); 1924 1925 return Success; 1926} 1927 1928int 1929SyncVerifyFence(SyncFence ** ppSyncFence, XID fid, ClientPtr client, Mask mode) 1930{ 1931 int rc = dixLookupResourceByType((void **) ppSyncFence, fid, RTFence, 1932 client, mode); 1933 1934 if (rc != Success) 1935 client->errorValue = fid; 1936 1937 return rc; 1938} 1939 1940static int 1941ProcSyncTriggerFence(ClientPtr client) 1942{ 1943 REQUEST(xSyncTriggerFenceReq); 1944 SyncFence *pFence; 1945 int rc; 1946 1947 REQUEST_SIZE_MATCH(xSyncTriggerFenceReq); 1948 1949 rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence, 1950 client, DixWriteAccess); 1951 if (rc != Success) 1952 return rc; 1953 1954 miSyncTriggerFence(pFence); 1955 1956 return Success; 1957} 1958 1959static int 1960ProcSyncResetFence(ClientPtr client) 1961{ 1962 REQUEST(xSyncResetFenceReq); 1963 SyncFence *pFence; 1964 int rc; 1965 1966 REQUEST_SIZE_MATCH(xSyncResetFenceReq); 1967 1968 rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence, 1969 client, DixWriteAccess); 1970 if (rc != Success) 1971 return rc; 1972 1973 if (pFence->funcs.CheckTriggered(pFence) != TRUE) 1974 return BadMatch; 1975 1976 pFence->funcs.Reset(pFence); 1977 1978 return Success; 1979} 1980 1981static int 1982ProcSyncDestroyFence(ClientPtr client) 1983{ 1984 REQUEST(xSyncDestroyFenceReq); 1985 SyncFence *pFence; 1986 int rc; 1987 1988 REQUEST_SIZE_MATCH(xSyncDestroyFenceReq); 1989 1990 rc = dixLookupResourceByType((void **) &pFence, stuff->fid, RTFence, 1991 client, DixDestroyAccess); 1992 if (rc != Success) 1993 return rc; 1994 1995 FreeResource(stuff->fid, RT_NONE); 1996 return Success; 1997} 1998 1999static int 2000ProcSyncQueryFence(ClientPtr client) 2001{ 2002 REQUEST(xSyncQueryFenceReq); 2003 xSyncQueryFenceReply rep; 2004 SyncFence *pFence; 2005 int rc; 2006 2007 REQUEST_SIZE_MATCH(xSyncQueryFenceReq); 2008 2009 rc = dixLookupResourceByType((void **) &pFence, stuff->fid, 2010 RTFence, client, DixReadAccess); 2011 if (rc != Success) 2012 return rc; 2013 2014 rep = (xSyncQueryFenceReply) { 2015 .type = X_Reply, 2016 .sequenceNumber = client->sequence, 2017 .length = 0, 2018 2019 .triggered = pFence->funcs.CheckTriggered(pFence) 2020 }; 2021 2022 if (client->swapped) { 2023 swaps(&rep.sequenceNumber); 2024 swapl(&rep.length); 2025 } 2026 2027 WriteToClient(client, sizeof(xSyncQueryFenceReply), &rep); 2028 return Success; 2029} 2030 2031static int 2032ProcSyncAwaitFence(ClientPtr client) 2033{ 2034 REQUEST(xSyncAwaitFenceReq); 2035 SyncAwaitUnion *pAwaitUnion; 2036 SyncAwait *pAwait; 2037 2038 /* Use CARD32 rather than XSyncFence because XIDs are hard-coded to 2039 * CARD32 in protocol definitions */ 2040 CARD32 *pProtocolFences; 2041 int status; 2042 int len; 2043 int items; 2044 int i; 2045 2046 REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq); 2047 2048 len = client->req_len << 2; 2049 len -= sz_xSyncAwaitFenceReq; 2050 items = len / sizeof(CARD32); 2051 2052 if (items * sizeof(CARD32) != len) { 2053 return BadLength; 2054 } 2055 if (items == 0) { 2056 client->errorValue = items; 2057 return BadValue; 2058 } 2059 2060 if (!(pAwaitUnion = SyncAwaitPrologue(client, items))) 2061 return BadAlloc; 2062 2063 /* don't need to do any more memory allocation for this request! */ 2064 2065 pProtocolFences = (CARD32 *) &stuff[1]; 2066 2067 pAwait = &(pAwaitUnion + 1)->await; /* skip over header */ 2068 for (i = 0; i < items; i++, pProtocolFences++, pAwait++) { 2069 if (*pProtocolFences == None) { 2070 /* this should take care of removing any triggers created by 2071 * this request that have already been registered on sync objects 2072 */ 2073 FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 2074 client->errorValue = *pProtocolFences; 2075 return SyncErrorBase + XSyncBadFence; 2076 } 2077 2078 pAwait->trigger.pSync = NULL; 2079 /* Provide acceptable values for these unused fields to 2080 * satisfy SyncInitTrigger's validation logic 2081 */ 2082 pAwait->trigger.value_type = XSyncAbsolute; 2083 pAwait->trigger.wait_value = 0; 2084 pAwait->trigger.test_type = 0; 2085 2086 status = SyncInitTrigger(client, &pAwait->trigger, 2087 *pProtocolFences, RTFence, XSyncCAAllTrigger); 2088 if (status != Success) { 2089 /* this should take care of removing any triggers created by 2090 * this request that have already been registered on sync objects 2091 */ 2092 FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 2093 return status; 2094 } 2095 /* this is not a mistake -- same function works for both cases */ 2096 pAwait->trigger.TriggerFired = SyncAwaitTriggerFired; 2097 pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired; 2098 /* event_threshold is unused for fence syncs */ 2099 pAwait->event_threshold = 0; 2100 pAwait->pHeader = &pAwaitUnion->header; 2101 pAwaitUnion->header.num_waitconditions++; 2102 } 2103 2104 SyncAwaitEpilogue(client, items, pAwaitUnion); 2105 2106 return Success; 2107} 2108 2109/* 2110 * ** Given an extension request, call the appropriate request procedure 2111 */ 2112static int 2113ProcSyncDispatch(ClientPtr client) 2114{ 2115 REQUEST(xReq); 2116 2117 switch (stuff->data) { 2118 case X_SyncInitialize: 2119 return ProcSyncInitialize(client); 2120 case X_SyncListSystemCounters: 2121 return ProcSyncListSystemCounters(client); 2122 case X_SyncCreateCounter: 2123 return ProcSyncCreateCounter(client); 2124 case X_SyncSetCounter: 2125 return ProcSyncSetCounter(client); 2126 case X_SyncChangeCounter: 2127 return ProcSyncChangeCounter(client); 2128 case X_SyncQueryCounter: 2129 return ProcSyncQueryCounter(client); 2130 case X_SyncDestroyCounter: 2131 return ProcSyncDestroyCounter(client); 2132 case X_SyncAwait: 2133 return ProcSyncAwait(client); 2134 case X_SyncCreateAlarm: 2135 return ProcSyncCreateAlarm(client); 2136 case X_SyncChangeAlarm: 2137 return ProcSyncChangeAlarm(client); 2138 case X_SyncQueryAlarm: 2139 return ProcSyncQueryAlarm(client); 2140 case X_SyncDestroyAlarm: 2141 return ProcSyncDestroyAlarm(client); 2142 case X_SyncSetPriority: 2143 return ProcSyncSetPriority(client); 2144 case X_SyncGetPriority: 2145 return ProcSyncGetPriority(client); 2146 case X_SyncCreateFence: 2147 return ProcSyncCreateFence(client); 2148 case X_SyncTriggerFence: 2149 return ProcSyncTriggerFence(client); 2150 case X_SyncResetFence: 2151 return ProcSyncResetFence(client); 2152 case X_SyncDestroyFence: 2153 return ProcSyncDestroyFence(client); 2154 case X_SyncQueryFence: 2155 return ProcSyncQueryFence(client); 2156 case X_SyncAwaitFence: 2157 return ProcSyncAwaitFence(client); 2158 default: 2159 return BadRequest; 2160 } 2161} 2162 2163/* 2164 * Boring Swapping stuff ... 2165 */ 2166 2167static int _X_COLD 2168SProcSyncInitialize(ClientPtr client) 2169{ 2170 REQUEST(xSyncInitializeReq); 2171 swaps(&stuff->length); 2172 REQUEST_SIZE_MATCH(xSyncInitializeReq); 2173 2174 return ProcSyncInitialize(client); 2175} 2176 2177static int _X_COLD 2178SProcSyncListSystemCounters(ClientPtr client) 2179{ 2180 REQUEST(xSyncListSystemCountersReq); 2181 swaps(&stuff->length); 2182 REQUEST_SIZE_MATCH(xSyncListSystemCountersReq); 2183 2184 return ProcSyncListSystemCounters(client); 2185} 2186 2187static int _X_COLD 2188SProcSyncCreateCounter(ClientPtr client) 2189{ 2190 REQUEST(xSyncCreateCounterReq); 2191 swaps(&stuff->length); 2192 REQUEST_SIZE_MATCH(xSyncCreateCounterReq); 2193 swapl(&stuff->cid); 2194 swapl(&stuff->initial_value_lo); 2195 swapl(&stuff->initial_value_hi); 2196 2197 return ProcSyncCreateCounter(client); 2198} 2199 2200static int _X_COLD 2201SProcSyncSetCounter(ClientPtr client) 2202{ 2203 REQUEST(xSyncSetCounterReq); 2204 swaps(&stuff->length); 2205 REQUEST_SIZE_MATCH(xSyncSetCounterReq); 2206 swapl(&stuff->cid); 2207 swapl(&stuff->value_lo); 2208 swapl(&stuff->value_hi); 2209 2210 return ProcSyncSetCounter(client); 2211} 2212 2213static int _X_COLD 2214SProcSyncChangeCounter(ClientPtr client) 2215{ 2216 REQUEST(xSyncChangeCounterReq); 2217 swaps(&stuff->length); 2218 REQUEST_SIZE_MATCH(xSyncChangeCounterReq); 2219 swapl(&stuff->cid); 2220 swapl(&stuff->value_lo); 2221 swapl(&stuff->value_hi); 2222 2223 return ProcSyncChangeCounter(client); 2224} 2225 2226static int _X_COLD 2227SProcSyncQueryCounter(ClientPtr client) 2228{ 2229 REQUEST(xSyncQueryCounterReq); 2230 swaps(&stuff->length); 2231 REQUEST_SIZE_MATCH(xSyncQueryCounterReq); 2232 swapl(&stuff->counter); 2233 2234 return ProcSyncQueryCounter(client); 2235} 2236 2237static int _X_COLD 2238SProcSyncDestroyCounter(ClientPtr client) 2239{ 2240 REQUEST(xSyncDestroyCounterReq); 2241 swaps(&stuff->length); 2242 REQUEST_SIZE_MATCH(xSyncDestroyCounterReq); 2243 swapl(&stuff->counter); 2244 2245 return ProcSyncDestroyCounter(client); 2246} 2247 2248static int _X_COLD 2249SProcSyncAwait(ClientPtr client) 2250{ 2251 REQUEST(xSyncAwaitReq); 2252 swaps(&stuff->length); 2253 REQUEST_AT_LEAST_SIZE(xSyncAwaitReq); 2254 SwapRestL(stuff); 2255 2256 return ProcSyncAwait(client); 2257} 2258 2259static int _X_COLD 2260SProcSyncCreateAlarm(ClientPtr client) 2261{ 2262 REQUEST(xSyncCreateAlarmReq); 2263 swaps(&stuff->length); 2264 REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq); 2265 swapl(&stuff->id); 2266 swapl(&stuff->valueMask); 2267 SwapRestL(stuff); 2268 2269 return ProcSyncCreateAlarm(client); 2270} 2271 2272static int _X_COLD 2273SProcSyncChangeAlarm(ClientPtr client) 2274{ 2275 REQUEST(xSyncChangeAlarmReq); 2276 swaps(&stuff->length); 2277 REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq); 2278 swapl(&stuff->alarm); 2279 swapl(&stuff->valueMask); 2280 SwapRestL(stuff); 2281 return ProcSyncChangeAlarm(client); 2282} 2283 2284static int _X_COLD 2285SProcSyncQueryAlarm(ClientPtr client) 2286{ 2287 REQUEST(xSyncQueryAlarmReq); 2288 swaps(&stuff->length); 2289 REQUEST_SIZE_MATCH(xSyncQueryAlarmReq); 2290 swapl(&stuff->alarm); 2291 2292 return ProcSyncQueryAlarm(client); 2293} 2294 2295static int _X_COLD 2296SProcSyncDestroyAlarm(ClientPtr client) 2297{ 2298 REQUEST(xSyncDestroyAlarmReq); 2299 swaps(&stuff->length); 2300 REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq); 2301 swapl(&stuff->alarm); 2302 2303 return ProcSyncDestroyAlarm(client); 2304} 2305 2306static int _X_COLD 2307SProcSyncSetPriority(ClientPtr client) 2308{ 2309 REQUEST(xSyncSetPriorityReq); 2310 swaps(&stuff->length); 2311 REQUEST_SIZE_MATCH(xSyncSetPriorityReq); 2312 swapl(&stuff->id); 2313 swapl(&stuff->priority); 2314 2315 return ProcSyncSetPriority(client); 2316} 2317 2318static int _X_COLD 2319SProcSyncGetPriority(ClientPtr client) 2320{ 2321 REQUEST(xSyncGetPriorityReq); 2322 swaps(&stuff->length); 2323 REQUEST_SIZE_MATCH(xSyncGetPriorityReq); 2324 swapl(&stuff->id); 2325 2326 return ProcSyncGetPriority(client); 2327} 2328 2329static int _X_COLD 2330SProcSyncCreateFence(ClientPtr client) 2331{ 2332 REQUEST(xSyncCreateFenceReq); 2333 swaps(&stuff->length); 2334 REQUEST_SIZE_MATCH(xSyncCreateFenceReq); 2335 swapl(&stuff->d); 2336 swapl(&stuff->fid); 2337 2338 return ProcSyncCreateFence(client); 2339} 2340 2341static int _X_COLD 2342SProcSyncTriggerFence(ClientPtr client) 2343{ 2344 REQUEST(xSyncTriggerFenceReq); 2345 swaps(&stuff->length); 2346 REQUEST_SIZE_MATCH(xSyncTriggerFenceReq); 2347 swapl(&stuff->fid); 2348 2349 return ProcSyncTriggerFence(client); 2350} 2351 2352static int _X_COLD 2353SProcSyncResetFence(ClientPtr client) 2354{ 2355 REQUEST(xSyncResetFenceReq); 2356 swaps(&stuff->length); 2357 REQUEST_SIZE_MATCH(xSyncResetFenceReq); 2358 swapl(&stuff->fid); 2359 2360 return ProcSyncResetFence(client); 2361} 2362 2363static int _X_COLD 2364SProcSyncDestroyFence(ClientPtr client) 2365{ 2366 REQUEST(xSyncDestroyFenceReq); 2367 swaps(&stuff->length); 2368 REQUEST_SIZE_MATCH(xSyncDestroyFenceReq); 2369 swapl(&stuff->fid); 2370 2371 return ProcSyncDestroyFence(client); 2372} 2373 2374static int _X_COLD 2375SProcSyncQueryFence(ClientPtr client) 2376{ 2377 REQUEST(xSyncQueryFenceReq); 2378 swaps(&stuff->length); 2379 REQUEST_SIZE_MATCH(xSyncQueryFenceReq); 2380 swapl(&stuff->fid); 2381 2382 return ProcSyncQueryFence(client); 2383} 2384 2385static int _X_COLD 2386SProcSyncAwaitFence(ClientPtr client) 2387{ 2388 REQUEST(xSyncAwaitFenceReq); 2389 swaps(&stuff->length); 2390 REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq); 2391 SwapRestL(stuff); 2392 2393 return ProcSyncAwaitFence(client); 2394} 2395 2396static int _X_COLD 2397SProcSyncDispatch(ClientPtr client) 2398{ 2399 REQUEST(xReq); 2400 2401 switch (stuff->data) { 2402 case X_SyncInitialize: 2403 return SProcSyncInitialize(client); 2404 case X_SyncListSystemCounters: 2405 return SProcSyncListSystemCounters(client); 2406 case X_SyncCreateCounter: 2407 return SProcSyncCreateCounter(client); 2408 case X_SyncSetCounter: 2409 return SProcSyncSetCounter(client); 2410 case X_SyncChangeCounter: 2411 return SProcSyncChangeCounter(client); 2412 case X_SyncQueryCounter: 2413 return SProcSyncQueryCounter(client); 2414 case X_SyncDestroyCounter: 2415 return SProcSyncDestroyCounter(client); 2416 case X_SyncAwait: 2417 return SProcSyncAwait(client); 2418 case X_SyncCreateAlarm: 2419 return SProcSyncCreateAlarm(client); 2420 case X_SyncChangeAlarm: 2421 return SProcSyncChangeAlarm(client); 2422 case X_SyncQueryAlarm: 2423 return SProcSyncQueryAlarm(client); 2424 case X_SyncDestroyAlarm: 2425 return SProcSyncDestroyAlarm(client); 2426 case X_SyncSetPriority: 2427 return SProcSyncSetPriority(client); 2428 case X_SyncGetPriority: 2429 return SProcSyncGetPriority(client); 2430 case X_SyncCreateFence: 2431 return SProcSyncCreateFence(client); 2432 case X_SyncTriggerFence: 2433 return SProcSyncTriggerFence(client); 2434 case X_SyncResetFence: 2435 return SProcSyncResetFence(client); 2436 case X_SyncDestroyFence: 2437 return SProcSyncDestroyFence(client); 2438 case X_SyncQueryFence: 2439 return SProcSyncQueryFence(client); 2440 case X_SyncAwaitFence: 2441 return SProcSyncAwaitFence(client); 2442 default: 2443 return BadRequest; 2444 } 2445} 2446 2447/* 2448 * Event Swapping 2449 */ 2450 2451static void _X_COLD 2452SCounterNotifyEvent(xSyncCounterNotifyEvent * from, 2453 xSyncCounterNotifyEvent * to) 2454{ 2455 to->type = from->type; 2456 to->kind = from->kind; 2457 cpswaps(from->sequenceNumber, to->sequenceNumber); 2458 cpswapl(from->counter, to->counter); 2459 cpswapl(from->wait_value_lo, to->wait_value_lo); 2460 cpswapl(from->wait_value_hi, to->wait_value_hi); 2461 cpswapl(from->counter_value_lo, to->counter_value_lo); 2462 cpswapl(from->counter_value_hi, to->counter_value_hi); 2463 cpswapl(from->time, to->time); 2464 cpswaps(from->count, to->count); 2465 to->destroyed = from->destroyed; 2466} 2467 2468static void _X_COLD 2469SAlarmNotifyEvent(xSyncAlarmNotifyEvent * from, xSyncAlarmNotifyEvent * to) 2470{ 2471 to->type = from->type; 2472 to->kind = from->kind; 2473 cpswaps(from->sequenceNumber, to->sequenceNumber); 2474 cpswapl(from->alarm, to->alarm); 2475 cpswapl(from->counter_value_lo, to->counter_value_lo); 2476 cpswapl(from->counter_value_hi, to->counter_value_hi); 2477 cpswapl(from->alarm_value_lo, to->alarm_value_lo); 2478 cpswapl(from->alarm_value_hi, to->alarm_value_hi); 2479 cpswapl(from->time, to->time); 2480 to->state = from->state; 2481} 2482 2483/* 2484 * ** Close everything down. ** This is fairly simple for now. 2485 */ 2486/* ARGSUSED */ 2487static void 2488SyncResetProc(ExtensionEntry * extEntry) 2489{ 2490 RTCounter = 0; 2491} 2492 2493/* 2494 * ** Initialise the extension. 2495 */ 2496void 2497SyncExtensionInit(void) 2498{ 2499 ExtensionEntry *extEntry; 2500 int s; 2501 2502 for (s = 0; s < screenInfo.numScreens; s++) 2503 miSyncSetup(screenInfo.screens[s]); 2504 2505 RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter"); 2506 xorg_list_init(&SysCounterList); 2507 RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm"); 2508 RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait"); 2509 RTFence = CreateNewResourceType(FreeFence, "SyncFence"); 2510 if (RTAwait) 2511 RTAwait |= RC_NEVERRETAIN; 2512 RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient"); 2513 if (RTAlarmClient) 2514 RTAlarmClient |= RC_NEVERRETAIN; 2515 2516 if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 || 2517 RTAlarmClient == 0 || 2518 (extEntry = AddExtension(SYNC_NAME, 2519 XSyncNumberEvents, XSyncNumberErrors, 2520 ProcSyncDispatch, SProcSyncDispatch, 2521 SyncResetProc, StandardMinorOpcode)) == NULL) { 2522 ErrorF("Sync Extension %d.%d failed to Initialise\n", 2523 SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION); 2524 return; 2525 } 2526 2527 SyncEventBase = extEntry->eventBase; 2528 SyncErrorBase = extEntry->errorBase; 2529 EventSwapVector[SyncEventBase + XSyncCounterNotify] = 2530 (EventSwapPtr) SCounterNotifyEvent; 2531 EventSwapVector[SyncEventBase + XSyncAlarmNotify] = 2532 (EventSwapPtr) SAlarmNotifyEvent; 2533 2534 SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter); 2535 SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm); 2536 SetResourceTypeErrorValue(RTFence, SyncErrorBase + XSyncBadFence); 2537 2538 /* 2539 * Although SERVERTIME is implemented by the OS layer, we initialise it 2540 * here because doing it in OsInit() is too early. The resource database 2541 * is not initialised when OsInit() is called. This is just about OK 2542 * because there is always a servertime counter. 2543 */ 2544 SyncInitServerTime(); 2545 SyncInitIdleTime(); 2546 2547#ifdef DEBUG 2548 fprintf(stderr, "Sync Extension %d.%d\n", 2549 SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION); 2550#endif 2551} 2552 2553/* 2554 * ***** SERVERTIME implementation - should go in its own file in OS directory? 2555 */ 2556 2557static void *ServertimeCounter; 2558static int64_t Now; 2559static int64_t *pnext_time; 2560 2561static void GetTime(void) 2562{ 2563 unsigned long millis = GetTimeInMillis(); 2564 unsigned long maxis = Now >> 32; 2565 2566 if (millis < (Now & 0xffffffff)) 2567 maxis++; 2568 2569 Now = ((int64_t)maxis << 32) | millis; 2570} 2571 2572/* 2573*** Server Block Handler 2574*** code inspired by multibuffer extension (now deprecated) 2575 */ 2576/*ARGSUSED*/ static void 2577ServertimeBlockHandler(void *env, void *wt) 2578{ 2579 unsigned long timeout; 2580 2581 if (pnext_time) { 2582 GetTime(); 2583 2584 if (Now >= *pnext_time) { 2585 timeout = 0; 2586 } 2587 else { 2588 timeout = *pnext_time - Now; 2589 } 2590 AdjustWaitForDelay(wt, timeout); /* os/utils.c */ 2591 } 2592} 2593 2594/* 2595*** Wakeup Handler 2596 */ 2597/*ARGSUSED*/ static void 2598ServertimeWakeupHandler(void *env, int rc) 2599{ 2600 if (pnext_time) { 2601 GetTime(); 2602 2603 if (Now >= *pnext_time) { 2604 SyncChangeCounter(ServertimeCounter, Now); 2605 } 2606 } 2607} 2608 2609static void 2610ServertimeQueryValue(void *pCounter, int64_t *pValue_return) 2611{ 2612 GetTime(); 2613 *pValue_return = Now; 2614} 2615 2616static void 2617ServertimeBracketValues(void *pCounter, int64_t *pbracket_less, 2618 int64_t *pbracket_greater) 2619{ 2620 if (!pnext_time && pbracket_greater) { 2621 RegisterBlockAndWakeupHandlers(ServertimeBlockHandler, 2622 ServertimeWakeupHandler, NULL); 2623 } 2624 else if (pnext_time && !pbracket_greater) { 2625 RemoveBlockAndWakeupHandlers(ServertimeBlockHandler, 2626 ServertimeWakeupHandler, NULL); 2627 } 2628 pnext_time = pbracket_greater; 2629} 2630 2631static void 2632SyncInitServerTime(void) 2633{ 2634 int64_t resolution = 4; 2635 2636 Now = GetTimeInMillis(); 2637 ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution, 2638 XSyncCounterNeverDecreases, 2639 ServertimeQueryValue, 2640 ServertimeBracketValues); 2641 pnext_time = NULL; 2642} 2643 2644/* 2645 * IDLETIME implementation 2646 */ 2647 2648typedef struct { 2649 int64_t *value_less; 2650 int64_t *value_greater; 2651 int deviceid; 2652} IdleCounterPriv; 2653 2654static void 2655IdleTimeQueryValue(void *pCounter, int64_t *pValue_return) 2656{ 2657 int deviceid; 2658 CARD32 idle; 2659 2660 if (pCounter) { 2661 SyncCounter *counter = pCounter; 2662 IdleCounterPriv *priv = SysCounterGetPrivate(counter); 2663 deviceid = priv->deviceid; 2664 } 2665 else 2666 deviceid = XIAllDevices; 2667 idle = GetTimeInMillis() - LastEventTime(deviceid).milliseconds; 2668 *pValue_return = idle; 2669} 2670 2671static void 2672IdleTimeBlockHandler(void *pCounter, void *wt) 2673{ 2674 SyncCounter *counter = pCounter; 2675 IdleCounterPriv *priv = SysCounterGetPrivate(counter); 2676 int64_t *less = priv->value_less; 2677 int64_t *greater = priv->value_greater; 2678 int64_t idle, old_idle; 2679 SyncTriggerList *list = counter->sync.pTriglist; 2680 SyncTrigger *trig; 2681 2682 if (!less && !greater) 2683 return; 2684 2685 old_idle = counter->value; 2686 IdleTimeQueryValue(counter, &idle); 2687 counter->value = idle; /* push, so CheckTrigger works */ 2688 2689 /** 2690 * There's an indefinite amount of time between ProcessInputEvents() 2691 * where the idle time is reset and the time we actually get here. idle 2692 * may be past the lower bracket if we dawdled with the events, so 2693 * check for whether we did reset and bomb out of select immediately. 2694 */ 2695 if (less && idle > *less && 2696 LastEventTimeWasReset(priv->deviceid)) { 2697 AdjustWaitForDelay(wt, 0); 2698 } else if (less && idle <= *less) { 2699 /* 2700 * We've been idle for less than the threshold value, and someone 2701 * wants to know about that, but now we need to know whether they 2702 * want level or edge trigger. Check the trigger list against the 2703 * current idle time, and if any succeed, bomb out of select() 2704 * immediately so we can reschedule. 2705 */ 2706 2707 for (list = counter->sync.pTriglist; list; list = list->next) { 2708 trig = list->pTrigger; 2709 if (trig->CheckTrigger(trig, old_idle)) { 2710 AdjustWaitForDelay(wt, 0); 2711 break; 2712 } 2713 } 2714 /* 2715 * We've been called exactly on the idle time, but we have a 2716 * NegativeTransition trigger which requires a transition from an 2717 * idle time greater than this. Schedule a wakeup for the next 2718 * millisecond so we won't miss a transition. 2719 */ 2720 if (idle == *less) 2721 AdjustWaitForDelay(wt, 1); 2722 } 2723 else if (greater) { 2724 /* 2725 * There's a threshold in the positive direction. If we've been 2726 * idle less than it, schedule a wakeup for sometime in the future. 2727 * If we've been idle more than it, and someone wants to know about 2728 * that level-triggered, schedule an immediate wakeup. 2729 */ 2730 2731 if (idle < *greater) { 2732 AdjustWaitForDelay(wt, *greater - idle); 2733 } 2734 else { 2735 for (list = counter->sync.pTriglist; list; 2736 list = list->next) { 2737 trig = list->pTrigger; 2738 if (trig->CheckTrigger(trig, old_idle)) { 2739 AdjustWaitForDelay(wt, 0); 2740 break; 2741 } 2742 } 2743 } 2744 } 2745 2746 counter->value = old_idle; /* pop */ 2747} 2748 2749static void 2750IdleTimeCheckBrackets(SyncCounter *counter, int64_t idle, 2751 int64_t *less, int64_t *greater) 2752{ 2753 if ((greater && idle >= *greater) || 2754 (less && idle <= *less)) { 2755 SyncChangeCounter(counter, idle); 2756 } 2757 else 2758 SyncUpdateCounter(counter, idle); 2759} 2760 2761static void 2762IdleTimeWakeupHandler(void *pCounter, int rc) 2763{ 2764 SyncCounter *counter = pCounter; 2765 IdleCounterPriv *priv = SysCounterGetPrivate(counter); 2766 int64_t *less = priv->value_less; 2767 int64_t *greater = priv->value_greater; 2768 int64_t idle; 2769 2770 if (!less && !greater) 2771 return; 2772 2773 IdleTimeQueryValue(pCounter, &idle); 2774 2775 /* 2776 There is no guarantee for the WakeupHandler to be called within a specific 2777 timeframe. Idletime may go to 0, but by the time we get here, it may be 2778 non-zero and alarms for a pos. transition on 0 won't get triggered. 2779 https://bugs.freedesktop.org/show_bug.cgi?id=70476 2780 */ 2781 if (LastEventTimeWasReset(priv->deviceid)) { 2782 LastEventTimeToggleResetFlag(priv->deviceid, FALSE); 2783 if (idle != 0) { 2784 IdleTimeCheckBrackets(counter, 0, less, greater); 2785 less = priv->value_less; 2786 greater = priv->value_greater; 2787 } 2788 } 2789 2790 IdleTimeCheckBrackets(counter, idle, less, greater); 2791} 2792 2793static void 2794IdleTimeBracketValues(void *pCounter, int64_t *pbracket_less, 2795 int64_t *pbracket_greater) 2796{ 2797 SyncCounter *counter = pCounter; 2798 IdleCounterPriv *priv = SysCounterGetPrivate(counter); 2799 int64_t *less = priv->value_less; 2800 int64_t *greater = priv->value_greater; 2801 Bool registered = (less || greater); 2802 2803 if (registered && !pbracket_less && !pbracket_greater) { 2804 RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler, 2805 IdleTimeWakeupHandler, pCounter); 2806 } 2807 else if (!registered && (pbracket_less || pbracket_greater)) { 2808 /* Reset flag must be zero so we don't force a idle timer reset on 2809 the first wakeup */ 2810 LastEventTimeToggleResetAll(FALSE); 2811 RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler, 2812 IdleTimeWakeupHandler, pCounter); 2813 } 2814 2815 priv->value_greater = pbracket_greater; 2816 priv->value_less = pbracket_less; 2817} 2818 2819static SyncCounter* 2820init_system_idle_counter(const char *name, int deviceid) 2821{ 2822 int64_t resolution = 4; 2823 int64_t idle; 2824 SyncCounter *idle_time_counter; 2825 2826 IdleTimeQueryValue(NULL, &idle); 2827 2828 idle_time_counter = SyncCreateSystemCounter(name, idle, resolution, 2829 XSyncCounterUnrestricted, 2830 IdleTimeQueryValue, 2831 IdleTimeBracketValues); 2832 2833 if (idle_time_counter != NULL) { 2834 IdleCounterPriv *priv = malloc(sizeof(IdleCounterPriv)); 2835 2836 priv->value_less = priv->value_greater = NULL; 2837 priv->deviceid = deviceid; 2838 2839 idle_time_counter->pSysCounterInfo->private = priv; 2840 } 2841 2842 return idle_time_counter; 2843} 2844 2845static void 2846SyncInitIdleTime(void) 2847{ 2848 init_system_idle_counter("IDLETIME", XIAllDevices); 2849} 2850 2851SyncCounter* 2852SyncInitDeviceIdleTime(DeviceIntPtr dev) 2853{ 2854 char timer_name[64]; 2855 sprintf(timer_name, "DEVICEIDLETIME %d", dev->id); 2856 2857 return init_system_idle_counter(timer_name, dev->id); 2858} 2859 2860void SyncRemoveDeviceIdleTime(SyncCounter *counter) 2861{ 2862 /* FreeAllResources() frees all system counters before the devices are 2863 shut down, check if there are any left before freeing the device's 2864 counter */ 2865 if (counter && !xorg_list_is_empty(&SysCounterList)) 2866 xorg_list_del(&counter->pSysCounterInfo->entry); 2867} 2868