sync.c revision f7df2e56
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 if (!(pCur = malloc(sizeof(SyncTriggerList)))) 203 return BadAlloc; 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, CARD64 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 || 252 XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value)); 253} 254 255static Bool 256SyncCheckTriggerNegativeComparison(SyncTrigger * pTrigger, CARD64 oldval) 257{ 258 SyncCounter *pCounter; 259 260 /* Non-counter sync objects should never get here because they 261 * never trigger this comparison. */ 262 if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE)) 263 return FALSE; 264 265 pCounter = (SyncCounter *) pTrigger->pSync; 266 267 return (pCounter == NULL || 268 XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value)); 269} 270 271static Bool 272SyncCheckTriggerPositiveTransition(SyncTrigger * pTrigger, CARD64 oldval) 273{ 274 SyncCounter *pCounter; 275 276 /* Non-counter sync objects should never get here because they 277 * never trigger this comparison. */ 278 if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE)) 279 return FALSE; 280 281 pCounter = (SyncCounter *) pTrigger->pSync; 282 283 return (pCounter == NULL || 284 (XSyncValueLessThan(oldval, pTrigger->test_value) && 285 XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value))); 286} 287 288static Bool 289SyncCheckTriggerNegativeTransition(SyncTrigger * pTrigger, CARD64 oldval) 290{ 291 SyncCounter *pCounter; 292 293 /* Non-counter sync objects should never get here because they 294 * never trigger this comparison. */ 295 if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE)) 296 return FALSE; 297 298 pCounter = (SyncCounter *) pTrigger->pSync; 299 300 return (pCounter == NULL || 301 (XSyncValueGreaterThan(oldval, pTrigger->test_value) && 302 XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value))); 303} 304 305static Bool 306SyncCheckTriggerFence(SyncTrigger * pTrigger, CARD64 unused) 307{ 308 SyncFence *pFence = (SyncFence *) pTrigger->pSync; 309 310 (void) unused; 311 312 return (pFence == NULL || pFence->funcs.CheckTriggered(pFence)); 313} 314 315static int 316SyncInitTrigger(ClientPtr client, SyncTrigger * pTrigger, XID syncObject, 317 RESTYPE resType, Mask changes) 318{ 319 SyncObject *pSync = pTrigger->pSync; 320 SyncCounter *pCounter = NULL; 321 int rc; 322 Bool newSyncObject = FALSE; 323 324 if (changes & XSyncCACounter) { 325 if (syncObject == None) 326 pSync = NULL; 327 else if (Success != (rc = dixLookupResourceByType((void **) &pSync, 328 syncObject, resType, 329 client, 330 DixReadAccess))) { 331 client->errorValue = syncObject; 332 return rc; 333 } 334 if (pSync != pTrigger->pSync) { /* new counter for trigger */ 335 SyncDeleteTriggerFromSyncObject(pTrigger); 336 pTrigger->pSync = pSync; 337 newSyncObject = TRUE; 338 } 339 } 340 341 /* if system counter, ask it what the current value is */ 342 343 if (pSync && SYNC_COUNTER == pSync->type) { 344 pCounter = (SyncCounter *) pSync; 345 346 if (IsSystemCounter(pCounter)) { 347 (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter, 348 &pCounter->value); 349 } 350 } 351 352 if (changes & XSyncCAValueType) { 353 if (pTrigger->value_type != XSyncRelative && 354 pTrigger->value_type != XSyncAbsolute) { 355 client->errorValue = pTrigger->value_type; 356 return BadValue; 357 } 358 } 359 360 if (changes & XSyncCATestType) { 361 362 if (pSync && SYNC_FENCE == pSync->type) { 363 pTrigger->CheckTrigger = SyncCheckTriggerFence; 364 } 365 else { 366 /* select appropriate CheckTrigger function */ 367 368 switch (pTrigger->test_type) { 369 case XSyncPositiveTransition: 370 pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition; 371 break; 372 case XSyncNegativeTransition: 373 pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition; 374 break; 375 case XSyncPositiveComparison: 376 pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison; 377 break; 378 case XSyncNegativeComparison: 379 pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison; 380 break; 381 default: 382 client->errorValue = pTrigger->test_type; 383 return BadValue; 384 } 385 } 386 } 387 388 if (changes & (XSyncCAValueType | XSyncCAValue)) { 389 if (pTrigger->value_type == XSyncAbsolute) 390 pTrigger->test_value = pTrigger->wait_value; 391 else { /* relative */ 392 393 Bool overflow; 394 395 if (pCounter == NULL) 396 return BadMatch; 397 398 XSyncValueAdd(&pTrigger->test_value, pCounter->value, 399 pTrigger->wait_value, &overflow); 400 if (overflow) { 401 client->errorValue = XSyncValueHigh32(pTrigger->wait_value); 402 return BadValue; 403 } 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 if ((rc = SyncAddTriggerToSyncObject(pTrigger)) != Success) 412 return rc; 413 } 414 else if (pCounter && IsSystemCounter(pCounter)) { 415 SyncComputeBracketValues(pCounter); 416 } 417 418 return Success; 419} 420 421/* AlarmNotify events happen in response to actions taken on an Alarm or 422 * the counter used by the alarm. AlarmNotify may be sent to multiple 423 * clients. The alarm maintains a list of clients interested in events. 424 */ 425static void 426SyncSendAlarmNotifyEvents(SyncAlarm * pAlarm) 427{ 428 SyncAlarmClientList *pcl; 429 xSyncAlarmNotifyEvent ane; 430 SyncTrigger *pTrigger = &pAlarm->trigger; 431 SyncCounter *pCounter; 432 433 if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM)) 434 return; 435 436 pCounter = (SyncCounter *) pTrigger->pSync; 437 438 UpdateCurrentTime(); 439 440 ane = (xSyncAlarmNotifyEvent) { 441 .type = SyncEventBase + XSyncAlarmNotify, 442 .kind = XSyncAlarmNotify, 443 .alarm = pAlarm->alarm_id, 444 .alarm_value_hi = XSyncValueHigh32(pTrigger->test_value), 445 .alarm_value_lo = XSyncValueLow32(pTrigger->test_value), 446 .time = currentTime.milliseconds, 447 .state = pAlarm->state 448 }; 449 450 if (pTrigger->pSync && SYNC_COUNTER == pTrigger->pSync->type) { 451 ane.counter_value_hi = XSyncValueHigh32(pCounter->value); 452 ane.counter_value_lo = XSyncValueLow32(pCounter->value); 453 } 454 else { 455 /* XXX what else can we do if there's no counter? */ 456 ane.counter_value_hi = ane.counter_value_lo = 0; 457 } 458 459 /* send to owner */ 460 if (pAlarm->events) 461 WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane); 462 463 /* send to other interested clients */ 464 for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next) 465 WriteEventsToClient(pcl->client, 1, (xEvent *) &ane); 466} 467 468/* CounterNotify events only occur in response to an Await. The events 469 * go only to the Awaiting client. 470 */ 471static void 472SyncSendCounterNotifyEvents(ClientPtr client, SyncAwait ** ppAwait, 473 int num_events) 474{ 475 xSyncCounterNotifyEvent *pEvents, *pev; 476 int i; 477 478 if (client->clientGone) 479 return; 480 pev = pEvents = calloc(num_events, sizeof(xSyncCounterNotifyEvent)); 481 if (!pEvents) 482 return; 483 UpdateCurrentTime(); 484 for (i = 0; i < num_events; i++, ppAwait++, pev++) { 485 SyncTrigger *pTrigger = &(*ppAwait)->trigger; 486 487 pev->type = SyncEventBase + XSyncCounterNotify; 488 pev->kind = XSyncCounterNotify; 489 pev->counter = pTrigger->pSync->id; 490 pev->wait_value_lo = XSyncValueLow32(pTrigger->test_value); 491 pev->wait_value_hi = XSyncValueHigh32(pTrigger->test_value); 492 if (SYNC_COUNTER == pTrigger->pSync->type) { 493 SyncCounter *pCounter = (SyncCounter *) pTrigger->pSync; 494 495 pev->counter_value_lo = XSyncValueLow32(pCounter->value); 496 pev->counter_value_hi = XSyncValueHigh32(pCounter->value); 497 } 498 else { 499 pev->counter_value_lo = 0; 500 pev->counter_value_hi = 0; 501 } 502 503 pev->time = currentTime.milliseconds; 504 pev->count = num_events - i - 1; /* events remaining */ 505 pev->destroyed = pTrigger->pSync->beingDestroyed; 506 } 507 /* swapping will be taken care of by this */ 508 WriteEventsToClient(client, num_events, (xEvent *) pEvents); 509 free(pEvents); 510} 511 512/* This function is called when an alarm's counter is destroyed. 513 * It is plugged into pTrigger->CounterDestroyed (for alarm triggers). 514 */ 515static void 516SyncAlarmCounterDestroyed(SyncTrigger * pTrigger) 517{ 518 SyncAlarm *pAlarm = (SyncAlarm *) pTrigger; 519 520 pAlarm->state = XSyncAlarmInactive; 521 SyncSendAlarmNotifyEvents(pAlarm); 522 pTrigger->pSync = NULL; 523} 524 525/* This function is called when an alarm "goes off." 526 * It is plugged into pTrigger->TriggerFired (for alarm triggers). 527 */ 528static void 529SyncAlarmTriggerFired(SyncTrigger * pTrigger) 530{ 531 SyncAlarm *pAlarm = (SyncAlarm *) pTrigger; 532 SyncCounter *pCounter; 533 CARD64 new_test_value; 534 535 if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM)) 536 return; 537 538 pCounter = (SyncCounter *) pTrigger->pSync; 539 540 /* no need to check alarm unless it's active */ 541 if (pAlarm->state != XSyncAlarmActive) 542 return; 543 544 /* " if the counter value is None, or if the delta is 0 and 545 * the test-type is PositiveComparison or NegativeComparison, 546 * no change is made to value (test-value) and the alarm 547 * state is changed to Inactive before the event is generated." 548 */ 549 if (pCounter == NULL || (XSyncValueIsZero(pAlarm->delta) 550 && (pAlarm->trigger.test_type == 551 XSyncPositiveComparison || 552 pAlarm->trigger.test_type == 553 XSyncNegativeComparison))) 554 pAlarm->state = XSyncAlarmInactive; 555 556 new_test_value = pAlarm->trigger.test_value; 557 558 if (pAlarm->state == XSyncAlarmActive) { 559 Bool overflow; 560 CARD64 oldvalue; 561 SyncTrigger *paTrigger = &pAlarm->trigger; 562 SyncCounter *paCounter; 563 564 if (!SyncCheckWarnIsCounter(paTrigger->pSync, 565 WARN_INVALID_COUNTER_ALARM)) 566 return; 567 568 paCounter = (SyncCounter *) pTrigger->pSync; 569 570 /* "The alarm is updated by repeatedly adding delta to the 571 * value of the trigger and re-initializing it until it 572 * becomes FALSE." 573 */ 574 oldvalue = paTrigger->test_value; 575 576 /* XXX really should do something smarter here */ 577 578 do { 579 XSyncValueAdd(&paTrigger->test_value, paTrigger->test_value, 580 pAlarm->delta, &overflow); 581 } while (!overflow && 582 (*paTrigger->CheckTrigger) (paTrigger, paCounter->value)); 583 584 new_test_value = paTrigger->test_value; 585 paTrigger->test_value = oldvalue; 586 587 /* "If this update would cause value to fall outside the range 588 * for an INT64...no change is made to value (test-value) and 589 * the alarm state is changed to Inactive before the event is 590 * generated." 591 */ 592 if (overflow) { 593 new_test_value = oldvalue; 594 pAlarm->state = XSyncAlarmInactive; 595 } 596 } 597 /* The AlarmNotify event has to have the "new state of the alarm" 598 * which we can't be sure of until this point. However, it has 599 * to have the "old" trigger test value. That's the reason for 600 * all the newvalue/oldvalue shuffling above. After we send the 601 * events, give the trigger its new test value. 602 */ 603 SyncSendAlarmNotifyEvents(pAlarm); 604 pTrigger->test_value = new_test_value; 605} 606 607/* This function is called when an Await unblocks, either as a result 608 * of the trigger firing OR the counter being destroyed. 609 * It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed 610 * (for Await triggers). 611 */ 612static void 613SyncAwaitTriggerFired(SyncTrigger * pTrigger) 614{ 615 SyncAwait *pAwait = (SyncAwait *) pTrigger; 616 int numwaits; 617 SyncAwaitUnion *pAwaitUnion; 618 SyncAwait **ppAwait; 619 int num_events = 0; 620 621 pAwaitUnion = (SyncAwaitUnion *) pAwait->pHeader; 622 numwaits = pAwaitUnion->header.num_waitconditions; 623 ppAwait = xallocarray(numwaits, sizeof(SyncAwait *)); 624 if (!ppAwait) 625 goto bail; 626 627 pAwait = &(pAwaitUnion + 1)->await; 628 629 /* "When a client is unblocked, all the CounterNotify events for 630 * the Await request are generated contiguously. If count is 0 631 * there are no more events to follow for this request. If 632 * count is n, there are at least n more events to follow." 633 * 634 * Thus, it is best to find all the counters for which events 635 * need to be sent first, so that an accurate count field can 636 * be stored in the events. 637 */ 638 for (; numwaits; numwaits--, pAwait++) { 639 CARD64 diff; 640 Bool overflow, diffgreater, diffequal; 641 642 /* "A CounterNotify event with the destroyed flag set to TRUE is 643 * always generated if the counter for one of the triggers is 644 * destroyed." 645 */ 646 if (pAwait->trigger.pSync->beingDestroyed) { 647 ppAwait[num_events++] = pAwait; 648 continue; 649 } 650 651 if (SYNC_COUNTER == pAwait->trigger.pSync->type) { 652 SyncCounter *pCounter = (SyncCounter *) pAwait->trigger.pSync; 653 654 /* "The difference between the counter and the test value is 655 * calculated by subtracting the test value from the value of 656 * the counter." 657 */ 658 XSyncValueSubtract(&diff, pCounter->value, 659 pAwait->trigger.test_value, &overflow); 660 661 /* "If the difference lies outside the range for an INT64, an 662 * event is not generated." 663 */ 664 if (overflow) 665 continue; 666 diffgreater = XSyncValueGreaterThan(diff, pAwait->event_threshold); 667 diffequal = XSyncValueEqual(diff, pAwait->event_threshold); 668 669 /* "If the test-type is PositiveTransition or 670 * PositiveComparison, a CounterNotify event is generated if 671 * the difference is at least event-threshold. If the test-type 672 * is NegativeTransition or NegativeComparison, a CounterNotify 673 * event is generated if the difference is at most 674 * event-threshold." 675 */ 676 677 if (((pAwait->trigger.test_type == XSyncPositiveComparison || 678 pAwait->trigger.test_type == XSyncPositiveTransition) 679 && (diffgreater || diffequal)) 680 || 681 ((pAwait->trigger.test_type == XSyncNegativeComparison || 682 pAwait->trigger.test_type == XSyncNegativeTransition) 683 && (!diffgreater) /* less or equal */ 684 ) 685 ) { 686 ppAwait[num_events++] = pAwait; 687 } 688 } 689 } 690 if (num_events) 691 SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait, 692 num_events); 693 free(ppAwait); 694 695 bail: 696 /* unblock the client */ 697 AttendClient(pAwaitUnion->header.client); 698 /* delete the await */ 699 FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 700} 701 702static CARD64 703SyncUpdateCounter(SyncCounter *pCounter, CARD64 newval) 704{ 705 CARD64 oldval = pCounter->value; 706 pCounter->value = newval; 707 return oldval; 708} 709 710/* This function should always be used to change a counter's value so that 711 * any triggers depending on the counter will be checked. 712 */ 713void 714SyncChangeCounter(SyncCounter * pCounter, CARD64 newval) 715{ 716 SyncTriggerList *ptl, *pnext; 717 CARD64 oldval; 718 719 oldval = SyncUpdateCounter(pCounter, newval); 720 721 /* run through triggers to see if any become true */ 722 for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) { 723 pnext = ptl->next; 724 if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, oldval)) 725 (*ptl->pTrigger->TriggerFired) (ptl->pTrigger); 726 } 727 728 if (IsSystemCounter(pCounter)) { 729 SyncComputeBracketValues(pCounter); 730 } 731} 732 733/* loosely based on dix/events.c/EventSelectForWindow */ 734static Bool 735SyncEventSelectForAlarm(SyncAlarm * pAlarm, ClientPtr client, Bool wantevents) 736{ 737 SyncAlarmClientList *pClients; 738 739 if (client == pAlarm->client) { /* alarm owner */ 740 pAlarm->events = wantevents; 741 return Success; 742 } 743 744 /* see if the client is already on the list (has events selected) */ 745 746 for (pClients = pAlarm->pEventClients; pClients; pClients = pClients->next) { 747 if (pClients->client == client) { 748 /* client's presence on the list indicates desire for 749 * events. If the client doesn't want events, remove it 750 * from the list. If the client does want events, do 751 * nothing, since it's already got them. 752 */ 753 if (!wantevents) { 754 FreeResource(pClients->delete_id, RT_NONE); 755 } 756 return Success; 757 } 758 } 759 760 /* if we get here, this client does not currently have 761 * events selected on the alarm 762 */ 763 764 if (!wantevents) 765 /* client doesn't want events, and we just discovered that it 766 * doesn't have them, so there's nothing to do. 767 */ 768 return Success; 769 770 /* add new client to pAlarm->pEventClients */ 771 772 pClients = malloc(sizeof(SyncAlarmClientList)); 773 if (!pClients) 774 return BadAlloc; 775 776 /* register it as a resource so it will be cleaned up 777 * if the client dies 778 */ 779 780 pClients->delete_id = FakeClientID(client->index); 781 782 /* link it into list after we know all the allocations succeed */ 783 pClients->next = pAlarm->pEventClients; 784 pAlarm->pEventClients = pClients; 785 pClients->client = client; 786 787 if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm)) 788 return BadAlloc; 789 790 return Success; 791} 792 793/* 794 * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm 795 */ 796static int 797SyncChangeAlarmAttributes(ClientPtr client, SyncAlarm * pAlarm, Mask mask, 798 CARD32 *values) 799{ 800 int status; 801 XSyncCounter counter; 802 Mask origmask = mask; 803 804 counter = pAlarm->trigger.pSync ? pAlarm->trigger.pSync->id : None; 805 806 while (mask) { 807 int index2 = lowbit(mask); 808 809 mask &= ~index2; 810 switch (index2) { 811 case XSyncCACounter: 812 mask &= ~XSyncCACounter; 813 /* sanity check in SyncInitTrigger */ 814 counter = *values++; 815 break; 816 817 case XSyncCAValueType: 818 mask &= ~XSyncCAValueType; 819 /* sanity check in SyncInitTrigger */ 820 pAlarm->trigger.value_type = *values++; 821 break; 822 823 case XSyncCAValue: 824 mask &= ~XSyncCAValue; 825 XSyncIntsToValue(&pAlarm->trigger.wait_value, values[1], values[0]); 826 values += 2; 827 break; 828 829 case XSyncCATestType: 830 mask &= ~XSyncCATestType; 831 /* sanity check in SyncInitTrigger */ 832 pAlarm->trigger.test_type = *values++; 833 break; 834 835 case XSyncCADelta: 836 mask &= ~XSyncCADelta; 837 XSyncIntsToValue(&pAlarm->delta, values[1], values[0]); 838 values += 2; 839 break; 840 841 case XSyncCAEvents: 842 mask &= ~XSyncCAEvents; 843 if ((*values != xTrue) && (*values != xFalse)) { 844 client->errorValue = *values; 845 return BadValue; 846 } 847 status = SyncEventSelectForAlarm(pAlarm, client, 848 (Bool) (*values++)); 849 if (status != Success) 850 return status; 851 break; 852 853 default: 854 client->errorValue = mask; 855 return BadValue; 856 } 857 } 858 859 /* "If the test-type is PositiveComparison or PositiveTransition 860 * and delta is less than zero, or if the test-type is 861 * NegativeComparison or NegativeTransition and delta is 862 * greater than zero, a Match error is generated." 863 */ 864 if (origmask & (XSyncCADelta | XSyncCATestType)) { 865 CARD64 zero; 866 867 XSyncIntToValue(&zero, 0); 868 if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) || 869 (pAlarm->trigger.test_type == XSyncPositiveTransition)) 870 && XSyncValueLessThan(pAlarm->delta, zero)) 871 || 872 (((pAlarm->trigger.test_type == XSyncNegativeComparison) || 873 (pAlarm->trigger.test_type == XSyncNegativeTransition)) 874 && XSyncValueGreaterThan(pAlarm->delta, zero)) 875 ) { 876 return BadMatch; 877 } 878 } 879 880 /* postpone this until now, when we're sure nothing else can go wrong */ 881 if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter, 882 origmask & XSyncCAAllTrigger)) != Success) 883 return status; 884 885 /* XXX spec does not really say to do this - needs clarification */ 886 pAlarm->state = XSyncAlarmActive; 887 return Success; 888} 889 890static SyncObject * 891SyncCreate(ClientPtr client, XID id, unsigned char type) 892{ 893 SyncObject *pSync; 894 895 switch (type) { 896 case SYNC_COUNTER: 897 pSync = malloc(sizeof(SyncCounter)); 898 break; 899 case SYNC_FENCE: 900 pSync = (SyncObject *) dixAllocateObjectWithPrivates(SyncFence, 901 PRIVATE_SYNC_FENCE); 902 break; 903 default: 904 return NULL; 905 } 906 907 if (!pSync) 908 return NULL; 909 910 pSync->client = client; 911 pSync->id = id; 912 pSync->pTriglist = NULL; 913 pSync->beingDestroyed = FALSE; 914 pSync->type = type; 915 916 return pSync; 917} 918 919int 920SyncCreateFenceFromFD(ClientPtr client, DrawablePtr pDraw, XID id, int fd, BOOL initially_triggered) 921{ 922#if HAVE_XSHMFENCE 923 SyncFence *pFence; 924 int status; 925 926 pFence = (SyncFence *) SyncCreate(client, id, SYNC_FENCE); 927 if (!pFence) 928 return BadAlloc; 929 930 status = miSyncInitFenceFromFD(pDraw, pFence, fd, initially_triggered); 931 if (status != Success) { 932 dixFreeObjectWithPrivates(pFence, PRIVATE_SYNC_FENCE); 933 return status; 934 } 935 936 if (!AddResource(id, RTFence, (void *) pFence)) 937 return BadAlloc; 938 939 return Success; 940#else 941 return BadImplementation; 942#endif 943} 944 945int 946SyncFDFromFence(ClientPtr client, DrawablePtr pDraw, SyncFence *pFence) 947{ 948#if HAVE_XSHMFENCE 949 return miSyncFDFromFence(pDraw, pFence); 950#else 951 return BadImplementation; 952#endif 953} 954 955static SyncCounter * 956SyncCreateCounter(ClientPtr client, XSyncCounter id, CARD64 initialvalue) 957{ 958 SyncCounter *pCounter; 959 960 if (!(pCounter = (SyncCounter *) SyncCreate(client, id, SYNC_COUNTER))) 961 return NULL; 962 963 pCounter->value = initialvalue; 964 pCounter->pSysCounterInfo = NULL; 965 966 if (!AddResource(id, RTCounter, (void *) pCounter)) 967 return NULL; 968 969 return pCounter; 970} 971 972static int FreeCounter(void *, XID); 973 974/* 975 * ***** System Counter utilities 976 */ 977 978SyncCounter* 979SyncCreateSystemCounter(const char *name, 980 CARD64 initial, 981 CARD64 resolution, 982 SyncCounterType counterType, 983 SyncSystemCounterQueryValue QueryValue, 984 SyncSystemCounterBracketValues BracketValues 985 ) 986{ 987 SyncCounter *pCounter; 988 989 /* this function may be called before SYNC has been initialized, so we 990 * have to make sure RTCounter is created. 991 */ 992 if (RTCounter == 0) { 993 RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter"); 994 if (RTCounter == 0) { 995 return NULL; 996 } 997 xorg_list_init(&SysCounterList); 998 } 999 1000 pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial); 1001 1002 if (pCounter) { 1003 SysCounterInfo *psci; 1004 1005 psci = malloc(sizeof(SysCounterInfo)); 1006 if (!psci) { 1007 FreeResource(pCounter->sync.id, RT_NONE); 1008 return pCounter; 1009 } 1010 pCounter->pSysCounterInfo = psci; 1011 psci->pCounter = pCounter; 1012 psci->name = strdup(name); 1013 psci->resolution = resolution; 1014 psci->counterType = counterType; 1015 psci->QueryValue = QueryValue; 1016 psci->BracketValues = BracketValues; 1017 psci->private = NULL; 1018 XSyncMaxValue(&psci->bracket_greater); 1019 XSyncMinValue(&psci->bracket_less); 1020 xorg_list_add(&psci->entry, &SysCounterList); 1021 } 1022 return pCounter; 1023} 1024 1025void 1026SyncDestroySystemCounter(void *pSysCounter) 1027{ 1028 SyncCounter *pCounter = (SyncCounter *) pSysCounter; 1029 1030 FreeResource(pCounter->sync.id, RT_NONE); 1031} 1032 1033static void 1034SyncComputeBracketValues(SyncCounter * pCounter) 1035{ 1036 SyncTriggerList *pCur; 1037 SyncTrigger *pTrigger; 1038 SysCounterInfo *psci; 1039 CARD64 *pnewgtval = NULL; 1040 CARD64 *pnewltval = NULL; 1041 SyncCounterType ct; 1042 1043 if (!pCounter) 1044 return; 1045 1046 psci = pCounter->pSysCounterInfo; 1047 ct = pCounter->pSysCounterInfo->counterType; 1048 if (ct == XSyncCounterNeverChanges) 1049 return; 1050 1051 XSyncMaxValue(&psci->bracket_greater); 1052 XSyncMinValue(&psci->bracket_less); 1053 1054 for (pCur = pCounter->sync.pTriglist; pCur; pCur = pCur->next) { 1055 pTrigger = pCur->pTrigger; 1056 1057 if (pTrigger->test_type == XSyncPositiveComparison && 1058 ct != XSyncCounterNeverIncreases) { 1059 if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) && 1060 XSyncValueLessThan(pTrigger->test_value, 1061 psci->bracket_greater)) { 1062 psci->bracket_greater = pTrigger->test_value; 1063 pnewgtval = &psci->bracket_greater; 1064 } 1065 else if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) && 1066 XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less)) { 1067 psci->bracket_less = pTrigger->test_value; 1068 pnewltval = &psci->bracket_less; 1069 } 1070 } 1071 else if (pTrigger->test_type == XSyncNegativeComparison && 1072 ct != XSyncCounterNeverDecreases) { 1073 if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) && 1074 XSyncValueGreaterThan(pTrigger->test_value, 1075 psci->bracket_less)) { 1076 psci->bracket_less = pTrigger->test_value; 1077 pnewltval = &psci->bracket_less; 1078 } 1079 else if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) && 1080 XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater)) { 1081 psci->bracket_greater = pTrigger->test_value; 1082 pnewgtval = &psci->bracket_greater; 1083 } 1084 } 1085 else if (pTrigger->test_type == XSyncNegativeTransition && 1086 ct != XSyncCounterNeverIncreases) { 1087 if (XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value) && 1088 XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less)) { 1089 /* 1090 * If the value is exactly equal to our threshold, we want one 1091 * more event in the negative direction to ensure we pick up 1092 * when the value is less than this threshold. 1093 */ 1094 psci->bracket_less = pTrigger->test_value; 1095 pnewltval = &psci->bracket_less; 1096 } 1097 else if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) && 1098 XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater)) { 1099 psci->bracket_greater = pTrigger->test_value; 1100 pnewgtval = &psci->bracket_greater; 1101 } 1102 } 1103 else if (pTrigger->test_type == XSyncPositiveTransition && 1104 ct != XSyncCounterNeverDecreases) { 1105 if (XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value) && 1106 XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater)) { 1107 /* 1108 * If the value is exactly equal to our threshold, we 1109 * want one more event in the positive direction to 1110 * ensure we pick up when the value *exceeds* this 1111 * threshold. 1112 */ 1113 psci->bracket_greater = pTrigger->test_value; 1114 pnewgtval = &psci->bracket_greater; 1115 } 1116 else if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) && 1117 XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less)) { 1118 psci->bracket_less = pTrigger->test_value; 1119 pnewltval = &psci->bracket_less; 1120 } 1121 } 1122 } /* end for each trigger */ 1123 1124 (*psci->BracketValues) ((void *) pCounter, pnewltval, pnewgtval); 1125 1126} 1127 1128/* 1129 * ***** Resource delete functions 1130 */ 1131 1132/* ARGSUSED */ 1133static int 1134FreeAlarm(void *addr, XID id) 1135{ 1136 SyncAlarm *pAlarm = (SyncAlarm *) addr; 1137 1138 pAlarm->state = XSyncAlarmDestroyed; 1139 1140 SyncSendAlarmNotifyEvents(pAlarm); 1141 1142 /* delete event selections */ 1143 1144 while (pAlarm->pEventClients) 1145 FreeResource(pAlarm->pEventClients->delete_id, RT_NONE); 1146 1147 SyncDeleteTriggerFromSyncObject(&pAlarm->trigger); 1148 1149 free(pAlarm); 1150 return Success; 1151} 1152 1153/* 1154 * ** Cleanup after the destruction of a Counter 1155 */ 1156/* ARGSUSED */ 1157static int 1158FreeCounter(void *env, XID id) 1159{ 1160 SyncCounter *pCounter = (SyncCounter *) env; 1161 SyncTriggerList *ptl, *pnext; 1162 1163 pCounter->sync.beingDestroyed = TRUE; 1164 /* tell all the counter's triggers that the 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 free(pCounter); 1177 return Success; 1178} 1179 1180/* 1181 * ** Cleanup after Await 1182 */ 1183/* ARGSUSED */ 1184static int 1185FreeAwait(void *addr, XID id) 1186{ 1187 SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr; 1188 SyncAwait *pAwait; 1189 int numwaits; 1190 1191 pAwait = &(pAwaitUnion + 1)->await; /* first await on list */ 1192 1193 /* remove triggers from counters */ 1194 1195 for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits; 1196 numwaits--, pAwait++) { 1197 /* If the counter is being destroyed, FreeCounter will delete 1198 * the trigger list itself, so don't do it here. 1199 */ 1200 SyncObject *pSync = pAwait->trigger.pSync; 1201 1202 if (pSync && !pSync->beingDestroyed) 1203 SyncDeleteTriggerFromSyncObject(&pAwait->trigger); 1204 } 1205 free(pAwaitUnion); 1206 return Success; 1207} 1208 1209/* loosely based on dix/events.c/OtherClientGone */ 1210static int 1211FreeAlarmClient(void *value, XID id) 1212{ 1213 SyncAlarm *pAlarm = (SyncAlarm *) value; 1214 SyncAlarmClientList *pCur, *pPrev; 1215 1216 for (pPrev = NULL, pCur = pAlarm->pEventClients; 1217 pCur; pPrev = pCur, pCur = pCur->next) { 1218 if (pCur->delete_id == id) { 1219 if (pPrev) 1220 pPrev->next = pCur->next; 1221 else 1222 pAlarm->pEventClients = pCur->next; 1223 free(pCur); 1224 return Success; 1225 } 1226 } 1227 FatalError("alarm client not on event list"); 1228 /*NOTREACHED*/} 1229 1230/* 1231 * ***** Proc functions 1232 */ 1233 1234/* 1235 * ** Initialize the extension 1236 */ 1237static int 1238ProcSyncInitialize(ClientPtr client) 1239{ 1240 xSyncInitializeReply rep = { 1241 .type = X_Reply, 1242 .sequenceNumber = client->sequence, 1243 .length = 0, 1244 .majorVersion = SERVER_SYNC_MAJOR_VERSION, 1245 .minorVersion = SERVER_SYNC_MINOR_VERSION, 1246 }; 1247 1248 REQUEST_SIZE_MATCH(xSyncInitializeReq); 1249 1250 if (client->swapped) { 1251 swaps(&rep.sequenceNumber); 1252 } 1253 WriteToClient(client, sizeof(rep), &rep); 1254 return Success; 1255} 1256 1257/* 1258 * ** Get list of system counters available through the extension 1259 */ 1260static int 1261ProcSyncListSystemCounters(ClientPtr client) 1262{ 1263 xSyncListSystemCountersReply rep = { 1264 .type = X_Reply, 1265 .sequenceNumber = client->sequence, 1266 .nCounters = 0, 1267 }; 1268 SysCounterInfo *psci; 1269 int len = 0; 1270 xSyncSystemCounter *list = NULL, *walklist = NULL; 1271 1272 REQUEST_SIZE_MATCH(xSyncListSystemCountersReq); 1273 1274 xorg_list_for_each_entry(psci, &SysCounterList, entry) { 1275 /* pad to 4 byte boundary */ 1276 len += pad_to_int32(sz_xSyncSystemCounter + strlen(psci->name)); 1277 ++rep.nCounters; 1278 } 1279 1280 if (len) { 1281 walklist = list = malloc(len); 1282 if (!list) 1283 return BadAlloc; 1284 } 1285 1286 rep.length = bytes_to_int32(len); 1287 1288 if (client->swapped) { 1289 swaps(&rep.sequenceNumber); 1290 swapl(&rep.length); 1291 swapl(&rep.nCounters); 1292 } 1293 1294 xorg_list_for_each_entry(psci, &SysCounterList, entry) { 1295 int namelen; 1296 char *pname_in_reply; 1297 1298 walklist->counter = psci->pCounter->sync.id; 1299 walklist->resolution_hi = XSyncValueHigh32(psci->resolution); 1300 walklist->resolution_lo = XSyncValueLow32(psci->resolution); 1301 namelen = strlen(psci->name); 1302 walklist->name_length = namelen; 1303 1304 if (client->swapped) { 1305 swapl(&walklist->counter); 1306 swapl(&walklist->resolution_hi); 1307 swapl(&walklist->resolution_lo); 1308 swaps(&walklist->name_length); 1309 } 1310 1311 pname_in_reply = ((char *) walklist) + sz_xSyncSystemCounter; 1312 strncpy(pname_in_reply, psci->name, namelen); 1313 walklist = (xSyncSystemCounter *) (((char *) walklist) + 1314 pad_to_int32(sz_xSyncSystemCounter + 1315 namelen)); 1316 } 1317 1318 WriteToClient(client, sizeof(rep), &rep); 1319 if (len) { 1320 WriteToClient(client, len, list); 1321 free(list); 1322 } 1323 1324 return Success; 1325} 1326 1327/* 1328 * ** Set client Priority 1329 */ 1330static int 1331ProcSyncSetPriority(ClientPtr client) 1332{ 1333 REQUEST(xSyncSetPriorityReq); 1334 ClientPtr priorityclient; 1335 int rc; 1336 1337 REQUEST_SIZE_MATCH(xSyncSetPriorityReq); 1338 1339 if (stuff->id == None) 1340 priorityclient = client; 1341 else { 1342 rc = dixLookupClient(&priorityclient, stuff->id, client, 1343 DixSetAttrAccess); 1344 if (rc != Success) 1345 return rc; 1346 } 1347 1348 if (priorityclient->priority != stuff->priority) { 1349 priorityclient->priority = stuff->priority; 1350 1351 /* The following will force the server back into WaitForSomething 1352 * so that the change in this client's priority is immediately 1353 * reflected. 1354 */ 1355 isItTimeToYield = TRUE; 1356 dispatchException |= DE_PRIORITYCHANGE; 1357 } 1358 return Success; 1359} 1360 1361/* 1362 * ** Get client Priority 1363 */ 1364static int 1365ProcSyncGetPriority(ClientPtr client) 1366{ 1367 REQUEST(xSyncGetPriorityReq); 1368 xSyncGetPriorityReply rep; 1369 ClientPtr priorityclient; 1370 int rc; 1371 1372 REQUEST_SIZE_MATCH(xSyncGetPriorityReq); 1373 1374 if (stuff->id == None) 1375 priorityclient = client; 1376 else { 1377 rc = dixLookupClient(&priorityclient, stuff->id, client, 1378 DixGetAttrAccess); 1379 if (rc != Success) 1380 return rc; 1381 } 1382 1383 rep = (xSyncGetPriorityReply) { 1384 .type = X_Reply, 1385 .sequenceNumber = client->sequence, 1386 .length = 0, 1387 .priority = priorityclient->priority 1388 }; 1389 1390 if (client->swapped) { 1391 swaps(&rep.sequenceNumber); 1392 swapl(&rep.priority); 1393 } 1394 1395 WriteToClient(client, sizeof(xSyncGetPriorityReply), &rep); 1396 1397 return Success; 1398} 1399 1400/* 1401 * ** Create a new counter 1402 */ 1403static int 1404ProcSyncCreateCounter(ClientPtr client) 1405{ 1406 REQUEST(xSyncCreateCounterReq); 1407 CARD64 initial; 1408 1409 REQUEST_SIZE_MATCH(xSyncCreateCounterReq); 1410 1411 LEGAL_NEW_RESOURCE(stuff->cid, client); 1412 1413 XSyncIntsToValue(&initial, stuff->initial_value_lo, 1414 stuff->initial_value_hi); 1415 if (!SyncCreateCounter(client, stuff->cid, initial)) 1416 return BadAlloc; 1417 1418 return Success; 1419} 1420 1421/* 1422 * ** Set Counter value 1423 */ 1424static int 1425ProcSyncSetCounter(ClientPtr client) 1426{ 1427 REQUEST(xSyncSetCounterReq); 1428 SyncCounter *pCounter; 1429 CARD64 newvalue; 1430 int rc; 1431 1432 REQUEST_SIZE_MATCH(xSyncSetCounterReq); 1433 1434 rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter, 1435 client, DixWriteAccess); 1436 if (rc != Success) 1437 return rc; 1438 1439 if (IsSystemCounter(pCounter)) { 1440 client->errorValue = stuff->cid; 1441 return BadAccess; 1442 } 1443 1444 XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi); 1445 SyncChangeCounter(pCounter, newvalue); 1446 return Success; 1447} 1448 1449/* 1450 * ** Change Counter value 1451 */ 1452static int 1453ProcSyncChangeCounter(ClientPtr client) 1454{ 1455 REQUEST(xSyncChangeCounterReq); 1456 SyncCounter *pCounter; 1457 CARD64 newvalue; 1458 Bool overflow; 1459 int rc; 1460 1461 REQUEST_SIZE_MATCH(xSyncChangeCounterReq); 1462 1463 rc = dixLookupResourceByType((void **) &pCounter, stuff->cid, RTCounter, 1464 client, DixWriteAccess); 1465 if (rc != Success) 1466 return rc; 1467 1468 if (IsSystemCounter(pCounter)) { 1469 client->errorValue = stuff->cid; 1470 return BadAccess; 1471 } 1472 1473 XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi); 1474 XSyncValueAdd(&newvalue, pCounter->value, newvalue, &overflow); 1475 if (overflow) { 1476 /* XXX 64 bit value can't fit in 32 bits; do the best we can */ 1477 client->errorValue = stuff->value_hi; 1478 return BadValue; 1479 } 1480 SyncChangeCounter(pCounter, newvalue); 1481 return Success; 1482} 1483 1484/* 1485 * ** Destroy a counter 1486 */ 1487static int 1488ProcSyncDestroyCounter(ClientPtr client) 1489{ 1490 REQUEST(xSyncDestroyCounterReq); 1491 SyncCounter *pCounter; 1492 int rc; 1493 1494 REQUEST_SIZE_MATCH(xSyncDestroyCounterReq); 1495 1496 rc = dixLookupResourceByType((void **) &pCounter, stuff->counter, 1497 RTCounter, client, DixDestroyAccess); 1498 if (rc != Success) 1499 return rc; 1500 1501 if (IsSystemCounter(pCounter)) { 1502 client->errorValue = stuff->counter; 1503 return BadAccess; 1504 } 1505 FreeResource(pCounter->sync.id, RT_NONE); 1506 return Success; 1507} 1508 1509static SyncAwaitUnion * 1510SyncAwaitPrologue(ClientPtr client, int items) 1511{ 1512 SyncAwaitUnion *pAwaitUnion; 1513 1514 /* all the memory for the entire await list is allocated 1515 * here in one chunk 1516 */ 1517 pAwaitUnion = xallocarray(items + 1, sizeof(SyncAwaitUnion)); 1518 if (!pAwaitUnion) 1519 return NULL; 1520 1521 /* first item is the header, remainder are real wait conditions */ 1522 1523 pAwaitUnion->header.delete_id = FakeClientID(client->index); 1524 pAwaitUnion->header.client = client; 1525 pAwaitUnion->header.num_waitconditions = 0; 1526 1527 if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion)) 1528 return NULL; 1529 1530 return pAwaitUnion; 1531} 1532 1533static void 1534SyncAwaitEpilogue(ClientPtr client, int items, SyncAwaitUnion * pAwaitUnion) 1535{ 1536 SyncAwait *pAwait; 1537 int i; 1538 1539 IgnoreClient(client); 1540 1541 /* see if any of the triggers are already true */ 1542 1543 pAwait = &(pAwaitUnion + 1)->await; /* skip over header */ 1544 for (i = 0; i < items; i++, pAwait++) { 1545 CARD64 value; 1546 1547 /* don't have to worry about NULL counters because the request 1548 * errors before we get here out if they occur 1549 */ 1550 switch (pAwait->trigger.pSync->type) { 1551 case SYNC_COUNTER: 1552 value = ((SyncCounter *) pAwait->trigger.pSync)->value; 1553 break; 1554 default: 1555 XSyncIntToValue(&value, 0); 1556 } 1557 1558 if ((*pAwait->trigger.CheckTrigger) (&pAwait->trigger, value)) { 1559 (*pAwait->trigger.TriggerFired) (&pAwait->trigger); 1560 break; /* once is enough */ 1561 } 1562 } 1563} 1564 1565/* 1566 * ** Await 1567 */ 1568static int 1569ProcSyncAwait(ClientPtr client) 1570{ 1571 REQUEST(xSyncAwaitReq); 1572 int len, items; 1573 int i; 1574 xSyncWaitCondition *pProtocolWaitConds; 1575 SyncAwaitUnion *pAwaitUnion; 1576 SyncAwait *pAwait; 1577 int status; 1578 1579 REQUEST_AT_LEAST_SIZE(xSyncAwaitReq); 1580 1581 len = client->req_len << 2; 1582 len -= sz_xSyncAwaitReq; 1583 items = len / sz_xSyncWaitCondition; 1584 1585 if (items * sz_xSyncWaitCondition != len) { 1586 return BadLength; 1587 } 1588 if (items == 0) { 1589 client->errorValue = items; /* XXX protocol change */ 1590 return BadValue; 1591 } 1592 1593 if (!(pAwaitUnion = SyncAwaitPrologue(client, items))) 1594 return BadAlloc; 1595 1596 /* don't need to do any more memory allocation for this request! */ 1597 1598 pProtocolWaitConds = (xSyncWaitCondition *) &stuff[1]; 1599 1600 pAwait = &(pAwaitUnion + 1)->await; /* skip over header */ 1601 for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++) { 1602 if (pProtocolWaitConds->counter == None) { /* XXX protocol change */ 1603 /* this should take care of removing any triggers created by 1604 * this request that have already been registered on sync objects 1605 */ 1606 FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 1607 client->errorValue = pProtocolWaitConds->counter; 1608 return SyncErrorBase + XSyncBadCounter; 1609 } 1610 1611 /* sanity checks are in SyncInitTrigger */ 1612 pAwait->trigger.pSync = NULL; 1613 pAwait->trigger.value_type = pProtocolWaitConds->value_type; 1614 XSyncIntsToValue(&pAwait->trigger.wait_value, 1615 pProtocolWaitConds->wait_value_lo, 1616 pProtocolWaitConds->wait_value_hi); 1617 pAwait->trigger.test_type = pProtocolWaitConds->test_type; 1618 1619 status = SyncInitTrigger(client, &pAwait->trigger, 1620 pProtocolWaitConds->counter, RTCounter, 1621 XSyncCAAllTrigger); 1622 if (status != Success) { 1623 /* this should take care of removing any triggers created by 1624 * this request that have already been registered on sync objects 1625 */ 1626 FreeResource(pAwaitUnion->header.delete_id, RT_NONE); 1627 return status; 1628 } 1629 /* this is not a mistake -- same function works for both cases */ 1630 pAwait->trigger.TriggerFired = SyncAwaitTriggerFired; 1631 pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired; 1632 XSyncIntsToValue(&pAwait->event_threshold, 1633 pProtocolWaitConds->event_threshold_lo, 1634 pProtocolWaitConds->event_threshold_hi); 1635 pAwait->pHeader = &pAwaitUnion->header; 1636 pAwaitUnion->header.num_waitconditions++; 1637 } 1638 1639 SyncAwaitEpilogue(client, items, pAwaitUnion); 1640 1641 return Success; 1642} 1643 1644/* 1645 * ** Query a counter 1646 */ 1647static int 1648ProcSyncQueryCounter(ClientPtr client) 1649{ 1650 REQUEST(xSyncQueryCounterReq); 1651 xSyncQueryCounterReply rep; 1652 SyncCounter *pCounter; 1653 int rc; 1654 1655 REQUEST_SIZE_MATCH(xSyncQueryCounterReq); 1656 1657 rc = dixLookupResourceByType((void **) &pCounter, stuff->counter, 1658 RTCounter, client, DixReadAccess); 1659 if (rc != Success) 1660 return rc; 1661 1662 /* if system counter, ask it what the current value is */ 1663 if (IsSystemCounter(pCounter)) { 1664 (*pCounter->pSysCounterInfo->QueryValue) ((void *) pCounter, 1665 &pCounter->value); 1666 } 1667 1668 rep = (xSyncQueryCounterReply) { 1669 .type = X_Reply, 1670 .sequenceNumber = client->sequence, 1671 .length = 0, 1672 .value_hi = XSyncValueHigh32(pCounter->value), 1673 .value_lo = XSyncValueLow32(pCounter->value) 1674 }; 1675 1676 if (client->swapped) { 1677 swaps(&rep.sequenceNumber); 1678 swapl(&rep.length); 1679 swapl(&rep.value_hi); 1680 swapl(&rep.value_lo); 1681 } 1682 WriteToClient(client, sizeof(xSyncQueryCounterReply), &rep); 1683 return Success; 1684} 1685 1686/* 1687 * ** Create Alarm 1688 */ 1689static int 1690ProcSyncCreateAlarm(ClientPtr client) 1691{ 1692 REQUEST(xSyncCreateAlarmReq); 1693 SyncAlarm *pAlarm; 1694 int status; 1695 unsigned long len, vmask; 1696 SyncTrigger *pTrigger; 1697 1698 REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq); 1699 1700 LEGAL_NEW_RESOURCE(stuff->id, client); 1701 1702 vmask = stuff->valueMask; 1703 len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq)); 1704 /* the "extra" call to Ones accounts for the presence of 64 bit values */ 1705 if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta)))) 1706 return BadLength; 1707 1708 if (!(pAlarm = malloc(sizeof(SyncAlarm)))) { 1709 return BadAlloc; 1710 } 1711 1712 /* set up defaults */ 1713 1714 pTrigger = &pAlarm->trigger; 1715 pTrigger->pSync = NULL; 1716 pTrigger->value_type = XSyncAbsolute; 1717 XSyncIntToValue(&pTrigger->wait_value, 0L); 1718 pTrigger->test_type = XSyncPositiveComparison; 1719 pTrigger->TriggerFired = SyncAlarmTriggerFired; 1720 pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed; 1721 status = SyncInitTrigger(client, pTrigger, None, RTCounter, 1722 XSyncCAAllTrigger); 1723 if (status != Success) { 1724 free(pAlarm); 1725 return status; 1726 } 1727 1728 pAlarm->client = client; 1729 pAlarm->alarm_id = stuff->id; 1730 XSyncIntToValue(&pAlarm->delta, 1L); 1731 pAlarm->events = TRUE; 1732 pAlarm->state = XSyncAlarmInactive; 1733 pAlarm->pEventClients = NULL; 1734 status = SyncChangeAlarmAttributes(client, pAlarm, vmask, 1735 (CARD32 *) &stuff[1]); 1736 if (status != Success) { 1737 free(pAlarm); 1738 return status; 1739 } 1740 1741 if (!AddResource(stuff->id, RTAlarm, pAlarm)) 1742 return BadAlloc; 1743 1744 /* see if alarm already triggered. NULL counter will not trigger 1745 * in CreateAlarm and sets alarm state to Inactive. 1746 */ 1747 1748 if (!pTrigger->pSync) { 1749 pAlarm->state = XSyncAlarmInactive; /* XXX protocol change */ 1750 } 1751 else { 1752 SyncCounter *pCounter; 1753 1754 if (!SyncCheckWarnIsCounter(pTrigger->pSync, 1755 WARN_INVALID_COUNTER_ALARM)) { 1756 FreeResource(stuff->id, RT_NONE); 1757 return BadAlloc; 1758 } 1759 1760 pCounter = (SyncCounter *) pTrigger->pSync; 1761 1762 if ((*pTrigger->CheckTrigger) (pTrigger, pCounter->value)) 1763 (*pTrigger->TriggerFired) (pTrigger); 1764 } 1765 1766 return Success; 1767} 1768 1769/* 1770 * ** Change Alarm 1771 */ 1772static int 1773ProcSyncChangeAlarm(ClientPtr client) 1774{ 1775 REQUEST(xSyncChangeAlarmReq); 1776 SyncAlarm *pAlarm; 1777 SyncCounter *pCounter = NULL; 1778 long vmask; 1779 int len, status; 1780 1781 REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq); 1782 1783 status = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm, 1784 client, DixWriteAccess); 1785 if (status != Success) 1786 return status; 1787 1788 vmask = stuff->valueMask; 1789 len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq)); 1790 /* the "extra" call to Ones accounts for the presence of 64 bit values */ 1791 if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta)))) 1792 return BadLength; 1793 1794 if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask, 1795 (CARD32 *) &stuff[1])) != Success) 1796 return status; 1797 1798 if (SyncCheckWarnIsCounter(pAlarm->trigger.pSync, 1799 WARN_INVALID_COUNTER_ALARM)) 1800 pCounter = (SyncCounter *) pAlarm->trigger.pSync; 1801 1802 /* see if alarm already triggered. NULL counter WILL trigger 1803 * in ChangeAlarm. 1804 */ 1805 1806 if (!pCounter || 1807 (*pAlarm->trigger.CheckTrigger) (&pAlarm->trigger, pCounter->value)) { 1808 (*pAlarm->trigger.TriggerFired) (&pAlarm->trigger); 1809 } 1810 return Success; 1811} 1812 1813static int 1814ProcSyncQueryAlarm(ClientPtr client) 1815{ 1816 REQUEST(xSyncQueryAlarmReq); 1817 SyncAlarm *pAlarm; 1818 xSyncQueryAlarmReply rep; 1819 SyncTrigger *pTrigger; 1820 int rc; 1821 1822 REQUEST_SIZE_MATCH(xSyncQueryAlarmReq); 1823 1824 rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm, 1825 client, DixReadAccess); 1826 if (rc != Success) 1827 return rc; 1828 1829 pTrigger = &pAlarm->trigger; 1830 rep = (xSyncQueryAlarmReply) { 1831 .type = X_Reply, 1832 .sequenceNumber = client->sequence, 1833 .length = 1834 bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply)), 1835 .counter = (pTrigger->pSync) ? pTrigger->pSync->id : None, 1836 1837#if 0 /* XXX unclear what to do, depends on whether relative value-types 1838 * are "consumed" immediately and are considered absolute from then 1839 * on. 1840 */ 1841 .value_type = pTrigger->value_type, 1842 .wait_value_hi = XSyncValueHigh32(pTrigger->wait_value), 1843 .wait_value_lo = XSyncValueLow32(pTrigger->wait_value), 1844#else 1845 .value_type = XSyncAbsolute, 1846 .wait_value_hi = XSyncValueHigh32(pTrigger->test_value), 1847 .wait_value_lo = XSyncValueLow32(pTrigger->test_value), 1848#endif 1849 1850 .test_type = pTrigger->test_type, 1851 .delta_hi = XSyncValueHigh32(pAlarm->delta), 1852 .delta_lo = XSyncValueLow32(pAlarm->delta), 1853 .events = pAlarm->events, 1854 .state = pAlarm->state 1855 }; 1856 1857 if (client->swapped) { 1858 swaps(&rep.sequenceNumber); 1859 swapl(&rep.length); 1860 swapl(&rep.counter); 1861 swapl(&rep.wait_value_hi); 1862 swapl(&rep.wait_value_lo); 1863 swapl(&rep.test_type); 1864 swapl(&rep.delta_hi); 1865 swapl(&rep.delta_lo); 1866 } 1867 1868 WriteToClient(client, sizeof(xSyncQueryAlarmReply), &rep); 1869 return Success; 1870} 1871 1872static int 1873ProcSyncDestroyAlarm(ClientPtr client) 1874{ 1875 SyncAlarm *pAlarm; 1876 int rc; 1877 1878 REQUEST(xSyncDestroyAlarmReq); 1879 1880 REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq); 1881 1882 rc = dixLookupResourceByType((void **) &pAlarm, stuff->alarm, RTAlarm, 1883 client, DixDestroyAccess); 1884 if (rc != Success) 1885 return rc; 1886 1887 FreeResource(stuff->alarm, RT_NONE); 1888 return Success; 1889} 1890 1891static int 1892ProcSyncCreateFence(ClientPtr client) 1893{ 1894 REQUEST(xSyncCreateFenceReq); 1895 DrawablePtr pDraw; 1896 SyncFence *pFence; 1897 int rc; 1898 1899 REQUEST_SIZE_MATCH(xSyncCreateFenceReq); 1900 1901 rc = dixLookupDrawable(&pDraw, stuff->d, client, M_ANY, DixGetAttrAccess); 1902 if (rc != Success) 1903 return rc; 1904 1905 LEGAL_NEW_RESOURCE(stuff->fid, client); 1906 1907 if (!(pFence = (SyncFence *) SyncCreate(client, stuff->fid, SYNC_FENCE))) 1908 return BadAlloc; 1909 1910 miSyncInitFence(pDraw->pScreen, pFence, stuff->initially_triggered); 1911 1912 if (!AddResource(stuff->fid, RTFence, (void *) pFence)) 1913 return BadAlloc; 1914 1915 return client->noClientException; 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 client->noClientException; 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 client->noClientException; 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 client->noClientException; 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 client->noClientException; 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 XSyncIntToValue(&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 XSyncIntToValue(&pAwait->event_threshold, 0); 2100 pAwait->pHeader = &pAwaitUnion->header; 2101 pAwaitUnion->header.num_waitconditions++; 2102 } 2103 2104 SyncAwaitEpilogue(client, items, pAwaitUnion); 2105 2106 return client->noClientException; 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 2330SProcSyncCreateFence(ClientPtr client) 2331{ 2332 REQUEST(xSyncCreateFenceReq); 2333 swaps(&stuff->length); 2334 REQUEST_SIZE_MATCH(xSyncCreateFenceReq); 2335 swapl(&stuff->fid); 2336 2337 return ProcSyncCreateFence(client); 2338} 2339 2340static int 2341SProcSyncTriggerFence(ClientPtr client) 2342{ 2343 REQUEST(xSyncTriggerFenceReq); 2344 swaps(&stuff->length); 2345 REQUEST_SIZE_MATCH(xSyncTriggerFenceReq); 2346 swapl(&stuff->fid); 2347 2348 return ProcSyncTriggerFence(client); 2349} 2350 2351static int 2352SProcSyncResetFence(ClientPtr client) 2353{ 2354 REQUEST(xSyncResetFenceReq); 2355 swaps(&stuff->length); 2356 REQUEST_SIZE_MATCH(xSyncResetFenceReq); 2357 swapl(&stuff->fid); 2358 2359 return ProcSyncResetFence(client); 2360} 2361 2362static int 2363SProcSyncDestroyFence(ClientPtr client) 2364{ 2365 REQUEST(xSyncDestroyFenceReq); 2366 swaps(&stuff->length); 2367 REQUEST_SIZE_MATCH(xSyncDestroyFenceReq); 2368 swapl(&stuff->fid); 2369 2370 return ProcSyncDestroyFence(client); 2371} 2372 2373static int 2374SProcSyncQueryFence(ClientPtr client) 2375{ 2376 REQUEST(xSyncQueryFenceReq); 2377 swaps(&stuff->length); 2378 REQUEST_SIZE_MATCH(xSyncQueryFenceReq); 2379 swapl(&stuff->fid); 2380 2381 return ProcSyncQueryFence(client); 2382} 2383 2384static int 2385SProcSyncAwaitFence(ClientPtr client) 2386{ 2387 REQUEST(xSyncAwaitFenceReq); 2388 swaps(&stuff->length); 2389 REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq); 2390 SwapRestL(stuff); 2391 2392 return ProcSyncAwaitFence(client); 2393} 2394 2395static int 2396SProcSyncDispatch(ClientPtr client) 2397{ 2398 REQUEST(xReq); 2399 2400 switch (stuff->data) { 2401 case X_SyncInitialize: 2402 return SProcSyncInitialize(client); 2403 case X_SyncListSystemCounters: 2404 return SProcSyncListSystemCounters(client); 2405 case X_SyncCreateCounter: 2406 return SProcSyncCreateCounter(client); 2407 case X_SyncSetCounter: 2408 return SProcSyncSetCounter(client); 2409 case X_SyncChangeCounter: 2410 return SProcSyncChangeCounter(client); 2411 case X_SyncQueryCounter: 2412 return SProcSyncQueryCounter(client); 2413 case X_SyncDestroyCounter: 2414 return SProcSyncDestroyCounter(client); 2415 case X_SyncAwait: 2416 return SProcSyncAwait(client); 2417 case X_SyncCreateAlarm: 2418 return SProcSyncCreateAlarm(client); 2419 case X_SyncChangeAlarm: 2420 return SProcSyncChangeAlarm(client); 2421 case X_SyncQueryAlarm: 2422 return SProcSyncQueryAlarm(client); 2423 case X_SyncDestroyAlarm: 2424 return SProcSyncDestroyAlarm(client); 2425 case X_SyncSetPriority: 2426 return SProcSyncSetPriority(client); 2427 case X_SyncGetPriority: 2428 return SProcSyncGetPriority(client); 2429 case X_SyncCreateFence: 2430 return SProcSyncCreateFence(client); 2431 case X_SyncTriggerFence: 2432 return SProcSyncTriggerFence(client); 2433 case X_SyncResetFence: 2434 return SProcSyncResetFence(client); 2435 case X_SyncDestroyFence: 2436 return SProcSyncDestroyFence(client); 2437 case X_SyncQueryFence: 2438 return SProcSyncQueryFence(client); 2439 case X_SyncAwaitFence: 2440 return SProcSyncAwaitFence(client); 2441 default: 2442 return BadRequest; 2443 } 2444} 2445 2446/* 2447 * Event Swapping 2448 */ 2449 2450static void 2451SCounterNotifyEvent(xSyncCounterNotifyEvent * from, 2452 xSyncCounterNotifyEvent * to) 2453{ 2454 to->type = from->type; 2455 to->kind = from->kind; 2456 cpswaps(from->sequenceNumber, to->sequenceNumber); 2457 cpswapl(from->counter, to->counter); 2458 cpswapl(from->wait_value_lo, to->wait_value_lo); 2459 cpswapl(from->wait_value_hi, to->wait_value_hi); 2460 cpswapl(from->counter_value_lo, to->counter_value_lo); 2461 cpswapl(from->counter_value_hi, to->counter_value_hi); 2462 cpswapl(from->time, to->time); 2463 cpswaps(from->count, to->count); 2464 to->destroyed = from->destroyed; 2465} 2466 2467static void 2468SAlarmNotifyEvent(xSyncAlarmNotifyEvent * from, xSyncAlarmNotifyEvent * to) 2469{ 2470 to->type = from->type; 2471 to->kind = from->kind; 2472 cpswaps(from->sequenceNumber, to->sequenceNumber); 2473 cpswapl(from->alarm, to->alarm); 2474 cpswapl(from->counter_value_lo, to->counter_value_lo); 2475 cpswapl(from->counter_value_hi, to->counter_value_hi); 2476 cpswapl(from->alarm_value_lo, to->alarm_value_lo); 2477 cpswapl(from->alarm_value_hi, to->alarm_value_hi); 2478 cpswapl(from->time, to->time); 2479 to->state = from->state; 2480} 2481 2482/* 2483 * ** Close everything down. ** This is fairly simple for now. 2484 */ 2485/* ARGSUSED */ 2486static void 2487SyncResetProc(ExtensionEntry * extEntry) 2488{ 2489 RTCounter = 0; 2490} 2491 2492/* 2493 * ** Initialise the extension. 2494 */ 2495void 2496SyncExtensionInit(void) 2497{ 2498 ExtensionEntry *extEntry; 2499 int s; 2500 2501 for (s = 0; s < screenInfo.numScreens; s++) 2502 miSyncSetup(screenInfo.screens[s]); 2503 2504 if (RTCounter == 0) { 2505 RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter"); 2506 xorg_list_init(&SysCounterList); 2507 } 2508 RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm"); 2509 RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait"); 2510 RTFence = CreateNewResourceType(FreeFence, "SyncFence"); 2511 if (RTAwait) 2512 RTAwait |= RC_NEVERRETAIN; 2513 RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient"); 2514 if (RTAlarmClient) 2515 RTAlarmClient |= RC_NEVERRETAIN; 2516 2517 if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 || 2518 RTAlarmClient == 0 || 2519 (extEntry = AddExtension(SYNC_NAME, 2520 XSyncNumberEvents, XSyncNumberErrors, 2521 ProcSyncDispatch, SProcSyncDispatch, 2522 SyncResetProc, StandardMinorOpcode)) == NULL) { 2523 ErrorF("Sync Extension %d.%d failed to Initialise\n", 2524 SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION); 2525 return; 2526 } 2527 2528 SyncEventBase = extEntry->eventBase; 2529 SyncErrorBase = extEntry->errorBase; 2530 EventSwapVector[SyncEventBase + XSyncCounterNotify] = 2531 (EventSwapPtr) SCounterNotifyEvent; 2532 EventSwapVector[SyncEventBase + XSyncAlarmNotify] = 2533 (EventSwapPtr) SAlarmNotifyEvent; 2534 2535 SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter); 2536 SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm); 2537 SetResourceTypeErrorValue(RTFence, SyncErrorBase + XSyncBadFence); 2538 2539 /* 2540 * Although SERVERTIME is implemented by the OS layer, we initialise it 2541 * here because doing it in OsInit() is too early. The resource database 2542 * is not initialised when OsInit() is called. This is just about OK 2543 * because there is always a servertime counter. 2544 */ 2545 SyncInitServerTime(); 2546 SyncInitIdleTime(); 2547 2548#ifdef DEBUG 2549 fprintf(stderr, "Sync Extension %d.%d\n", 2550 SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION); 2551#endif 2552} 2553 2554/* 2555 * ***** SERVERTIME implementation - should go in its own file in OS directory? 2556 */ 2557 2558static void *ServertimeCounter; 2559static XSyncValue Now; 2560static XSyncValue *pnext_time; 2561 2562#define GetTime()\ 2563{\ 2564 unsigned long millis = GetTimeInMillis();\ 2565 unsigned long maxis = XSyncValueHigh32(Now);\ 2566 if (millis < XSyncValueLow32(Now)) maxis++;\ 2567 XSyncIntsToValue(&Now, millis, maxis);\ 2568} 2569 2570/* 2571*** Server Block Handler 2572*** code inspired by multibuffer extension (now deprecated) 2573 */ 2574 /*ARGSUSED*/ static void 2575ServertimeBlockHandler(void *env, struct timeval **wt, void *LastSelectMask) 2576{ 2577 XSyncValue delay; 2578 unsigned long timeout; 2579 2580 if (pnext_time) { 2581 GetTime(); 2582 2583 if (XSyncValueGreaterOrEqual(Now, *pnext_time)) { 2584 timeout = 0; 2585 } 2586 else { 2587 Bool overflow; 2588 2589 XSyncValueSubtract(&delay, *pnext_time, Now, &overflow); 2590 (void) overflow; 2591 timeout = XSyncValueLow32(delay); 2592 } 2593 AdjustWaitForDelay(wt, timeout); /* os/utils.c */ 2594 } 2595} 2596 2597/* 2598*** Wakeup Handler 2599 */ 2600 /*ARGSUSED*/ static void 2601ServertimeWakeupHandler(void *env, int rc, void *LastSelectMask) 2602{ 2603 if (pnext_time) { 2604 GetTime(); 2605 2606 if (XSyncValueGreaterOrEqual(Now, *pnext_time)) { 2607 SyncChangeCounter(ServertimeCounter, Now); 2608 } 2609 } 2610} 2611 2612static void 2613ServertimeQueryValue(void *pCounter, CARD64 * pValue_return) 2614{ 2615 GetTime(); 2616 *pValue_return = Now; 2617} 2618 2619static void 2620ServertimeBracketValues(void *pCounter, CARD64 * pbracket_less, 2621 CARD64 * pbracket_greater) 2622{ 2623 if (!pnext_time && pbracket_greater) { 2624 RegisterBlockAndWakeupHandlers(ServertimeBlockHandler, 2625 ServertimeWakeupHandler, NULL); 2626 } 2627 else if (pnext_time && !pbracket_greater) { 2628 RemoveBlockAndWakeupHandlers(ServertimeBlockHandler, 2629 ServertimeWakeupHandler, NULL); 2630 } 2631 pnext_time = pbracket_greater; 2632} 2633 2634static void 2635SyncInitServerTime(void) 2636{ 2637 CARD64 resolution; 2638 2639 XSyncIntsToValue(&Now, GetTimeInMillis(), 0); 2640 XSyncIntToValue(&resolution, 4); 2641 ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution, 2642 XSyncCounterNeverDecreases, 2643 ServertimeQueryValue, 2644 ServertimeBracketValues); 2645 pnext_time = NULL; 2646} 2647 2648/* 2649 * IDLETIME implementation 2650 */ 2651 2652typedef struct { 2653 XSyncValue *value_less; 2654 XSyncValue *value_greater; 2655 int deviceid; 2656} IdleCounterPriv; 2657 2658static void 2659IdleTimeQueryValue(void *pCounter, CARD64 * pValue_return) 2660{ 2661 int deviceid; 2662 CARD32 idle; 2663 2664 if (pCounter) { 2665 SyncCounter *counter = pCounter; 2666 IdleCounterPriv *priv = SysCounterGetPrivate(counter); 2667 deviceid = priv->deviceid; 2668 } 2669 else 2670 deviceid = XIAllDevices; 2671 idle = GetTimeInMillis() - LastEventTime(deviceid).milliseconds; 2672 XSyncIntsToValue(pValue_return, idle, 0); 2673} 2674 2675static void 2676IdleTimeBlockHandler(void *pCounter, struct timeval **wt, void *LastSelectMask) 2677{ 2678 SyncCounter *counter = pCounter; 2679 IdleCounterPriv *priv = SysCounterGetPrivate(counter); 2680 XSyncValue *less = priv->value_less, 2681 *greater = priv->value_greater; 2682 XSyncValue idle, old_idle; 2683 SyncTriggerList *list = counter->sync.pTriglist; 2684 SyncTrigger *trig; 2685 2686 if (!less && !greater) 2687 return; 2688 2689 old_idle = counter->value; 2690 IdleTimeQueryValue(counter, &idle); 2691 counter->value = idle; /* push, so CheckTrigger works */ 2692 2693 /** 2694 * There's an indefinite amount of time between ProcessInputEvents() 2695 * where the idle time is reset and the time we actually get here. idle 2696 * may be past the lower bracket if we dawdled with the events, so 2697 * check for whether we did reset and bomb out of select immediately. 2698 */ 2699 if (less && XSyncValueGreaterThan(idle, *less) && 2700 LastEventTimeWasReset(priv->deviceid)) { 2701 AdjustWaitForDelay(wt, 0); 2702 } else if (less && XSyncValueLessOrEqual(idle, *less)) { 2703 /* 2704 * We've been idle for less than the threshold value, and someone 2705 * wants to know about that, but now we need to know whether they 2706 * want level or edge trigger. Check the trigger list against the 2707 * current idle time, and if any succeed, bomb out of select() 2708 * immediately so we can reschedule. 2709 */ 2710 2711 for (list = counter->sync.pTriglist; list; list = list->next) { 2712 trig = list->pTrigger; 2713 if (trig->CheckTrigger(trig, old_idle)) { 2714 AdjustWaitForDelay(wt, 0); 2715 break; 2716 } 2717 } 2718 /* 2719 * We've been called exactly on the idle time, but we have a 2720 * NegativeTransition trigger which requires a transition from an 2721 * idle time greater than this. Schedule a wakeup for the next 2722 * millisecond so we won't miss a transition. 2723 */ 2724 if (XSyncValueEqual(idle, *less)) 2725 AdjustWaitForDelay(wt, 1); 2726 } 2727 else if (greater) { 2728 /* 2729 * There's a threshold in the positive direction. If we've been 2730 * idle less than it, schedule a wakeup for sometime in the future. 2731 * If we've been idle more than it, and someone wants to know about 2732 * that level-triggered, schedule an immediate wakeup. 2733 */ 2734 2735 if (XSyncValueLessThan(idle, *greater)) { 2736 XSyncValue value; 2737 Bool overflow; 2738 2739 XSyncValueSubtract(&value, *greater, idle, &overflow); 2740 AdjustWaitForDelay(wt, XSyncValueLow32(value)); 2741 } 2742 else { 2743 for (list = counter->sync.pTriglist; list; 2744 list = list->next) { 2745 trig = list->pTrigger; 2746 if (trig->CheckTrigger(trig, old_idle)) { 2747 AdjustWaitForDelay(wt, 0); 2748 break; 2749 } 2750 } 2751 } 2752 } 2753 2754 counter->value = old_idle; /* pop */ 2755} 2756 2757static void 2758IdleTimeCheckBrackets(SyncCounter *counter, XSyncValue idle, XSyncValue *less, XSyncValue *greater) 2759{ 2760 if ((greater && XSyncValueGreaterOrEqual(idle, *greater)) || 2761 (less && XSyncValueLessOrEqual(idle, *less))) { 2762 SyncChangeCounter(counter, idle); 2763 } 2764 else 2765 SyncUpdateCounter(counter, idle); 2766} 2767 2768static void 2769IdleTimeWakeupHandler(void *pCounter, int rc, void *LastSelectMask) 2770{ 2771 SyncCounter *counter = pCounter; 2772 IdleCounterPriv *priv = SysCounterGetPrivate(counter); 2773 XSyncValue *less = priv->value_less, 2774 *greater = priv->value_greater; 2775 XSyncValue idle; 2776 2777 if (!less && !greater) 2778 return; 2779 2780 IdleTimeQueryValue(pCounter, &idle); 2781 2782 /* 2783 There is no guarantee for the WakeupHandler to be called within a specific 2784 timeframe. Idletime may go to 0, but by the time we get here, it may be 2785 non-zero and alarms for a pos. transition on 0 won't get triggered. 2786 https://bugs.freedesktop.org/show_bug.cgi?id=70476 2787 */ 2788 if (LastEventTimeWasReset(priv->deviceid)) { 2789 LastEventTimeToggleResetFlag(priv->deviceid, FALSE); 2790 if (!XSyncValueIsZero(idle)) { 2791 XSyncValue zero; 2792 XSyncIntsToValue(&zero, 0, 0); 2793 IdleTimeCheckBrackets(counter, zero, less, greater); 2794 less = priv->value_less; 2795 greater = priv->value_greater; 2796 } 2797 } 2798 2799 IdleTimeCheckBrackets(counter, idle, less, greater); 2800} 2801 2802static void 2803IdleTimeBracketValues(void *pCounter, CARD64 * pbracket_less, 2804 CARD64 * pbracket_greater) 2805{ 2806 SyncCounter *counter = pCounter; 2807 IdleCounterPriv *priv = SysCounterGetPrivate(counter); 2808 XSyncValue *less = priv->value_less, 2809 *greater = priv->value_greater; 2810 Bool registered = (less || greater); 2811 2812 if (registered && !pbracket_less && !pbracket_greater) { 2813 RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler, 2814 IdleTimeWakeupHandler, pCounter); 2815 } 2816 else if (!registered && (pbracket_less || pbracket_greater)) { 2817 /* Reset flag must be zero so we don't force a idle timer reset on 2818 the first wakeup */ 2819 LastEventTimeToggleResetAll(FALSE); 2820 RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler, 2821 IdleTimeWakeupHandler, pCounter); 2822 } 2823 2824 priv->value_greater = pbracket_greater; 2825 priv->value_less = pbracket_less; 2826} 2827 2828static SyncCounter* 2829init_system_idle_counter(const char *name, int deviceid) 2830{ 2831 CARD64 resolution; 2832 XSyncValue idle; 2833 SyncCounter *idle_time_counter; 2834 2835 IdleTimeQueryValue(NULL, &idle); 2836 XSyncIntToValue(&resolution, 4); 2837 2838 idle_time_counter = SyncCreateSystemCounter(name, idle, resolution, 2839 XSyncCounterUnrestricted, 2840 IdleTimeQueryValue, 2841 IdleTimeBracketValues); 2842 2843 if (idle_time_counter != NULL) { 2844 IdleCounterPriv *priv = malloc(sizeof(IdleCounterPriv)); 2845 2846 priv->value_less = priv->value_greater = NULL; 2847 priv->deviceid = deviceid; 2848 2849 idle_time_counter->pSysCounterInfo->private = priv; 2850 } 2851 2852 return idle_time_counter; 2853} 2854 2855static void 2856SyncInitIdleTime(void) 2857{ 2858 init_system_idle_counter("IDLETIME", XIAllDevices); 2859} 2860 2861SyncCounter* 2862SyncInitDeviceIdleTime(DeviceIntPtr dev) 2863{ 2864 char timer_name[64]; 2865 sprintf(timer_name, "DEVICEIDLETIME %d", dev->id); 2866 2867 return init_system_idle_counter(timer_name, dev->id); 2868} 2869 2870void SyncRemoveDeviceIdleTime(SyncCounter *counter) 2871{ 2872 /* FreeAllResources() frees all system counters before the devices are 2873 shut down, check if there are any left before freeing the device's 2874 counter */ 2875 if (counter && !xorg_list_is_empty(&SysCounterList)) 2876 xorg_list_del(&counter->pSysCounterInfo->entry); 2877} 2878