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