1706f2543Smrg/*
2706f2543Smrg
3706f2543SmrgCopyright 1991, 1993, 1998  The Open Group
4706f2543Smrg
5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that
7706f2543Smrgthe above copyright notice appear in all copies and that both that
8706f2543Smrgcopyright notice and this permission notice appear in supporting
9706f2543Smrgdocumentation.
10706f2543Smrg
11706f2543SmrgThe above copyright notice and this permission notice shall be included
12706f2543Smrgin all copies or substantial portions of the Software.
13706f2543Smrg
14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15706f2543SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16706f2543SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17706f2543SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18706f2543SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19706f2543SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20706f2543SmrgOTHER DEALINGS IN THE SOFTWARE.
21706f2543Smrg
22706f2543SmrgExcept as contained in this notice, the name of The Open Group shall
23706f2543Smrgnot be used in advertising or otherwise to promote the sale, use or
24706f2543Smrgother dealings in this Software without prior written authorization
25706f2543Smrgfrom The Open Group.
26706f2543Smrg
27706f2543Smrg
28706f2543SmrgCopyright 1991, 1993 by Digital Equipment Corporation, Maynard, Massachusetts,
29706f2543Smrgand Olivetti Research Limited, Cambridge, England.
30706f2543Smrg
31706f2543Smrg                        All Rights Reserved
32706f2543Smrg
33706f2543SmrgPermission to use, copy, modify, and distribute this software and its
34706f2543Smrgdocumentation for any purpose and without fee is hereby granted,
35706f2543Smrgprovided that the above copyright notice appear in all copies and that
36706f2543Smrgboth that copyright notice and this permission notice appear in
37706f2543Smrgsupporting documentation, and that the names of Digital or Olivetti
38706f2543Smrgnot be used in advertising or publicity pertaining to distribution of the
39706f2543Smrgsoftware without specific, written prior permission.  Digital and Olivetti
40706f2543Smrgmake no representations about the suitability of this software
41706f2543Smrgfor any purpose.  It is provided "as is" without express or implied warranty.
42706f2543Smrg
43706f2543SmrgDIGITAL AND OLIVETTI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
44706f2543SmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
45706f2543SmrgFITNESS, IN NO EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR
46706f2543SmrgCONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
47706f2543SmrgUSE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
48706f2543SmrgOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
49706f2543SmrgPERFORMANCE OF THIS SOFTWARE.
50706f2543Smrg
51706f2543Smrg*/
52706f2543Smrg
53706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
54706f2543Smrg#include <dix-config.h>
55706f2543Smrg#endif
56706f2543Smrg
57706f2543Smrg#include <string.h>
58706f2543Smrg
59706f2543Smrg#include <X11/X.h>
60706f2543Smrg#include <X11/Xproto.h>
61706f2543Smrg#include <X11/Xmd.h>
62706f2543Smrg#include "scrnintstr.h"
63706f2543Smrg#include "os.h"
64706f2543Smrg#include "extnsionst.h"
65706f2543Smrg#include "dixstruct.h"
66706f2543Smrg#include "pixmapstr.h"
67706f2543Smrg#include "resource.h"
68706f2543Smrg#include "opaque.h"
69706f2543Smrg#include <X11/extensions/syncproto.h>
70706f2543Smrg#include "syncsrv.h"
71706f2543Smrg#include "syncsdk.h"
72706f2543Smrg#include "protocol-versions.h"
73706f2543Smrg
74706f2543Smrg#include <stdio.h>
75706f2543Smrg#if !defined(WIN32)
76706f2543Smrg#include <sys/time.h>
77706f2543Smrg#endif
78706f2543Smrg
79706f2543Smrg#include "modinit.h"
80706f2543Smrg
81706f2543Smrg/*
82706f2543Smrg * Local Global Variables
83706f2543Smrg */
84706f2543Smrgstatic int      SyncEventBase;
85706f2543Smrgstatic int      SyncErrorBase;
86706f2543Smrgstatic RESTYPE  RTCounter = 0;
87706f2543Smrgstatic RESTYPE  RTAwait;
88706f2543Smrgstatic RESTYPE  RTAlarm;
89706f2543Smrgstatic RESTYPE  RTAlarmClient;
90706f2543Smrgstatic RESTYPE  RTFence;
91706f2543Smrgstatic int SyncNumSystemCounters = 0;
92706f2543Smrgstatic SyncCounter **SysCounterList = NULL;
93706f2543Smrgstatic int SyncNumInvalidCounterWarnings = 0;
94706f2543Smrg#define MAX_INVALID_COUNTER_WARNINGS	   5
95706f2543Smrg
96706f2543Smrgstatic const char *WARN_INVALID_COUNTER_COMPARE =
97706f2543Smrg"Warning: Non-counter XSync object using Counter-only\n"
98706f2543Smrg"         comparison.  Result will never be true.\n";
99706f2543Smrg
100706f2543Smrgstatic const char *WARN_INVALID_COUNTER_ALARM =
101706f2543Smrg"Warning: Non-counter XSync object used in alarm.  This is\n"
102706f2543Smrg"         the result of a programming error in the X server.\n";
103706f2543Smrg
104706f2543Smrg#define IsSystemCounter(pCounter) \
105706f2543Smrg    (pCounter && (pCounter->sync.client == NULL))
106706f2543Smrg
107706f2543Smrg/* these are all the alarm attributes that pertain to the alarm's trigger */
108706f2543Smrg#define XSyncCAAllTrigger \
109706f2543Smrg    (XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType)
110706f2543Smrg
111706f2543Smrgstatic void SyncComputeBracketValues(SyncCounter *);
112706f2543Smrg
113706f2543Smrgstatic void SyncInitServerTime(void);
114706f2543Smrg
115706f2543Smrgstatic void SyncInitIdleTime(void);
116706f2543Smrg
117706f2543Smrgstatic Bool
118706f2543SmrgSyncCheckWarnIsCounter(const SyncObject* pSync, const char *warning)
119706f2543Smrg{
120706f2543Smrg    if (pSync && (SYNC_COUNTER != pSync->type))
121706f2543Smrg    {
122706f2543Smrg	if (SyncNumInvalidCounterWarnings++ < MAX_INVALID_COUNTER_WARNINGS)
123706f2543Smrg	{
124706f2543Smrg	    ErrorF("%s", warning);
125706f2543Smrg	    ErrorF("         Counter type: %d\n", pSync->type);
126706f2543Smrg	}
127706f2543Smrg
128706f2543Smrg	return FALSE;
129706f2543Smrg    }
130706f2543Smrg
131706f2543Smrg    return TRUE;
132706f2543Smrg}
133706f2543Smrg
134706f2543Smrg/*  Each counter maintains a simple linked list of triggers that are
135706f2543Smrg *  interested in the counter.  The two functions below are used to
136706f2543Smrg *  delete and add triggers on this list.
137706f2543Smrg */
138706f2543Smrgstatic void
139706f2543SmrgSyncDeleteTriggerFromSyncObject(SyncTrigger *pTrigger)
140706f2543Smrg{
141706f2543Smrg    SyncTriggerList *pCur;
142706f2543Smrg    SyncTriggerList *pPrev;
143706f2543Smrg    SyncCounter *pCounter;
144706f2543Smrg
145706f2543Smrg    /* pSync needs to be stored in pTrigger before calling here. */
146706f2543Smrg
147706f2543Smrg    if (!pTrigger->pSync)
148706f2543Smrg	return;
149706f2543Smrg
150706f2543Smrg    pPrev = NULL;
151706f2543Smrg    pCur = pTrigger->pSync->pTriglist;
152706f2543Smrg
153706f2543Smrg    while (pCur)
154706f2543Smrg    {
155706f2543Smrg	if (pCur->pTrigger == pTrigger)
156706f2543Smrg	{
157706f2543Smrg	    if (pPrev)
158706f2543Smrg		pPrev->next = pCur->next;
159706f2543Smrg	    else
160706f2543Smrg		pTrigger->pSync->pTriglist = pCur->next;
161706f2543Smrg
162706f2543Smrg	    free(pCur);
163706f2543Smrg	    break;
164706f2543Smrg	}
165706f2543Smrg
166706f2543Smrg	pPrev = pCur;
167706f2543Smrg	pCur = pCur->next;
168706f2543Smrg    }
169706f2543Smrg
170706f2543Smrg    if (SYNC_COUNTER == pTrigger->pSync->type)
171706f2543Smrg    {
172706f2543Smrg	pCounter = (SyncCounter *)pTrigger->pSync;
173706f2543Smrg
174706f2543Smrg	if (IsSystemCounter(pCounter))
175706f2543Smrg	    SyncComputeBracketValues(pCounter);
176706f2543Smrg    } else if (SYNC_FENCE == pTrigger->pSync->type) {
177706f2543Smrg	SyncFence* pFence = (SyncFence*) pTrigger->pSync;
178706f2543Smrg	pFence->funcs.DeleteTrigger(pTrigger);
179706f2543Smrg    }
180706f2543Smrg}
181706f2543Smrg
182706f2543Smrg
183706f2543Smrgstatic int
184706f2543SmrgSyncAddTriggerToSyncObject(SyncTrigger *pTrigger)
185706f2543Smrg{
186706f2543Smrg    SyncTriggerList *pCur;
187706f2543Smrg    SyncCounter *pCounter;
188706f2543Smrg
189706f2543Smrg    if (!pTrigger->pSync)
190706f2543Smrg	return Success;
191706f2543Smrg
192706f2543Smrg    /* don't do anything if it's already there */
193706f2543Smrg    for (pCur = pTrigger->pSync->pTriglist; pCur; pCur = pCur->next)
194706f2543Smrg    {
195706f2543Smrg	if (pCur->pTrigger == pTrigger)
196706f2543Smrg	    return Success;
197706f2543Smrg    }
198706f2543Smrg
199706f2543Smrg    if (!(pCur = malloc(sizeof(SyncTriggerList))))
200706f2543Smrg	return BadAlloc;
201706f2543Smrg
202706f2543Smrg    pCur->pTrigger = pTrigger;
203706f2543Smrg    pCur->next = pTrigger->pSync->pTriglist;
204706f2543Smrg    pTrigger->pSync->pTriglist = pCur;
205706f2543Smrg
206706f2543Smrg    if (SYNC_COUNTER == pTrigger->pSync->type)
207706f2543Smrg    {
208706f2543Smrg	pCounter = (SyncCounter *)pTrigger->pSync;
209706f2543Smrg
210706f2543Smrg	if (IsSystemCounter(pCounter))
211706f2543Smrg	    SyncComputeBracketValues(pCounter);
212706f2543Smrg    } else if (SYNC_FENCE == pTrigger->pSync->type) {
213706f2543Smrg	SyncFence* pFence = (SyncFence*) pTrigger->pSync;
214706f2543Smrg	pFence->funcs.AddTrigger(pTrigger);
215706f2543Smrg    }
216706f2543Smrg
217706f2543Smrg    return Success;
218706f2543Smrg}
219706f2543Smrg
220706f2543Smrg
221706f2543Smrg/*  Below are five possible functions that can be plugged into
222706f2543Smrg *  pTrigger->CheckTrigger for counter sync objects, corresponding to
223706f2543Smrg *  the four possible test-types, and the one possible function that
224706f2543Smrg *  can be plugged into pTrigger->CheckTrigger for fence sync objects.
225706f2543Smrg *  These functions are called after the sync object's state changes
226706f2543Smrg *  but are also passed the old state so they can inspect both the old
227706f2543Smrg *  and new values.  (PositiveTransition and NegativeTransition need to
228706f2543Smrg *  see both pieces of information.)  These functions return the truth
229706f2543Smrg *  value of the trigger.
230706f2543Smrg *
231706f2543Smrg *  All of them include the condition pTrigger->pSync == NULL.
232706f2543Smrg *  This is because the spec says that a trigger with a sync value
233706f2543Smrg *  of None is always TRUE.
234706f2543Smrg */
235706f2543Smrg
236706f2543Smrgstatic Bool
237706f2543SmrgSyncCheckTriggerPositiveComparison(SyncTrigger *pTrigger, CARD64 oldval)
238706f2543Smrg{
239706f2543Smrg    SyncCounter *pCounter;
240706f2543Smrg
241706f2543Smrg    /* Non-counter sync objects should never get here because they
242706f2543Smrg     * never trigger this comparison. */
243706f2543Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
244706f2543Smrg	return FALSE;
245706f2543Smrg
246706f2543Smrg    pCounter = (SyncCounter *)pTrigger->pSync;
247706f2543Smrg
248706f2543Smrg    return (pCounter == NULL ||
249706f2543Smrg	    XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value));
250706f2543Smrg}
251706f2543Smrg
252706f2543Smrgstatic Bool
253706f2543SmrgSyncCheckTriggerNegativeComparison(SyncTrigger *pTrigger,  CARD64 oldval)
254706f2543Smrg{
255706f2543Smrg    SyncCounter *pCounter;
256706f2543Smrg
257706f2543Smrg    /* Non-counter sync objects should never get here because they
258706f2543Smrg     * never trigger this comparison. */
259706f2543Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
260706f2543Smrg	return FALSE;
261706f2543Smrg
262706f2543Smrg    pCounter = (SyncCounter *)pTrigger->pSync;
263706f2543Smrg
264706f2543Smrg    return (pCounter == NULL ||
265706f2543Smrg	    XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value));
266706f2543Smrg}
267706f2543Smrg
268706f2543Smrgstatic Bool
269706f2543SmrgSyncCheckTriggerPositiveTransition(SyncTrigger *pTrigger, CARD64 oldval)
270706f2543Smrg{
271706f2543Smrg    SyncCounter *pCounter;
272706f2543Smrg
273706f2543Smrg    /* Non-counter sync objects should never get here because they
274706f2543Smrg     * never trigger this comparison. */
275706f2543Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
276706f2543Smrg	return FALSE;
277706f2543Smrg
278706f2543Smrg    pCounter = (SyncCounter *)pTrigger->pSync;
279706f2543Smrg
280706f2543Smrg    return (pCounter == NULL ||
281706f2543Smrg	    (XSyncValueLessThan(oldval, pTrigger->test_value) &&
282706f2543Smrg	     XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value)));
283706f2543Smrg}
284706f2543Smrg
285706f2543Smrgstatic Bool
286706f2543SmrgSyncCheckTriggerNegativeTransition(SyncTrigger *pTrigger, CARD64 oldval)
287706f2543Smrg{
288706f2543Smrg    SyncCounter *pCounter;
289706f2543Smrg
290706f2543Smrg    /* Non-counter sync objects should never get here because they
291706f2543Smrg     * never trigger this comparison. */
292706f2543Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_COMPARE))
293706f2543Smrg	return FALSE;
294706f2543Smrg
295706f2543Smrg    pCounter = (SyncCounter *)pTrigger->pSync;
296706f2543Smrg
297706f2543Smrg    return (pCounter == NULL ||
298706f2543Smrg	    (XSyncValueGreaterThan(oldval, pTrigger->test_value) &&
299706f2543Smrg	     XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value)));
300706f2543Smrg}
301706f2543Smrg
302706f2543Smrgstatic Bool
303706f2543SmrgSyncCheckTriggerFence(SyncTrigger *pTrigger, CARD64 unused)
304706f2543Smrg{
305706f2543Smrg    SyncFence* pFence = (SyncFence*) pTrigger->pSync;
306706f2543Smrg    (void)unused;
307706f2543Smrg
308706f2543Smrg    return (pFence == NULL ||
309706f2543Smrg	    pFence->funcs.CheckTriggered(pFence));
310706f2543Smrg}
311706f2543Smrg
312706f2543Smrgstatic int
313706f2543SmrgSyncInitTrigger(ClientPtr client, SyncTrigger *pTrigger, XID syncObject,
314706f2543Smrg		RESTYPE resType, Mask changes)
315706f2543Smrg{
316706f2543Smrg    SyncObject *pSync = pTrigger->pSync;
317706f2543Smrg    SyncCounter *pCounter = NULL;
318706f2543Smrg    int		rc;
319706f2543Smrg    Bool	newSyncObject = FALSE;
320706f2543Smrg
321706f2543Smrg    if (changes & XSyncCACounter)
322706f2543Smrg    {
323706f2543Smrg	if (syncObject == None)
324706f2543Smrg	    pSync = NULL;
325706f2543Smrg	else if (Success != (rc = dixLookupResourceByType ((pointer *)&pSync,
326706f2543Smrg				syncObject, resType, client, DixReadAccess)))
327706f2543Smrg	{
328706f2543Smrg	    client->errorValue = syncObject;
329706f2543Smrg	    return rc;
330706f2543Smrg	}
331706f2543Smrg	if (pSync != pTrigger->pSync)
332706f2543Smrg	{ /* new counter for trigger */
333706f2543Smrg	    SyncDeleteTriggerFromSyncObject(pTrigger);
334706f2543Smrg	    pTrigger->pSync = pSync;
335706f2543Smrg	    newSyncObject = TRUE;
336706f2543Smrg	}
337706f2543Smrg    }
338706f2543Smrg
339706f2543Smrg    /* if system counter, ask it what the current value is */
340706f2543Smrg
341706f2543Smrg    if (pSync && SYNC_COUNTER == pSync->type)
342706f2543Smrg    {
343706f2543Smrg	pCounter = (SyncCounter *)pSync;
344706f2543Smrg
345706f2543Smrg	if (IsSystemCounter(pCounter))
346706f2543Smrg	{
347706f2543Smrg	    (*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
348706f2543Smrg						      &pCounter->value);
349706f2543Smrg	}
350706f2543Smrg    }
351706f2543Smrg
352706f2543Smrg    if (changes & XSyncCAValueType)
353706f2543Smrg    {
354706f2543Smrg	if (pTrigger->value_type != XSyncRelative &&
355706f2543Smrg	    pTrigger->value_type != XSyncAbsolute)
356706f2543Smrg	{
357706f2543Smrg	    client->errorValue = pTrigger->value_type;
358706f2543Smrg	    return BadValue;
359706f2543Smrg	}
360706f2543Smrg    }
361706f2543Smrg
362706f2543Smrg    if (changes & XSyncCATestType)
363706f2543Smrg    {
364706f2543Smrg
365706f2543Smrg	if (pSync && SYNC_FENCE == pSync->type)
366706f2543Smrg	{
367706f2543Smrg	    pTrigger->CheckTrigger = SyncCheckTriggerFence;
368706f2543Smrg	}
369706f2543Smrg	else
370706f2543Smrg	{
371706f2543Smrg	    /* select appropriate CheckTrigger function */
372706f2543Smrg
373706f2543Smrg	    switch (pTrigger->test_type)
374706f2543Smrg	    {
375706f2543Smrg	    case XSyncPositiveTransition:
376706f2543Smrg		pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition;
377706f2543Smrg		break;
378706f2543Smrg	    case XSyncNegativeTransition:
379706f2543Smrg		pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition;
380706f2543Smrg		break;
381706f2543Smrg	    case XSyncPositiveComparison:
382706f2543Smrg		pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison;
383706f2543Smrg		break;
384706f2543Smrg	    case XSyncNegativeComparison:
385706f2543Smrg		pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison;
386706f2543Smrg		break;
387706f2543Smrg	    default:
388706f2543Smrg		client->errorValue = pTrigger->test_type;
389706f2543Smrg		return BadValue;
390706f2543Smrg	    }
391706f2543Smrg	}
392706f2543Smrg    }
393706f2543Smrg
394706f2543Smrg    if (changes & (XSyncCAValueType | XSyncCAValue))
395706f2543Smrg    {
396706f2543Smrg	if (pTrigger->value_type == XSyncAbsolute)
397706f2543Smrg	    pTrigger->test_value = pTrigger->wait_value;
398706f2543Smrg	else /* relative */
399706f2543Smrg	{
400706f2543Smrg	    Bool overflow;
401706f2543Smrg	    if (pCounter == NULL)
402706f2543Smrg		return BadMatch;
403706f2543Smrg
404706f2543Smrg	    XSyncValueAdd(&pTrigger->test_value, pCounter->value,
405706f2543Smrg			  pTrigger->wait_value, &overflow);
406706f2543Smrg	    if (overflow)
407706f2543Smrg	    {
408706f2543Smrg		client->errorValue = XSyncValueHigh32(pTrigger->wait_value);
409706f2543Smrg		return BadValue;
410706f2543Smrg	    }
411706f2543Smrg	}
412706f2543Smrg    }
413706f2543Smrg
414706f2543Smrg    /*  we wait until we're sure there are no errors before registering
415706f2543Smrg     *  a new counter on a trigger
416706f2543Smrg     */
417706f2543Smrg    if (newSyncObject)
418706f2543Smrg    {
419706f2543Smrg	if ((rc = SyncAddTriggerToSyncObject(pTrigger)) != Success)
420706f2543Smrg	    return rc;
421706f2543Smrg    }
422706f2543Smrg    else if (pCounter && IsSystemCounter(pCounter))
423706f2543Smrg    {
424706f2543Smrg	SyncComputeBracketValues(pCounter);
425706f2543Smrg    }
426706f2543Smrg
427706f2543Smrg    return Success;
428706f2543Smrg}
429706f2543Smrg
430706f2543Smrg/*  AlarmNotify events happen in response to actions taken on an Alarm or
431706f2543Smrg *  the counter used by the alarm.  AlarmNotify may be sent to multiple
432706f2543Smrg *  clients.  The alarm maintains a list of clients interested in events.
433706f2543Smrg */
434706f2543Smrgstatic void
435706f2543SmrgSyncSendAlarmNotifyEvents(SyncAlarm *pAlarm)
436706f2543Smrg{
437706f2543Smrg    SyncAlarmClientList *pcl;
438706f2543Smrg    xSyncAlarmNotifyEvent ane;
439706f2543Smrg    SyncTrigger *pTrigger = &pAlarm->trigger;
440706f2543Smrg    SyncCounter *pCounter;
441706f2543Smrg
442706f2543Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
443706f2543Smrg	return;
444706f2543Smrg
445706f2543Smrg    pCounter = (SyncCounter *)pTrigger->pSync;
446706f2543Smrg
447706f2543Smrg    UpdateCurrentTime();
448706f2543Smrg
449706f2543Smrg    ane.type = SyncEventBase + XSyncAlarmNotify;
450706f2543Smrg    ane.kind = XSyncAlarmNotify;
451706f2543Smrg    ane.alarm = pAlarm->alarm_id;
452706f2543Smrg    if (pTrigger->pSync && SYNC_COUNTER == pTrigger->pSync->type)
453706f2543Smrg    {
454706f2543Smrg	ane.counter_value_hi = XSyncValueHigh32(pCounter->value);
455706f2543Smrg	ane.counter_value_lo = XSyncValueLow32(pCounter->value);
456706f2543Smrg    }
457706f2543Smrg    else
458706f2543Smrg    { /* XXX what else can we do if there's no counter? */
459706f2543Smrg	ane.counter_value_hi = ane.counter_value_lo = 0;
460706f2543Smrg    }
461706f2543Smrg
462706f2543Smrg    ane.alarm_value_hi = XSyncValueHigh32(pTrigger->test_value);
463706f2543Smrg    ane.alarm_value_lo = XSyncValueLow32(pTrigger->test_value);
464706f2543Smrg    ane.time = currentTime.milliseconds;
465706f2543Smrg    ane.state = pAlarm->state;
466706f2543Smrg
467706f2543Smrg    /* send to owner */
468706f2543Smrg    if (pAlarm->events)
469706f2543Smrg	WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane);
470706f2543Smrg
471706f2543Smrg    /* send to other interested clients */
472706f2543Smrg    for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next)
473706f2543Smrg	WriteEventsToClient(pcl->client, 1, (xEvent *) &ane);
474706f2543Smrg}
475706f2543Smrg
476706f2543Smrg
477706f2543Smrg/*  CounterNotify events only occur in response to an Await.  The events
478706f2543Smrg *  go only to the Awaiting client.
479706f2543Smrg */
480706f2543Smrgstatic void
481706f2543SmrgSyncSendCounterNotifyEvents(ClientPtr client, SyncAwait **ppAwait,
482706f2543Smrg			    int num_events)
483706f2543Smrg{
484706f2543Smrg    xSyncCounterNotifyEvent *pEvents, *pev;
485706f2543Smrg    int i;
486706f2543Smrg
487706f2543Smrg    if (client->clientGone)
488706f2543Smrg	return;
489706f2543Smrg    pev = pEvents = malloc(num_events * sizeof(xSyncCounterNotifyEvent));
490706f2543Smrg    if (!pEvents)
491706f2543Smrg	return;
492706f2543Smrg    UpdateCurrentTime();
493706f2543Smrg    for (i = 0; i < num_events; i++, ppAwait++, pev++)
494706f2543Smrg    {
495706f2543Smrg	SyncTrigger *pTrigger = &(*ppAwait)->trigger;
496706f2543Smrg	pev->type = SyncEventBase + XSyncCounterNotify;
497706f2543Smrg	pev->kind = XSyncCounterNotify;
498706f2543Smrg	pev->counter = pTrigger->pSync->id;
499706f2543Smrg	pev->wait_value_lo = XSyncValueLow32(pTrigger->test_value);
500706f2543Smrg	pev->wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
501706f2543Smrg	if (SYNC_COUNTER == pTrigger->pSync->type)
502706f2543Smrg	{
503706f2543Smrg	    SyncCounter *pCounter = (SyncCounter *)pTrigger->pSync;
504706f2543Smrg
505706f2543Smrg	    pev->counter_value_lo = XSyncValueLow32(pCounter->value);
506706f2543Smrg	    pev->counter_value_hi = XSyncValueHigh32(pCounter->value);
507706f2543Smrg	}
508706f2543Smrg	else
509706f2543Smrg	{
510706f2543Smrg	    pev->counter_value_lo = 0;
511706f2543Smrg	    pev->counter_value_hi = 0;
512706f2543Smrg	}
513706f2543Smrg
514706f2543Smrg	pev->time = currentTime.milliseconds;
515706f2543Smrg	pev->count = num_events - i - 1; /* events remaining */
516706f2543Smrg	pev->destroyed = pTrigger->pSync->beingDestroyed;
517706f2543Smrg    }
518706f2543Smrg    /* swapping will be taken care of by this */
519706f2543Smrg    WriteEventsToClient(client, num_events, (xEvent *)pEvents);
520706f2543Smrg    free(pEvents);
521706f2543Smrg}
522706f2543Smrg
523706f2543Smrg
524706f2543Smrg/* This function is called when an alarm's counter is destroyed.
525706f2543Smrg * It is plugged into pTrigger->CounterDestroyed (for alarm triggers).
526706f2543Smrg */
527706f2543Smrgstatic void
528706f2543SmrgSyncAlarmCounterDestroyed(SyncTrigger *pTrigger)
529706f2543Smrg{
530706f2543Smrg    SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
531706f2543Smrg
532706f2543Smrg    pAlarm->state = XSyncAlarmInactive;
533706f2543Smrg    SyncSendAlarmNotifyEvents(pAlarm);
534706f2543Smrg    pTrigger->pSync = NULL;
535706f2543Smrg}
536706f2543Smrg
537706f2543Smrg
538706f2543Smrg/*  This function is called when an alarm "goes off."
539706f2543Smrg *  It is plugged into pTrigger->TriggerFired (for alarm triggers).
540706f2543Smrg */
541706f2543Smrgstatic void
542706f2543SmrgSyncAlarmTriggerFired(SyncTrigger *pTrigger)
543706f2543Smrg{
544706f2543Smrg    SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
545706f2543Smrg    SyncCounter *pCounter;
546706f2543Smrg    CARD64 new_test_value;
547706f2543Smrg
548706f2543Smrg    if (!SyncCheckWarnIsCounter(pTrigger->pSync, WARN_INVALID_COUNTER_ALARM))
549706f2543Smrg	return;
550706f2543Smrg
551706f2543Smrg    pCounter = (SyncCounter *)pTrigger->pSync;
552706f2543Smrg
553706f2543Smrg    /* no need to check alarm unless it's active */
554706f2543Smrg    if (pAlarm->state != XSyncAlarmActive)
555706f2543Smrg	return;
556706f2543Smrg
557706f2543Smrg    /*  " if the counter value is None, or if the delta is 0 and
558706f2543Smrg     *    the test-type is PositiveComparison or NegativeComparison,
559706f2543Smrg     *    no change is made to value (test-value) and the alarm
560706f2543Smrg     *    state is changed to Inactive before the event is generated."
561706f2543Smrg     */
562706f2543Smrg    if (pCounter == NULL
563706f2543Smrg	|| (XSyncValueIsZero(pAlarm->delta)
564706f2543Smrg	    && (pAlarm->trigger.test_type == XSyncPositiveComparison
565706f2543Smrg		|| pAlarm->trigger.test_type == XSyncNegativeComparison)))
566706f2543Smrg	pAlarm->state = XSyncAlarmInactive;
567706f2543Smrg
568706f2543Smrg    new_test_value = pAlarm->trigger.test_value;
569706f2543Smrg
570706f2543Smrg    if (pAlarm->state == XSyncAlarmActive)
571706f2543Smrg    {
572706f2543Smrg	Bool overflow;
573706f2543Smrg	CARD64 oldvalue;
574706f2543Smrg	SyncTrigger *paTrigger = &pAlarm->trigger;
575706f2543Smrg	SyncCounter *paCounter;
576706f2543Smrg
577706f2543Smrg	if (!SyncCheckWarnIsCounter(paTrigger->pSync,
578706f2543Smrg				    WARN_INVALID_COUNTER_ALARM))
579706f2543Smrg	    return;
580706f2543Smrg
581706f2543Smrg	paCounter = (SyncCounter *)pTrigger->pSync;
582706f2543Smrg
583706f2543Smrg	/* "The alarm is updated by repeatedly adding delta to the
584706f2543Smrg	 *  value of the trigger and re-initializing it until it
585706f2543Smrg	 *  becomes FALSE."
586706f2543Smrg	 */
587706f2543Smrg	oldvalue = paTrigger->test_value;
588706f2543Smrg
589706f2543Smrg	/* XXX really should do something smarter here */
590706f2543Smrg
591706f2543Smrg	do
592706f2543Smrg	{
593706f2543Smrg	    XSyncValueAdd(&paTrigger->test_value, paTrigger->test_value,
594706f2543Smrg			  pAlarm->delta, &overflow);
595706f2543Smrg	} while (!overflow &&
596706f2543Smrg	      (*paTrigger->CheckTrigger)(paTrigger,
597706f2543Smrg					paCounter->value));
598706f2543Smrg
599706f2543Smrg	new_test_value = paTrigger->test_value;
600706f2543Smrg	paTrigger->test_value = oldvalue;
601706f2543Smrg
602706f2543Smrg	/* "If this update would cause value to fall outside the range
603706f2543Smrg	 *  for an INT64...no change is made to value (test-value) and
604706f2543Smrg	 *  the alarm state is changed to Inactive before the event is
605706f2543Smrg	 *  generated."
606706f2543Smrg	 */
607706f2543Smrg	if (overflow)
608706f2543Smrg	{
609706f2543Smrg	    new_test_value = oldvalue;
610706f2543Smrg	    pAlarm->state = XSyncAlarmInactive;
611706f2543Smrg	}
612706f2543Smrg    }
613706f2543Smrg    /*  The AlarmNotify event has to have the "new state of the alarm"
614706f2543Smrg     *  which we can't be sure of until this point.  However, it has
615706f2543Smrg     *  to have the "old" trigger test value.  That's the reason for
616706f2543Smrg     *  all the newvalue/oldvalue shuffling above.  After we send the
617706f2543Smrg     *  events, give the trigger its new test value.
618706f2543Smrg     */
619706f2543Smrg    SyncSendAlarmNotifyEvents(pAlarm);
620706f2543Smrg    pTrigger->test_value = new_test_value;
621706f2543Smrg}
622706f2543Smrg
623706f2543Smrg
624706f2543Smrg/*  This function is called when an Await unblocks, either as a result
625706f2543Smrg *  of the trigger firing OR the counter being destroyed.
626706f2543Smrg *  It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed
627706f2543Smrg *  (for Await triggers).
628706f2543Smrg */
629706f2543Smrgstatic void
630706f2543SmrgSyncAwaitTriggerFired(SyncTrigger *pTrigger)
631706f2543Smrg{
632706f2543Smrg    SyncAwait *pAwait = (SyncAwait *)pTrigger;
633706f2543Smrg    int numwaits;
634706f2543Smrg    SyncAwaitUnion *pAwaitUnion;
635706f2543Smrg    SyncAwait **ppAwait;
636706f2543Smrg    int num_events = 0;
637706f2543Smrg
638706f2543Smrg    pAwaitUnion = (SyncAwaitUnion *)pAwait->pHeader;
639706f2543Smrg    numwaits = pAwaitUnion->header.num_waitconditions;
640706f2543Smrg    ppAwait = malloc(numwaits * sizeof(SyncAwait *));
641706f2543Smrg    if (!ppAwait)
642706f2543Smrg	goto bail;
643706f2543Smrg
644706f2543Smrg    pAwait = &(pAwaitUnion+1)->await;
645706f2543Smrg
646706f2543Smrg    /* "When a client is unblocked, all the CounterNotify events for
647706f2543Smrg     *  the Await request are generated contiguously. If count is 0
648706f2543Smrg     *  there are no more events to follow for this request. If
649706f2543Smrg     *  count is n, there are at least n more events to follow."
650706f2543Smrg     *
651706f2543Smrg     *  Thus, it is best to find all the counters for which events
652706f2543Smrg     *  need to be sent first, so that an accurate count field can
653706f2543Smrg     *  be stored in the events.
654706f2543Smrg     */
655706f2543Smrg    for ( ; numwaits; numwaits--, pAwait++)
656706f2543Smrg    {
657706f2543Smrg	CARD64 diff;
658706f2543Smrg	Bool overflow, diffgreater, diffequal;
659706f2543Smrg
660706f2543Smrg	/* "A CounterNotify event with the destroyed flag set to TRUE is
661706f2543Smrg	 *  always generated if the counter for one of the triggers is
662706f2543Smrg	 *  destroyed."
663706f2543Smrg	 */
664706f2543Smrg	if (pAwait->trigger.pSync->beingDestroyed)
665706f2543Smrg	{
666706f2543Smrg	    ppAwait[num_events++] = pAwait;
667706f2543Smrg	    continue;
668706f2543Smrg	}
669706f2543Smrg
670706f2543Smrg	if (SYNC_COUNTER == pAwait->trigger.pSync->type)
671706f2543Smrg	{
672706f2543Smrg	    SyncCounter *pCounter = (SyncCounter *) pAwait->trigger.pSync;
673706f2543Smrg
674706f2543Smrg	    /* "The difference between the counter and the test value is
675706f2543Smrg	     *  calculated by subtracting the test value from the value of
676706f2543Smrg	     *  the counter."
677706f2543Smrg	     */
678706f2543Smrg	    XSyncValueSubtract(&diff, pCounter->value,
679706f2543Smrg			       pAwait->trigger.test_value, &overflow);
680706f2543Smrg
681706f2543Smrg	    /* "If the difference lies outside the range for an INT64, an
682706f2543Smrg	     *  event is not generated."
683706f2543Smrg	     */
684706f2543Smrg	    if (overflow)
685706f2543Smrg		continue;
686706f2543Smrg	    diffgreater = XSyncValueGreaterThan(diff, pAwait->event_threshold);
687706f2543Smrg	    diffequal   = XSyncValueEqual(diff, pAwait->event_threshold);
688706f2543Smrg
689706f2543Smrg	    /* "If the test-type is PositiveTransition or
690706f2543Smrg	     *  PositiveComparison, a CounterNotify event is generated if
691706f2543Smrg	     *  the difference is at least event-threshold. If the test-type
692706f2543Smrg	     *  is NegativeTransition or NegativeComparison, a CounterNotify
693706f2543Smrg	     *  event is generated if the difference is at most
694706f2543Smrg	     *  event-threshold."
695706f2543Smrg	     */
696706f2543Smrg
697706f2543Smrg	    if ( ((pAwait->trigger.test_type == XSyncPositiveComparison ||
698706f2543Smrg		   pAwait->trigger.test_type == XSyncPositiveTransition)
699706f2543Smrg		  && (diffgreater || diffequal))
700706f2543Smrg		 ||
701706f2543Smrg		 ((pAwait->trigger.test_type == XSyncNegativeComparison ||
702706f2543Smrg		   pAwait->trigger.test_type == XSyncNegativeTransition)
703706f2543Smrg		  && (!diffgreater) /* less or equal */
704706f2543Smrg		 )
705706f2543Smrg	       )
706706f2543Smrg	    {
707706f2543Smrg		ppAwait[num_events++] = pAwait;
708706f2543Smrg	    }
709706f2543Smrg	}
710706f2543Smrg    }
711706f2543Smrg    if (num_events)
712706f2543Smrg	SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait,
713706f2543Smrg				    num_events);
714706f2543Smrg    free(ppAwait);
715706f2543Smrg
716706f2543Smrgbail:
717706f2543Smrg    /* unblock the client */
718706f2543Smrg    AttendClient(pAwaitUnion->header.client);
719706f2543Smrg    /* delete the await */
720706f2543Smrg    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
721706f2543Smrg}
722706f2543Smrg
723706f2543Smrg
724706f2543Smrg/*  This function should always be used to change a counter's value so that
725706f2543Smrg *  any triggers depending on the counter will be checked.
726706f2543Smrg */
727706f2543Smrgvoid
728706f2543SmrgSyncChangeCounter(SyncCounter *pCounter, CARD64 newval)
729706f2543Smrg{
730706f2543Smrg    SyncTriggerList       *ptl, *pnext;
731706f2543Smrg    CARD64 oldval;
732706f2543Smrg
733706f2543Smrg    oldval = pCounter->value;
734706f2543Smrg    pCounter->value = newval;
735706f2543Smrg
736706f2543Smrg    /* run through triggers to see if any become true */
737706f2543Smrg    for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext)
738706f2543Smrg    {
739706f2543Smrg	pnext = ptl->next;
740706f2543Smrg	if ((*ptl->pTrigger->CheckTrigger)(ptl->pTrigger, oldval))
741706f2543Smrg	    (*ptl->pTrigger->TriggerFired)(ptl->pTrigger);
742706f2543Smrg    }
743706f2543Smrg
744706f2543Smrg    if (IsSystemCounter(pCounter))
745706f2543Smrg    {
746706f2543Smrg	SyncComputeBracketValues(pCounter);
747706f2543Smrg    }
748706f2543Smrg}
749706f2543Smrg
750706f2543Smrg
751706f2543Smrg/* loosely based on dix/events.c/EventSelectForWindow */
752706f2543Smrgstatic Bool
753706f2543SmrgSyncEventSelectForAlarm(SyncAlarm *pAlarm, ClientPtr client, Bool wantevents)
754706f2543Smrg{
755706f2543Smrg    SyncAlarmClientList *pClients;
756706f2543Smrg
757706f2543Smrg    if (client == pAlarm->client) /* alarm owner */
758706f2543Smrg    {
759706f2543Smrg	pAlarm->events = wantevents;
760706f2543Smrg	return Success;
761706f2543Smrg    }
762706f2543Smrg
763706f2543Smrg    /* see if the client is already on the list (has events selected) */
764706f2543Smrg
765706f2543Smrg    for (pClients = pAlarm->pEventClients; pClients;
766706f2543Smrg	 pClients = pClients->next)
767706f2543Smrg    {
768706f2543Smrg	if (pClients->client == client)
769706f2543Smrg	{
770706f2543Smrg	    /* client's presence on the list indicates desire for
771706f2543Smrg	     * events.  If the client doesn't want events, remove it
772706f2543Smrg	     * from the list.  If the client does want events, do
773706f2543Smrg	     * nothing, since it's already got them.
774706f2543Smrg	     */
775706f2543Smrg	    if (!wantevents)
776706f2543Smrg	    {
777706f2543Smrg		FreeResource(pClients->delete_id, RT_NONE);
778706f2543Smrg	    }
779706f2543Smrg	    return Success;
780706f2543Smrg	}
781706f2543Smrg    }
782706f2543Smrg
783706f2543Smrg    /*  if we get here, this client does not currently have
784706f2543Smrg     *  events selected on the alarm
785706f2543Smrg     */
786706f2543Smrg
787706f2543Smrg    if (!wantevents)
788706f2543Smrg	/* client doesn't want events, and we just discovered that it
789706f2543Smrg	 * doesn't have them, so there's nothing to do.
790706f2543Smrg	 */
791706f2543Smrg	return Success;
792706f2543Smrg
793706f2543Smrg    /* add new client to pAlarm->pEventClients */
794706f2543Smrg
795706f2543Smrg    pClients = malloc(sizeof(SyncAlarmClientList));
796706f2543Smrg    if (!pClients)
797706f2543Smrg	return BadAlloc;
798706f2543Smrg
799706f2543Smrg    /*  register it as a resource so it will be cleaned up
800706f2543Smrg     *  if the client dies
801706f2543Smrg     */
802706f2543Smrg
803706f2543Smrg    pClients->delete_id = FakeClientID(client->index);
804706f2543Smrg
805706f2543Smrg    /* link it into list after we know all the allocations succeed */
806706f2543Smrg    pClients->next = pAlarm->pEventClients;
807706f2543Smrg    pAlarm->pEventClients = pClients;
808706f2543Smrg    pClients->client = client;
809706f2543Smrg
810706f2543Smrg    if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm))
811706f2543Smrg	return BadAlloc;
812706f2543Smrg
813706f2543Smrg    return Success;
814706f2543Smrg}
815706f2543Smrg
816706f2543Smrg/*
817706f2543Smrg * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm
818706f2543Smrg */
819706f2543Smrgstatic int
820706f2543SmrgSyncChangeAlarmAttributes(ClientPtr client, SyncAlarm *pAlarm, Mask mask,
821706f2543Smrg			  CARD32 *values)
822706f2543Smrg{
823706f2543Smrg    int		   status;
824706f2543Smrg    XSyncCounter   counter;
825706f2543Smrg    Mask	   origmask = mask;
826706f2543Smrg
827706f2543Smrg    counter =
828706f2543Smrg	pAlarm->trigger.pSync ? pAlarm->trigger.pSync->id : None;
829706f2543Smrg
830706f2543Smrg    while (mask)
831706f2543Smrg    {
832706f2543Smrg	int    index2 = lowbit(mask);
833706f2543Smrg	mask &= ~index2;
834706f2543Smrg	switch (index2)
835706f2543Smrg	{
836706f2543Smrg	  case XSyncCACounter:
837706f2543Smrg	    mask &= ~XSyncCACounter;
838706f2543Smrg	    /* sanity check in SyncInitTrigger */
839706f2543Smrg	    counter = *values++;
840706f2543Smrg	    break;
841706f2543Smrg
842706f2543Smrg	  case XSyncCAValueType:
843706f2543Smrg	    mask &= ~XSyncCAValueType;
844706f2543Smrg	    /* sanity check in SyncInitTrigger */
845706f2543Smrg	    pAlarm->trigger.value_type = *values++;
846706f2543Smrg	    break;
847706f2543Smrg
848706f2543Smrg	  case XSyncCAValue:
849706f2543Smrg	    mask &= ~XSyncCAValue;
850706f2543Smrg	    XSyncIntsToValue(&pAlarm->trigger.wait_value, values[1], values[0]);
851706f2543Smrg	    values += 2;
852706f2543Smrg	    break;
853706f2543Smrg
854706f2543Smrg	  case XSyncCATestType:
855706f2543Smrg	    mask &= ~XSyncCATestType;
856706f2543Smrg	    /* sanity check in SyncInitTrigger */
857706f2543Smrg	    pAlarm->trigger.test_type = *values++;
858706f2543Smrg	    break;
859706f2543Smrg
860706f2543Smrg	  case XSyncCADelta:
861706f2543Smrg	    mask &= ~XSyncCADelta;
862706f2543Smrg	    XSyncIntsToValue(&pAlarm->delta, values[1], values[0]);
863706f2543Smrg	    values += 2;
864706f2543Smrg	    break;
865706f2543Smrg
866706f2543Smrg	  case XSyncCAEvents:
867706f2543Smrg	    mask &= ~XSyncCAEvents;
868706f2543Smrg	    if ((*values != xTrue) && (*values != xFalse))
869706f2543Smrg	    {
870706f2543Smrg		client->errorValue = *values;
871706f2543Smrg		return BadValue;
872706f2543Smrg	    }
873706f2543Smrg	    status = SyncEventSelectForAlarm(pAlarm, client,
874706f2543Smrg					     (Bool)(*values++));
875706f2543Smrg	    if (status != Success)
876706f2543Smrg		return status;
877706f2543Smrg	    break;
878706f2543Smrg
879706f2543Smrg	  default:
880706f2543Smrg	    client->errorValue = mask;
881706f2543Smrg	    return BadValue;
882706f2543Smrg	}
883706f2543Smrg    }
884706f2543Smrg
885706f2543Smrg    /* "If the test-type is PositiveComparison or PositiveTransition
886706f2543Smrg     *  and delta is less than zero, or if the test-type is
887706f2543Smrg     *  NegativeComparison or NegativeTransition and delta is
888706f2543Smrg     *  greater than zero, a Match error is generated."
889706f2543Smrg     */
890706f2543Smrg    if (origmask & (XSyncCADelta|XSyncCATestType))
891706f2543Smrg    {
892706f2543Smrg	CARD64 zero;
893706f2543Smrg	XSyncIntToValue(&zero, 0);
894706f2543Smrg	if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) ||
895706f2543Smrg	      (pAlarm->trigger.test_type == XSyncPositiveTransition))
896706f2543Smrg	     && XSyncValueLessThan(pAlarm->delta, zero))
897706f2543Smrg	    ||
898706f2543Smrg	    (((pAlarm->trigger.test_type == XSyncNegativeComparison) ||
899706f2543Smrg	      (pAlarm->trigger.test_type == XSyncNegativeTransition))
900706f2543Smrg	     && XSyncValueGreaterThan(pAlarm->delta, zero))
901706f2543Smrg	   )
902706f2543Smrg	{
903706f2543Smrg	    return BadMatch;
904706f2543Smrg	}
905706f2543Smrg    }
906706f2543Smrg
907706f2543Smrg    /* postpone this until now, when we're sure nothing else can go wrong */
908706f2543Smrg    if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter,
909706f2543Smrg			     origmask & XSyncCAAllTrigger)) != Success)
910706f2543Smrg	return status;
911706f2543Smrg
912706f2543Smrg    /* XXX spec does not really say to do this - needs clarification */
913706f2543Smrg    pAlarm->state = XSyncAlarmActive;
914706f2543Smrg    return Success;
915706f2543Smrg}
916706f2543Smrg
917706f2543Smrgstatic SyncObject *
918706f2543SmrgSyncCreate(ClientPtr client, XID id, unsigned char type)
919706f2543Smrg{
920706f2543Smrg    SyncObject *pSync;
921706f2543Smrg
922706f2543Smrg    switch (type) {
923706f2543Smrg    case SYNC_COUNTER:
924706f2543Smrg	pSync = malloc(sizeof(SyncCounter));
925706f2543Smrg	break;
926706f2543Smrg    case SYNC_FENCE:
927706f2543Smrg	pSync = (SyncObject*)dixAllocateObjectWithPrivates(SyncFence,
928706f2543Smrg							   PRIVATE_SYNC_FENCE);
929706f2543Smrg	break;
930706f2543Smrg    default:
931706f2543Smrg	return NULL;
932706f2543Smrg    }
933706f2543Smrg
934706f2543Smrg    if (!pSync)
935706f2543Smrg	return NULL;
936706f2543Smrg
937706f2543Smrg    pSync->client = client;
938706f2543Smrg    pSync->id = id;
939706f2543Smrg    pSync->pTriglist = NULL;
940706f2543Smrg    pSync->beingDestroyed = FALSE;
941706f2543Smrg    pSync->type = type;
942706f2543Smrg
943706f2543Smrg    return pSync;
944706f2543Smrg}
945706f2543Smrg
946706f2543Smrg
947706f2543Smrgstatic SyncCounter *
948706f2543SmrgSyncCreateCounter(ClientPtr client, XSyncCounter id, CARD64 initialvalue)
949706f2543Smrg{
950706f2543Smrg    SyncCounter *pCounter;
951706f2543Smrg
952706f2543Smrg    if (!(pCounter = (SyncCounter *)SyncCreate(client,
953706f2543Smrg					       id,
954706f2543Smrg					       SYNC_COUNTER)))
955706f2543Smrg	return NULL;
956706f2543Smrg
957706f2543Smrg    pCounter->value = initialvalue;
958706f2543Smrg    pCounter->pSysCounterInfo = NULL;
959706f2543Smrg
960706f2543Smrg    if (!AddResource(id, RTCounter, (pointer) pCounter))
961706f2543Smrg	return NULL;
962706f2543Smrg
963706f2543Smrg    return pCounter;
964706f2543Smrg}
965706f2543Smrg
966706f2543Smrgstatic int FreeCounter(void *, XID);
967706f2543Smrg
968706f2543Smrg/*
969706f2543Smrg * ***** System Counter utilities
970706f2543Smrg */
971706f2543Smrg
972706f2543Smrgpointer
973706f2543SmrgSyncCreateSystemCounter(
974706f2543Smrg	char *name,
975706f2543Smrg	CARD64 initial,
976706f2543Smrg	CARD64 resolution,
977706f2543Smrg	SyncCounterType counterType,
978706f2543Smrg	void (*QueryValue)(pointer /* pCounter */,
979706f2543Smrg	      	           CARD64 * /* pValue_return */),
980706f2543Smrg	void (*BracketValues)(pointer /* pCounter */,
981706f2543Smrg	       	              CARD64 * /* pbracket_less */,
982706f2543Smrg	                      CARD64 * /* pbracket_greater */)
983706f2543Smrg	)
984706f2543Smrg{
985706f2543Smrg    SyncCounter    *pCounter;
986706f2543Smrg
987706f2543Smrg    SysCounterList = realloc(SysCounterList,
988706f2543Smrg			    (SyncNumSystemCounters+1)*sizeof(SyncCounter *));
989706f2543Smrg    if (!SysCounterList)
990706f2543Smrg	return NULL;
991706f2543Smrg
992706f2543Smrg    /* this function may be called before SYNC has been initialized, so we
993706f2543Smrg     * have to make sure RTCounter is created.
994706f2543Smrg     */
995706f2543Smrg    if (RTCounter == 0)
996706f2543Smrg    {
997706f2543Smrg	RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
998706f2543Smrg	if (RTCounter == 0)
999706f2543Smrg	{
1000706f2543Smrg	    return NULL;
1001706f2543Smrg	}
1002706f2543Smrg    }
1003706f2543Smrg
1004706f2543Smrg    pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial);
1005706f2543Smrg
1006706f2543Smrg    if (pCounter)
1007706f2543Smrg    {
1008706f2543Smrg	SysCounterInfo *psci;
1009706f2543Smrg
1010706f2543Smrg	psci = malloc(sizeof(SysCounterInfo));
1011706f2543Smrg	if (!psci)
1012706f2543Smrg	{
1013706f2543Smrg	    FreeResource(pCounter->sync.id, RT_NONE);
1014706f2543Smrg	    return pCounter;
1015706f2543Smrg	}
1016706f2543Smrg	pCounter->pSysCounterInfo = psci;
1017706f2543Smrg	psci->name = name;
1018706f2543Smrg	psci->resolution = resolution;
1019706f2543Smrg	psci->counterType = counterType;
1020706f2543Smrg	psci->QueryValue = QueryValue;
1021706f2543Smrg	psci->BracketValues = BracketValues;
1022706f2543Smrg	XSyncMaxValue(&psci->bracket_greater);
1023706f2543Smrg	XSyncMinValue(&psci->bracket_less);
1024706f2543Smrg	SysCounterList[SyncNumSystemCounters++] = pCounter;
1025706f2543Smrg    }
1026706f2543Smrg    return pCounter;
1027706f2543Smrg}
1028706f2543Smrg
1029706f2543Smrgvoid
1030706f2543SmrgSyncDestroySystemCounter(pointer pSysCounter)
1031706f2543Smrg{
1032706f2543Smrg    SyncCounter *pCounter = (SyncCounter *)pSysCounter;
1033706f2543Smrg    FreeResource(pCounter->sync.id, RT_NONE);
1034706f2543Smrg}
1035706f2543Smrg
1036706f2543Smrgstatic void
1037706f2543SmrgSyncComputeBracketValues(SyncCounter *pCounter)
1038706f2543Smrg{
1039706f2543Smrg    SyncTriggerList *pCur;
1040706f2543Smrg    SyncTrigger *pTrigger;
1041706f2543Smrg    SysCounterInfo *psci;
1042706f2543Smrg    CARD64 *pnewgtval = NULL;
1043706f2543Smrg    CARD64 *pnewltval = NULL;
1044706f2543Smrg    SyncCounterType ct;
1045706f2543Smrg
1046706f2543Smrg    if (!pCounter)
1047706f2543Smrg	return;
1048706f2543Smrg
1049706f2543Smrg    psci = pCounter->pSysCounterInfo;
1050706f2543Smrg    ct = pCounter->pSysCounterInfo->counterType;
1051706f2543Smrg    if (ct == XSyncCounterNeverChanges)
1052706f2543Smrg	return;
1053706f2543Smrg
1054706f2543Smrg    XSyncMaxValue(&psci->bracket_greater);
1055706f2543Smrg    XSyncMinValue(&psci->bracket_less);
1056706f2543Smrg
1057706f2543Smrg    for (pCur = pCounter->sync.pTriglist; pCur; pCur = pCur->next)
1058706f2543Smrg    {
1059706f2543Smrg	pTrigger = pCur->pTrigger;
1060706f2543Smrg
1061706f2543Smrg        if (pTrigger->test_type == XSyncPositiveComparison &&
1062706f2543Smrg	    ct != XSyncCounterNeverIncreases)
1063706f2543Smrg	{
1064706f2543Smrg	    if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
1065706f2543Smrg		XSyncValueLessThan(pTrigger->test_value,
1066706f2543Smrg				   psci->bracket_greater))
1067706f2543Smrg	    {
1068706f2543Smrg		psci->bracket_greater = pTrigger->test_value;
1069706f2543Smrg		pnewgtval = &psci->bracket_greater;
1070706f2543Smrg	    }
1071706f2543Smrg	}
1072706f2543Smrg	else if (pTrigger->test_type == XSyncNegativeComparison &&
1073706f2543Smrg		 ct != XSyncCounterNeverDecreases)
1074706f2543Smrg	{
1075706f2543Smrg	    if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
1076706f2543Smrg		XSyncValueGreaterThan(pTrigger->test_value,
1077706f2543Smrg				      psci->bracket_less))
1078706f2543Smrg	    {
1079706f2543Smrg		psci->bracket_less = pTrigger->test_value;
1080706f2543Smrg		pnewltval = &psci->bracket_less;
1081706f2543Smrg	    }
1082706f2543Smrg	}
1083706f2543Smrg	else if (pTrigger->test_type == XSyncNegativeTransition &&
1084706f2543Smrg		   ct != XSyncCounterNeverIncreases)
1085706f2543Smrg	{
1086706f2543Smrg	    if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
1087706f2543Smrg		XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less))
1088706f2543Smrg	    {
1089706f2543Smrg		psci->bracket_less = pTrigger->test_value;
1090706f2543Smrg		pnewltval = &psci->bracket_less;
1091706f2543Smrg	    } else if (XSyncValueEqual(pCounter->value, pTrigger->test_value) &&
1092706f2543Smrg		       XSyncValueLessThan(pTrigger->test_value,
1093706f2543Smrg					  psci->bracket_greater))
1094706f2543Smrg	    {
1095706f2543Smrg	        /*
1096706f2543Smrg		 * The value is exactly equal to our threshold.  We want one
1097706f2543Smrg		 * more event in the positive direction to ensure we pick up
1098706f2543Smrg		 * when the value *exceeds* this threshold.
1099706f2543Smrg		 */
1100706f2543Smrg	        psci->bracket_greater = pTrigger->test_value;
1101706f2543Smrg		pnewgtval = &psci->bracket_greater;
1102706f2543Smrg	    }
1103706f2543Smrg	}
1104706f2543Smrg        else if (pTrigger->test_type == XSyncPositiveTransition &&
1105706f2543Smrg		  ct != XSyncCounterNeverDecreases)
1106706f2543Smrg	{
1107706f2543Smrg	    if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
1108706f2543Smrg		XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater))
1109706f2543Smrg	    {
1110706f2543Smrg		psci->bracket_greater = pTrigger->test_value;
1111706f2543Smrg		pnewgtval = &psci->bracket_greater;
1112706f2543Smrg	    } else if (XSyncValueEqual(pCounter->value, pTrigger->test_value) &&
1113706f2543Smrg		       XSyncValueGreaterThan(pTrigger->test_value,
1114706f2543Smrg					     psci->bracket_less))
1115706f2543Smrg	    {
1116706f2543Smrg	        /*
1117706f2543Smrg		 * The value is exactly equal to our threshold.  We want one
1118706f2543Smrg		 * more event in the negative direction to ensure we pick up
1119706f2543Smrg		 * when the value is less than this threshold.
1120706f2543Smrg		 */
1121706f2543Smrg	        psci->bracket_less = pTrigger->test_value;
1122706f2543Smrg		pnewltval = &psci->bracket_less;
1123706f2543Smrg	    }
1124706f2543Smrg	}
1125706f2543Smrg    } /* end for each trigger */
1126706f2543Smrg
1127706f2543Smrg    if (pnewgtval || pnewltval)
1128706f2543Smrg    {
1129706f2543Smrg	(*psci->BracketValues)((pointer)pCounter, pnewltval, pnewgtval);
1130706f2543Smrg    }
1131706f2543Smrg}
1132706f2543Smrg
1133706f2543Smrg/*
1134706f2543Smrg * *****  Resource delete functions
1135706f2543Smrg */
1136706f2543Smrg
1137706f2543Smrg/* ARGSUSED */
1138706f2543Smrgstatic int
1139706f2543SmrgFreeAlarm(void *addr, XID id)
1140706f2543Smrg{
1141706f2543Smrg    SyncAlarm      *pAlarm = (SyncAlarm *) addr;
1142706f2543Smrg
1143706f2543Smrg    pAlarm->state = XSyncAlarmDestroyed;
1144706f2543Smrg
1145706f2543Smrg    SyncSendAlarmNotifyEvents(pAlarm);
1146706f2543Smrg
1147706f2543Smrg    /* delete event selections */
1148706f2543Smrg
1149706f2543Smrg    while (pAlarm->pEventClients)
1150706f2543Smrg	FreeResource(pAlarm->pEventClients->delete_id, RT_NONE);
1151706f2543Smrg
1152706f2543Smrg    SyncDeleteTriggerFromSyncObject(&pAlarm->trigger);
1153706f2543Smrg
1154706f2543Smrg    free(pAlarm);
1155706f2543Smrg    return Success;
1156706f2543Smrg}
1157706f2543Smrg
1158706f2543Smrg
1159706f2543Smrg/*
1160706f2543Smrg * ** Cleanup after the destruction of a Counter
1161706f2543Smrg */
1162706f2543Smrg/* ARGSUSED */
1163706f2543Smrgstatic int
1164706f2543SmrgFreeCounter(void *env, XID id)
1165706f2543Smrg{
1166706f2543Smrg    SyncCounter     *pCounter = (SyncCounter *) env;
1167706f2543Smrg    SyncTriggerList *ptl, *pnext;
1168706f2543Smrg
1169706f2543Smrg    pCounter->sync.beingDestroyed = TRUE;
1170706f2543Smrg    /* tell all the counter's triggers that the counter has been destroyed */
1171706f2543Smrg    for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext)
1172706f2543Smrg    {
1173706f2543Smrg	(*ptl->pTrigger->CounterDestroyed)(ptl->pTrigger);
1174706f2543Smrg	pnext = ptl->next;
1175706f2543Smrg	free(ptl); /* destroy the trigger list as we go */
1176706f2543Smrg    }
1177706f2543Smrg    if (IsSystemCounter(pCounter))
1178706f2543Smrg    {
1179706f2543Smrg	int i, found = 0;
1180706f2543Smrg
1181706f2543Smrg	free(pCounter->pSysCounterInfo);
1182706f2543Smrg
1183706f2543Smrg	/* find the counter in the list of system counters and remove it */
1184706f2543Smrg
1185706f2543Smrg	if (SysCounterList)
1186706f2543Smrg	{
1187706f2543Smrg	    for (i = 0; i < SyncNumSystemCounters; i++)
1188706f2543Smrg	    {
1189706f2543Smrg		if (SysCounterList[i] == pCounter)
1190706f2543Smrg		{
1191706f2543Smrg		    found = i;
1192706f2543Smrg		    break;
1193706f2543Smrg		}
1194706f2543Smrg	    }
1195706f2543Smrg	    if (found < (SyncNumSystemCounters-1))
1196706f2543Smrg	    {
1197706f2543Smrg		for (i = found; i < SyncNumSystemCounters-1; i++)
1198706f2543Smrg		{
1199706f2543Smrg		    SysCounterList[i] = SysCounterList[i+1];
1200706f2543Smrg		}
1201706f2543Smrg	    }
1202706f2543Smrg	}
1203706f2543Smrg	SyncNumSystemCounters--;
1204706f2543Smrg    }
1205706f2543Smrg    free(pCounter);
1206706f2543Smrg    return Success;
1207706f2543Smrg}
1208706f2543Smrg
1209706f2543Smrg/*
1210706f2543Smrg * ** Cleanup after Await
1211706f2543Smrg */
1212706f2543Smrg/* ARGSUSED */
1213706f2543Smrgstatic int
1214706f2543SmrgFreeAwait(void *addr, XID id)
1215706f2543Smrg{
1216706f2543Smrg    SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr;
1217706f2543Smrg    SyncAwait *pAwait;
1218706f2543Smrg    int numwaits;
1219706f2543Smrg
1220706f2543Smrg    pAwait = &(pAwaitUnion+1)->await; /* first await on list */
1221706f2543Smrg
1222706f2543Smrg    /* remove triggers from counters */
1223706f2543Smrg
1224706f2543Smrg    for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits;
1225706f2543Smrg	 numwaits--, pAwait++)
1226706f2543Smrg    {
1227706f2543Smrg	/* If the counter is being destroyed, FreeCounter will delete
1228706f2543Smrg	 * the trigger list itself, so don't do it here.
1229706f2543Smrg	 */
1230706f2543Smrg	SyncObject *pSync = pAwait->trigger.pSync;
1231706f2543Smrg	if (pSync && !pSync->beingDestroyed)
1232706f2543Smrg	    SyncDeleteTriggerFromSyncObject(&pAwait->trigger);
1233706f2543Smrg    }
1234706f2543Smrg    free(pAwaitUnion);
1235706f2543Smrg    return Success;
1236706f2543Smrg}
1237706f2543Smrg
1238706f2543Smrg/* loosely based on dix/events.c/OtherClientGone */
1239706f2543Smrgstatic int
1240706f2543SmrgFreeAlarmClient(void *value, XID id)
1241706f2543Smrg{
1242706f2543Smrg    SyncAlarm *pAlarm = (SyncAlarm *)value;
1243706f2543Smrg    SyncAlarmClientList *pCur, *pPrev;
1244706f2543Smrg
1245706f2543Smrg    for (pPrev = NULL, pCur = pAlarm->pEventClients;
1246706f2543Smrg	 pCur;
1247706f2543Smrg	 pPrev = pCur, pCur = pCur->next)
1248706f2543Smrg    {
1249706f2543Smrg	if (pCur->delete_id == id)
1250706f2543Smrg	{
1251706f2543Smrg	    if (pPrev)
1252706f2543Smrg		pPrev->next = pCur->next;
1253706f2543Smrg	    else
1254706f2543Smrg		pAlarm->pEventClients = pCur->next;
1255706f2543Smrg	    free(pCur);
1256706f2543Smrg	    return Success;
1257706f2543Smrg	}
1258706f2543Smrg    }
1259706f2543Smrg    FatalError("alarm client not on event list");
1260706f2543Smrg    /*NOTREACHED*/
1261706f2543Smrg}
1262706f2543Smrg
1263706f2543Smrg
1264706f2543Smrg/*
1265706f2543Smrg * *****  Proc functions
1266706f2543Smrg */
1267706f2543Smrg
1268706f2543Smrg
1269706f2543Smrg/*
1270706f2543Smrg * ** Initialize the extension
1271706f2543Smrg */
1272706f2543Smrgstatic int
1273706f2543SmrgProcSyncInitialize(ClientPtr client)
1274706f2543Smrg{
1275706f2543Smrg    xSyncInitializeReply  rep;
1276706f2543Smrg    int   n;
1277706f2543Smrg
1278706f2543Smrg    REQUEST_SIZE_MATCH(xSyncInitializeReq);
1279706f2543Smrg
1280706f2543Smrg    memset(&rep, 0, sizeof(xSyncInitializeReply));
1281706f2543Smrg    rep.type = X_Reply;
1282706f2543Smrg    rep.sequenceNumber = client->sequence;
1283706f2543Smrg    rep.majorVersion = SERVER_SYNC_MAJOR_VERSION;
1284706f2543Smrg    rep.minorVersion = SERVER_SYNC_MINOR_VERSION;
1285706f2543Smrg    rep.length = 0;
1286706f2543Smrg
1287706f2543Smrg    if (client->swapped)
1288706f2543Smrg    {
1289706f2543Smrg	swaps(&rep.sequenceNumber, n);
1290706f2543Smrg    }
1291706f2543Smrg    WriteToClient(client, sizeof(rep), (char *) &rep);
1292706f2543Smrg    return Success;
1293706f2543Smrg}
1294706f2543Smrg
1295706f2543Smrg/*
1296706f2543Smrg * ** Get list of system counters available through the extension
1297706f2543Smrg */
1298706f2543Smrgstatic int
1299706f2543SmrgProcSyncListSystemCounters(ClientPtr client)
1300706f2543Smrg{
1301706f2543Smrg    xSyncListSystemCountersReply  rep;
1302706f2543Smrg    int i, len;
1303706f2543Smrg    xSyncSystemCounter *list = NULL, *walklist = NULL;
1304706f2543Smrg
1305706f2543Smrg    REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
1306706f2543Smrg
1307706f2543Smrg    rep.type = X_Reply;
1308706f2543Smrg    rep.sequenceNumber = client->sequence;
1309706f2543Smrg    rep.nCounters = SyncNumSystemCounters;
1310706f2543Smrg
1311706f2543Smrg    for (i = len = 0; i < SyncNumSystemCounters; i++)
1312706f2543Smrg    {
1313706f2543Smrg	char *name = SysCounterList[i]->pSysCounterInfo->name;
1314706f2543Smrg	/* pad to 4 byte boundary */
1315706f2543Smrg	len += pad_to_int32(sz_xSyncSystemCounter + strlen(name));
1316706f2543Smrg    }
1317706f2543Smrg
1318706f2543Smrg    if (len)
1319706f2543Smrg    {
1320706f2543Smrg	walklist = list = malloc(len);
1321706f2543Smrg	if (!list)
1322706f2543Smrg	    return BadAlloc;
1323706f2543Smrg    }
1324706f2543Smrg
1325706f2543Smrg    rep.length = bytes_to_int32(len);
1326706f2543Smrg
1327706f2543Smrg    if (client->swapped)
1328706f2543Smrg    {
1329706f2543Smrg	char n;
1330706f2543Smrg	swaps(&rep.sequenceNumber, n);
1331706f2543Smrg	swapl(&rep.length, n);
1332706f2543Smrg	swapl(&rep.nCounters, n);
1333706f2543Smrg    }
1334706f2543Smrg
1335706f2543Smrg    for (i = 0; i < SyncNumSystemCounters; i++)
1336706f2543Smrg    {
1337706f2543Smrg	int namelen;
1338706f2543Smrg	char *pname_in_reply;
1339706f2543Smrg	SysCounterInfo *psci = SysCounterList[i]->pSysCounterInfo;
1340706f2543Smrg
1341706f2543Smrg	walklist->counter = SysCounterList[i]->sync.id;
1342706f2543Smrg	walklist->resolution_hi = XSyncValueHigh32(psci->resolution);
1343706f2543Smrg	walklist->resolution_lo = XSyncValueLow32(psci->resolution);
1344706f2543Smrg	namelen = strlen(psci->name);
1345706f2543Smrg	walklist->name_length = namelen;
1346706f2543Smrg
1347706f2543Smrg	if (client->swapped)
1348706f2543Smrg	{
1349706f2543Smrg	    char n;
1350706f2543Smrg	    swapl(&walklist->counter, n);
1351706f2543Smrg	    swapl(&walklist->resolution_hi, n);
1352706f2543Smrg	    swapl(&walklist->resolution_lo, n);
1353706f2543Smrg	    swaps(&walklist->name_length, n);
1354706f2543Smrg	}
1355706f2543Smrg
1356706f2543Smrg	pname_in_reply = ((char *)walklist) + sz_xSyncSystemCounter;
1357706f2543Smrg	strncpy(pname_in_reply, psci->name, namelen);
1358706f2543Smrg	walklist = (xSyncSystemCounter *) (((char *)walklist) +
1359706f2543Smrg				pad_to_int32(sz_xSyncSystemCounter + namelen));
1360706f2543Smrg    }
1361706f2543Smrg
1362706f2543Smrg    WriteToClient(client, sizeof(rep), (char *) &rep);
1363706f2543Smrg    if (len)
1364706f2543Smrg    {
1365706f2543Smrg	WriteToClient(client, len, (char *) list);
1366706f2543Smrg	free(list);
1367706f2543Smrg    }
1368706f2543Smrg
1369706f2543Smrg    return Success;
1370706f2543Smrg}
1371706f2543Smrg
1372706f2543Smrg/*
1373706f2543Smrg * ** Set client Priority
1374706f2543Smrg */
1375706f2543Smrgstatic int
1376706f2543SmrgProcSyncSetPriority(ClientPtr client)
1377706f2543Smrg{
1378706f2543Smrg    REQUEST(xSyncSetPriorityReq);
1379706f2543Smrg    ClientPtr priorityclient;
1380706f2543Smrg    int rc;
1381706f2543Smrg
1382706f2543Smrg    REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
1383706f2543Smrg
1384706f2543Smrg    if (stuff->id == None)
1385706f2543Smrg	priorityclient = client;
1386706f2543Smrg    else {
1387706f2543Smrg	rc = dixLookupClient(&priorityclient, stuff->id, client,
1388706f2543Smrg			     DixSetAttrAccess);
1389706f2543Smrg	if (rc != Success)
1390706f2543Smrg	    return rc;
1391706f2543Smrg    }
1392706f2543Smrg
1393706f2543Smrg    if (priorityclient->priority != stuff->priority)
1394706f2543Smrg    {
1395706f2543Smrg	priorityclient->priority = stuff->priority;
1396706f2543Smrg
1397706f2543Smrg	/*  The following will force the server back into WaitForSomething
1398706f2543Smrg	 *  so that the change in this client's priority is immediately
1399706f2543Smrg	 *  reflected.
1400706f2543Smrg	 */
1401706f2543Smrg	isItTimeToYield = TRUE;
1402706f2543Smrg	dispatchException |= DE_PRIORITYCHANGE;
1403706f2543Smrg    }
1404706f2543Smrg    return Success;
1405706f2543Smrg}
1406706f2543Smrg
1407706f2543Smrg/*
1408706f2543Smrg * ** Get client Priority
1409706f2543Smrg */
1410706f2543Smrgstatic int
1411706f2543SmrgProcSyncGetPriority(ClientPtr client)
1412706f2543Smrg{
1413706f2543Smrg    REQUEST(xSyncGetPriorityReq);
1414706f2543Smrg    xSyncGetPriorityReply rep;
1415706f2543Smrg    ClientPtr priorityclient;
1416706f2543Smrg    int rc;
1417706f2543Smrg
1418706f2543Smrg    REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
1419706f2543Smrg
1420706f2543Smrg    if (stuff->id == None)
1421706f2543Smrg	priorityclient = client;
1422706f2543Smrg    else {
1423706f2543Smrg	rc = dixLookupClient(&priorityclient, stuff->id, client,
1424706f2543Smrg			     DixGetAttrAccess);
1425706f2543Smrg	if (rc != Success)
1426706f2543Smrg	    return rc;
1427706f2543Smrg    }
1428706f2543Smrg
1429706f2543Smrg    rep.type = X_Reply;
1430706f2543Smrg    rep.length = 0;
1431706f2543Smrg    rep.sequenceNumber = client->sequence;
1432706f2543Smrg    rep.priority = priorityclient->priority;
1433706f2543Smrg
1434706f2543Smrg    if (client->swapped)
1435706f2543Smrg    {
1436706f2543Smrg	char n;
1437706f2543Smrg	swaps(&rep.sequenceNumber, n);
1438706f2543Smrg	swapl(&rep.priority, n);
1439706f2543Smrg    }
1440706f2543Smrg
1441706f2543Smrg    WriteToClient(client, sizeof(xSyncGetPriorityReply), (char *) &rep);
1442706f2543Smrg
1443706f2543Smrg    return Success;
1444706f2543Smrg}
1445706f2543Smrg
1446706f2543Smrg/*
1447706f2543Smrg * ** Create a new counter
1448706f2543Smrg */
1449706f2543Smrgstatic int
1450706f2543SmrgProcSyncCreateCounter(ClientPtr client)
1451706f2543Smrg{
1452706f2543Smrg    REQUEST(xSyncCreateCounterReq);
1453706f2543Smrg    CARD64          initial;
1454706f2543Smrg
1455706f2543Smrg    REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
1456706f2543Smrg
1457706f2543Smrg    LEGAL_NEW_RESOURCE(stuff->cid, client);
1458706f2543Smrg
1459706f2543Smrg    XSyncIntsToValue(&initial, stuff->initial_value_lo, stuff->initial_value_hi);
1460706f2543Smrg    if (!SyncCreateCounter(client, stuff->cid, initial))
1461706f2543Smrg	return BadAlloc;
1462706f2543Smrg
1463706f2543Smrg    return Success;
1464706f2543Smrg}
1465706f2543Smrg
1466706f2543Smrg/*
1467706f2543Smrg * ** Set Counter value
1468706f2543Smrg */
1469706f2543Smrgstatic int
1470706f2543SmrgProcSyncSetCounter(ClientPtr client)
1471706f2543Smrg{
1472706f2543Smrg    REQUEST(xSyncSetCounterReq);
1473706f2543Smrg    SyncCounter    *pCounter;
1474706f2543Smrg    CARD64	   newvalue;
1475706f2543Smrg    int	rc;
1476706f2543Smrg
1477706f2543Smrg    REQUEST_SIZE_MATCH(xSyncSetCounterReq);
1478706f2543Smrg
1479706f2543Smrg    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
1480706f2543Smrg				 client, DixWriteAccess);
1481706f2543Smrg    if (rc != Success)
1482706f2543Smrg	return rc;
1483706f2543Smrg
1484706f2543Smrg    if (IsSystemCounter(pCounter))
1485706f2543Smrg    {
1486706f2543Smrg	client->errorValue = stuff->cid;
1487706f2543Smrg	return BadAccess;
1488706f2543Smrg    }
1489706f2543Smrg
1490706f2543Smrg    XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
1491706f2543Smrg    SyncChangeCounter(pCounter, newvalue);
1492706f2543Smrg    return Success;
1493706f2543Smrg}
1494706f2543Smrg
1495706f2543Smrg/*
1496706f2543Smrg * ** Change Counter value
1497706f2543Smrg */
1498706f2543Smrgstatic int
1499706f2543SmrgProcSyncChangeCounter(ClientPtr client)
1500706f2543Smrg{
1501706f2543Smrg    REQUEST(xSyncChangeCounterReq);
1502706f2543Smrg    SyncCounter    *pCounter;
1503706f2543Smrg    CARD64          newvalue;
1504706f2543Smrg    Bool	    overflow;
1505706f2543Smrg    int	rc;
1506706f2543Smrg
1507706f2543Smrg    REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
1508706f2543Smrg
1509706f2543Smrg    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
1510706f2543Smrg				 client, DixWriteAccess);
1511706f2543Smrg    if (rc != Success)
1512706f2543Smrg	return rc;
1513706f2543Smrg
1514706f2543Smrg    if (IsSystemCounter(pCounter))
1515706f2543Smrg    {
1516706f2543Smrg	client->errorValue = stuff->cid;
1517706f2543Smrg	return BadAccess;
1518706f2543Smrg    }
1519706f2543Smrg
1520706f2543Smrg    XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
1521706f2543Smrg    XSyncValueAdd(&newvalue, pCounter->value, newvalue, &overflow);
1522706f2543Smrg    if (overflow)
1523706f2543Smrg    {
1524706f2543Smrg	/* XXX 64 bit value can't fit in 32 bits; do the best we can */
1525706f2543Smrg	client->errorValue = stuff->value_hi;
1526706f2543Smrg	return BadValue;
1527706f2543Smrg    }
1528706f2543Smrg    SyncChangeCounter(pCounter, newvalue);
1529706f2543Smrg    return Success;
1530706f2543Smrg}
1531706f2543Smrg
1532706f2543Smrg/*
1533706f2543Smrg * ** Destroy a counter
1534706f2543Smrg */
1535706f2543Smrgstatic int
1536706f2543SmrgProcSyncDestroyCounter(ClientPtr client)
1537706f2543Smrg{
1538706f2543Smrg    REQUEST(xSyncDestroyCounterReq);
1539706f2543Smrg    SyncCounter    *pCounter;
1540706f2543Smrg    int rc;
1541706f2543Smrg
1542706f2543Smrg    REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
1543706f2543Smrg
1544706f2543Smrg    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter, RTCounter,
1545706f2543Smrg				 client, DixDestroyAccess);
1546706f2543Smrg    if (rc != Success)
1547706f2543Smrg	return rc;
1548706f2543Smrg
1549706f2543Smrg    if (IsSystemCounter(pCounter))
1550706f2543Smrg    {
1551706f2543Smrg	client->errorValue = stuff->counter;
1552706f2543Smrg	return BadAccess;
1553706f2543Smrg    }
1554706f2543Smrg    FreeResource(pCounter->sync.id, RT_NONE);
1555706f2543Smrg    return Success;
1556706f2543Smrg}
1557706f2543Smrg
1558706f2543Smrgstatic SyncAwaitUnion*
1559706f2543SmrgSyncAwaitPrologue(ClientPtr client, int items)
1560706f2543Smrg{
1561706f2543Smrg    SyncAwaitUnion *pAwaitUnion;
1562706f2543Smrg
1563706f2543Smrg    /*  all the memory for the entire await list is allocated
1564706f2543Smrg     *  here in one chunk
1565706f2543Smrg     */
1566706f2543Smrg    pAwaitUnion = malloc((items+1) * sizeof(SyncAwaitUnion));
1567706f2543Smrg    if (!pAwaitUnion)
1568706f2543Smrg	return NULL;
1569706f2543Smrg
1570706f2543Smrg    /* first item is the header, remainder are real wait conditions */
1571706f2543Smrg
1572706f2543Smrg    pAwaitUnion->header.delete_id = FakeClientID(client->index);
1573706f2543Smrg    pAwaitUnion->header.client = client;
1574706f2543Smrg    pAwaitUnion->header.num_waitconditions = 0;
1575706f2543Smrg
1576706f2543Smrg    if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion))
1577706f2543Smrg	return NULL;
1578706f2543Smrg
1579706f2543Smrg    return pAwaitUnion;
1580706f2543Smrg}
1581706f2543Smrg
1582706f2543Smrgstatic void
1583706f2543SmrgSyncAwaitEpilogue(ClientPtr client, int items, SyncAwaitUnion *pAwaitUnion)
1584706f2543Smrg{
1585706f2543Smrg    SyncAwait *pAwait;
1586706f2543Smrg    int i;
1587706f2543Smrg
1588706f2543Smrg    IgnoreClient(client);
1589706f2543Smrg
1590706f2543Smrg    /* see if any of the triggers are already true */
1591706f2543Smrg
1592706f2543Smrg    pAwait = &(pAwaitUnion+1)->await; /* skip over header */
1593706f2543Smrg    for (i = 0; i < items; i++, pAwait++)
1594706f2543Smrg    {
1595706f2543Smrg	CARD64 value;
1596706f2543Smrg
1597706f2543Smrg	/*  don't have to worry about NULL counters because the request
1598706f2543Smrg	 *  errors before we get here out if they occur
1599706f2543Smrg	 */
1600706f2543Smrg	switch (pAwait->trigger.pSync->type) {
1601706f2543Smrg	case SYNC_COUNTER:
1602706f2543Smrg	    value = ((SyncCounter *)pAwait->trigger.pSync)->value;
1603706f2543Smrg	    break;
1604706f2543Smrg	default:
1605706f2543Smrg	    XSyncIntToValue(&value, 0);
1606706f2543Smrg	}
1607706f2543Smrg
1608706f2543Smrg	if ((*pAwait->trigger.CheckTrigger)(&pAwait->trigger, value))
1609706f2543Smrg	{
1610706f2543Smrg	    (*pAwait->trigger.TriggerFired)(&pAwait->trigger);
1611706f2543Smrg	    break; /* once is enough */
1612706f2543Smrg	}
1613706f2543Smrg    }
1614706f2543Smrg}
1615706f2543Smrg
1616706f2543Smrg/*
1617706f2543Smrg * ** Await
1618706f2543Smrg */
1619706f2543Smrgstatic int
1620706f2543SmrgProcSyncAwait(ClientPtr client)
1621706f2543Smrg{
1622706f2543Smrg    REQUEST(xSyncAwaitReq);
1623706f2543Smrg    int             len, items;
1624706f2543Smrg    int             i;
1625706f2543Smrg    xSyncWaitCondition *pProtocolWaitConds;
1626706f2543Smrg    SyncAwaitUnion *pAwaitUnion;
1627706f2543Smrg    SyncAwait	   *pAwait;
1628706f2543Smrg    int		   status;
1629706f2543Smrg
1630706f2543Smrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
1631706f2543Smrg
1632706f2543Smrg    len = client->req_len << 2;
1633706f2543Smrg    len -= sz_xSyncAwaitReq;
1634706f2543Smrg    items = len / sz_xSyncWaitCondition;
1635706f2543Smrg
1636706f2543Smrg    if (items * sz_xSyncWaitCondition != len)
1637706f2543Smrg    {
1638706f2543Smrg	return BadLength;
1639706f2543Smrg    }
1640706f2543Smrg    if (items == 0)
1641706f2543Smrg    {
1642706f2543Smrg	client->errorValue = items; /* XXX protocol change */
1643706f2543Smrg	return BadValue;
1644706f2543Smrg    }
1645706f2543Smrg
1646706f2543Smrg    if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
1647706f2543Smrg	return BadAlloc;
1648706f2543Smrg
1649706f2543Smrg    /* don't need to do any more memory allocation for this request! */
1650706f2543Smrg
1651706f2543Smrg    pProtocolWaitConds = (xSyncWaitCondition *) & stuff[1];
1652706f2543Smrg
1653706f2543Smrg    pAwait = &(pAwaitUnion+1)->await; /* skip over header */
1654706f2543Smrg    for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++)
1655706f2543Smrg    {
1656706f2543Smrg	if (pProtocolWaitConds->counter == None) /* XXX protocol change */
1657706f2543Smrg	{
1658706f2543Smrg	    /*  this should take care of removing any triggers created by
1659706f2543Smrg	     *  this request that have already been registered on sync objects
1660706f2543Smrg	     */
1661706f2543Smrg	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
1662706f2543Smrg	    client->errorValue = pProtocolWaitConds->counter;
1663706f2543Smrg	    return SyncErrorBase + XSyncBadCounter;
1664706f2543Smrg	}
1665706f2543Smrg
1666706f2543Smrg	/* sanity checks are in SyncInitTrigger */
1667706f2543Smrg	pAwait->trigger.pSync = NULL;
1668706f2543Smrg	pAwait->trigger.value_type = pProtocolWaitConds->value_type;
1669706f2543Smrg	XSyncIntsToValue(&pAwait->trigger.wait_value,
1670706f2543Smrg			 pProtocolWaitConds->wait_value_lo,
1671706f2543Smrg			 pProtocolWaitConds->wait_value_hi);
1672706f2543Smrg	pAwait->trigger.test_type = pProtocolWaitConds->test_type;
1673706f2543Smrg
1674706f2543Smrg	status = SyncInitTrigger(client, &pAwait->trigger,
1675706f2543Smrg				 pProtocolWaitConds->counter, RTCounter,
1676706f2543Smrg				 XSyncCAAllTrigger);
1677706f2543Smrg	if (status != Success)
1678706f2543Smrg	{
1679706f2543Smrg	    /*  this should take care of removing any triggers created by
1680706f2543Smrg	     *  this request that have already been registered on sync objects
1681706f2543Smrg	     */
1682706f2543Smrg	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
1683706f2543Smrg	    return status;
1684706f2543Smrg	}
1685706f2543Smrg	/* this is not a mistake -- same function works for both cases */
1686706f2543Smrg	pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
1687706f2543Smrg	pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
1688706f2543Smrg	XSyncIntsToValue(&pAwait->event_threshold,
1689706f2543Smrg			 pProtocolWaitConds->event_threshold_lo,
1690706f2543Smrg			 pProtocolWaitConds->event_threshold_hi);
1691706f2543Smrg	pAwait->pHeader = &pAwaitUnion->header;
1692706f2543Smrg	pAwaitUnion->header.num_waitconditions++;
1693706f2543Smrg    }
1694706f2543Smrg
1695706f2543Smrg    SyncAwaitEpilogue(client, items, pAwaitUnion);
1696706f2543Smrg
1697706f2543Smrg    return Success;
1698706f2543Smrg}
1699706f2543Smrg
1700706f2543Smrg
1701706f2543Smrg/*
1702706f2543Smrg * ** Query a counter
1703706f2543Smrg */
1704706f2543Smrgstatic int
1705706f2543SmrgProcSyncQueryCounter(ClientPtr client)
1706706f2543Smrg{
1707706f2543Smrg    REQUEST(xSyncQueryCounterReq);
1708706f2543Smrg    xSyncQueryCounterReply rep;
1709706f2543Smrg    SyncCounter    *pCounter;
1710706f2543Smrg    int rc;
1711706f2543Smrg
1712706f2543Smrg    REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
1713706f2543Smrg
1714706f2543Smrg    rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter,
1715706f2543Smrg				 RTCounter, client, DixReadAccess);
1716706f2543Smrg    if (rc != Success)
1717706f2543Smrg	return rc;
1718706f2543Smrg
1719706f2543Smrg    rep.type = X_Reply;
1720706f2543Smrg    rep.length = 0;
1721706f2543Smrg    rep.sequenceNumber = client->sequence;
1722706f2543Smrg
1723706f2543Smrg    /* if system counter, ask it what the current value is */
1724706f2543Smrg
1725706f2543Smrg    if (IsSystemCounter(pCounter))
1726706f2543Smrg    {
1727706f2543Smrg	(*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
1728706f2543Smrg						  &pCounter->value);
1729706f2543Smrg    }
1730706f2543Smrg
1731706f2543Smrg    rep.value_hi = XSyncValueHigh32(pCounter->value);
1732706f2543Smrg    rep.value_lo = XSyncValueLow32(pCounter->value);
1733706f2543Smrg    if (client->swapped)
1734706f2543Smrg    {
1735706f2543Smrg	char n;
1736706f2543Smrg	swaps(&rep.sequenceNumber, n);
1737706f2543Smrg	swapl(&rep.length, n);
1738706f2543Smrg	swapl(&rep.value_hi, n);
1739706f2543Smrg	swapl(&rep.value_lo, n);
1740706f2543Smrg    }
1741706f2543Smrg    WriteToClient(client, sizeof(xSyncQueryCounterReply), (char *) &rep);
1742706f2543Smrg    return Success;
1743706f2543Smrg}
1744706f2543Smrg
1745706f2543Smrg
1746706f2543Smrg/*
1747706f2543Smrg * ** Create Alarm
1748706f2543Smrg */
1749706f2543Smrgstatic int
1750706f2543SmrgProcSyncCreateAlarm(ClientPtr client)
1751706f2543Smrg{
1752706f2543Smrg    REQUEST(xSyncCreateAlarmReq);
1753706f2543Smrg    SyncAlarm      *pAlarm;
1754706f2543Smrg    int             status;
1755706f2543Smrg    unsigned long   len, vmask;
1756706f2543Smrg    SyncTrigger	    *pTrigger;
1757706f2543Smrg
1758706f2543Smrg    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
1759706f2543Smrg
1760706f2543Smrg    LEGAL_NEW_RESOURCE(stuff->id, client);
1761706f2543Smrg
1762706f2543Smrg    vmask = stuff->valueMask;
1763706f2543Smrg    len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq));
1764706f2543Smrg    /* the "extra" call to Ones accounts for the presence of 64 bit values */
1765706f2543Smrg    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
1766706f2543Smrg	return BadLength;
1767706f2543Smrg
1768706f2543Smrg    if (!(pAlarm = malloc(sizeof(SyncAlarm))))
1769706f2543Smrg    {
1770706f2543Smrg	return BadAlloc;
1771706f2543Smrg    }
1772706f2543Smrg
1773706f2543Smrg    /* set up defaults */
1774706f2543Smrg
1775706f2543Smrg    pTrigger = &pAlarm->trigger;
1776706f2543Smrg    pTrigger->pSync = NULL;
1777706f2543Smrg    pTrigger->value_type = XSyncAbsolute;
1778706f2543Smrg    XSyncIntToValue(&pTrigger->wait_value, 0L);
1779706f2543Smrg    pTrigger->test_type = XSyncPositiveComparison;
1780706f2543Smrg    pTrigger->TriggerFired = SyncAlarmTriggerFired;
1781706f2543Smrg    pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed;
1782706f2543Smrg    status = SyncInitTrigger(client, pTrigger, None, RTCounter,
1783706f2543Smrg			     XSyncCAAllTrigger);
1784706f2543Smrg    if (status != Success)
1785706f2543Smrg    {
1786706f2543Smrg	free(pAlarm);
1787706f2543Smrg	return status;
1788706f2543Smrg    }
1789706f2543Smrg
1790706f2543Smrg    pAlarm->client = client;
1791706f2543Smrg    pAlarm->alarm_id = stuff->id;
1792706f2543Smrg    XSyncIntToValue(&pAlarm->delta, 1L);
1793706f2543Smrg    pAlarm->events = TRUE;
1794706f2543Smrg    pAlarm->state = XSyncAlarmInactive;
1795706f2543Smrg    pAlarm->pEventClients = NULL;
1796706f2543Smrg    status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
1797706f2543Smrg				       (CARD32 *)&stuff[1]);
1798706f2543Smrg    if (status != Success)
1799706f2543Smrg    {
1800706f2543Smrg	free(pAlarm);
1801706f2543Smrg	return status;
1802706f2543Smrg    }
1803706f2543Smrg
1804706f2543Smrg    if (!AddResource(stuff->id, RTAlarm, pAlarm))
1805706f2543Smrg	return BadAlloc;
1806706f2543Smrg
1807706f2543Smrg    /*  see if alarm already triggered.  NULL counter will not trigger
1808706f2543Smrg     *  in CreateAlarm and sets alarm state to Inactive.
1809706f2543Smrg     */
1810706f2543Smrg
1811706f2543Smrg    if (!pTrigger->pSync)
1812706f2543Smrg    {
1813706f2543Smrg	pAlarm->state = XSyncAlarmInactive; /* XXX protocol change */
1814706f2543Smrg    }
1815706f2543Smrg    else
1816706f2543Smrg    {
1817706f2543Smrg	SyncCounter *pCounter;
1818706f2543Smrg
1819706f2543Smrg	if (!SyncCheckWarnIsCounter(pTrigger->pSync,
1820706f2543Smrg				    WARN_INVALID_COUNTER_ALARM))
1821706f2543Smrg	{
1822706f2543Smrg	    FreeResource(stuff->id, RT_NONE);
1823706f2543Smrg	    return BadAlloc;
1824706f2543Smrg	}
1825706f2543Smrg
1826706f2543Smrg	pCounter = (SyncCounter *)pTrigger->pSync;
1827706f2543Smrg
1828706f2543Smrg	if ((*pTrigger->CheckTrigger)(pTrigger, pCounter->value))
1829706f2543Smrg	    (*pTrigger->TriggerFired)(pTrigger);
1830706f2543Smrg    }
1831706f2543Smrg
1832706f2543Smrg    return Success;
1833706f2543Smrg}
1834706f2543Smrg
1835706f2543Smrg/*
1836706f2543Smrg * ** Change Alarm
1837706f2543Smrg */
1838706f2543Smrgstatic int
1839706f2543SmrgProcSyncChangeAlarm(ClientPtr client)
1840706f2543Smrg{
1841706f2543Smrg    REQUEST(xSyncChangeAlarmReq);
1842706f2543Smrg    SyncAlarm   *pAlarm;
1843706f2543Smrg    SyncCounter *pCounter = NULL;
1844706f2543Smrg    long        vmask;
1845706f2543Smrg    int         len, status;
1846706f2543Smrg
1847706f2543Smrg    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
1848706f2543Smrg
1849706f2543Smrg    status = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
1850706f2543Smrg				     client, DixWriteAccess);
1851706f2543Smrg    if (status != Success)
1852706f2543Smrg	return status;
1853706f2543Smrg
1854706f2543Smrg    vmask = stuff->valueMask;
1855706f2543Smrg    len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq));
1856706f2543Smrg    /* the "extra" call to Ones accounts for the presence of 64 bit values */
1857706f2543Smrg    if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
1858706f2543Smrg	return BadLength;
1859706f2543Smrg
1860706f2543Smrg    if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
1861706f2543Smrg					    (CARD32 *)&stuff[1])) != Success)
1862706f2543Smrg	return status;
1863706f2543Smrg
1864706f2543Smrg    if (SyncCheckWarnIsCounter(pAlarm->trigger.pSync,
1865706f2543Smrg			       WARN_INVALID_COUNTER_ALARM))
1866706f2543Smrg	pCounter = (SyncCounter *)pAlarm->trigger.pSync;
1867706f2543Smrg
1868706f2543Smrg    /*  see if alarm already triggered.  NULL counter WILL trigger
1869706f2543Smrg     *  in ChangeAlarm.
1870706f2543Smrg     */
1871706f2543Smrg
1872706f2543Smrg    if (!pCounter ||
1873706f2543Smrg	(*pAlarm->trigger.CheckTrigger)(&pAlarm->trigger, pCounter->value))
1874706f2543Smrg    {
1875706f2543Smrg	(*pAlarm->trigger.TriggerFired)(&pAlarm->trigger);
1876706f2543Smrg    }
1877706f2543Smrg    return Success;
1878706f2543Smrg}
1879706f2543Smrg
1880706f2543Smrgstatic int
1881706f2543SmrgProcSyncQueryAlarm(ClientPtr client)
1882706f2543Smrg{
1883706f2543Smrg    REQUEST(xSyncQueryAlarmReq);
1884706f2543Smrg    SyncAlarm      *pAlarm;
1885706f2543Smrg    xSyncQueryAlarmReply rep;
1886706f2543Smrg    SyncTrigger    *pTrigger;
1887706f2543Smrg    int rc;
1888706f2543Smrg
1889706f2543Smrg    REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
1890706f2543Smrg
1891706f2543Smrg    rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
1892706f2543Smrg				 client, DixReadAccess);
1893706f2543Smrg    if (rc != Success)
1894706f2543Smrg	return rc;
1895706f2543Smrg
1896706f2543Smrg    rep.type = X_Reply;
1897706f2543Smrg    rep.length = bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply));
1898706f2543Smrg    rep.sequenceNumber = client->sequence;
1899706f2543Smrg
1900706f2543Smrg    pTrigger = &pAlarm->trigger;
1901706f2543Smrg    rep.counter = (pTrigger->pSync) ? pTrigger->pSync->id : None;
1902706f2543Smrg
1903706f2543Smrg#if 0 /* XXX unclear what to do, depends on whether relative value-types
1904706f2543Smrg       * are "consumed" immediately and are considered absolute from then
1905706f2543Smrg       * on.
1906706f2543Smrg       */
1907706f2543Smrg    rep.value_type = pTrigger->value_type;
1908706f2543Smrg    rep.wait_value_hi = XSyncValueHigh32(pTrigger->wait_value);
1909706f2543Smrg    rep.wait_value_lo = XSyncValueLow32(pTrigger->wait_value);
1910706f2543Smrg#else
1911706f2543Smrg    rep.value_type = XSyncAbsolute;
1912706f2543Smrg    rep.wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
1913706f2543Smrg    rep.wait_value_lo = XSyncValueLow32(pTrigger->test_value);
1914706f2543Smrg#endif
1915706f2543Smrg
1916706f2543Smrg    rep.test_type = pTrigger->test_type;
1917706f2543Smrg    rep.delta_hi = XSyncValueHigh32(pAlarm->delta);
1918706f2543Smrg    rep.delta_lo = XSyncValueLow32(pAlarm->delta);
1919706f2543Smrg    rep.events = pAlarm->events;
1920706f2543Smrg    rep.state = pAlarm->state;
1921706f2543Smrg
1922706f2543Smrg    if (client->swapped)
1923706f2543Smrg    {
1924706f2543Smrg	char n;
1925706f2543Smrg	swaps(&rep.sequenceNumber, n);
1926706f2543Smrg	swapl(&rep.length, n);
1927706f2543Smrg	swapl(&rep.counter, n);
1928706f2543Smrg	swapl(&rep.wait_value_hi, n);
1929706f2543Smrg	swapl(&rep.wait_value_lo, n);
1930706f2543Smrg	swapl(&rep.test_type, n);
1931706f2543Smrg	swapl(&rep.delta_hi, n);
1932706f2543Smrg	swapl(&rep.delta_lo, n);
1933706f2543Smrg    }
1934706f2543Smrg
1935706f2543Smrg    WriteToClient(client, sizeof(xSyncQueryAlarmReply), (char *) &rep);
1936706f2543Smrg    return Success;
1937706f2543Smrg}
1938706f2543Smrg
1939706f2543Smrgstatic int
1940706f2543SmrgProcSyncDestroyAlarm(ClientPtr client)
1941706f2543Smrg{
1942706f2543Smrg    SyncAlarm *pAlarm;
1943706f2543Smrg    int rc;
1944706f2543Smrg    REQUEST(xSyncDestroyAlarmReq);
1945706f2543Smrg
1946706f2543Smrg    REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
1947706f2543Smrg
1948706f2543Smrg    rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
1949706f2543Smrg				 client, DixDestroyAccess);
1950706f2543Smrg    if (rc != Success)
1951706f2543Smrg	return rc;
1952706f2543Smrg
1953706f2543Smrg    FreeResource(stuff->alarm, RT_NONE);
1954706f2543Smrg    return Success;
1955706f2543Smrg}
1956706f2543Smrg
1957706f2543Smrgstatic int
1958706f2543SmrgProcSyncCreateFence(ClientPtr client)
1959706f2543Smrg{
1960706f2543Smrg    REQUEST(xSyncCreateFenceReq);
1961706f2543Smrg    DrawablePtr pDraw;
1962706f2543Smrg    SyncFence *pFence;
1963706f2543Smrg    int rc;
1964706f2543Smrg
1965706f2543Smrg    REQUEST_SIZE_MATCH(xSyncCreateFenceReq);
1966706f2543Smrg
1967706f2543Smrg    rc = dixLookupDrawable(&pDraw, stuff->d, client, M_ANY, DixGetAttrAccess);
1968706f2543Smrg    if (rc != Success)
1969706f2543Smrg	return rc;
1970706f2543Smrg
1971706f2543Smrg    LEGAL_NEW_RESOURCE(stuff->fid, client);
1972706f2543Smrg
1973706f2543Smrg    if (!(pFence = (SyncFence *)SyncCreate(client,
1974706f2543Smrg					   stuff->fid,
1975706f2543Smrg					   SYNC_FENCE)))
1976706f2543Smrg	return BadAlloc;
1977706f2543Smrg
1978706f2543Smrg    miSyncInitFence(pDraw->pScreen, pFence, stuff->initially_triggered);
1979706f2543Smrg
1980706f2543Smrg    if (!AddResource(stuff->fid, RTFence, (pointer) pFence))
1981706f2543Smrg	return BadAlloc;
1982706f2543Smrg
1983706f2543Smrg    return client->noClientException;
1984706f2543Smrg}
1985706f2543Smrg
1986706f2543Smrgstatic int
1987706f2543SmrgFreeFence(void *obj, XID id)
1988706f2543Smrg{
1989706f2543Smrg    SyncFence *pFence = (SyncFence *) obj;
1990706f2543Smrg
1991706f2543Smrg    miSyncDestroyFence(pFence);
1992706f2543Smrg
1993706f2543Smrg    return Success;
1994706f2543Smrg}
1995706f2543Smrg
1996706f2543Smrgint SyncVerifyFence(SyncFence **ppSyncFence, XID fid,
1997706f2543Smrg		    ClientPtr client, Mask mode)
1998706f2543Smrg{
1999706f2543Smrg    int rc = dixLookupResourceByType((pointer *)ppSyncFence, fid, RTFence,
2000706f2543Smrg				     client, mode);
2001706f2543Smrg
2002706f2543Smrg    if (rc != Success)
2003706f2543Smrg	client->errorValue = fid;
2004706f2543Smrg
2005706f2543Smrg    return rc;
2006706f2543Smrg}
2007706f2543Smrg
2008706f2543Smrgstatic int
2009706f2543SmrgProcSyncTriggerFence(ClientPtr client)
2010706f2543Smrg{
2011706f2543Smrg    REQUEST(xSyncTriggerFenceReq);
2012706f2543Smrg    SyncFence *pFence;
2013706f2543Smrg    int rc;
2014706f2543Smrg
2015706f2543Smrg    REQUEST_SIZE_MATCH(xSyncTriggerFenceReq);
2016706f2543Smrg
2017706f2543Smrg    rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
2018706f2543Smrg				 client, DixWriteAccess);
2019706f2543Smrg    if (rc != Success)
2020706f2543Smrg	return rc;
2021706f2543Smrg
2022706f2543Smrg    miSyncTriggerFence(pFence);
2023706f2543Smrg
2024706f2543Smrg    return client->noClientException;
2025706f2543Smrg}
2026706f2543Smrg
2027706f2543Smrgstatic int
2028706f2543SmrgProcSyncResetFence(ClientPtr client)
2029706f2543Smrg{
2030706f2543Smrg    REQUEST(xSyncResetFenceReq);
2031706f2543Smrg    SyncFence *pFence;
2032706f2543Smrg    int rc;
2033706f2543Smrg
2034706f2543Smrg    REQUEST_SIZE_MATCH(xSyncResetFenceReq);
2035706f2543Smrg
2036706f2543Smrg    rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
2037706f2543Smrg				 client, DixWriteAccess);
2038706f2543Smrg    if (rc != Success)
2039706f2543Smrg	return rc;
2040706f2543Smrg
2041706f2543Smrg    if (pFence->funcs.CheckTriggered(pFence) != TRUE)
2042706f2543Smrg	return BadMatch;
2043706f2543Smrg
2044706f2543Smrg    pFence->funcs.Reset(pFence);
2045706f2543Smrg
2046706f2543Smrg    return client->noClientException;
2047706f2543Smrg}
2048706f2543Smrg
2049706f2543Smrgstatic int
2050706f2543SmrgProcSyncDestroyFence(ClientPtr client)
2051706f2543Smrg{
2052706f2543Smrg    REQUEST(xSyncDestroyFenceReq);
2053706f2543Smrg    SyncFence *pFence;
2054706f2543Smrg    int rc;
2055706f2543Smrg
2056706f2543Smrg    REQUEST_SIZE_MATCH(xSyncDestroyFenceReq);
2057706f2543Smrg
2058706f2543Smrg    rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
2059706f2543Smrg				 client, DixDestroyAccess);
2060706f2543Smrg    if (rc != Success)
2061706f2543Smrg	return rc;
2062706f2543Smrg
2063706f2543Smrg    FreeResource(stuff->fid, RT_NONE);
2064706f2543Smrg    return client->noClientException;
2065706f2543Smrg}
2066706f2543Smrg
2067706f2543Smrgstatic int
2068706f2543SmrgProcSyncQueryFence(ClientPtr client)
2069706f2543Smrg{
2070706f2543Smrg    REQUEST(xSyncQueryFenceReq);
2071706f2543Smrg    xSyncQueryFenceReply rep;
2072706f2543Smrg    SyncFence *pFence;
2073706f2543Smrg    int rc;
2074706f2543Smrg
2075706f2543Smrg    REQUEST_SIZE_MATCH(xSyncQueryFenceReq);
2076706f2543Smrg
2077706f2543Smrg    rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid,
2078706f2543Smrg				 RTFence, client, DixReadAccess);
2079706f2543Smrg    if (rc != Success)
2080706f2543Smrg	return rc;
2081706f2543Smrg
2082706f2543Smrg    rep.type = X_Reply;
2083706f2543Smrg    rep.length = 0;
2084706f2543Smrg    rep.sequenceNumber = client->sequence;
2085706f2543Smrg
2086706f2543Smrg    rep.triggered = pFence->funcs.CheckTriggered(pFence);
2087706f2543Smrg
2088706f2543Smrg    if (client->swapped)
2089706f2543Smrg    {
2090706f2543Smrg	char n;
2091706f2543Smrg	swaps(&rep.sequenceNumber, n);
2092706f2543Smrg	swapl(&rep.length, n);
2093706f2543Smrg    }
2094706f2543Smrg
2095706f2543Smrg    WriteToClient(client, sizeof(xSyncQueryFenceReply), (char *) &rep);
2096706f2543Smrg    return client->noClientException;
2097706f2543Smrg}
2098706f2543Smrg
2099706f2543Smrgstatic int
2100706f2543SmrgProcSyncAwaitFence(ClientPtr client)
2101706f2543Smrg{
2102706f2543Smrg    REQUEST(xSyncAwaitFenceReq);
2103706f2543Smrg    SyncAwaitUnion *pAwaitUnion;
2104706f2543Smrg    SyncAwait *pAwait;
2105706f2543Smrg    /* Use CARD32 rather than XSyncFence because XIDs are hard-coded to
2106706f2543Smrg     * CARD32 in protocol definitions */
2107706f2543Smrg    CARD32 *pProtocolFences;
2108706f2543Smrg    int status;
2109706f2543Smrg    int len;
2110706f2543Smrg    int items;
2111706f2543Smrg    int i;
2112706f2543Smrg
2113706f2543Smrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
2114706f2543Smrg
2115706f2543Smrg    len = client->req_len << 2;
2116706f2543Smrg    len -= sz_xSyncAwaitFenceReq;
2117706f2543Smrg    items = len / sizeof(CARD32);
2118706f2543Smrg
2119706f2543Smrg    if (items * sizeof(CARD32) != len)
2120706f2543Smrg    {
2121706f2543Smrg	return BadLength;
2122706f2543Smrg    }
2123706f2543Smrg    if (items == 0)
2124706f2543Smrg    {
2125706f2543Smrg	client->errorValue = items;
2126706f2543Smrg	return BadValue;
2127706f2543Smrg    }
2128706f2543Smrg
2129706f2543Smrg    if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
2130706f2543Smrg	return BadAlloc;
2131706f2543Smrg
2132706f2543Smrg    /* don't need to do any more memory allocation for this request! */
2133706f2543Smrg
2134706f2543Smrg    pProtocolFences = (CARD32 *) & stuff[1];
2135706f2543Smrg
2136706f2543Smrg    pAwait = &(pAwaitUnion+1)->await; /* skip over header */
2137706f2543Smrg    for (i = 0; i < items; i++, pProtocolFences++, pAwait++)
2138706f2543Smrg    {
2139706f2543Smrg	if (*pProtocolFences == None)
2140706f2543Smrg	{
2141706f2543Smrg	    /*  this should take care of removing any triggers created by
2142706f2543Smrg	     *  this request that have already been registered on sync objects
2143706f2543Smrg	     */
2144706f2543Smrg	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
2145706f2543Smrg	    client->errorValue = *pProtocolFences;
2146706f2543Smrg	    return SyncErrorBase + XSyncBadFence;
2147706f2543Smrg	}
2148706f2543Smrg
2149706f2543Smrg	pAwait->trigger.pSync = NULL;
2150706f2543Smrg	/* Provide acceptable values for these unused fields to
2151706f2543Smrg	 * satisfy SyncInitTrigger's validation logic
2152706f2543Smrg	 */
2153706f2543Smrg	pAwait->trigger.value_type = XSyncAbsolute;
2154706f2543Smrg	XSyncIntToValue(&pAwait->trigger.wait_value, 0);
2155706f2543Smrg	pAwait->trigger.test_type = 0;
2156706f2543Smrg
2157706f2543Smrg	status = SyncInitTrigger(client, &pAwait->trigger,
2158706f2543Smrg				 *pProtocolFences, RTFence,
2159706f2543Smrg				 XSyncCAAllTrigger);
2160706f2543Smrg	if (status != Success)
2161706f2543Smrg	{
2162706f2543Smrg	    /*  this should take care of removing any triggers created by
2163706f2543Smrg	     *  this request that have already been registered on sync objects
2164706f2543Smrg	     */
2165706f2543Smrg	    FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
2166706f2543Smrg	    return status;
2167706f2543Smrg	}
2168706f2543Smrg	/* this is not a mistake -- same function works for both cases */
2169706f2543Smrg	pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
2170706f2543Smrg	pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
2171706f2543Smrg	/* event_threshold is unused for fence syncs */
2172706f2543Smrg	XSyncIntToValue(&pAwait->event_threshold, 0);
2173706f2543Smrg	pAwait->pHeader = &pAwaitUnion->header;
2174706f2543Smrg	pAwaitUnion->header.num_waitconditions++;
2175706f2543Smrg    }
2176706f2543Smrg
2177706f2543Smrg    SyncAwaitEpilogue(client, items, pAwaitUnion);
2178706f2543Smrg
2179706f2543Smrg    return client->noClientException;
2180706f2543Smrg}
2181706f2543Smrg
2182706f2543Smrg/*
2183706f2543Smrg * ** Given an extension request, call the appropriate request procedure
2184706f2543Smrg */
2185706f2543Smrgstatic int
2186706f2543SmrgProcSyncDispatch(ClientPtr client)
2187706f2543Smrg{
2188706f2543Smrg    REQUEST(xReq);
2189706f2543Smrg
2190706f2543Smrg    switch (stuff->data)
2191706f2543Smrg    {
2192706f2543Smrg      case X_SyncInitialize:
2193706f2543Smrg	return ProcSyncInitialize(client);
2194706f2543Smrg      case X_SyncListSystemCounters:
2195706f2543Smrg	return ProcSyncListSystemCounters(client);
2196706f2543Smrg      case X_SyncCreateCounter:
2197706f2543Smrg	return ProcSyncCreateCounter(client);
2198706f2543Smrg      case X_SyncSetCounter:
2199706f2543Smrg	return ProcSyncSetCounter(client);
2200706f2543Smrg      case X_SyncChangeCounter:
2201706f2543Smrg	return ProcSyncChangeCounter(client);
2202706f2543Smrg      case X_SyncQueryCounter:
2203706f2543Smrg	return ProcSyncQueryCounter(client);
2204706f2543Smrg      case X_SyncDestroyCounter:
2205706f2543Smrg	return ProcSyncDestroyCounter(client);
2206706f2543Smrg      case X_SyncAwait:
2207706f2543Smrg	return ProcSyncAwait(client);
2208706f2543Smrg      case X_SyncCreateAlarm:
2209706f2543Smrg	return ProcSyncCreateAlarm(client);
2210706f2543Smrg      case X_SyncChangeAlarm:
2211706f2543Smrg	return ProcSyncChangeAlarm(client);
2212706f2543Smrg      case X_SyncQueryAlarm:
2213706f2543Smrg	return ProcSyncQueryAlarm(client);
2214706f2543Smrg      case X_SyncDestroyAlarm:
2215706f2543Smrg	return ProcSyncDestroyAlarm(client);
2216706f2543Smrg      case X_SyncSetPriority:
2217706f2543Smrg	return ProcSyncSetPriority(client);
2218706f2543Smrg      case X_SyncGetPriority:
2219706f2543Smrg	return ProcSyncGetPriority(client);
2220706f2543Smrg      case X_SyncCreateFence:
2221706f2543Smrg	return ProcSyncCreateFence(client);
2222706f2543Smrg      case X_SyncTriggerFence:
2223706f2543Smrg	return ProcSyncTriggerFence(client);
2224706f2543Smrg      case X_SyncResetFence:
2225706f2543Smrg	return ProcSyncResetFence(client);
2226706f2543Smrg      case X_SyncDestroyFence:
2227706f2543Smrg	return ProcSyncDestroyFence(client);
2228706f2543Smrg      case X_SyncQueryFence:
2229706f2543Smrg	return ProcSyncQueryFence(client);
2230706f2543Smrg      case X_SyncAwaitFence:
2231706f2543Smrg	return ProcSyncAwaitFence(client);
2232706f2543Smrg      default:
2233706f2543Smrg	return BadRequest;
2234706f2543Smrg    }
2235706f2543Smrg}
2236706f2543Smrg
2237706f2543Smrg/*
2238706f2543Smrg * Boring Swapping stuff ...
2239706f2543Smrg */
2240706f2543Smrg
2241706f2543Smrgstatic int
2242706f2543SmrgSProcSyncInitialize(ClientPtr client)
2243706f2543Smrg{
2244706f2543Smrg    REQUEST(xSyncInitializeReq);
2245706f2543Smrg    char   n;
2246706f2543Smrg
2247706f2543Smrg    swaps(&stuff->length, n);
2248706f2543Smrg    REQUEST_SIZE_MATCH (xSyncInitializeReq);
2249706f2543Smrg
2250706f2543Smrg    return ProcSyncInitialize(client);
2251706f2543Smrg}
2252706f2543Smrg
2253706f2543Smrgstatic int
2254706f2543SmrgSProcSyncListSystemCounters(ClientPtr client)
2255706f2543Smrg{
2256706f2543Smrg    REQUEST(xSyncListSystemCountersReq);
2257706f2543Smrg    char   n;
2258706f2543Smrg
2259706f2543Smrg    swaps(&stuff->length, n);
2260706f2543Smrg    REQUEST_SIZE_MATCH (xSyncListSystemCountersReq);
2261706f2543Smrg
2262706f2543Smrg    return ProcSyncListSystemCounters(client);
2263706f2543Smrg}
2264706f2543Smrg
2265706f2543Smrgstatic int
2266706f2543SmrgSProcSyncCreateCounter(ClientPtr client)
2267706f2543Smrg{
2268706f2543Smrg    REQUEST(xSyncCreateCounterReq);
2269706f2543Smrg    char   n;
2270706f2543Smrg
2271706f2543Smrg    swaps(&stuff->length, n);
2272706f2543Smrg    REQUEST_SIZE_MATCH (xSyncCreateCounterReq);
2273706f2543Smrg    swapl(&stuff->cid, n);
2274706f2543Smrg    swapl(&stuff->initial_value_lo, n);
2275706f2543Smrg    swapl(&stuff->initial_value_hi, n);
2276706f2543Smrg
2277706f2543Smrg    return ProcSyncCreateCounter(client);
2278706f2543Smrg}
2279706f2543Smrg
2280706f2543Smrgstatic int
2281706f2543SmrgSProcSyncSetCounter(ClientPtr client)
2282706f2543Smrg{
2283706f2543Smrg    REQUEST(xSyncSetCounterReq);
2284706f2543Smrg    char   n;
2285706f2543Smrg
2286706f2543Smrg    swaps(&stuff->length, n);
2287706f2543Smrg    REQUEST_SIZE_MATCH (xSyncSetCounterReq);
2288706f2543Smrg    swapl(&stuff->cid, n);
2289706f2543Smrg    swapl(&stuff->value_lo, n);
2290706f2543Smrg    swapl(&stuff->value_hi, n);
2291706f2543Smrg
2292706f2543Smrg    return ProcSyncSetCounter(client);
2293706f2543Smrg}
2294706f2543Smrg
2295706f2543Smrgstatic int
2296706f2543SmrgSProcSyncChangeCounter(ClientPtr client)
2297706f2543Smrg{
2298706f2543Smrg    REQUEST(xSyncChangeCounterReq);
2299706f2543Smrg    char   n;
2300706f2543Smrg
2301706f2543Smrg    swaps(&stuff->length, n);
2302706f2543Smrg    REQUEST_SIZE_MATCH (xSyncChangeCounterReq);
2303706f2543Smrg    swapl(&stuff->cid, n);
2304706f2543Smrg    swapl(&stuff->value_lo, n);
2305706f2543Smrg    swapl(&stuff->value_hi, n);
2306706f2543Smrg
2307706f2543Smrg    return ProcSyncChangeCounter(client);
2308706f2543Smrg}
2309706f2543Smrg
2310706f2543Smrgstatic int
2311706f2543SmrgSProcSyncQueryCounter(ClientPtr client)
2312706f2543Smrg{
2313706f2543Smrg    REQUEST(xSyncQueryCounterReq);
2314706f2543Smrg    char   n;
2315706f2543Smrg
2316706f2543Smrg    swaps(&stuff->length, n);
2317706f2543Smrg    REQUEST_SIZE_MATCH (xSyncQueryCounterReq);
2318706f2543Smrg    swapl(&stuff->counter, n);
2319706f2543Smrg
2320706f2543Smrg    return ProcSyncQueryCounter(client);
2321706f2543Smrg}
2322706f2543Smrg
2323706f2543Smrgstatic int
2324706f2543SmrgSProcSyncDestroyCounter(ClientPtr client)
2325706f2543Smrg{
2326706f2543Smrg    REQUEST(xSyncDestroyCounterReq);
2327706f2543Smrg    char   n;
2328706f2543Smrg
2329706f2543Smrg    swaps(&stuff->length, n);
2330706f2543Smrg    REQUEST_SIZE_MATCH (xSyncDestroyCounterReq);
2331706f2543Smrg    swapl(&stuff->counter, n);
2332706f2543Smrg
2333706f2543Smrg    return ProcSyncDestroyCounter(client);
2334706f2543Smrg}
2335706f2543Smrg
2336706f2543Smrgstatic int
2337706f2543SmrgSProcSyncAwait(ClientPtr client)
2338706f2543Smrg{
2339706f2543Smrg    REQUEST(xSyncAwaitReq);
2340706f2543Smrg    char   n;
2341706f2543Smrg
2342706f2543Smrg    swaps(&stuff->length, n);
2343706f2543Smrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
2344706f2543Smrg    SwapRestL(stuff);
2345706f2543Smrg
2346706f2543Smrg    return ProcSyncAwait(client);
2347706f2543Smrg}
2348706f2543Smrg
2349706f2543Smrgstatic int
2350706f2543SmrgSProcSyncCreateAlarm(ClientPtr client)
2351706f2543Smrg{
2352706f2543Smrg    REQUEST(xSyncCreateAlarmReq);
2353706f2543Smrg    char   n;
2354706f2543Smrg
2355706f2543Smrg    swaps(&stuff->length, n);
2356706f2543Smrg    REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
2357706f2543Smrg    swapl(&stuff->id, n);
2358706f2543Smrg    swapl(&stuff->valueMask, n);
2359706f2543Smrg    SwapRestL(stuff);
2360706f2543Smrg
2361706f2543Smrg    return ProcSyncCreateAlarm(client);
2362706f2543Smrg}
2363706f2543Smrg
2364706f2543Smrgstatic int
2365706f2543SmrgSProcSyncChangeAlarm(ClientPtr client)
2366706f2543Smrg{
2367706f2543Smrg    REQUEST(xSyncChangeAlarmReq);
2368706f2543Smrg    char   n;
2369706f2543Smrg
2370706f2543Smrg    swaps(&stuff->length, n);
2371706f2543Smrg    REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
2372706f2543Smrg    swapl(&stuff->alarm, n);
2373706f2543Smrg    swapl(&stuff->valueMask, n);
2374706f2543Smrg    SwapRestL(stuff);
2375706f2543Smrg    return ProcSyncChangeAlarm(client);
2376706f2543Smrg}
2377706f2543Smrg
2378706f2543Smrgstatic int
2379706f2543SmrgSProcSyncQueryAlarm(ClientPtr client)
2380706f2543Smrg{
2381706f2543Smrg    REQUEST(xSyncQueryAlarmReq);
2382706f2543Smrg    char   n;
2383706f2543Smrg
2384706f2543Smrg    swaps(&stuff->length, n);
2385706f2543Smrg    REQUEST_SIZE_MATCH (xSyncQueryAlarmReq);
2386706f2543Smrg    swapl(&stuff->alarm, n);
2387706f2543Smrg
2388706f2543Smrg    return ProcSyncQueryAlarm(client);
2389706f2543Smrg}
2390706f2543Smrg
2391706f2543Smrgstatic int
2392706f2543SmrgSProcSyncDestroyAlarm(ClientPtr client)
2393706f2543Smrg{
2394706f2543Smrg    REQUEST(xSyncDestroyAlarmReq);
2395706f2543Smrg    char   n;
2396706f2543Smrg
2397706f2543Smrg    swaps(&stuff->length, n);
2398706f2543Smrg    REQUEST_SIZE_MATCH (xSyncDestroyAlarmReq);
2399706f2543Smrg    swapl(&stuff->alarm, n);
2400706f2543Smrg
2401706f2543Smrg    return ProcSyncDestroyAlarm(client);
2402706f2543Smrg}
2403706f2543Smrg
2404706f2543Smrgstatic int
2405706f2543SmrgSProcSyncSetPriority(ClientPtr client)
2406706f2543Smrg{
2407706f2543Smrg    REQUEST(xSyncSetPriorityReq);
2408706f2543Smrg    char   n;
2409706f2543Smrg
2410706f2543Smrg    swaps(&stuff->length, n);
2411706f2543Smrg    REQUEST_SIZE_MATCH (xSyncSetPriorityReq);
2412706f2543Smrg    swapl(&stuff->id, n);
2413706f2543Smrg    swapl(&stuff->priority, n);
2414706f2543Smrg
2415706f2543Smrg    return ProcSyncSetPriority(client);
2416706f2543Smrg}
2417706f2543Smrg
2418706f2543Smrgstatic int
2419706f2543SmrgSProcSyncGetPriority(ClientPtr client)
2420706f2543Smrg{
2421706f2543Smrg    REQUEST(xSyncGetPriorityReq);
2422706f2543Smrg    char   n;
2423706f2543Smrg
2424706f2543Smrg    swaps(&stuff->length, n);
2425706f2543Smrg    REQUEST_SIZE_MATCH (xSyncGetPriorityReq);
2426706f2543Smrg    swapl(&stuff->id, n);
2427706f2543Smrg
2428706f2543Smrg    return ProcSyncGetPriority(client);
2429706f2543Smrg}
2430706f2543Smrg
2431706f2543Smrgstatic int
2432706f2543SmrgSProcSyncCreateFence(ClientPtr client)
2433706f2543Smrg{
2434706f2543Smrg    REQUEST(xSyncCreateFenceReq);
2435706f2543Smrg    char n;
2436706f2543Smrg
2437706f2543Smrg    swaps(&stuff->length, n);
2438706f2543Smrg    REQUEST_SIZE_MATCH (xSyncCreateFenceReq);
2439706f2543Smrg    swapl(&stuff->fid, n);
2440706f2543Smrg
2441706f2543Smrg    return ProcSyncCreateFence(client);
2442706f2543Smrg}
2443706f2543Smrg
2444706f2543Smrgstatic int
2445706f2543SmrgSProcSyncTriggerFence(ClientPtr client)
2446706f2543Smrg{
2447706f2543Smrg    REQUEST(xSyncTriggerFenceReq);
2448706f2543Smrg    char n;
2449706f2543Smrg
2450706f2543Smrg    swaps(&stuff->length, n);
2451706f2543Smrg    REQUEST_SIZE_MATCH (xSyncTriggerFenceReq);
2452706f2543Smrg    swapl(&stuff->fid, n);
2453706f2543Smrg
2454706f2543Smrg    return ProcSyncTriggerFence(client);
2455706f2543Smrg}
2456706f2543Smrg
2457706f2543Smrgstatic int
2458706f2543SmrgSProcSyncResetFence(ClientPtr client)
2459706f2543Smrg{
2460706f2543Smrg    REQUEST(xSyncResetFenceReq);
2461706f2543Smrg    char n;
2462706f2543Smrg
2463706f2543Smrg    swaps(&stuff->length, n);
2464706f2543Smrg    REQUEST_SIZE_MATCH (xSyncResetFenceReq);
2465706f2543Smrg    swapl(&stuff->fid, n);
2466706f2543Smrg
2467706f2543Smrg    return ProcSyncResetFence(client);
2468706f2543Smrg}
2469706f2543Smrg
2470706f2543Smrgstatic int
2471706f2543SmrgSProcSyncDestroyFence(ClientPtr client)
2472706f2543Smrg{
2473706f2543Smrg    REQUEST(xSyncDestroyFenceReq);
2474706f2543Smrg    char n;
2475706f2543Smrg
2476706f2543Smrg    swaps(&stuff->length, n);
2477706f2543Smrg    REQUEST_SIZE_MATCH (xSyncDestroyFenceReq);
2478706f2543Smrg    swapl(&stuff->fid, n);
2479706f2543Smrg
2480706f2543Smrg    return ProcSyncDestroyFence(client);
2481706f2543Smrg}
2482706f2543Smrg
2483706f2543Smrgstatic int
2484706f2543SmrgSProcSyncQueryFence(ClientPtr client)
2485706f2543Smrg{
2486706f2543Smrg    REQUEST(xSyncQueryFenceReq);
2487706f2543Smrg    char   n;
2488706f2543Smrg
2489706f2543Smrg    swaps(&stuff->length, n);
2490706f2543Smrg    REQUEST_SIZE_MATCH (xSyncQueryFenceReq);
2491706f2543Smrg    swapl(&stuff->fid, n);
2492706f2543Smrg
2493706f2543Smrg    return ProcSyncQueryFence(client);
2494706f2543Smrg}
2495706f2543Smrg
2496706f2543Smrgstatic int
2497706f2543SmrgSProcSyncAwaitFence(ClientPtr client)
2498706f2543Smrg{
2499706f2543Smrg    REQUEST(xSyncAwaitFenceReq);
2500706f2543Smrg    char   n;
2501706f2543Smrg
2502706f2543Smrg    swaps(&stuff->length, n);
2503706f2543Smrg    REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
2504706f2543Smrg    SwapRestL(stuff);
2505706f2543Smrg
2506706f2543Smrg    return ProcSyncAwaitFence(client);
2507706f2543Smrg}
2508706f2543Smrg
2509706f2543Smrgstatic int
2510706f2543SmrgSProcSyncDispatch(ClientPtr client)
2511706f2543Smrg{
2512706f2543Smrg    REQUEST(xReq);
2513706f2543Smrg
2514706f2543Smrg    switch (stuff->data)
2515706f2543Smrg    {
2516706f2543Smrg      case X_SyncInitialize:
2517706f2543Smrg	return SProcSyncInitialize(client);
2518706f2543Smrg      case X_SyncListSystemCounters:
2519706f2543Smrg	return SProcSyncListSystemCounters(client);
2520706f2543Smrg      case X_SyncCreateCounter:
2521706f2543Smrg	return SProcSyncCreateCounter(client);
2522706f2543Smrg      case X_SyncSetCounter:
2523706f2543Smrg	return SProcSyncSetCounter(client);
2524706f2543Smrg      case X_SyncChangeCounter:
2525706f2543Smrg	return SProcSyncChangeCounter(client);
2526706f2543Smrg      case X_SyncQueryCounter:
2527706f2543Smrg	return SProcSyncQueryCounter(client);
2528706f2543Smrg      case X_SyncDestroyCounter:
2529706f2543Smrg	return SProcSyncDestroyCounter(client);
2530706f2543Smrg      case X_SyncAwait:
2531706f2543Smrg	return SProcSyncAwait(client);
2532706f2543Smrg      case X_SyncCreateAlarm:
2533706f2543Smrg	return SProcSyncCreateAlarm(client);
2534706f2543Smrg      case X_SyncChangeAlarm:
2535706f2543Smrg	return SProcSyncChangeAlarm(client);
2536706f2543Smrg      case X_SyncQueryAlarm:
2537706f2543Smrg	return SProcSyncQueryAlarm(client);
2538706f2543Smrg      case X_SyncDestroyAlarm:
2539706f2543Smrg	return SProcSyncDestroyAlarm(client);
2540706f2543Smrg      case X_SyncSetPriority:
2541706f2543Smrg	return SProcSyncSetPriority(client);
2542706f2543Smrg      case X_SyncGetPriority:
2543706f2543Smrg	return SProcSyncGetPriority(client);
2544706f2543Smrg      case X_SyncCreateFence:
2545706f2543Smrg	return SProcSyncCreateFence(client);
2546706f2543Smrg      case X_SyncTriggerFence:
2547706f2543Smrg	return SProcSyncTriggerFence(client);
2548706f2543Smrg      case X_SyncResetFence:
2549706f2543Smrg	return SProcSyncResetFence(client);
2550706f2543Smrg      case X_SyncDestroyFence:
2551706f2543Smrg	return SProcSyncDestroyFence(client);
2552706f2543Smrg      case X_SyncQueryFence:
2553706f2543Smrg	return SProcSyncQueryFence(client);
2554706f2543Smrg      case X_SyncAwaitFence:
2555706f2543Smrg	return SProcSyncAwaitFence(client);
2556706f2543Smrg      default:
2557706f2543Smrg	return BadRequest;
2558706f2543Smrg    }
2559706f2543Smrg}
2560706f2543Smrg
2561706f2543Smrg/*
2562706f2543Smrg * Event Swapping
2563706f2543Smrg */
2564706f2543Smrg
2565706f2543Smrgstatic void
2566706f2543SmrgSCounterNotifyEvent(xSyncCounterNotifyEvent *from, xSyncCounterNotifyEvent *to)
2567706f2543Smrg{
2568706f2543Smrg    to->type = from->type;
2569706f2543Smrg    to->kind = from->kind;
2570706f2543Smrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
2571706f2543Smrg    cpswapl(from->counter, to->counter);
2572706f2543Smrg    cpswapl(from->wait_value_lo, to->wait_value_lo);
2573706f2543Smrg    cpswapl(from->wait_value_hi, to->wait_value_hi);
2574706f2543Smrg    cpswapl(from->counter_value_lo, to->counter_value_lo);
2575706f2543Smrg    cpswapl(from->counter_value_hi, to->counter_value_hi);
2576706f2543Smrg    cpswapl(from->time, to->time);
2577706f2543Smrg    cpswaps(from->count, to->count);
2578706f2543Smrg    to->destroyed = from->destroyed;
2579706f2543Smrg}
2580706f2543Smrg
2581706f2543Smrg
2582706f2543Smrgstatic void
2583706f2543SmrgSAlarmNotifyEvent(xSyncAlarmNotifyEvent *from, xSyncAlarmNotifyEvent *to)
2584706f2543Smrg{
2585706f2543Smrg    to->type = from->type;
2586706f2543Smrg    to->kind = from->kind;
2587706f2543Smrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
2588706f2543Smrg    cpswapl(from->alarm, to->alarm);
2589706f2543Smrg    cpswapl(from->counter_value_lo, to->counter_value_lo);
2590706f2543Smrg    cpswapl(from->counter_value_hi, to->counter_value_hi);
2591706f2543Smrg    cpswapl(from->alarm_value_lo, to->alarm_value_lo);
2592706f2543Smrg    cpswapl(from->alarm_value_hi, to->alarm_value_hi);
2593706f2543Smrg    cpswapl(from->time, to->time);
2594706f2543Smrg    to->state = from->state;
2595706f2543Smrg}
2596706f2543Smrg
2597706f2543Smrg/*
2598706f2543Smrg * ** Close everything down. ** This is fairly simple for now.
2599706f2543Smrg */
2600706f2543Smrg/* ARGSUSED */
2601706f2543Smrgstatic void
2602706f2543SmrgSyncResetProc(ExtensionEntry *extEntry)
2603706f2543Smrg{
2604706f2543Smrg    free(SysCounterList);
2605706f2543Smrg    SysCounterList = NULL;
2606706f2543Smrg    RTCounter = 0;
2607706f2543Smrg}
2608706f2543Smrg
2609706f2543Smrg/*
2610706f2543Smrg * ** Initialise the extension.
2611706f2543Smrg */
2612706f2543Smrgvoid
2613706f2543SmrgSyncExtensionInit(void)
2614706f2543Smrg{
2615706f2543Smrg    ExtensionEntry *extEntry;
2616706f2543Smrg    int 	    s;
2617706f2543Smrg
2618706f2543Smrg    for (s = 0; s < screenInfo.numScreens; s++)
2619706f2543Smrg	miSyncSetup(screenInfo.screens[s]);
2620706f2543Smrg
2621706f2543Smrg    if (RTCounter == 0)
2622706f2543Smrg    {
2623706f2543Smrg	RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
2624706f2543Smrg    }
2625706f2543Smrg    RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm");
2626706f2543Smrg    RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait");
2627706f2543Smrg    RTFence = CreateNewResourceType(FreeFence, "SyncFence");
2628706f2543Smrg    if (RTAwait)
2629706f2543Smrg	RTAwait |= RC_NEVERRETAIN;
2630706f2543Smrg    RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient");
2631706f2543Smrg    if (RTAlarmClient)
2632706f2543Smrg	RTAlarmClient |= RC_NEVERRETAIN;
2633706f2543Smrg
2634706f2543Smrg    if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 ||
2635706f2543Smrg	RTAlarmClient == 0 ||
2636706f2543Smrg	(extEntry = AddExtension(SYNC_NAME,
2637706f2543Smrg				 XSyncNumberEvents, XSyncNumberErrors,
2638706f2543Smrg				 ProcSyncDispatch, SProcSyncDispatch,
2639706f2543Smrg				 SyncResetProc,
2640706f2543Smrg				 StandardMinorOpcode)) == NULL)
2641706f2543Smrg    {
2642706f2543Smrg	ErrorF("Sync Extension %d.%d failed to Initialise\n",
2643706f2543Smrg		SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
2644706f2543Smrg	return;
2645706f2543Smrg    }
2646706f2543Smrg
2647706f2543Smrg    SyncEventBase = extEntry->eventBase;
2648706f2543Smrg    SyncErrorBase = extEntry->errorBase;
2649706f2543Smrg    EventSwapVector[SyncEventBase + XSyncCounterNotify] = (EventSwapPtr) SCounterNotifyEvent;
2650706f2543Smrg    EventSwapVector[SyncEventBase + XSyncAlarmNotify] = (EventSwapPtr) SAlarmNotifyEvent;
2651706f2543Smrg
2652706f2543Smrg    SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter);
2653706f2543Smrg    SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm);
2654706f2543Smrg    SetResourceTypeErrorValue(RTFence, SyncErrorBase + XSyncBadFence);
2655706f2543Smrg
2656706f2543Smrg    /*
2657706f2543Smrg     * Although SERVERTIME is implemented by the OS layer, we initialise it
2658706f2543Smrg     * here because doing it in OsInit() is too early. The resource database
2659706f2543Smrg     * is not initialised when OsInit() is called. This is just about OK
2660706f2543Smrg     * because there is always a servertime counter.
2661706f2543Smrg     */
2662706f2543Smrg    SyncInitServerTime();
2663706f2543Smrg    SyncInitIdleTime();
2664706f2543Smrg
2665706f2543Smrg#ifdef DEBUG
2666706f2543Smrg    fprintf(stderr, "Sync Extension %d.%d\n",
2667706f2543Smrg	    SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
2668706f2543Smrg#endif
2669706f2543Smrg}
2670706f2543Smrg
2671706f2543Smrg
2672706f2543Smrg/*
2673706f2543Smrg * ***** SERVERTIME implementation - should go in its own file in OS directory?
2674706f2543Smrg */
2675706f2543Smrg
2676706f2543Smrg
2677706f2543Smrg
2678706f2543Smrgstatic pointer ServertimeCounter;
2679706f2543Smrgstatic XSyncValue Now;
2680706f2543Smrgstatic XSyncValue *pnext_time;
2681706f2543Smrg
2682706f2543Smrg#define GetTime()\
2683706f2543Smrg{\
2684706f2543Smrg    unsigned long millis = GetTimeInMillis();\
2685706f2543Smrg    unsigned long maxis = XSyncValueHigh32(Now);\
2686706f2543Smrg    if (millis < XSyncValueLow32(Now)) maxis++;\
2687706f2543Smrg    XSyncIntsToValue(&Now, millis, maxis);\
2688706f2543Smrg}
2689706f2543Smrg
2690706f2543Smrg/*
2691706f2543Smrg*** Server Block Handler
2692706f2543Smrg*** code inspired by multibuffer extension (now deprecated)
2693706f2543Smrg */
2694706f2543Smrg/*ARGSUSED*/
2695706f2543Smrgstatic void
2696706f2543SmrgServertimeBlockHandler(void *env, struct timeval **wt, void *LastSelectMask)
2697706f2543Smrg{
2698706f2543Smrg    XSyncValue delay;
2699706f2543Smrg    unsigned long timeout;
2700706f2543Smrg
2701706f2543Smrg    if (pnext_time)
2702706f2543Smrg    {
2703706f2543Smrg        GetTime();
2704706f2543Smrg
2705706f2543Smrg        if (XSyncValueGreaterOrEqual(Now, *pnext_time))
2706706f2543Smrg	{
2707706f2543Smrg            timeout = 0;
2708706f2543Smrg        }
2709706f2543Smrg	else
2710706f2543Smrg	{
2711706f2543Smrg	    Bool overflow;
2712706f2543Smrg            XSyncValueSubtract(&delay, *pnext_time, Now, &overflow);
2713706f2543Smrg	    (void)overflow;
2714706f2543Smrg            timeout = XSyncValueLow32(delay);
2715706f2543Smrg        }
2716706f2543Smrg        AdjustWaitForDelay(wt, timeout); /* os/utils.c */
2717706f2543Smrg    }
2718706f2543Smrg}
2719706f2543Smrg
2720706f2543Smrg/*
2721706f2543Smrg*** Wakeup Handler
2722706f2543Smrg */
2723706f2543Smrg/*ARGSUSED*/
2724706f2543Smrgstatic void
2725706f2543SmrgServertimeWakeupHandler(void *env, int rc, void *LastSelectMask)
2726706f2543Smrg{
2727706f2543Smrg    if (pnext_time)
2728706f2543Smrg    {
2729706f2543Smrg        GetTime();
2730706f2543Smrg
2731706f2543Smrg        if (XSyncValueGreaterOrEqual(Now, *pnext_time))
2732706f2543Smrg	{
2733706f2543Smrg            SyncChangeCounter(ServertimeCounter, Now);
2734706f2543Smrg        }
2735706f2543Smrg    }
2736706f2543Smrg}
2737706f2543Smrg
2738706f2543Smrgstatic void
2739706f2543SmrgServertimeQueryValue(void *pCounter, CARD64 *pValue_return)
2740706f2543Smrg{
2741706f2543Smrg    GetTime();
2742706f2543Smrg    *pValue_return = Now;
2743706f2543Smrg}
2744706f2543Smrg
2745706f2543Smrgstatic void
2746706f2543SmrgServertimeBracketValues(void *pCounter, CARD64 *pbracket_less,
2747706f2543Smrg			CARD64 *pbracket_greater)
2748706f2543Smrg{
2749706f2543Smrg    if (!pnext_time && pbracket_greater)
2750706f2543Smrg    {
2751706f2543Smrg	RegisterBlockAndWakeupHandlers(ServertimeBlockHandler,
2752706f2543Smrg				       ServertimeWakeupHandler,
2753706f2543Smrg				       NULL);
2754706f2543Smrg    }
2755706f2543Smrg    else if (pnext_time && !pbracket_greater)
2756706f2543Smrg    {
2757706f2543Smrg	RemoveBlockAndWakeupHandlers(ServertimeBlockHandler,
2758706f2543Smrg				     ServertimeWakeupHandler,
2759706f2543Smrg				     NULL);
2760706f2543Smrg    }
2761706f2543Smrg    pnext_time = pbracket_greater;
2762706f2543Smrg}
2763706f2543Smrg
2764706f2543Smrgstatic void
2765706f2543SmrgSyncInitServerTime(void)
2766706f2543Smrg{
2767706f2543Smrg    CARD64 resolution;
2768706f2543Smrg
2769706f2543Smrg    XSyncIntsToValue(&Now, GetTimeInMillis(), 0);
2770706f2543Smrg    XSyncIntToValue(&resolution, 4);
2771706f2543Smrg    ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution,
2772706f2543Smrg			    XSyncCounterNeverDecreases,
2773706f2543Smrg			    ServertimeQueryValue, ServertimeBracketValues);
2774706f2543Smrg    pnext_time = NULL;
2775706f2543Smrg}
2776706f2543Smrg
2777706f2543Smrg
2778706f2543Smrg
2779706f2543Smrg/*
2780706f2543Smrg * IDLETIME implementation
2781706f2543Smrg */
2782706f2543Smrg
2783706f2543Smrgstatic SyncCounter *IdleTimeCounter;
2784706f2543Smrgstatic XSyncValue *pIdleTimeValueLess;
2785706f2543Smrgstatic XSyncValue *pIdleTimeValueGreater;
2786706f2543Smrg
2787706f2543Smrgstatic void
2788706f2543SmrgIdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return)
2789706f2543Smrg{
2790706f2543Smrg    CARD32 idle = GetTimeInMillis() - lastDeviceEventTime.milliseconds;
2791706f2543Smrg    XSyncIntsToValue (pValue_return, idle, 0);
2792706f2543Smrg}
2793706f2543Smrg
2794706f2543Smrgstatic void
2795706f2543SmrgIdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask)
2796706f2543Smrg{
2797706f2543Smrg    XSyncValue idle, old_idle;
2798706f2543Smrg    SyncTriggerList *list = IdleTimeCounter->sync.pTriglist;
2799706f2543Smrg    SyncTrigger *trig;
2800706f2543Smrg
2801706f2543Smrg    if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
2802706f2543Smrg	return;
2803706f2543Smrg
2804706f2543Smrg    old_idle = IdleTimeCounter->value;
2805706f2543Smrg    IdleTimeQueryValue (NULL, &idle);
2806706f2543Smrg    IdleTimeCounter->value = idle; /* push, so CheckTrigger works */
2807706f2543Smrg
2808706f2543Smrg    if (pIdleTimeValueLess &&
2809706f2543Smrg        XSyncValueLessOrEqual (idle, *pIdleTimeValueLess))
2810706f2543Smrg    {
2811706f2543Smrg	/*
2812706f2543Smrg	 * We've been idle for less than the threshold value, and someone
2813706f2543Smrg	 * wants to know about that, but now we need to know whether they
2814706f2543Smrg	 * want level or edge trigger.  Check the trigger list against the
2815706f2543Smrg	 * current idle time, and if any succeed, bomb out of select()
2816706f2543Smrg	 * immediately so we can reschedule.
2817706f2543Smrg	 */
2818706f2543Smrg
2819706f2543Smrg	for (list = IdleTimeCounter->sync.pTriglist; list; list = list->next) {
2820706f2543Smrg	    trig = list->pTrigger;
2821706f2543Smrg	    if (trig->CheckTrigger(trig, old_idle)) {
2822706f2543Smrg		AdjustWaitForDelay(wt, 0);
2823706f2543Smrg		break;
2824706f2543Smrg	    }
2825706f2543Smrg	}
2826706f2543Smrg	/*
2827706f2543Smrg	 * We've been called exactly on the idle time, but we have a
2828706f2543Smrg	 * NegativeTransition trigger which requires a transition from an
2829706f2543Smrg	 * idle time greater than this.  Schedule a wakeup for the next
2830706f2543Smrg	 * millisecond so we won't miss a transition.
2831706f2543Smrg	 */
2832706f2543Smrg	if (XSyncValueEqual (idle, *pIdleTimeValueLess))
2833706f2543Smrg	    AdjustWaitForDelay(wt, 1);
2834706f2543Smrg    }
2835706f2543Smrg    else if (pIdleTimeValueGreater)
2836706f2543Smrg    {
2837706f2543Smrg	/*
2838706f2543Smrg	 * There's a threshold in the positive direction.  If we've been
2839706f2543Smrg	 * idle less than it, schedule a wakeup for sometime in the future.
2840706f2543Smrg	 * If we've been idle more than it, and someone wants to know about
2841706f2543Smrg	 * that level-triggered, schedule an immediate wakeup.
2842706f2543Smrg	 */
2843706f2543Smrg	unsigned long timeout = -1;
2844706f2543Smrg
2845706f2543Smrg	if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) {
2846706f2543Smrg	    XSyncValue value;
2847706f2543Smrg	    Bool overflow;
2848706f2543Smrg
2849706f2543Smrg	    XSyncValueSubtract (&value, *pIdleTimeValueGreater,
2850706f2543Smrg	                        idle, &overflow);
2851706f2543Smrg	    timeout = min(timeout, XSyncValueLow32 (value));
2852706f2543Smrg	} else {
2853706f2543Smrg	    for (list = IdleTimeCounter->sync.pTriglist; list; list = list->next) {
2854706f2543Smrg		trig = list->pTrigger;
2855706f2543Smrg		if (trig->CheckTrigger(trig, old_idle)) {
2856706f2543Smrg		    timeout = min(timeout, 0);
2857706f2543Smrg		    break;
2858706f2543Smrg		}
2859706f2543Smrg	    }
2860706f2543Smrg	}
2861706f2543Smrg
2862706f2543Smrg	AdjustWaitForDelay (wt, timeout);
2863706f2543Smrg    }
2864706f2543Smrg
2865706f2543Smrg    IdleTimeCounter->value = old_idle; /* pop */
2866706f2543Smrg}
2867706f2543Smrg
2868706f2543Smrgstatic void
2869706f2543SmrgIdleTimeWakeupHandler (pointer env, int rc, pointer LastSelectMask)
2870706f2543Smrg{
2871706f2543Smrg    XSyncValue idle;
2872706f2543Smrg
2873706f2543Smrg    if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
2874706f2543Smrg	return;
2875706f2543Smrg
2876706f2543Smrg    IdleTimeQueryValue (NULL, &idle);
2877706f2543Smrg
2878706f2543Smrg    if ((pIdleTimeValueGreater &&
2879706f2543Smrg         XSyncValueGreaterOrEqual (idle, *pIdleTimeValueGreater)) ||
2880706f2543Smrg        (pIdleTimeValueLess &&
2881706f2543Smrg	 XSyncValueLessOrEqual (idle, *pIdleTimeValueLess)))
2882706f2543Smrg    {
2883706f2543Smrg	SyncChangeCounter (IdleTimeCounter, idle);
2884706f2543Smrg    }
2885706f2543Smrg}
2886706f2543Smrg
2887706f2543Smrgstatic void
2888706f2543SmrgIdleTimeBracketValues (pointer pCounter, CARD64 *pbracket_less,
2889706f2543Smrg                       CARD64 *pbracket_greater)
2890706f2543Smrg{
2891706f2543Smrg    Bool registered = (pIdleTimeValueLess || pIdleTimeValueGreater);
2892706f2543Smrg
2893706f2543Smrg    if (registered && !pbracket_less && !pbracket_greater)
2894706f2543Smrg    {
2895706f2543Smrg	RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler,
2896706f2543Smrg	                             IdleTimeWakeupHandler,
2897706f2543Smrg	                             NULL);
2898706f2543Smrg    }
2899706f2543Smrg    else if (!registered && (pbracket_less || pbracket_greater))
2900706f2543Smrg    {
2901706f2543Smrg	RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
2902706f2543Smrg	                               IdleTimeWakeupHandler,
2903706f2543Smrg	                               NULL);
2904706f2543Smrg    }
2905706f2543Smrg
2906706f2543Smrg    pIdleTimeValueGreater = pbracket_greater;
2907706f2543Smrg    pIdleTimeValueLess    = pbracket_less;
2908706f2543Smrg}
2909706f2543Smrg
2910706f2543Smrgstatic void
2911706f2543SmrgSyncInitIdleTime (void)
2912706f2543Smrg{
2913706f2543Smrg    CARD64 resolution;
2914706f2543Smrg    XSyncValue idle;
2915706f2543Smrg
2916706f2543Smrg    IdleTimeQueryValue (NULL, &idle);
2917706f2543Smrg    XSyncIntToValue (&resolution, 4);
2918706f2543Smrg
2919706f2543Smrg    IdleTimeCounter = SyncCreateSystemCounter ("IDLETIME", idle, resolution,
2920706f2543Smrg                                               XSyncCounterUnrestricted,
2921706f2543Smrg                                               IdleTimeQueryValue,
2922706f2543Smrg                                               IdleTimeBracketValues);
2923706f2543Smrg
2924706f2543Smrg    pIdleTimeValueLess = pIdleTimeValueGreater = NULL;
2925706f2543Smrg}
2926