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