📄 sync.c
字号:
if (pTrigger->test_type != XSyncPositiveTransition && pTrigger->test_type != XSyncNegativeTransition && pTrigger->test_type != XSyncPositiveComparison && pTrigger->test_type != XSyncNegativeComparison) { client->errorValue = pTrigger->test_type; return BadValue; } /* select appropriate CheckTrigger function */ switch (pTrigger->test_type) { case XSyncPositiveTransition: pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition; break; case XSyncNegativeTransition: pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition; break; case XSyncPositiveComparison: pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison; break; case XSyncNegativeComparison: pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison; break; } } if (changes & (XSyncCAValueType | XSyncCAValue)) { if (pTrigger->value_type == XSyncAbsolute) pTrigger->test_value = pTrigger->wait_value; else /* relative */ { Bool overflow; if (pCounter == NULL) return BadMatch; XSyncValueAdd(&pTrigger->test_value, pCounter->value, pTrigger->wait_value, &overflow); if (overflow) { client->errorValue = XSyncValueHigh32(pTrigger->wait_value); return BadValue; } } } /* we wait until we're sure there are no errors before registering * a new counter on a trigger */ if (newcounter) { if ((status = SyncAddTriggerToCounter(pTrigger)) != Success) return status; } else if (IsSystemCounter(pCounter)) { SyncComputeBracketValues(pCounter, /*startOver*/ TRUE); } return Success;}/* AlarmNotify events happen in response to actions taken on an Alarm or * the counter used by the alarm. AlarmNotify may be sent to multiple * clients. The alarm maintains a list of clients interested in events. */static voidSyncSendAlarmNotifyEvents(pAlarm) SyncAlarm *pAlarm;{ SyncAlarmClientList *pcl; xSyncAlarmNotifyEvent ane; SyncTrigger *pTrigger = &pAlarm->trigger; UpdateCurrentTime(); ane.type = SyncEventBase + XSyncAlarmNotify; ane.kind = XSyncAlarmNotify; ane.sequenceNumber = pAlarm->client->sequence; ane.alarm = pAlarm->alarm_id; if (pTrigger->pCounter) { ane.counter_value_hi = XSyncValueHigh32(pTrigger->pCounter->value); ane.counter_value_lo = XSyncValueLow32(pTrigger->pCounter->value); } else { /* XXX what else can we do if there's no counter? */ ane.counter_value_hi = ane.counter_value_lo = 0; } ane.alarm_value_hi = XSyncValueHigh32(pTrigger->test_value); ane.alarm_value_lo = XSyncValueLow32(pTrigger->test_value); ane.time = currentTime.milliseconds; ane.state = pAlarm->state; /* send to owner */ if (pAlarm->events && !pAlarm->client->clientGone) WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane); /* send to other interested clients */ for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next) { if (!pAlarm->client->clientGone) { ane.sequenceNumber = pcl->client->sequence; WriteEventsToClient(pcl->client, 1, (xEvent *) &ane); } }}/* CounterNotify events only occur in response to an Await. The events * go only to the Awaiting client. */static voidSyncSendCounterNotifyEvents(client, ppAwait, num_events) ClientPtr client; SyncAwait **ppAwait; int num_events;{ xSyncCounterNotifyEvent *pEvents, *pev; int i; if (client->clientGone) return; pev = pEvents = (xSyncCounterNotifyEvent *) ALLOCATE_LOCAL(num_events * sizeof(xSyncCounterNotifyEvent)); if (!pEvents) return; UpdateCurrentTime(); for (i = 0; i < num_events; i++, ppAwait++, pev++) { SyncTrigger *pTrigger = &(*ppAwait)->trigger; pev->type = SyncEventBase + XSyncCounterNotify; pev->kind = XSyncCounterNotify; pev->sequenceNumber = client->sequence; pev->counter = pTrigger->pCounter->id; pev->wait_value_lo = XSyncValueLow32(pTrigger->test_value); pev->wait_value_hi = XSyncValueHigh32(pTrigger->test_value); pev->counter_value_lo = XSyncValueLow32(pTrigger->pCounter->value); pev->counter_value_hi = XSyncValueHigh32(pTrigger->pCounter->value); pev->time = currentTime.milliseconds; pev->count = num_events - i - 1; /* events remaining */ pev->destroyed = pTrigger->pCounter->beingDestroyed; } /* swapping will be taken care of by this */ WriteEventsToClient(client, num_events, (xEvent *)pEvents); DEALLOCATE_LOCAL(pEvents);}/* This function is called when an alarm's counter is destroyed. * It is plugged into pTrigger->CounterDestroyed (for alarm triggers). */voidSyncAlarmCounterDestroyed(pTrigger) SyncTrigger *pTrigger;{ SyncAlarm *pAlarm = (SyncAlarm *)pTrigger; pAlarm->state = XSyncAlarmInactive; SyncSendAlarmNotifyEvents(pAlarm); pTrigger->pCounter = NULL;}/* This function is called when an alarm "goes off." * It is plugged into pTrigger->TriggerFired (for alarm triggers). */static voidSyncAlarmTriggerFired(pTrigger) SyncTrigger *pTrigger;{ SyncAlarm *pAlarm = (SyncAlarm *)pTrigger; CARD64 new_test_value; /* no need to check alarm unless it's active */ if (pAlarm->state != XSyncAlarmActive) return; /* " if the counter value is None, or if the delta is 0 and * the test-type is PositiveComparison or NegativeComparison, * no change is made to value (test-value) and the alarm * state is changed to Inactive before the event is generated." */ if (pAlarm->trigger.pCounter == NULL || (XSyncValueIsZero(pAlarm->delta) && (pAlarm->trigger.test_type == XSyncPositiveComparison || pAlarm->trigger.test_type == XSyncNegativeComparison))) pAlarm->state = XSyncAlarmInactive; new_test_value = pAlarm->trigger.test_value; if (pAlarm->state == XSyncAlarmActive) { Bool overflow; CARD64 oldvalue; SyncTrigger *paTrigger = &pAlarm->trigger; /* "The alarm is updated by repeatedly adding delta to the * value of the trigger and re-initializing it until it * becomes FALSE." */ oldvalue = paTrigger->test_value; /* XXX really should do something smarter here */ do { XSyncValueAdd(&paTrigger->test_value, paTrigger->test_value, pAlarm->delta, &overflow); } while (!overflow && (*paTrigger->CheckTrigger)(paTrigger, paTrigger->pCounter->value)); new_test_value = paTrigger->test_value; paTrigger->test_value = oldvalue; /* "If this update would cause value to fall outside the range * for an INT64...no change is made to value (test-value) and * the alarm state is changed to Inactive before the event is * generated." */ if (overflow) { new_test_value = oldvalue; pAlarm->state = XSyncAlarmInactive; } } /* The AlarmNotify event has to have the "new state of the alarm" * which we can't be sure of until this point. However, it has * to have the "old" trigger test value. That's the reason for * all the newvalue/oldvalue shuffling above. After we send the * events, give the trigger its new test value. */ SyncSendAlarmNotifyEvents(pAlarm); pTrigger->test_value = new_test_value;}/* This function is called when an Await unblocks, either as a result * of the trigger firing OR the counter being destroyed. * It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed * (for Await triggers). */static voidSyncAwaitTriggerFired(pTrigger) SyncTrigger *pTrigger;{ SyncAwait *pAwait = (SyncAwait *)pTrigger; int numwaits; SyncAwaitUnion *pAwaitUnion; SyncAwait **ppAwait; int num_events = 0; pAwaitUnion = (SyncAwaitUnion *)pAwait->pHeader; numwaits = pAwaitUnion->header.num_waitconditions; ppAwait = (SyncAwait **)ALLOCATE_LOCAL(numwaits * sizeof(SyncAwait *)); if (!ppAwait) goto bail; pAwait = &(pAwaitUnion+1)->await; /* "When a client is unblocked, all the CounterNotify events for * the Await request are generated contiguously. If count is 0 * there are no more events to follow for this request. If * count is n, there are at least n more events to follow." * * Thus, it is best to find all the counters for which events * need to be sent first, so that an accurate count field can * be stored in the events. */ for ( ; numwaits; numwaits--, pAwait++) { CARD64 diff; Bool overflow, diffgreater, diffequal; /* "A CounterNotify event with the destroyed flag set to TRUE is * always generated if the counter for one of the triggers is * destroyed." */ if (pAwait->trigger.pCounter->beingDestroyed) { ppAwait[num_events++] = pAwait; continue; } /* "The difference between the counter and the test value is * calculated by subtracting the test value from the value of * the counter." */ XSyncValueSubtract(&diff, pAwait->trigger.pCounter->value, pAwait->trigger.test_value, &overflow); /* "If the difference lies outside the range for an INT64, an * event is not generated." */ if (overflow) continue; diffgreater = XSyncValueGreaterThan(diff, pAwait->event_threshold); diffequal = XSyncValueEqual(diff, pAwait->event_threshold); /* "If the test-type is PositiveTransition or * PositiveComparison, a CounterNotify event is generated if * the difference is at least event-threshold. If the test-type * is NegativeTransition or NegativeComparison, a CounterNotify * event is generated if the difference is at most * event-threshold." */ if ( ((pAwait->trigger.test_type == XSyncPositiveComparison || pAwait->trigger.test_type == XSyncPositiveTransition) && (diffgreater || diffequal)) || ((pAwait->trigger.test_type == XSyncNegativeComparison || pAwait->trigger.test_type == XSyncNegativeTransition) && (!diffgreater) /* less or equal */ ) ) { ppAwait[num_events++] = pAwait; } } if (num_events) SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait, num_events); DEALLOCATE_LOCAL(ppAwait);bail: /* unblock the client */ AttendClient(pAwaitUnion->header.client); /* delete the await */ FreeResource(pAwaitUnion->header.delete_id, RT_NONE);}/* This function should always be used to change a counter's value so that * any triggers depending on the counter will be checked. */voidSyncChangeCounter(pCounter, newval) SyncCounter *pCounter; CARD64 newval;{ SyncTriggerList *ptl, *pnext; CARD64 oldval; oldval = pCounter->value; pCounter->value = newval; /* run through triggers to see if any become true */ for (ptl = pCounter->pTriglist; ptl; ptl = pnext) { pnext = ptl->next; if ((*ptl->pTrigger->CheckTrigger)(ptl->pTrigger, oldval)) (*ptl->pTrigger->TriggerFired)(ptl->pTrigger); } if (IsSystemCounter(pCounter)) { SyncComputeBracketValues(pCounter, /* startOver */ FALSE); }}/* loosely based on dix/events.c/EventSelectForWindow */static BoolSyncEventSelectForAlarm(pAlarm, client, wantevents) SyncAlarm *pAlarm; ClientPtr client; Bool wantevents;{ SyncAlarmClientList *pClients; if (client == pAlarm->client) /* alarm owner */ { pAlarm->events = wantevents; return Success; } /* see if the client is already on the list (has events selected) */ for (pClients = pAlarm->pEventClients; pClients; pClients = pClients->next) { if (pClients->client == client) { /* client's presence on the list indicates desire for * events. If the client doesn't want events, remove it * from the list. If the client does want events, do * nothing, since it's already got them. */ if (!wantevents) { FreeResource(pClients->delete_id, RT_NONE); } return Success; } } /* if we get here, this client does not currently have * events selected on the alarm */ if (!wantevents) /* client doesn't want events, and we just discovered that it * doesn't have them, so there's nothing to do. */ return Success; /* add new client to pAlarm->pEventClients */ pClients = (SyncAlarmClientList *) xalloc(sizeof(SyncAlarmClientList)); if (!pClients) return BadAlloc; /* register it as a resource so it will be cleaned up * if the client dies */ pClients->delete_id = FakeClientID(client->index); if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm)) { xfree(pClients); return BadAlloc; } /* link it into list after we know all the allocations succeed */ pClients->next = pAlarm->pEventClients; pAlarm->pEventClients = pClients; pClients->client = client; return Success;}/* * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm */static int SyncChangeAlarmAttributes(client, pAlarm, mask, values) ClientPtr client; SyncAlarm *pAlarm; Mask mask; CARD32 *values;{ int status; XSyncCounter counter; Mask origmask = mask; counter = pAlarm->trigger.pCounter ? pAlarm->trigger.pCounter->id : None; while (mask) { int index2 = lowbit(mask); mask &= ~index2; switch (index2) { case XSyncCACounter: mask &= ~XSyncCACounter; /* sanity check in SyncInitTrigger */ counter = *values++; break; case XSyncCAValueType: mask &= ~XSyncCAValueType; /* sanity check in SyncInitTrigger */ pAlarm->trigger.value_type = *values++; break; case XSyncCAValue: mask &= ~XSyncCAValue; XSyncIntsToValue(&pAlarm->trigger.wait_value, values[1], values[0]); values += 2; break; case XSyncCATestType: mask &= ~XSyncCATestType; /* sanity check in SyncInitTrigger */ pAlarm->trigger.test_type = *values++; break; case XSyncCADelta: mask &= ~XSyncCADelta; XSyncIntsToValue(&pAlarm->delta, values[1], values[0]); values += 2; break; case XSyncCAEvents: mask &= ~XSyncCAEvents; if ((*values != xTrue) && (*values != xFalse)) { client->errorValue = *values; return BadValue; } status = SyncEventSelectForAlarm(pAlarm, client, (Bool)(*values++)); if (status != Success) return status; break; default: client->errorValue = mask; return BadValue; } } /* "If the test-type is PositiveComparison or PositiveTransition * and delta is less than zero, or if the test-type is * NegativeComparison or NegativeTransition and delta is * greater than zero, a Match error is generated." */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -