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