c_bool v_readerWaitForHistoricalData( v_reader r, c_time timeout) { struct historicalWaitArg arg; c_iter entries; c_object e; v_readerEntrySetLock(r); entries = c_select(r->entrySet.entries, 0); v_readerEntrySetUnlock(r); arg._expire_time = c_timeAdd(v_timeGet(), timeout); arg._status = TRUE; e = c_iterTakeFirst(entries); while (e != NULL) { if (arg._status == TRUE) { if (r->qos->durability.kind == V_DURABILITY_VOLATILE) { getHistoricalData(e, NULL); } waitForHistoricalData(e, &arg); } c_free(e); e = c_iterTakeFirst(entries); } c_iterFree(entries); return(arg._status); }
static void v_networkQueueUpdateNextWakeup( v_networkQueue queue, c_bool *hasChanged) { c_time now; c_time soon; c_time newWakeup; c_ulonglong msecsTime; c_ulonglong msecsResult; c_ulonglong msecsLeftOver; static c_time minSleepTime = MIN_SLEEPTIME; *hasChanged = FALSE; if (queue->periodic) { now = v_timeGet(); soon = c_timeAdd(now, minSleepTime); TIME_TO_MSEC(soon, msecsTime); /* Do a ++ because we are doing a ceil and TIME_TO_MSEC is doing a trunc. * Only if time was an exact multiple of milliseconds, this approach is * not completely correct. But it saves us the hassle and this works fine */ msecsTime++; msecsLeftOver = (msecsTime - queue->phaseMilliSeconds) % queue->msecsResolution; msecsResult = msecsTime - msecsLeftOver + queue->msecsResolution; MSEC_TO_TIME(msecsResult, newWakeup); if (c_timeCompare(newWakeup,queue->nextWakeup) == C_GT) { queue->nextWakeup = newWakeup; *hasChanged = TRUE; } } }
void v_leaseUpdate( v_lease lease) { if (lease != NULL) { assert(C_TYPECHECK(lease, v_lease)); v_leaseLock(lease); lease->expiryTime = c_timeAdd(v_timeGet(), lease->duration); v_leaseUnlock(lease); } }
c_iter v_deadLineInstanceListCheckDeadlineMissed( v_deadLineInstanceList list, v_duration deadlineTime, c_time now) { c_time expiryTime; v_instance listItem; c_iter missed; assert(C_TYPECHECK(list,v_deadLineInstanceList)); missed = NULL; if (v_instanceAlone(v_instance(list))) { /* list is empty */ assert (list->deadlineLease != NULL); v_leaseManagerDeregister(list->leaseManager, list->deadlineLease); c_free(list->deadlineLease); list->deadlineLease = NULL; } else { listItem = v_instance(list)->prev; expiryTime = c_timeSub(now, deadlineTime); while ((listItem != NULL) && (v_objectKind(listItem) != K_DEADLINEINSTANCE) && (c_timeCompare(expiryTime, listItem->lastCheckTime) != C_LT)) { missed = c_iterInsert(missed, listItem); listItem->lastCheckTime = now; listItem = listItem->prev; } /* determine next wake-up time */ if (v_objectKind(listItem) == K_DEADLINEINSTANCE) { /* listItem is the deadline list itself, so if there * were instances all instances have been missed. Just * set the new check to be in 'deadlineTime'. */ expiryTime = deadlineTime; } else { /* * The new lease duration can be calculated: * lastCheckTime + deadlineTime = next expiry time * next expiry time - now = lease duration */ expiryTime = c_timeAdd(listItem->lastCheckTime, deadlineTime); expiryTime = c_timeSub(expiryTime, now); v_leaseRenew(list->deadlineLease, expiryTime); } } return missed; }
void v_leaseInit( v_lease _this, v_kernel k, v_duration leaseDuration) { if (_this != NULL) { assert(C_TYPECHECK(_this, v_lease)); c_mutexInit(&_this->mutex,SHARED_MUTEX); _this->expiryTime = c_timeAdd(v_timeGet(), leaseDuration); _this->duration = leaseDuration; _this->observers = c_setNew(v_kernelType(k, K_LEASEMANAGER)); } }
v_networkReaderWaitResult v_networkReaderWaitDelayed( v_networkReader reader, c_ulong queueId, v_networkQueue *queue) { c_time sleep = {0,1000000}; /* Simply sleeping here for resolution time, is not correct. We should wakeup on, or just after the next wakeuptime.*/ sleep = c_timeAdd(sleep,v_networkQueue(reader->queues[queueId-1])->nextWakeup); sleep = c_timeSub(v_networkQueue(reader->queues[queueId-1])->nextWakeup, v_timeGet()); c_timeNanoSleep(sleep); return V_WAITRESULT_TIMEOUT | v_networkReaderWait(reader, queueId, queue); }
void v_leaseRenew( v_lease lease, v_duration leaseDuration) { c_iter observers = NULL; v_leaseManager observer; if (lease != NULL) { assert(C_TYPECHECK(lease, v_lease)); v_leaseLock(lease); lease->expiryTime = c_timeAdd(v_timeGet(), leaseDuration); lease->duration = leaseDuration; /* Collect all observers, so they can be notified of the lease change * Must do a seperate collect as the lease mutex is 'lower' then the * leaseManager mutex. So to prevent deadlock we can not directly notify * the lease manager as we walk the collection */ if(lease->observers) { c_walk(lease->observers, v_leaseCollectObservers, &observers); } v_leaseUnlock(lease); if(observers) { observer = v_leaseManager(c_iterTakeFirst(observers)); while (observer != NULL) { v_leaseManagerNotify( observer, lease, V_EVENT_LEASE_RENEWED); c_free(observer); observer = v_leaseManager(c_iterTakeFirst(observers)); } c_iterFree(observers); } } }
v_dataReaderSample v_dataReaderSampleNew( v_dataReaderInstance instance, v_message message) { v_dataReader dataReader; v_dataReaderSample sample; v_readerQos readerQos; v_index index; assert(instance != NULL); assert(C_TYPECHECK(message,v_message)); index = v_index(instance->index); dataReader = v_dataReader(index->reader); readerQos = v_reader(dataReader)->qos; if (dataReader->cachedSample != NULL) { sample = dataReader->cachedSample; /* Unfinished proto for cache size control * #define _SL_ */ #ifdef _SL_ dataReader->cachedSample = sample->prev; sample->prev = NULL; dataReader->cachedSampleCount--; #else dataReader->cachedSample = NULL; #endif } else { sample = v_dataReaderSample(c_extentCreate(dataReader->sampleExtent)); } v_readerSample(sample)->instance = (c_voidp)instance; v_readerSample(sample)->viewSamples = NULL; if ((message->transactionId != 0) && (v_reader(dataReader)->subQos->presentation.coherent_access)) { v_readerSample(sample)->sampleState = L_TRANSACTION; } else { v_readerSample(sample)->sampleState = 0; } #ifdef _NAT_ sample->insertTime = v_timeGet(); #else #define _INCORRECT_BUT_LOW_INSERT_LATENCY_ #ifdef _INCORRECT_BUT_LOW_INSERT_LATENCY_ if (v_timeIsZero(v_reader(dataReader)->qos->latency.duration)) { sample->insertTime = v_timeGet(); } else { sample->insertTime = message->allocTime; } #else sample->insertTime = v_timeGet(); #endif #endif if (readerQos->lifespan.used) { v_lifespanSample(sample)->expiryTime = c_timeAdd(sample->insertTime, readerQos->lifespan.duration); } else { v_lifespanSample(sample)->expiryTime = c_timeAdd(sample->insertTime, v_messageQos_getLifespanPeriod(message->qos)); } sample->disposeCount = instance->disposeCount; sample->noWritersCount = instance->noWritersCount; sample->publicationHandle = message->writerGID; sample->readId = 0; sample->prev = NULL; assert(message); v_dataReaderSampleTemplate(sample)->message = c_keep(message); v_lifespanAdminInsert(v_dataReaderEntry(index->entry)->lifespanAdmin, v_lifespanSample(sample)); dataReader->notReadCount++; return sample; }
v_networkReaderWaitResult v_networkQueueWait( v_networkQueue queue) { v_networkReaderWaitResult result = V_WAITRESULT_NONE; c_syncResult syncResult; c_bool hasChanged; c_time interval; c_time minSleepTime = MIN_SLEEPTIME; c_equality eq; c_mutexLock(&queue->mutex); /* First update nextWakeup */ v_networkQueueUpdateNextWakeup(queue, &hasChanged); if (hasChanged) { result |= V_WAITRESULT_TIMEOUT; } /* With the new nextWakeup, check if any data is expiring */ if ((int)v_networkQueueHasExpiringData(queue)) { result |= V_WAITRESULT_MSGWAITING; } /* Also check if no request has been issued lately */ if ((int)queue->triggered) { result |= V_WAITRESULT_TRIGGERED; } /* Now go to sleep if needed */ while (result == V_WAITRESULT_NONE) { if (queue->periodic) { c_time org = v_timeGet(); interval = c_timeSub(queue->nextWakeup,org); eq = c_timeCompare(minSleepTime, interval); if (eq == C_LT) { queue->threadWaiting = TRUE; syncResult = c_condTimedWait(&queue->cv, &queue->mutex, interval); queue->threadWaiting = FALSE; } else { syncResult = SYNC_RESULT_TIMEOUT; } if (syncResult == SYNC_RESULT_TIMEOUT) { result |= V_WAITRESULT_TIMEOUT; queue->nextWakeup = c_timeAdd(queue->nextWakeup, queue->resolution); } } else { /* Wait infinitely if the queue is not periodic */ queue->threadWaiting = TRUE; syncResult = c_condWait(&queue->cv, &queue->mutex); queue->threadWaiting = FALSE; } /* Test current status of queue */ if ((int)queue->triggered) { result |= V_WAITRESULT_TRIGGERED; } if (v_networkQueueHasExpiringData(queue)) { result |= V_WAITRESULT_MSGWAITING; } } queue->triggered = 0; c_mutexUnlock(&queue->mutex); return result; }
c_bool v_networkQueueWrite( v_networkQueue queue, v_message msg, v_networkReaderEntry entry, c_long sequenceNumber, v_gid sender, c_bool sendTo, /* for p2p writing */ v_gid receiver) { c_bool result = TRUE; c_bool wasEmpty; c_bool found; v_networkStatusMarker *currentMarkerPtr; v_networkStatusMarker currentMarker; v_networkStatusMarker marker; v_networkQueueSample newHolder; c_ulonglong msecsTime; c_ulonglong msecsResult; c_ulonglong msecsLeftOver; c_time sendBeforeNoTrunc; c_time sendBefore; c_time now; c_ulong priorityLookingFor; c_equality eq; c_bool newMarkerCreated = FALSE; c_bool sendNow = FALSE; V_MESSAGE_STAMP(msg,readerInsertTime); c_mutexLock(&queue->mutex); /* numberOfSamplesArrived statistics */ v_networkQueueStatisticsAdd(numberOfSamplesArrived,queue->statistics); if (queue->currentMsgCount == queue->maxMsgCount) { c_mutexUnlock(&queue->mutex); /* numberOfSamplesRejected stat */ v_networkQueueStatisticsAdd(numberOfSamplesRejected,queue->statistics); return FALSE; } currentMarkerPtr = &(queue->firstStatusMarker); currentMarker = *currentMarkerPtr; if (queue->threadWaiting) { wasEmpty = !v_networkQueueHasExpiringData(queue); } else { wasEmpty = FALSE; } marker = NULL; found = FALSE; priorityLookingFor = v_messageQos_getTransportPriority(msg->qos); if (queue->periodic) { if (v_messageQos_isZeroLatency(msg->qos)) { sendBefore = C_TIME_ZERO; sendNow = TRUE; } else { #ifdef _NAT_ now = v_timeGet(); #else now = msg->allocTime; #endif sendBeforeNoTrunc = c_timeAdd(now, v_messageQos_getLatencyPeriod(msg->qos)); TIME_TO_MSEC(sendBeforeNoTrunc, msecsTime); msecsLeftOver = (c_ulonglong)((msecsTime - queue->phaseMilliSeconds) % queue->msecsResolution); msecsResult = (c_ulonglong)(msecsTime - msecsLeftOver); MSEC_TO_TIME(msecsResult, sendBefore); } while ((currentMarker != NULL) && (!found)) { eq = c_timeCompare(sendBefore, currentMarker->sendBefore); switch (eq) { case C_GT: currentMarkerPtr = ¤tMarker->next; currentMarker = *currentMarkerPtr; break; case C_EQ: if (priorityLookingFor < currentMarker->priority) { currentMarkerPtr = ¤tMarker->next; currentMarker = *currentMarkerPtr; } else { found = TRUE; if (priorityLookingFor == currentMarker->priority) { marker = currentMarker; } } break; case C_LT: found = TRUE; break; default: assert(FALSE); break; } } } else { if (currentMarker) { sendBefore = C_TIME_ZERO; if (c_timeIsZero(currentMarker->sendBefore)) { marker = currentMarker; } } } /* Insert after end of list */ if (marker == NULL) { newMarkerCreated = TRUE; if (queue->freeStatusMarkers == NULL) { marker = v_networkStatusMarker(c_new(queue->statusMarkerType)); } else { marker = queue->freeStatusMarkers; queue->freeStatusMarkers = marker->next; } if (marker != NULL) { marker->sendBefore = sendBefore; marker->priority = priorityLookingFor; marker->firstSample = NULL; marker->lastSample = NULL; marker->next = *currentMarkerPtr; /* no keep, transfer refCount */ if (marker->next == NULL) { queue->lastStatusMarker = marker; /* no keep, not reference counted */ } *currentMarkerPtr = marker; /* no keep, transfer refCount */ } else { OS_REPORT(OS_ERROR, "v_networkQueueWrite",0, "Failed to send message."); c_mutexUnlock(&queue->mutex); return FALSE; } } V_MESSAGE_STAMP(msg,readerLookupTime); assert(marker != NULL); if (queue->freeSamples == NULL) { newHolder = c_new(queue->sampleType); } else { newHolder = queue->freeSamples; queue->freeSamples = newHolder->next; } if (newHolder) { queue->currentMsgCount++; /* numberOfSamplesInserted & numberOfSamplesWaiting + stats*/ v_networkQueueStatisticsAdd(numberOfSamplesInserted,queue->statistics); v_networkQueueStatisticsCounterInc(numberOfSamplesWaiting,queue->statistics); newHolder->message = c_keep(msg); newHolder->entry = c_keep(entry); newHolder->sequenceNumber = sequenceNumber; newHolder->sender = sender; newHolder->sendTo = sendTo; newHolder->receiver = receiver; if (marker->lastSample != NULL) { newHolder->next = v_networkQueueSample(marker->lastSample)->next; /* no keep, transfer refCount */ v_networkQueueSample(marker->lastSample)->next = newHolder; /* no keep, transfer refCount */ } else { newHolder->next = marker->firstSample; /* no keep, transfer refCount */ marker->firstSample = newHolder; /* no keep, transfer refCount */ } marker->lastSample = newHolder; /* Write done, wake up waiters if needed */ if (wasEmpty && queue->threadWaiting) { if (sendNow || v_networkQueueHasExpiringData(queue)) { c_condBroadcast(&queue->cv); } } } else { OS_REPORT(OS_ERROR, "v_networkQueueWrite",0, "Failed to send message."); result = FALSE; } c_mutexUnlock(&queue->mutex); return result; }
void v_leaseRenew( v_lease lease, v_duration* leaseDuration /* may be NULL */) { c_iter observers = NULL; v_leaseManager observer; c_time newExpiryTime; c_equality cmp; if (lease != NULL) { assert(C_TYPECHECK(lease, v_lease)); v_leaseLock(lease); /* Is a new lease duration provided, if so replace the current lease * duration with the new one */ if(leaseDuration != NULL) { lease->duration = *leaseDuration; } /* else do nothing */ /* Calculate the new expiry time */ newExpiryTime = c_timeAdd(v_timeGet(), lease->duration); /* Is the new expiryTime earlier then the current expiryTime? */ cmp = c_timeCompare(newExpiryTime, lease->expiryTime); /* Always replace the current expiry time with the new expiryTime */ lease->expiryTime = newExpiryTime; /* If the new expiryTime is earlier then the previous expiryTime. Then * this means the observers must be notified so they can take the * earlier expiryTime into account */ if (cmp == C_LT) { /* Collect all observers, so they can be notified of the lease change * Must do a seperate collect as the lease mutex is 'lower' then the * leaseManager mutex. So to prevent deadlock we can not directly notify * the lease manager as we walk the collection */ if(lease->observers) { c_walk(lease->observers, v_leaseCollectObservers, &observers); } v_leaseUnlock(lease); if(observers) { observer = v_leaseManager(c_iterTakeFirst(observers)); while (observer != NULL) { v_leaseManagerNotify( observer, lease, V_EVENT_LEASE_RENEWED); c_free(observer); observer = v_leaseManager(c_iterTakeFirst(observers)); } c_iterFree(observers); } } else { /* No need to notify observers, the new expiryTime is not earlier * then what it was before. */ v_leaseUnlock(lease); } } }
v_historyResult v_readerWaitForHistoricalDataWithCondition( v_reader _this, c_char* filter, c_char* params[], c_ulong paramsLength, c_time minSourceTime, c_time maxSourceTime, struct v_resourcePolicy *resourceLimits, c_time timeout) { c_iter entries; c_object e; v_historyResult result; v_historicalDataRequest request; c_bool doRequest, doWait; struct historicalWaitArg arg; C_STRUCT(v_event) event; arg._expire_time = c_timeAdd(v_timeGet(), timeout); arg._status = TRUE; request = v_historicalDataRequestNew(v_objectKernel(_this), filter, params, paramsLength, minSourceTime, maxSourceTime, resourceLimits); if(request){ V_READER_LOCK(_this); if(_this->historicalDataRequest) { /* Historical data request already in progress or complete, check * whether request is equal to the original one. */ doRequest = FALSE; if(v_historicalDataRequestEquals(request, _this->historicalDataRequest)){ /* Request is equal to original request*/ result = V_HISTORY_RESULT_OK; if(_this->historicalDataComplete){ /* Request has already been fulfilled. Consider this call * a no-operation. */ doWait = FALSE; } else { /* Request is still in progress, wait for data to arrive*/ doWait = TRUE; } } else { /* The requested parameters are not equal to the originally * requested set. Return a precondition not met. */ doWait = FALSE; result = V_HISTORY_RESULT_PRE_NOT_MET; } c_free(request); } else { /* No active request, so validate it now.*/ if(v_historicalDataRequestIsValid(request, _this)){ /* This request is valid, so request data.*/ doRequest = TRUE; doWait = TRUE; result = V_HISTORY_RESULT_OK; _this->historicalDataRequest = request; } else { /* Request is not valid, so return bad parameter.*/ doRequest = FALSE; doWait = FALSE; result = V_HISTORY_RESULT_BAD_PARAM; c_free(request); } } V_READER_UNLOCK(_this); } else { doRequest = FALSE; doWait = FALSE; result = V_HISTORY_RESULT_ERROR; } if(doWait){ v_readerEntrySetLock(_this); entries = c_select(_this->entrySet.entries, 0); v_readerEntrySetUnlock(_this); if(doRequest){ /* Historical data must be requested, since this is the first time * the operation is called and the request is valid. */ if (_this->qos->durability.kind == V_DURABILITY_VOLATILE) { /* If reader is volatile, the historical data from the * group(s) has/have not been retrieved yet, so do it now. */ e = c_iterTakeFirst(entries); while (e != NULL) { getHistoricalData(e, _this->historicalDataRequest); c_free(e); e = c_iterTakeFirst(entries); } c_iterFree(entries); } event.kind = V_EVENT_HISTORY_REQUEST; event.source = v_publicHandle(v_public(_this)); event.userData = _this->historicalDataRequest; v_observableNotify(v_observable(v_objectKernel(_this)),&event); } V_READER_LOCK(_this); if(!_this->historicalDataComplete){ if (c_timeCompare(timeout, C_TIME_INFINITE) != C_EQ) { if (c_condTimedWait(&_this->historicalDataCondition, &V_READER_GET_LOCK(_this), timeout) != SYNC_RESULT_SUCCESS) { result = V_HISTORY_RESULT_TIMEOUT; } } else if (c_condWait(&_this->historicalDataCondition, &V_READER_GET_LOCK(_this)) != SYNC_RESULT_SUCCESS) { result = V_HISTORY_RESULT_TIMEOUT; } assert( (result == V_HISTORY_RESULT_OK) == _this->historicalDataComplete); } V_READER_UNLOCK(_this); } return result; }