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