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