sync.c revision f241d193
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 == XSyncPositiveTransition &&
1172		   ct != XSyncCounterNeverIncreases)
1173		 ||
1174		 (pTrigger->test_type == XSyncNegativeTransition &&
1175		  ct != XSyncCounterNeverDecreases)
1176		 )
1177	{
1178	    if (XSyncValueLessThan(pCounter->value, pTrigger->test_value))
1179	    {
1180		if (XSyncValueLessThan(pTrigger->test_value,
1181				       psci->bracket_greater))
1182		{
1183		    psci->bracket_greater = pTrigger->test_value;
1184		    pnewgtval = &psci->bracket_greater;
1185		}
1186		else
1187		if (XSyncValueGreaterThan(pTrigger->test_value,
1188					  psci->bracket_less))
1189		{
1190		    psci->bracket_less = pTrigger->test_value;
1191		    pnewltval = &psci->bracket_less;
1192		}
1193	    }
1194	}
1195    } /* end for each trigger */
1196
1197    if (pnewgtval || pnewltval)
1198    {
1199	(*psci->BracketValues)((pointer)pCounter, pnewltval, pnewgtval);
1200    }
1201}
1202
1203/*
1204 * *****  Resource delete functions
1205 */
1206
1207/* ARGSUSED */
1208static int
1209FreeAlarm(addr, id)
1210    pointer         addr;
1211    XID             id;
1212{
1213    SyncAlarm      *pAlarm = (SyncAlarm *) addr;
1214
1215    pAlarm->state = XSyncAlarmDestroyed;
1216
1217    SyncSendAlarmNotifyEvents(pAlarm);
1218
1219    /* delete event selections */
1220
1221    while (pAlarm->pEventClients)
1222	FreeResource(pAlarm->pEventClients->delete_id, RT_NONE);
1223
1224    SyncDeleteTriggerFromCounter(&pAlarm->trigger);
1225
1226    xfree(pAlarm);
1227    return Success;
1228}
1229
1230
1231/*
1232 * ** Cleanup after the destruction of a Counter
1233 */
1234/* ARGSUSED */
1235static int
1236FreeCounter(env, id)
1237    pointer         env;
1238    XID             id;
1239{
1240    SyncCounter     *pCounter = (SyncCounter *) env;
1241    SyncTriggerList *ptl, *pnext;
1242
1243    pCounter->beingDestroyed = TRUE;
1244    /* tell all the counter's triggers that the counter has been destroyed */
1245    for (ptl = pCounter->pTriglist; ptl; ptl = pnext)
1246    {
1247	(*ptl->pTrigger->CounterDestroyed)(ptl->pTrigger);
1248	pnext = ptl->next;
1249	xfree(ptl); /* destroy the trigger list as we go */
1250    }
1251    if (IsSystemCounter(pCounter))
1252    {
1253	int i, found = 0;
1254
1255	xfree(pCounter->pSysCounterInfo);
1256
1257	/* find the counter in the list of system counters and remove it */
1258
1259	if (SysCounterList)
1260	{
1261	    for (i = 0; i < SyncNumSystemCounters; i++)
1262	    {
1263		if (SysCounterList[i] == pCounter)
1264		{
1265		    found = i;
1266		    break;
1267		}
1268	    }
1269	    if (found < (SyncNumSystemCounters-1))
1270	    {
1271		for (i = found; i < SyncNumSystemCounters-1; i++)
1272		{
1273		    SysCounterList[i] = SysCounterList[i+1];
1274		}
1275	    }
1276	}
1277	SyncNumSystemCounters--;
1278    }
1279    xfree(pCounter);
1280    return Success;
1281}
1282
1283/*
1284 * ** Cleanup after Await
1285 */
1286/* ARGSUSED */
1287static int
1288FreeAwait(addr, id)
1289    pointer         addr;
1290    XID             id;
1291{
1292    SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr;
1293    SyncAwait *pAwait;
1294    int numwaits;
1295
1296    pAwait = &(pAwaitUnion+1)->await; /* first await on list */
1297
1298    /* remove triggers from counters */
1299
1300    for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits;
1301	 numwaits--, pAwait++)
1302    {
1303	/* If the counter is being destroyed, FreeCounter will delete
1304	 * the trigger list itself, so don't do it here.
1305	 */
1306	SyncCounter *pCounter = pAwait->trigger.pCounter;
1307	if (pCounter && !pCounter->beingDestroyed)
1308	    SyncDeleteTriggerFromCounter(&pAwait->trigger);
1309    }
1310    xfree(pAwaitUnion);
1311    return Success;
1312}
1313
1314/* loosely based on dix/events.c/OtherClientGone */
1315static int
1316FreeAlarmClient(value, id)
1317    pointer value; /* must conform to DeleteType */
1318    XID   id;
1319{
1320    SyncAlarm *pAlarm = (SyncAlarm *)value;
1321    SyncAlarmClientList *pCur, *pPrev;
1322
1323    for (pPrev = NULL, pCur = pAlarm->pEventClients;
1324	 pCur;
1325	 pPrev = pCur, pCur = pCur->next)
1326    {
1327	if (pCur->delete_id == id)
1328	{
1329	    if (pPrev)
1330		pPrev->next = pCur->next;
1331	    else
1332		pAlarm->pEventClients = pCur->next;
1333	    xfree(pCur);
1334	    return(Success);
1335	}
1336    }
1337    FatalError("alarm client not on event list");
1338    /*NOTREACHED*/
1339}
1340
1341
1342/*
1343 * *****  Proc functions
1344 */
1345
1346
1347/*
1348 * ** Initialize the extension
1349 */
1350static int
1351ProcSyncInitialize(client)
1352    ClientPtr       client;
1353{
1354    xSyncInitializeReply  rep;
1355    int   n;
1356
1357    REQUEST_SIZE_MATCH(xSyncInitializeReq);
1358
1359    rep.type = X_Reply;
1360    rep.sequenceNumber = client->sequence;
1361    rep.majorVersion = SYNC_MAJOR_VERSION;
1362    rep.minorVersion = SYNC_MINOR_VERSION;
1363    rep.length = 0;
1364
1365    if (client->swapped)
1366    {
1367	swaps(&rep.sequenceNumber, n);
1368    }
1369    WriteToClient(client, sizeof(rep), (char *) &rep);
1370    return (client->noClientException);
1371}
1372
1373/*
1374 * ** Get list of system counters available through the extension
1375 */
1376static int
1377ProcSyncListSystemCounters(client)
1378    ClientPtr       client;
1379{
1380    xSyncListSystemCountersReply  rep;
1381    int i, len;
1382    xSyncSystemCounter *list = NULL, *walklist = NULL;
1383
1384    REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
1385
1386    rep.type = X_Reply;
1387    rep.sequenceNumber = client->sequence;
1388    rep.nCounters = SyncNumSystemCounters;
1389
1390    for (i = len = 0; i < SyncNumSystemCounters; i++)
1391    {
1392	char *name = SysCounterList[i]->pSysCounterInfo->name;
1393	/* pad to 4 byte boundary */
1394	len += (sz_xSyncSystemCounter + strlen(name) + 3) & ~3;
1395    }
1396
1397    if (len)
1398    {
1399	walklist = list = (xSyncSystemCounter *) xalloc(len);
1400	if (!list)
1401	    return BadAlloc;
1402    }
1403
1404    rep.length = len >> 2;
1405
1406    if (client->swapped)
1407    {
1408	char n;
1409	swaps(&rep.sequenceNumber, n);
1410	swapl(&rep.length, n);
1411	swapl(&rep.nCounters, n);
1412    }
1413
1414    for (i = 0; i < SyncNumSystemCounters; i++)
1415    {
1416	int namelen;
1417	char *pname_in_reply;
1418	SysCounterInfo *psci = SysCounterList[i]->pSysCounterInfo;
1419
1420	walklist->counter = SysCounterList[i]->id;
1421	walklist->resolution_hi = XSyncValueHigh32(psci->resolution);
1422	walklist->resolution_lo = XSyncValueLow32(psci->resolution);
1423	namelen = strlen(psci->name);
1424	walklist->name_length = namelen;
1425
1426	if (client->swapped)
1427	{
1428	    char n;
1429	    swapl(&walklist->counter, n);
1430	    swapl(&walklist->resolution_hi, n);
1431	    swapl(&walklist->resolution_lo, n);
1432	    swaps(&walklist->name_length, n);
1433	}
1434
1435	pname_in_reply = ((char *)walklist) + sz_xSyncSystemCounter;
1436	strncpy(pname_in_reply, psci->name, namelen);
1437	walklist = (xSyncSystemCounter *) (((char *)walklist) +
1438				((sz_xSyncSystemCounter + namelen + 3) & ~3));
1439    }
1440
1441    WriteToClient(client, sizeof(rep), (char *) &rep);
1442    if (len)
1443    {
1444	WriteToClient(client, len, (char *) list);
1445	xfree(list);
1446    }
1447
1448    return (client->noClientException);
1449}
1450
1451/*
1452 * ** Set client Priority
1453 */
1454static int
1455ProcSyncSetPriority(client)
1456    ClientPtr       client;
1457{
1458    REQUEST(xSyncSetPriorityReq);
1459    ClientPtr priorityclient;
1460    int rc;
1461
1462    REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
1463
1464    if (stuff->id == None)
1465	priorityclient = client;
1466    else {
1467	rc = dixLookupClient(&priorityclient, stuff->id, client,
1468			     DixSetAttrAccess);
1469	if (rc != Success)
1470	    return rc;
1471    }
1472
1473    if (priorityclient->priority != stuff->priority)
1474    {
1475	priorityclient->priority = stuff->priority;
1476
1477	/*  The following will force the server back into WaitForSomething
1478	 *  so that the change in this client's priority is immediately
1479	 *  reflected.
1480	 */
1481	isItTimeToYield = TRUE;
1482	dispatchException |= DE_PRIORITYCHANGE;
1483    }
1484    return Success;
1485}
1486
1487/*
1488 * ** Get client Priority
1489 */
1490static int
1491ProcSyncGetPriority(client)
1492    ClientPtr       client;
1493{
1494    REQUEST(xSyncGetPriorityReq);
1495    xSyncGetPriorityReply rep;
1496    ClientPtr priorityclient;
1497    int rc;
1498
1499    REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
1500
1501    if (stuff->id == None)
1502	priorityclient = client;
1503    else {
1504	rc = dixLookupClient(&priorityclient, stuff->id, client,
1505			     DixGetAttrAccess);
1506	if (rc != Success)
1507	    return rc;
1508    }
1509
1510    rep.type = X_Reply;
1511    rep.length = 0;
1512    rep.sequenceNumber = client->sequence;
1513    rep.priority = priorityclient->priority;
1514
1515    if (client->swapped)
1516    {
1517	char n;
1518	swaps(&rep.sequenceNumber, n);
1519	swapl(&rep.priority, n);
1520    }
1521
1522    WriteToClient(client, sizeof(xSyncGetPriorityReply), (char *) &rep);
1523
1524    return (client->noClientException);
1525}
1526
1527/*
1528 * ** Create a new counter
1529 */
1530static int
1531ProcSyncCreateCounter(client)
1532    ClientPtr       client;
1533{
1534    REQUEST(xSyncCreateCounterReq);
1535    CARD64          initial;
1536
1537    REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
1538
1539    LEGAL_NEW_RESOURCE(stuff->cid, client);
1540
1541    XSyncIntsToValue(&initial, stuff->initial_value_lo, stuff->initial_value_hi);
1542    if (!SyncCreateCounter(client, stuff->cid, initial))
1543	return BadAlloc;
1544
1545    return (client->noClientException);
1546}
1547
1548/*
1549 * ** Set Counter value
1550 */
1551static int
1552ProcSyncSetCounter(client)
1553    ClientPtr       client;
1554{
1555    REQUEST(xSyncSetCounterReq);
1556    SyncCounter    *pCounter;
1557    CARD64	   newvalue;
1558
1559    REQUEST_SIZE_MATCH(xSyncSetCounterReq);
1560
1561    pCounter = (SyncCounter *)SecurityLookupIDByType(client, stuff->cid,
1562					   RTCounter, DixWriteAccess);
1563    if (pCounter == NULL)
1564    {
1565	client->errorValue = stuff->cid;
1566	return SyncErrorBase + XSyncBadCounter;
1567    }
1568
1569    if (IsSystemCounter(pCounter))
1570    {
1571	client->errorValue = stuff->cid;
1572	return BadAccess;
1573    }
1574
1575    XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
1576    SyncChangeCounter(pCounter, newvalue);
1577    return Success;
1578}
1579
1580/*
1581 * ** Change Counter value
1582 */
1583static int
1584ProcSyncChangeCounter(client)
1585    ClientPtr       client;
1586{
1587    REQUEST(xSyncChangeCounterReq);
1588    SyncCounter    *pCounter;
1589    CARD64          newvalue;
1590    Bool	    overflow;
1591
1592    REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
1593
1594    pCounter = (SyncCounter *) SecurityLookupIDByType(client, stuff->cid,
1595					    RTCounter, DixWriteAccess);
1596    if (pCounter == NULL)
1597    {
1598	client->errorValue = stuff->cid;
1599	return SyncErrorBase + XSyncBadCounter;
1600    }
1601
1602    if (IsSystemCounter(pCounter))
1603    {
1604	client->errorValue = stuff->cid;
1605	return BadAccess;
1606    }
1607
1608    XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
1609    XSyncValueAdd(&newvalue, pCounter->value, newvalue, &overflow);
1610    if (overflow)
1611    {
1612	/* XXX 64 bit value can't fit in 32 bits; do the best we can */
1613	client->errorValue = stuff->value_hi;
1614	return BadValue;
1615    }
1616    SyncChangeCounter(pCounter, newvalue);
1617    return Success;
1618}
1619
1620/*
1621 * ** Destroy a counter
1622 */
1623static int
1624ProcSyncDestroyCounter(client)
1625    ClientPtr       client;
1626{
1627    REQUEST(xSyncDestroyCounterReq);
1628    SyncCounter    *pCounter;
1629
1630    REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
1631
1632    pCounter = (SyncCounter *)SecurityLookupIDByType(client, stuff->counter,
1633					   RTCounter, DixDestroyAccess);
1634    if (pCounter == NULL)
1635    {
1636	client->errorValue = stuff->counter;
1637	return SyncErrorBase + XSyncBadCounter;
1638    }
1639    if (IsSystemCounter(pCounter))
1640    {
1641	client->errorValue = stuff->counter;
1642	return BadAccess;
1643    }
1644    FreeResource(pCounter->id, RT_NONE);
1645    return Success;
1646}
1647
1648
1649/*
1650 * ** Await
1651 */
1652static int
1653ProcSyncAwait(client)
1654    ClientPtr       client;
1655{
1656    REQUEST(xSyncAwaitReq);
1657    int             len, items;
1658    int             i;
1659    xSyncWaitCondition *pProtocolWaitConds;
1660    SyncAwaitUnion *pAwaitUnion;
1661    SyncAwait	   *pAwait;
1662    int		   status;
1663
1664    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
1665
1666    len = client->req_len << 2;
1667    len -= sz_xSyncAwaitReq;
1668    items = len / sz_xSyncWaitCondition;
1669
1670    if (items * sz_xSyncWaitCondition != len)
1671    {
1672	return BadLength;
1673    }
1674    if (items == 0)
1675    {
1676	client->errorValue = items; /* XXX protocol change */
1677	return BadValue;
1678    }
1679
1680    pProtocolWaitConds = (xSyncWaitCondition *) & stuff[1];
1681
1682    /*  all the memory for the entire await list is allocated
1683     *  here in one chunk
1684     */
1685    pAwaitUnion = (SyncAwaitUnion *)xalloc((items+1) * sizeof(SyncAwaitUnion));
1686    if (!pAwaitUnion)
1687	return BadAlloc;
1688
1689    /* first item is the header, remainder are real wait conditions */
1690
1691    pAwaitUnion->header.delete_id = FakeClientID(client->index);
1692    if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion))
1693    {
1694	xfree(pAwaitUnion);
1695	return BadAlloc;
1696    }
1697
1698    /* don't need to do any more memory allocation for this request! */
1699
1700    pAwaitUnion->header.client = client;
1701    pAwaitUnion->header.num_waitconditions = 0;
1702
1703    pAwait = &(pAwaitUnion+1)->await; /* skip over header */
1704    for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++)
1705    {
1706	if (pProtocolWaitConds->counter == None) /* XXX protocol change */
1707	{
1708	    /*  this should take care of removing any triggers created by
1709	     *  this request that have already been registered on counters
1710	     */
1711	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
1712	    client->errorValue = pProtocolWaitConds->counter;
1713	    return SyncErrorBase + XSyncBadCounter;
1714	}
1715
1716	/* sanity checks are in SyncInitTrigger */
1717	pAwait->trigger.pCounter = NULL;
1718	pAwait->trigger.value_type = pProtocolWaitConds->value_type;
1719	XSyncIntsToValue(&pAwait->trigger.wait_value,
1720			 pProtocolWaitConds->wait_value_lo,
1721			 pProtocolWaitConds->wait_value_hi);
1722	pAwait->trigger.test_type = pProtocolWaitConds->test_type;
1723
1724	status = SyncInitTrigger(client, &pAwait->trigger,
1725			 pProtocolWaitConds->counter, XSyncCAAllTrigger);
1726	if (status != Success)
1727	{
1728	    /*  this should take care of removing any triggers created by
1729	     *  this request that have already been registered on counters
1730	     */
1731	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
1732	    return status;
1733	}
1734	/* this is not a mistake -- same function works for both cases */
1735	pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
1736	pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
1737	XSyncIntsToValue(&pAwait->event_threshold,
1738			 pProtocolWaitConds->event_threshold_lo,
1739			 pProtocolWaitConds->event_threshold_hi);
1740	pAwait->pHeader = &pAwaitUnion->header;
1741	pAwaitUnion->header.num_waitconditions++;
1742    }
1743
1744    IgnoreClient(client);
1745
1746    /* see if any of the triggers are already true */
1747
1748    pAwait = &(pAwaitUnion+1)->await; /* skip over header */
1749    for (i = 0; i < items; i++, pAwait++)
1750    {
1751	/*  don't have to worry about NULL counters because the request
1752	 *  errors before we get here out if they occur
1753	 */
1754	if ((*pAwait->trigger.CheckTrigger)(&pAwait->trigger,
1755					    pAwait->trigger.pCounter->value))
1756	{
1757	    (*pAwait->trigger.TriggerFired)(&pAwait->trigger);
1758	    break; /* once is enough */
1759	}
1760    }
1761    return Success;
1762}
1763
1764
1765/*
1766 * ** Query a counter
1767 */
1768static int
1769ProcSyncQueryCounter(client)
1770    ClientPtr       client;
1771{
1772    REQUEST(xSyncQueryCounterReq);
1773    xSyncQueryCounterReply rep;
1774    SyncCounter    *pCounter;
1775
1776    REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
1777
1778    pCounter = (SyncCounter *)SecurityLookupIDByType(client, stuff->counter,
1779					    RTCounter, DixReadAccess);
1780    if (pCounter == NULL)
1781    {
1782	client->errorValue = stuff->counter;
1783	return SyncErrorBase + XSyncBadCounter;
1784    }
1785
1786    rep.type = X_Reply;
1787    rep.length = 0;
1788    rep.sequenceNumber = client->sequence;
1789
1790    /* if system counter, ask it what the current value is */
1791
1792    if (IsSystemCounter(pCounter))
1793    {
1794	(*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
1795						  &pCounter->value);
1796    }
1797
1798    rep.value_hi = XSyncValueHigh32(pCounter->value);
1799    rep.value_lo = XSyncValueLow32(pCounter->value);
1800    if (client->swapped)
1801    {
1802	char n;
1803	swaps(&rep.sequenceNumber, n);
1804	swapl(&rep.length, n);
1805	swapl(&rep.value_hi, n);
1806	swapl(&rep.value_lo, n);
1807    }
1808    WriteToClient(client, sizeof(xSyncQueryCounterReply), (char *) &rep);
1809    return (client->noClientException);
1810}
1811
1812
1813/*
1814 * ** Create Alarm
1815 */
1816static int
1817ProcSyncCreateAlarm(client)
1818    ClientPtr       client;
1819{
1820    REQUEST(xSyncCreateAlarmReq);
1821    SyncAlarm      *pAlarm;
1822    int             status;
1823    unsigned long   len, vmask;
1824    SyncTrigger	    *pTrigger;
1825
1826    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
1827
1828    LEGAL_NEW_RESOURCE(stuff->id, client);
1829
1830    vmask = stuff->valueMask;
1831    len = client->req_len - (sizeof(xSyncCreateAlarmReq) >> 2);
1832    /* the "extra" call to Ones accounts for the presence of 64 bit values */
1833    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
1834	return BadLength;
1835
1836    if (!(pAlarm = (SyncAlarm *) xalloc(sizeof(SyncAlarm))))
1837    {
1838	return BadAlloc;
1839    }
1840
1841    /* set up defaults */
1842
1843    pTrigger = &pAlarm->trigger;
1844    pTrigger->pCounter = NULL;
1845    pTrigger->value_type = XSyncAbsolute;
1846    XSyncIntToValue(&pTrigger->wait_value, 0L);
1847    pTrigger->test_type = XSyncPositiveComparison;
1848    pTrigger->TriggerFired = SyncAlarmTriggerFired;
1849    pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed;
1850    status = SyncInitTrigger(client, pTrigger, None, XSyncCAAllTrigger);
1851    if (status != Success)
1852    {
1853	xfree(pAlarm);
1854	return status;
1855    }
1856
1857    pAlarm->client = client;
1858    pAlarm->alarm_id = stuff->id;
1859    XSyncIntToValue(&pAlarm->delta, 1L);
1860    pAlarm->events = TRUE;
1861    pAlarm->state = XSyncAlarmInactive;
1862    pAlarm->pEventClients = NULL;
1863    status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
1864				       (CARD32 *)&stuff[1]);
1865    if (status != Success)
1866    {
1867	xfree(pAlarm);
1868	return status;
1869    }
1870
1871    if (!AddResource(stuff->id, RTAlarm, pAlarm))
1872    {
1873	xfree(pAlarm);
1874	return BadAlloc;
1875    }
1876
1877    /*  see if alarm already triggered.  NULL counter will not trigger
1878     *  in CreateAlarm and sets alarm state to Inactive.
1879     */
1880
1881    if (!pTrigger->pCounter)
1882    {
1883	pAlarm->state = XSyncAlarmInactive; /* XXX protocol change */
1884    }
1885    else if ((*pTrigger->CheckTrigger)(pTrigger, pTrigger->pCounter->value))
1886    {
1887	(*pTrigger->TriggerFired)(pTrigger);
1888    }
1889
1890    return Success;
1891}
1892
1893/*
1894 * ** Change Alarm
1895 */
1896static int
1897ProcSyncChangeAlarm(client)
1898    ClientPtr       client;
1899{
1900    REQUEST(xSyncChangeAlarmReq);
1901    SyncAlarm   *pAlarm;
1902    long        vmask;
1903    int         len, status;
1904
1905    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
1906
1907    if (!(pAlarm = (SyncAlarm *)SecurityLookupIDByType(client, stuff->alarm,
1908					      RTAlarm, DixWriteAccess)))
1909    {
1910	client->errorValue = stuff->alarm;
1911	return SyncErrorBase + XSyncBadAlarm;
1912    }
1913
1914    vmask = stuff->valueMask;
1915    len = client->req_len - (sizeof(xSyncChangeAlarmReq) >> 2);
1916    /* the "extra" call to Ones accounts for the presence of 64 bit values */
1917    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
1918	return BadLength;
1919
1920    if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
1921					    (CARD32 *)&stuff[1])) != Success)
1922	return status;
1923
1924    /*  see if alarm already triggered.  NULL counter WILL trigger
1925     *  in ChangeAlarm.
1926     */
1927
1928    if (!pAlarm->trigger.pCounter ||
1929	(*pAlarm->trigger.CheckTrigger)(&pAlarm->trigger,
1930					pAlarm->trigger.pCounter->value))
1931    {
1932	(*pAlarm->trigger.TriggerFired)(&pAlarm->trigger);
1933    }
1934    return Success;
1935}
1936
1937static int
1938ProcSyncQueryAlarm(client)
1939    ClientPtr       client;
1940{
1941    REQUEST(xSyncQueryAlarmReq);
1942    SyncAlarm      *pAlarm;
1943    xSyncQueryAlarmReply rep;
1944    SyncTrigger    *pTrigger;
1945
1946    REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
1947
1948    pAlarm = (SyncAlarm *)SecurityLookupIDByType(client, stuff->alarm,
1949						RTAlarm, DixReadAccess);
1950    if (!pAlarm)
1951    {
1952	client->errorValue = stuff->alarm;
1953	return (SyncErrorBase + XSyncBadAlarm);
1954    }
1955
1956    rep.type = X_Reply;
1957    rep.length = (sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply)) >> 2;
1958    rep.sequenceNumber = client->sequence;
1959
1960    pTrigger = &pAlarm->trigger;
1961    rep.counter = (pTrigger->pCounter) ? pTrigger->pCounter->id : None;
1962
1963#if 0 /* XXX unclear what to do, depends on whether relative value-types
1964       * are "consumed" immediately and are considered absolute from then
1965       * on.
1966       */
1967    rep.value_type = pTrigger->value_type;
1968    rep.wait_value_hi = XSyncValueHigh32(pTrigger->wait_value);
1969    rep.wait_value_lo = XSyncValueLow32(pTrigger->wait_value);
1970#else
1971    rep.value_type = XSyncAbsolute;
1972    rep.wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
1973    rep.wait_value_lo = XSyncValueLow32(pTrigger->test_value);
1974#endif
1975
1976    rep.test_type = pTrigger->test_type;
1977    rep.delta_hi = XSyncValueHigh32(pAlarm->delta);
1978    rep.delta_lo = XSyncValueLow32(pAlarm->delta);
1979    rep.events = pAlarm->events;
1980    rep.state = pAlarm->state;
1981
1982    if (client->swapped)
1983    {
1984	char n;
1985	swaps(&rep.sequenceNumber, n);
1986	swapl(&rep.length, n);
1987	swapl(&rep.counter, n);
1988	swapl(&rep.wait_value_hi, n);
1989	swapl(&rep.wait_value_lo, n);
1990	swapl(&rep.test_type, n);
1991	swapl(&rep.delta_hi, n);
1992	swapl(&rep.delta_lo, n);
1993    }
1994
1995    WriteToClient(client, sizeof(xSyncQueryAlarmReply), (char *) &rep);
1996    return (client->noClientException);
1997}
1998
1999
2000static int
2001ProcSyncDestroyAlarm(client)
2002    ClientPtr       client;
2003{
2004    REQUEST(xSyncDestroyAlarmReq);
2005
2006    REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
2007
2008    if (!((SyncAlarm *)SecurityLookupIDByType(client, stuff->alarm,
2009					      RTAlarm, DixDestroyAccess)))
2010    {
2011	client->errorValue = stuff->alarm;
2012	return SyncErrorBase + XSyncBadAlarm;
2013    }
2014
2015    FreeResource(stuff->alarm, RT_NONE);
2016    return (client->noClientException);
2017}
2018
2019/*
2020 * ** Given an extension request, call the appropriate request procedure
2021 */
2022static int
2023ProcSyncDispatch(client)
2024    ClientPtr       client;
2025{
2026    REQUEST(xReq);
2027
2028    switch (stuff->data)
2029    {
2030
2031      case X_SyncInitialize:
2032	return ProcSyncInitialize(client);
2033      case X_SyncListSystemCounters:
2034	return ProcSyncListSystemCounters(client);
2035      case X_SyncCreateCounter:
2036	return ProcSyncCreateCounter(client);
2037      case X_SyncSetCounter:
2038	return ProcSyncSetCounter(client);
2039      case X_SyncChangeCounter:
2040	return ProcSyncChangeCounter(client);
2041      case X_SyncQueryCounter:
2042	return ProcSyncQueryCounter(client);
2043      case X_SyncDestroyCounter:
2044	return ProcSyncDestroyCounter(client);
2045      case X_SyncAwait:
2046	return ProcSyncAwait(client);
2047      case X_SyncCreateAlarm:
2048	return ProcSyncCreateAlarm(client);
2049      case X_SyncChangeAlarm:
2050	return ProcSyncChangeAlarm(client);
2051      case X_SyncQueryAlarm:
2052	return ProcSyncQueryAlarm(client);
2053      case X_SyncDestroyAlarm:
2054	return ProcSyncDestroyAlarm(client);
2055      case X_SyncSetPriority:
2056	return ProcSyncSetPriority(client);
2057      case X_SyncGetPriority:
2058	return ProcSyncGetPriority(client);
2059      default:
2060	return BadRequest;
2061    }
2062}
2063
2064/*
2065 * Boring Swapping stuff ...
2066 */
2067
2068static int
2069SProcSyncInitialize(client)
2070    ClientPtr       client;
2071{
2072    REQUEST(xSyncInitializeReq);
2073    char   n;
2074
2075    swaps(&stuff->length, n);
2076    REQUEST_SIZE_MATCH (xSyncInitializeReq);
2077
2078    return ProcSyncInitialize(client);
2079}
2080
2081static int
2082SProcSyncListSystemCounters(client)
2083    ClientPtr       client;
2084{
2085    REQUEST(xSyncListSystemCountersReq);
2086    char   n;
2087
2088    swaps(&stuff->length, n);
2089    REQUEST_SIZE_MATCH (xSyncListSystemCountersReq);
2090
2091    return ProcSyncListSystemCounters(client);
2092}
2093
2094static int
2095SProcSyncCreateCounter(client)
2096    ClientPtr       client;
2097{
2098    REQUEST(xSyncCreateCounterReq);
2099    char   n;
2100
2101    swaps(&stuff->length, n);
2102    REQUEST_SIZE_MATCH (xSyncCreateCounterReq);
2103    swapl(&stuff->cid, n);
2104    swapl(&stuff->initial_value_lo, n);
2105    swapl(&stuff->initial_value_hi, n);
2106
2107    return ProcSyncCreateCounter(client);
2108}
2109
2110static int
2111SProcSyncSetCounter(client)
2112    ClientPtr       client;
2113{
2114    REQUEST(xSyncSetCounterReq);
2115    char   n;
2116
2117    swaps(&stuff->length, n);
2118    REQUEST_SIZE_MATCH (xSyncSetCounterReq);
2119    swapl(&stuff->cid, n);
2120    swapl(&stuff->value_lo, n);
2121    swapl(&stuff->value_hi, n);
2122
2123    return ProcSyncSetCounter(client);
2124}
2125
2126static int
2127SProcSyncChangeCounter(client)
2128    ClientPtr       client;
2129{
2130    REQUEST(xSyncChangeCounterReq);
2131    char   n;
2132
2133    swaps(&stuff->length, n);
2134    REQUEST_SIZE_MATCH (xSyncChangeCounterReq);
2135    swapl(&stuff->cid, n);
2136    swapl(&stuff->value_lo, n);
2137    swapl(&stuff->value_hi, n);
2138
2139    return ProcSyncChangeCounter(client);
2140}
2141
2142static int
2143SProcSyncQueryCounter(client)
2144    ClientPtr       client;
2145{
2146    REQUEST(xSyncQueryCounterReq);
2147    char   n;
2148
2149    swaps(&stuff->length, n);
2150    REQUEST_SIZE_MATCH (xSyncQueryCounterReq);
2151    swapl(&stuff->counter, n);
2152
2153    return ProcSyncQueryCounter(client);
2154}
2155
2156static int
2157SProcSyncDestroyCounter(client)
2158    ClientPtr       client;
2159{
2160    REQUEST(xSyncDestroyCounterReq);
2161    char   n;
2162
2163    swaps(&stuff->length, n);
2164    REQUEST_SIZE_MATCH (xSyncDestroyCounterReq);
2165    swapl(&stuff->counter, n);
2166
2167    return ProcSyncDestroyCounter(client);
2168}
2169
2170static int
2171SProcSyncAwait(client)
2172    ClientPtr       client;
2173{
2174    REQUEST(xSyncAwaitReq);
2175    char   n;
2176
2177    swaps(&stuff->length, n);
2178    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
2179    SwapRestL(stuff);
2180
2181    return ProcSyncAwait(client);
2182}
2183
2184
2185static int
2186SProcSyncCreateAlarm(client)
2187    ClientPtr       client;
2188{
2189    REQUEST(xSyncCreateAlarmReq);
2190    char   n;
2191
2192    swaps(&stuff->length, n);
2193    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
2194    swapl(&stuff->id, n);
2195    swapl(&stuff->valueMask, n);
2196    SwapRestL(stuff);
2197
2198    return ProcSyncCreateAlarm(client);
2199}
2200
2201static int
2202SProcSyncChangeAlarm(client)
2203    ClientPtr       client;
2204{
2205    REQUEST(xSyncChangeAlarmReq);
2206    char   n;
2207
2208    swaps(&stuff->length, n);
2209    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
2210    swapl(&stuff->alarm, n);
2211    swapl(&stuff->valueMask, n);
2212    SwapRestL(stuff);
2213    return ProcSyncChangeAlarm(client);
2214}
2215
2216static int
2217SProcSyncQueryAlarm(client)
2218    ClientPtr       client;
2219{
2220    REQUEST(xSyncQueryAlarmReq);
2221    char   n;
2222
2223    swaps(&stuff->length, n);
2224    REQUEST_SIZE_MATCH (xSyncQueryAlarmReq);
2225    swapl(&stuff->alarm, n);
2226
2227    return ProcSyncQueryAlarm(client);
2228}
2229
2230static int
2231SProcSyncDestroyAlarm(client)
2232    ClientPtr       client;
2233{
2234    REQUEST(xSyncDestroyAlarmReq);
2235    char   n;
2236
2237    swaps(&stuff->length, n);
2238    REQUEST_SIZE_MATCH (xSyncDestroyAlarmReq);
2239    swapl(&stuff->alarm, n);
2240
2241    return ProcSyncDestroyAlarm(client);
2242}
2243
2244static int
2245SProcSyncSetPriority(client)
2246    ClientPtr       client;
2247{
2248    REQUEST(xSyncSetPriorityReq);
2249    char   n;
2250
2251    swaps(&stuff->length, n);
2252    REQUEST_SIZE_MATCH (xSyncSetPriorityReq);
2253    swapl(&stuff->id, n);
2254    swapl(&stuff->priority, n);
2255
2256    return ProcSyncSetPriority(client);
2257}
2258
2259static int
2260SProcSyncGetPriority(client)
2261    ClientPtr       client;
2262{
2263    REQUEST(xSyncGetPriorityReq);
2264    char   n;
2265
2266    swaps(&stuff->length, n);
2267    REQUEST_SIZE_MATCH (xSyncGetPriorityReq);
2268    swapl(&stuff->id, n);
2269
2270    return ProcSyncGetPriority(client);
2271}
2272
2273
2274static int
2275SProcSyncDispatch(client)
2276    ClientPtr       client;
2277{
2278    REQUEST(xReq);
2279
2280    switch (stuff->data)
2281    {
2282      case X_SyncInitialize:
2283	return SProcSyncInitialize(client);
2284      case X_SyncListSystemCounters:
2285	return SProcSyncListSystemCounters(client);
2286      case X_SyncCreateCounter:
2287	return SProcSyncCreateCounter(client);
2288      case X_SyncSetCounter:
2289	return SProcSyncSetCounter(client);
2290      case X_SyncChangeCounter:
2291	return SProcSyncChangeCounter(client);
2292      case X_SyncQueryCounter:
2293	return SProcSyncQueryCounter(client);
2294      case X_SyncDestroyCounter:
2295	return SProcSyncDestroyCounter(client);
2296      case X_SyncAwait:
2297	return SProcSyncAwait(client);
2298      case X_SyncCreateAlarm:
2299	return SProcSyncCreateAlarm(client);
2300      case X_SyncChangeAlarm:
2301	return SProcSyncChangeAlarm(client);
2302      case X_SyncQueryAlarm:
2303	return SProcSyncQueryAlarm(client);
2304      case X_SyncDestroyAlarm:
2305	return SProcSyncDestroyAlarm(client);
2306      case X_SyncSetPriority:
2307	return SProcSyncSetPriority(client);
2308      case X_SyncGetPriority:
2309	return SProcSyncGetPriority(client);
2310      default:
2311	return BadRequest;
2312    }
2313}
2314
2315/*
2316 * Event Swapping
2317 */
2318
2319static void
2320SCounterNotifyEvent(from, to)
2321    xSyncCounterNotifyEvent *from, *to;
2322{
2323    to->type = from->type;
2324    to->kind = from->kind;
2325    cpswaps(from->sequenceNumber, to->sequenceNumber);
2326    cpswapl(from->counter, to->counter);
2327    cpswapl(from->wait_value_lo, to->wait_value_lo);
2328    cpswapl(from->wait_value_hi, to->wait_value_hi);
2329    cpswapl(from->counter_value_lo, to->counter_value_lo);
2330    cpswapl(from->counter_value_hi, to->counter_value_hi);
2331    cpswapl(from->time, to->time);
2332    cpswaps(from->count, to->count);
2333    to->destroyed = from->destroyed;
2334}
2335
2336
2337static void
2338SAlarmNotifyEvent(from, to)
2339    xSyncAlarmNotifyEvent *from, *to;
2340{
2341    to->type = from->type;
2342    to->kind = from->kind;
2343    cpswaps(from->sequenceNumber, to->sequenceNumber);
2344    cpswapl(from->alarm, to->alarm);
2345    cpswapl(from->counter_value_lo, to->counter_value_lo);
2346    cpswapl(from->counter_value_hi, to->counter_value_hi);
2347    cpswapl(from->alarm_value_lo, to->alarm_value_lo);
2348    cpswapl(from->alarm_value_hi, to->alarm_value_hi);
2349    cpswapl(from->time, to->time);
2350    to->state = from->state;
2351}
2352
2353/*
2354 * ** Close everything down. ** This is fairly simple for now.
2355 */
2356/* ARGSUSED */
2357static void
2358SyncResetProc(extEntry)
2359    ExtensionEntry *extEntry;
2360{
2361    xfree(SysCounterList);
2362    SysCounterList = NULL;
2363    RTCounter = 0;
2364}
2365
2366
2367/*
2368 * ** Initialise the extension.
2369 */
2370void
2371SyncExtensionInit(INITARGS)
2372{
2373    ExtensionEntry *extEntry;
2374
2375    if (RTCounter == 0)
2376    {
2377	RTCounter = CreateNewResourceType(FreeCounter);
2378    }
2379    RTAlarm = CreateNewResourceType(FreeAlarm);
2380    RTAwait = CreateNewResourceType(FreeAwait)|RC_NEVERRETAIN;
2381    RTAlarmClient = CreateNewResourceType(FreeAlarmClient)|RC_NEVERRETAIN;
2382
2383    if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 ||
2384	RTAlarmClient == 0 ||
2385	(extEntry = AddExtension(SYNC_NAME,
2386				 XSyncNumberEvents, XSyncNumberErrors,
2387				 ProcSyncDispatch, SProcSyncDispatch,
2388				 SyncResetProc,
2389				 StandardMinorOpcode)) == NULL)
2390    {
2391	ErrorF("Sync Extension %d.%d failed to Initialise\n",
2392		SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
2393	return;
2394    }
2395
2396    SyncEventBase = extEntry->eventBase;
2397    SyncErrorBase = extEntry->errorBase;
2398    EventSwapVector[SyncEventBase + XSyncCounterNotify] = (EventSwapPtr) SCounterNotifyEvent;
2399    EventSwapVector[SyncEventBase + XSyncAlarmNotify] = (EventSwapPtr) SAlarmNotifyEvent;
2400
2401    /*
2402     * Although SERVERTIME is implemented by the OS layer, we initialise it
2403     * here because doing it in OsInit() is too early. The resource database
2404     * is not initialised when OsInit() is called. This is just about OK
2405     * because there is always a servertime counter.
2406     */
2407    SyncInitServerTime();
2408    SyncInitIdleTime();
2409
2410#ifdef DEBUG
2411    fprintf(stderr, "Sync Extension %d.%d\n",
2412	    SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
2413#endif
2414}
2415
2416
2417/*
2418 * ***** SERVERTIME implementation - should go in its own file in OS directory?
2419 */
2420
2421
2422
2423static pointer ServertimeCounter;
2424static XSyncValue Now;
2425static XSyncValue *pnext_time;
2426
2427#define GetTime()\
2428{\
2429    unsigned long millis = GetTimeInMillis();\
2430    unsigned long maxis = XSyncValueHigh32(Now);\
2431    if (millis < XSyncValueLow32(Now)) maxis++;\
2432    XSyncIntsToValue(&Now, millis, maxis);\
2433}
2434
2435/*
2436*** Server Block Handler
2437*** code inspired by multibuffer extension
2438 */
2439/*ARGSUSED*/
2440static void ServertimeBlockHandler(env, wt, LastSelectMask)
2441pointer env;
2442struct timeval **wt;
2443pointer LastSelectMask;
2444{
2445    XSyncValue delay;
2446    unsigned long timeout;
2447
2448    if (pnext_time)
2449    {
2450        GetTime();
2451
2452        if (XSyncValueGreaterOrEqual(Now, *pnext_time))
2453	{
2454            timeout = 0;
2455        }
2456	else
2457	{
2458	    Bool overflow;
2459            XSyncValueSubtract(&delay, *pnext_time, Now, &overflow);
2460	    (void)overflow;
2461            timeout = XSyncValueLow32(delay);
2462        }
2463        AdjustWaitForDelay(wt, timeout); /* os/utils.c */
2464    }
2465}
2466
2467/*
2468*** Wakeup Handler
2469 */
2470/*ARGSUSED*/
2471static void ServertimeWakeupHandler(env, rc, LastSelectMask)
2472pointer env;
2473int rc;
2474pointer LastSelectMask;
2475{
2476    if (pnext_time)
2477    {
2478        GetTime();
2479
2480        if (XSyncValueGreaterOrEqual(Now, *pnext_time))
2481	{
2482            SyncChangeCounter(ServertimeCounter, Now);
2483        }
2484    }
2485}
2486
2487static void
2488ServertimeQueryValue(pCounter, pValue_return)
2489    pointer pCounter;
2490    CARD64 *pValue_return;
2491{
2492    GetTime();
2493    *pValue_return = Now;
2494}
2495
2496static void
2497ServertimeBracketValues(pCounter, pbracket_less, pbracket_greater)
2498    pointer pCounter;
2499    CARD64 *pbracket_less;
2500    CARD64 *pbracket_greater;
2501{
2502    if (!pnext_time && pbracket_greater)
2503    {
2504	RegisterBlockAndWakeupHandlers(ServertimeBlockHandler,
2505				       ServertimeWakeupHandler,
2506				       NULL);
2507    }
2508    else if (pnext_time && !pbracket_greater)
2509    {
2510	RemoveBlockAndWakeupHandlers(ServertimeBlockHandler,
2511				     ServertimeWakeupHandler,
2512				     NULL);
2513    }
2514    pnext_time = pbracket_greater;
2515}
2516
2517static void
2518SyncInitServerTime(void)
2519{
2520    CARD64 resolution;
2521
2522    XSyncIntsToValue(&Now, GetTimeInMillis(), 0);
2523    XSyncIntToValue(&resolution, 4);
2524    ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution,
2525			    XSyncCounterNeverDecreases,
2526			    ServertimeQueryValue, ServertimeBracketValues);
2527    pnext_time = NULL;
2528}
2529
2530
2531
2532/*
2533 * IDLETIME implementation
2534 */
2535
2536static SyncCounter *IdleTimeCounter;
2537static XSyncValue *pIdleTimeValueLess;
2538static XSyncValue *pIdleTimeValueGreater;
2539
2540static void
2541IdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return)
2542{
2543    CARD32 idle = GetTimeInMillis() - lastDeviceEventTime.milliseconds;
2544    XSyncIntsToValue (pValue_return, idle, 0);
2545}
2546
2547static void
2548IdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask)
2549{
2550    XSyncValue idle, old_idle;
2551    SyncTriggerList *list = IdleTimeCounter->pTriglist;
2552    SyncTrigger *trig;
2553
2554    if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
2555	return;
2556
2557    old_idle = IdleTimeCounter->value;
2558    IdleTimeQueryValue (NULL, &idle);
2559    IdleTimeCounter->value = idle; /* push, so CheckTrigger works */
2560
2561    if (pIdleTimeValueLess &&
2562        XSyncValueLessOrEqual (idle, *pIdleTimeValueLess))
2563    {
2564	/*
2565	 * We've been idle for less than the threshold value, and someone
2566	 * wants to know about that, but now we need to know whether they
2567	 * want level or edge trigger.  Check the trigger list against the
2568	 * current idle time, and if any succeed, bomb out of select()
2569	 * immediately so we can reschedule.
2570	 */
2571
2572	for (list = IdleTimeCounter->pTriglist; list; list = list->next) {
2573	    trig = list->pTrigger;
2574	    if (trig->CheckTrigger(trig, old_idle)) {
2575		AdjustWaitForDelay(wt, 0);
2576		break;
2577	    }
2578	}
2579    }
2580    else if (pIdleTimeValueGreater)
2581    {
2582	/*
2583	 * There's a threshold in the positive direction.  If we've been
2584	 * idle less than it, schedule a wakeup for sometime in the future.
2585	 * If we've been idle more than it, and someone wants to know about
2586	 * that level-triggered, schedule an immediate wakeup.
2587	 */
2588	unsigned long timeout = -1;
2589
2590	if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) {
2591	    XSyncValue value;
2592	    Bool overflow;
2593
2594	    XSyncValueSubtract (&value, *pIdleTimeValueGreater,
2595	                        idle, &overflow);
2596	    timeout = min(timeout, XSyncValueLow32 (value));
2597	} else {
2598	    for (list = IdleTimeCounter->pTriglist; list; list = list->next) {
2599		trig = list->pTrigger;
2600		if (trig->CheckTrigger(trig, old_idle)) {
2601		    timeout = min(timeout, 0);
2602		    break;
2603		}
2604	    }
2605	}
2606
2607	AdjustWaitForDelay (wt, timeout);
2608    }
2609
2610    IdleTimeCounter->value = old_idle; /* pop */
2611}
2612
2613static void
2614IdleTimeWakeupHandler (pointer env,
2615                       int rc,
2616                       pointer LastSelectMask)
2617{
2618    XSyncValue idle;
2619
2620    if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
2621	return;
2622
2623    IdleTimeQueryValue (NULL, &idle);
2624
2625    if ((pIdleTimeValueGreater &&
2626         XSyncValueGreaterOrEqual (idle, *pIdleTimeValueGreater)) ||
2627        (pIdleTimeValueLess &&
2628	 XSyncValueLessOrEqual (idle, *pIdleTimeValueLess)))
2629    {
2630	SyncChangeCounter (IdleTimeCounter, idle);
2631    }
2632}
2633
2634static void
2635IdleTimeBracketValues (pointer pCounter,
2636                       CARD64 *pbracket_less,
2637                       CARD64 *pbracket_greater)
2638{
2639    Bool registered = (pIdleTimeValueLess || pIdleTimeValueGreater);
2640
2641    if (registered && !pbracket_less && !pbracket_greater)
2642    {
2643	RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler,
2644	                             IdleTimeWakeupHandler,
2645	                             NULL);
2646    }
2647    else if (!registered && (pbracket_less || pbracket_greater))
2648    {
2649	RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
2650	                               IdleTimeWakeupHandler,
2651	                               NULL);
2652    }
2653
2654    pIdleTimeValueGreater = pbracket_greater;
2655    pIdleTimeValueLess    = pbracket_less;
2656}
2657
2658static void
2659SyncInitIdleTime (void)
2660{
2661    CARD64 resolution;
2662    XSyncValue idle;
2663
2664    IdleTimeQueryValue (NULL, &idle);
2665    XSyncIntToValue (&resolution, 4);
2666
2667    IdleTimeCounter = SyncCreateSystemCounter ("IDLETIME", idle, resolution,
2668                                               XSyncCounterUnrestricted,
2669                                               IdleTimeQueryValue,
2670                                               IdleTimeBracketValues);
2671
2672    pIdleTimeValueLess = pIdleTimeValueGreater = NULL;
2673}
2674