/************************************************************** * Protected functions **************************************************************/ void v_lifespanAdminInsert( v_lifespanAdmin admin, v_lifespanSample sample) { v_lifespanSample placeHolder; c_equality eq; assert(C_TYPECHECK(admin,v_lifespanAdmin)); assert(C_TYPECHECK(sample,v_lifespanSample)); assert(admin->sampleCount >= 0); CHECK_ADMIN(admin, sample); eq = c_timeCompare(sample->expiryTime, C_TIME_INFINITE); if (eq == C_EQ) { return; /* no insert, since sample never expires! */ } if (admin->head == NULL) { assert(admin->tail == NULL); admin->head = c_keep(sample); admin->tail = c_keep(sample); } else { placeHolder = admin->tail; eq = c_timeCompare(placeHolder->expiryTime, sample->expiryTime); while ((placeHolder->prev != NULL) && (eq != C_LT) /* >= */) { placeHolder = placeHolder->prev; if (placeHolder != NULL) { eq = c_timeCompare(placeHolder->expiryTime, sample->expiryTime); } } if (eq != C_LT) { /* insert before placeholder */ assert(placeHolder == admin->head); sample->next = admin->head; /* transfer ref count */ admin->head->prev = sample; admin->head = c_keep(sample); } else { if (placeHolder->next != NULL) { placeHolder->next->prev = sample; } else { assert(placeHolder == admin->tail); c_free(admin->tail); admin->tail = c_keep(sample); } sample->next = placeHolder->next; /* transfer refcount */ placeHolder->next = c_keep(sample); sample->prev = placeHolder; } } admin->sampleCount++; CHECK_ADMIN(admin, sample); }
void v_lifespanAdminTakeExpired( v_lifespanAdmin admin, v_lifespanSampleAction action, c_voidp arg) { c_bool proceed; v_lifespanSample removed; c_time now; c_equality eq; assert(C_TYPECHECK(admin,v_lifespanAdmin)); CHECK_ADMIN(admin, NULL); if (admin->head != NULL) { now = v_timeGet(); eq = c_timeCompare(now, admin->head->expiryTime); proceed = TRUE; while ((proceed) && (eq != C_LT /* >= */) && (admin->head != NULL)) { removed = admin->head; if (action) { proceed = action(removed, arg); } else { proceed = TRUE; } if ((proceed) && (removed == admin->head)) { /* The action routine might have already removed the sample, so * we check if the head of the list has not changed! */ admin->head = removed->next; /* transfer refcount */ removed->next = NULL; if (admin->head == NULL) { assert(removed == admin->tail); c_free(admin->tail); admin->tail = NULL; proceed = FALSE; } else { admin->head->prev = NULL; } assert(admin->sampleCount > 0); admin->sampleCount--; CHECK_ADMIN(admin, removed); c_free(removed); } if (admin->head != NULL) { eq = c_timeCompare(now, admin->head->expiryTime); } } } CHECK_ADMIN(admin, NULL); }
c_bool collectExpired( c_object o, c_voidp arg) { v_leaseAction leaseAction = v_leaseAction(o); struct collectExpiredArg *a = (struct collectExpiredArg *)arg; c_time headExpTime; c_time leaseExpTime; c_bool setHead; c_equality cmp; setHead = TRUE; leaseExpTime = v_leaseExpiryTime(leaseAction->lease); /* * A lease is expired if the expiry time is greater than or equal * to the current time! */ cmp = c_timeCompare(a->now, leaseExpTime); if ((cmp == C_GT) || (cmp == C_EQ)) { a->expiredLeases = c_iterInsert(a->expiredLeases, c_keep(leaseAction)); /* An expired lease can still become the next expirytime, * if it should be repeated */ if (leaseAction->repeat) { v_leaseRenew(leaseAction->lease, NULL); } else { setHead = FALSE; } } if (setHead) { if (a->firstLeaseToExpire == NULL) { a->firstLeaseToExpire = c_keep(leaseAction); } else { headExpTime = v_leaseExpiryTime(a->firstLeaseToExpire->lease); leaseExpTime = v_leaseExpiryTime(leaseAction->lease); if (c_timeCompare(headExpTime, leaseExpTime) == C_GT) { c_free(a->firstLeaseToExpire); a->firstLeaseToExpire = c_keep(leaseAction); } } } return TRUE; }
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; } } }
static c_bool getBestQuality( c_object o, c_voidp arg) { d_quality* quality; d_quality current; c_bool result; assert(C_TYPECHECK(o,d_groupInfo)); assert(arg); if(o && arg){ quality = (d_quality*) arg; current = d_groupInfoQuality(o); if(c_timeCompare(current, *quality) == C_GT){ quality->seconds = current.seconds; quality->nanoseconds = current.nanoseconds; } result = TRUE; } else { result = FALSE; } return result; }
c_bool determineFirstLeaseToExpire( c_object o, c_voidp arg) { c_time headExpTime; c_time leaseExpTime; v_leaseAction leaseAction = v_leaseAction(o); v_leaseManager lm = v_leaseManager(arg); if (lm->firstLeaseToExpire == NULL) { lm->firstLeaseToExpire = c_keep(leaseAction); } else { headExpTime = v_leaseExpiryTime(lm->firstLeaseToExpire->lease); leaseExpTime = v_leaseExpiryTime(leaseAction->lease); if (c_timeCompare(headExpTime, leaseExpTime) == C_GT) { c_free(lm->firstLeaseToExpire); lm->firstLeaseToExpire = c_keep(leaseAction); } } return TRUE; }
void v_deadLineInstanceListSetDuration( v_deadLineInstanceList list, v_duration duration) { v_kernel k; v_result result; assert(C_TYPECHECK(list,v_deadLineInstanceList)); list->leaseDuration = duration; if (list->deadlineLease != NULL) { if (c_timeCompare(duration, C_TIME_INFINITE) != C_EQ) { v_leaseRenew(list->deadlineLease,duration); } else { v_leaseManagerDeregister(list->leaseManager, list->deadlineLease); c_free(list->deadlineLease); list->deadlineLease = NULL; } } else { if ((v_objectKind(v_instance(list)->prev) != K_DEADLINEINSTANCE) && /* not in list */ (c_timeCompare(duration, C_TIME_INFINITE) != C_EQ)) { /* new instance */ k = v_objectKernel(list->leaseManager); list->deadlineLease = v_leaseNew(k, duration); if(list->deadlineLease) { result = v_leaseManagerRegister( list->leaseManager, list->deadlineLease, list->actionId, v_public(list->actionObject), TRUE /* repeat lease if expired */); if(result != V_RESULT_OK) { c_free(list->deadlineLease); list->deadlineLease = NULL; OS_REPORT_1(OS_ERROR, "v_deadLineInstanceList", 0, "A fatal error was detected when trying to register the deadline lease." "The result code was %d.", result); } } } } }
c_bool v_historicalDataRequestIsValid( v_historicalDataRequest request, v_reader reader) { c_bool result; q_expr expr; assert(C_TYPECHECK(request,v_historicalDataRequest)); assert(C_TYPECHECK(reader,v_reader)); if(request && reader){ if(!v_resourcePolicyValid(request->resourceLimits)){ result = FALSE; } else if((reader->qos->resource.max_samples != -1) && (reader->qos->resource.max_samples < request->resourceLimits.max_samples)) { result = FALSE; } else if((reader->qos->resource.max_instances != -1) && (reader->qos->resource.max_instances < request->resourceLimits.max_instances)) { result = FALSE; } else if((reader->qos->resource.max_samples_per_instance != -1) && (reader->qos->resource.max_samples_per_instance < request->resourceLimits.max_samples_per_instance)) { result = FALSE; } else if(!c_timeValid(request->minSourceTimestamp)){ result = FALSE; } else if(!c_timeValid(request->maxSourceTimestamp)){ result = FALSE; } else if(c_timeCompare(request->minSourceTimestamp, request->maxSourceTimestamp) == C_GT) { result = FALSE; } else if(request->filter){ expr = q_parse(request->filter); if(expr){ q_dispose(expr); result = TRUE; } else { result = FALSE; } } else { result = TRUE; } } else { result = FALSE; } return result; }
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; }
c_bool v_leaseManagerNotify( v_leaseManager _this, v_lease lease, v_eventKind event) { struct findLeaseActionArg arg; assert(_this != NULL); assert(C_TYPECHECK(_this, v_leaseManager)); c_mutexLock(&_this->mutex); if (event & V_EVENT_LEASE_RENEWED) { if (_this->firstLeaseToExpire) { if (_this->firstLeaseToExpire->lease == lease) { /* If the lease is the head we are forced to wake-up the thread, since we do not know the remaining sleeptime of the thread. */ c_condBroadcast(&_this->cond); } else { arg.lease = lease; arg.action = NULL; c_setWalk(_this->leases, findLeaseAction, &arg); if (arg.action) { /* determine if this is the new head */ if (c_timeCompare(v_leaseExpiryTime(_this->firstLeaseToExpire->lease), v_leaseExpiryTime(lease)) == C_GT) { c_free(_this->firstLeaseToExpire); _this->firstLeaseToExpire = c_keep(arg.action); c_condBroadcast(&_this->cond); } c_free(arg.action); } /* else lease is not registered, so no interest in this update! */ } } } else { if (event & V_EVENT_TERMINATE) { _this->quit = TRUE; c_condBroadcast(&_this->cond); } } c_mutexUnlock(&_this->mutex); return TRUE; }
/* put at end of list */ void v_deadLineInstanceListInsertInstance( v_deadLineInstanceList list, v_instance instance) { v_instance head = v_instance(list); v_kernel k; v_result result; assert(C_TYPECHECK(instance,v_instance)); assert(C_TYPECHECK(list,v_deadLineInstanceList)); assert(v_instanceAlone(instance)); assert(c_refCount(list) > 0); assert(c_refCount(instance) > 0); /* As the instance is put at the end of the list no need to update the lease! */ v_instanceUpdate(instance); /* Updates instance checkTime */ v_instanceAppend(head,instance); if (list->deadlineLease == NULL) { if (c_timeCompare(list->leaseDuration, C_TIME_INFINITE) != C_EQ) { k = v_objectKernel(list->leaseManager); list->deadlineLease = v_leaseNew(k, list->leaseDuration); if(list->deadlineLease) { result = v_leaseManagerRegister( list->leaseManager, list->deadlineLease, list->actionId, v_public(list->actionObject), TRUE /* repeat lease if expired */); if(result != V_RESULT_OK) { c_free(list->deadlineLease); list->deadlineLease = NULL; OS_REPORT_1(OS_ERROR, "v_deadLineInstanceList", 0, "A fatal error was detected when trying to register the deadline lease." "The result code was %d.", result); } } } } }
v_result v_deliveryWaitListWait ( v_deliveryWaitList _this, v_duration timeout) { v_result result = V_RESULT_OK; c_syncResult r; assert(C_TYPECHECK(_this,v_deliveryWaitList)); if (_this->readerGID != NULL) { c_mutexLock(&_this->mutex); if(c_timeCompare(timeout, C_TIME_INFINITE) != C_EQ) { r = c_condTimedWait(&_this->cv,&_this->mutex,timeout); } else { r = c_condWait(&_this->cv,&_this->mutex); } c_mutexUnlock(&_this->mutex); switch (r) { case SYNC_RESULT_SUCCESS: result = V_RESULT_OK; break; case SYNC_RESULT_TIMEOUT: result = V_RESULT_TIMEOUT; break; case SYNC_RESULT_UNAVAILABLE: case SYNC_RESULT_BUSY: case SYNC_RESULT_INVALID: case SYNC_RESULT_FAIL: default: result = V_RESULT_PRECONDITION_NOT_MET; break; } } return result; }
static c_bool waitForHistoricalData( c_object o, c_voidp arg) { v_entry entry; c_iter proxies; v_proxy proxy; v_group group; c_time waitTime; struct historicalWaitArg *parms = (struct historicalWaitArg *)arg; assert(o != NULL); assert(arg != NULL); entry = v_entry(o); assert(entry != NULL); assert(C_TYPECHECK(entry,v_entry)); proxies = c_select(entry->groups, 0); proxy = c_iterTakeFirst(proxies); while ((proxy != NULL) && (parms->_status == TRUE)) { group = v_group(v_proxyClaim(proxy)); if (group) { if (group->complete == FALSE) { waitTime = c_timeSub(parms->_expire_time, v_timeGet()); if (c_timeCompare(waitTime, C_TIME_ZERO) == C_GT) { parms->_status = v_groupWaitForComplete(group, waitTime); } else { parms->_status = FALSE; /* time out */ } } v_proxyRelease(proxy); } c_free(proxy); proxy = c_iterTakeFirst(proxies); } c_iterFree(proxies); return parms->_status; }
static c_bool v_readerQosConsistent( v_readerQos qos) { c_bool result; c_equality cmp; result = TRUE; if (qos != NULL) { cmp = c_timeCompare(qos->deadline.period, qos->pacing.minSeperation); if (cmp == C_LT) { result = FALSE; } if ((qos->resource.max_samples_per_instance != V_LENGTH_UNLIMITED) && (qos->history.kind != V_HISTORY_KEEPALL) && (qos->history.depth > qos->resource.max_samples_per_instance)) { result = FALSE; } } return result; }
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; }
v_networkQueue v_networkQueueNew( c_base base, c_ulong queueSize, c_ulong priority, c_bool reliable, c_bool P2P, c_time resolution, v_networkQueueStatistics statistics) { v_networkQueue result = NULL; c_type type; c_equality equality; c_bool hasChanged; c_time now; type = c_resolve(base, "kernelModule::v_networkQueue"); assert(type); result = v_networkQueue(c_new(type)); c_free(type); if (result) { /* Queue properties */ result->maxMsgCount = queueSize; result->currentMsgCount = 0; /* Cached type */ result->statusMarkerType = c_resolve(base, "kernelModule::v_networkStatusMarker"); assert(result->statusMarkerType != NULL); result->sampleType = c_resolve(base, "kernelModule::v_networkQueueSample"); assert(result->sampleType != NULL); /* Linked list of in-use marker items */ result->firstStatusMarker = NULL; result->lastStatusMarker = NULL; /* Linked list of free marker and message items */ result->freeStatusMarkers = NULL; result->freeSamples = NULL; /* Init cv stuff */ c_mutexInit(&result->mutex, SHARED_MUTEX); c_condInit(&result->cv, &result->mutex, SHARED_COND); /* Currently no differentiation wrt qos */ result->priority = priority; result->reliable = reliable; result->P2P = P2P; result->statistics = statistics; equality = c_timeCompare(C_TIME_ZERO, resolution); if (equality == C_EQ) { result->periodic = FALSE; result->resolution = C_TIME_INFINITE; result->msecsResolution = 0xFFFFFFFF; result->phaseMilliSeconds = 0; result->nextWakeup = C_TIME_INFINITE; } else { assert(equality == C_LT); result->periodic = TRUE; result->resolution = resolution; TIME_TO_MSEC(resolution, result->msecsResolution); /* A semi-random phase to avoid wake-ups at the same time */ now = v_timeGet(); result->phaseMilliSeconds = ((c_ulong)(now.nanoseconds/1000000 * 1.618)) % result->msecsResolution; v_networkQueueUpdateNextWakeup(result, &hasChanged); assert(hasChanged); } result->threadWaiting = FALSE; } else { OS_REPORT(OS_ERROR, "v_networkQueueNew",0, "Failed to allocate network queue."); } return result; }
/************************************************************** * register/deregister of leases **************************************************************/ v_result v_leaseManagerRegister( v_leaseManager _this, v_lease lease, v_leaseActionId actionId, v_public actionObject, c_bool repeatLease) { c_bool obsAdded; v_leaseAction leaseAction; v_leaseAction found; v_result result; v_kernel k; assert(_this != NULL); assert(C_TYPECHECK(_this, v_leaseManager)); assert(lease != NULL); assert(C_TYPECHECK(lease, v_lease)); assert(actionObject != NULL); assert(C_TYPECHECK(actionObject, v_public)); /* Step 1: Create a lease action object. This object will contain the relevant * information needed when reacting to an expired lease. This action information * can be different depending on which lease manager a lease is being registered * to, hence why the leaseAction object resides at leaseManager level and not * at lease level as it did in the past */ k = v_objectKernel(_this); leaseAction = v_leaseAction(v_objectNew(k, K_LEASEACTION)); if(!leaseAction) { OS_REPORT(OS_ERROR, "v_leaseManager", 0, "Failed to create a v_leaseManager object. " "Most likely not enough shared memory available to " "complete the operation."); result = V_RESULT_OUT_OF_MEMORY; } else { leaseAction->lease = v_lease(c_keep(lease)); assert(leaseAction->lease); leaseAction->actionId = actionId; leaseAction->actionObject = v_publicHandle(actionObject); leaseAction->repeat = repeatLease; /* Step 2: insert the leaseAction object into the set of leases. */ c_mutexLock(&_this->mutex); found = c_setInsert(_this->leases, leaseAction); if(!found) { /* Because the leaseAction object was just allocated we only have * to check if found is a NULL pointer. As it can never find the * action already being present in the set. */ OS_REPORT(OS_ERROR, "v_leaseManager", 0, "Unable to register the lease to the list of " "leases of the leaseManager object! Most likely not enough shared " "memory available to complete the operation."); result = V_RESULT_OUT_OF_MEMORY; c_free(leaseAction); leaseAction = NULL; } else { assert(found == leaseAction); /* Step 3: Determine if the newly inserted leaseAction will become the * 'next lease to expire'. E.G., if the lease contained within the * leaseAction object has an expiry time that is the closest to the * present time compared to the other leases managed within this lease * manager. To prevent the lease time from changing while we evaluate the * lease we will lock the lease object. */ v_leaseLock(lease); if(!_this->firstLeaseToExpire) { _this->firstLeaseToExpire = c_keep(leaseAction); /* head changed, so signal */ c_condBroadcast(&_this->cond); } else if ((_this->firstLeaseToExpire->lease != lease) && (c_timeCompare(v_leaseExpiryTime(_this->firstLeaseToExpire->lease), v_leaseExpiryTimeNoLock(lease)) == C_GT)) { c_free(_this->firstLeaseToExpire); _this->firstLeaseToExpire = c_keep(leaseAction); /* head changed, so signal */ c_condBroadcast(&_this->cond); }/* else do nothing as the newly added lease expires after the firstLeaseToExpire */ /* Step 4: Now that the lease was successfully inserted into the lease manager, * we need to register the leaseManager as an observer of the lease to ensure that the * lease manager is notified if the lease expiry time and/or duration changes. */ obsAdded = v_leaseAddObserverNoLock(lease, _this); if(!obsAdded) { OS_REPORT(OS_ERROR, "v_leaseManager", 0, "Unable to register the lease manager to the list of " "observers of the lease object! Possibly not enough " "shared memory available to complete the operation."); result = V_RESULT_INTERNAL_ERROR; v_leaseUnlock(lease); /* Remove the lease from the leaseManager */ found = c_setRemove(_this->leases, leaseAction, NULL, NULL); if(found != leaseAction) { OS_REPORT(OS_ERROR, "v_leaseManager", 0, "Unable to unregister the lease to the list of " "leases of the leaseManager object after previous internal error!"); } c_free(leaseAction); leaseAction = NULL; } else { /* Now that the lease manager is in the observer list of the lease, we can unlock the lease * as from now on we will be notified of any changes to the lease expiry time and/or duration */ v_leaseUnlock(lease); result = V_RESULT_OK; } } c_mutexUnlock(&_this->mutex); } if(leaseAction) { /* Done with the leaseAction object in this operation. If the object is not a NULL * pointer then everything went ok. The leases set of the leaseManager should be * the only one maintaining a ref count now (and possibly the 'firstLeaseToExpire' * attribute. But we do not need the leaseAction object in this operation anymore * and we are not returning it, so we need to lower the ref count for the new operation */ c_free(leaseAction); }/* else do nothing */ 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); } } }
/************************************************************** * Main / notify fnctions **************************************************************/ void v_leaseManagerMain( v_leaseManager _this) { v_leaseAction leaseAction; c_time waitTime = C_TIME_ZERO; c_time expTime; v_duration duration; struct collectExpiredArg arg; c_syncResult waitResult = SYNC_RESULT_SUCCESS; assert(_this != NULL); assert(C_TYPECHECK(_this, v_leaseManager)); c_mutexLock(&_this->mutex); /* initialize the current time once before the loop */ arg.now = v_timeGet(); while (_this->quit == FALSE) { if (_this->firstLeaseToExpire != NULL) { v_leaseGetExpiryAndDuration(_this->firstLeaseToExpire->lease, &expTime, &duration); if (c_timeCompare(expTime, C_TIME_INFINITE) != C_EQ) { waitTime = c_timeSub(expTime, arg.now); if (c_timeCompare(waitTime, C_TIME_ZERO) == C_GT) { waitResult = c_condTimedWait(&_this->cond, &_this->mutex, waitTime); } else { /* If the duration specified with the lease is C_TIME_ZERO, * it is expected that the expiryTime lies in the past, so * only warn if an actual duration was specified. */ if(c_timeCompare(duration, C_TIME_ZERO) != C_EQ){ OS_REPORT(OS_WARNING, "v_leaseManager", 0, "The wait time has become negative! This means " "that the leaseManager could not wake up in time to " "evaluate the lease expiry statusses. This could be " "due to scheduling problems or clock alignment issues on " "multi core machines. The lease manager will continue to " "function normal after this though."); } } } else { /* The shortest expiry time is from a lease with an infinite duration. So * wait indefinately */ waitResult = c_condWait(&_this->cond, &_this->mutex); } } else { /* no leases registered, so wait until the first one is registered */ waitResult = c_condWait(&_this->cond, &_this->mutex); } if (waitResult == SYNC_RESULT_FAIL) { OS_REPORT(OS_CRITICAL, "v_leaseManagerMain", 0, "c_condTimedWait / c_condWait failed - thread will terminate"); break; } /** * First walk through the collection of leases and record all * expired leases in an iterator. We cannot remove expired leases * while walking through the set, since it interferes with the * walk. * Any lease with a repeat bool to TRUE will automatically be renewed * while collecting all the leases. */ arg.expiredLeases = NULL; arg.firstLeaseToExpire = NULL; arg.now = v_timeGet(); c_setWalk(_this->leases, collectExpired, &arg); c_free(_this->firstLeaseToExpire); _this->firstLeaseToExpire = arg.firstLeaseToExpire;/* takes over ref count from arg object */ c_mutexUnlock(&_this->mutex); leaseAction = v_leaseAction(c_iterTakeFirst(arg.expiredLeases)); while (leaseAction != NULL) { if(!leaseAction->repeat) { v_leaseManagerDeregister(_this, leaseAction->lease); } v_leaseManagerProcessLeaseAction(_this, leaseAction, arg.now); c_free(leaseAction); leaseAction = v_leaseAction(c_iterTakeFirst(arg.expiredLeases)); } c_iterFree(arg.expiredLeases); c_mutexLock(&_this->mutex); } _this->quit = FALSE; /* for a next time */ c_mutexUnlock(&_this->mutex); }
static d_storeResult d_instanceRemove ( d_instance instance, v_message message) { d_sample current, sample; v_state state; v_message m; d_storeResult result; if ((instance != NULL) && (message != NULL)) { sample = NULL; current = d_instanceGetHead(instance); while(!sample && current){ m = d_sampleGetMessage(current); if(c_timeCompare(m->writeTime, message->writeTime) == C_EQ){ if(v_gidCompare(m->writerGID, message->writerGID) == C_EQ){ if(m->sequenceNumber == message->sequenceNumber){ sample = current; } } } if(!sample){ current = current->older; } } if(sample){ if (sample->newer != NULL) { d_sample(sample->newer)->older = c_keep(sample->older); } else { assert(d_instanceGetHead(instance) == sample); d_instanceSetHead(instance,sample->older); } if (sample->older != NULL) { d_sample(sample->older)->newer = sample->newer; } else { assert(d_instanceGetTail(instance) == sample); d_instanceSetTail(instance,sample->newer); } state = v_nodeState(d_sampleGetMessage(sample)); if (v_stateTest(state, L_WRITE)) { instance->count--; instance->messageCount--; } if (v_stateTest(state, L_DISPOSED)) { instance->count--; } c_free(sample); if (instance->oldest == NULL) { v_stateSet(instance->state, L_EMPTY); } } assert((instance->count == 0) == (d_instanceGetTail(instance) == NULL)); assert((instance->count == 0) == (d_instanceGetHead(instance) == NULL)); result = D_STORE_RESULT_OK; } else { result = D_STORE_RESULT_ILL_PARAM; } return result; }
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; }
c_bool v_historicalDataRequestEquals( v_historicalDataRequest req1, v_historicalDataRequest req2) { c_bool result; c_long i, size1, size2; if(req1 && req2){ if(c_timeCompare( req1->minSourceTimestamp, req2->minSourceTimestamp) != C_EQ) { result = FALSE; } else if(c_timeCompare( req1->maxSourceTimestamp, req2->maxSourceTimestamp) != C_EQ) { result = FALSE; } else if(req1->resourceLimits.max_samples != req2->resourceLimits.max_samples) { result = FALSE; } else if(req1->resourceLimits.max_instances != req2->resourceLimits.max_instances) { result = FALSE; } else if(req1->resourceLimits.max_samples_per_instance != req2->resourceLimits.max_samples_per_instance) { result = FALSE; } else if((req1->filter && req2->filter)){ if(strcmp(req1->filter, req2->filter) != 0){ result = FALSE; } else if(req1->filterParams && req2->filterParams){ size1 = c_arraySize(req1->filterParams); size2 = c_arraySize(req2->filterParams); if(size1 == size2){ result = TRUE; for(i=0; i<size1 && result; i++){ if(strcmp(req1->filterParams[i], req2->filterParams[i]) != 0) { result = FALSE; } } } else { result = FALSE; } } else if(!req1->filterParams && !req2->filterParams){ result = TRUE; } else { result = FALSE; } } else if((!req1->filter && !req2->filter)){ result = TRUE; } else { result = FALSE; } } else if(req1 || req2){ result = FALSE; } else { result = TRUE; } return result; }
void v_lifespanAdminRemove( v_lifespanAdmin admin, v_lifespanSample sample) { c_equality eq; assert(C_TYPECHECK(admin,v_lifespanAdmin)); assert(C_TYPECHECK(sample,v_lifespanSample)); eq = c_timeCompare(sample->expiryTime, C_TIME_INFINITE); if (eq == C_EQ) { return; /* no insert, since sample never expires! */ } CHECK_ADMIN(admin, sample); if (sample == admin->head) { assert(sample->prev == NULL); if (sample == admin->tail) { assert(c_refCount(sample) > 2); assert(sample->next == NULL); c_free(sample); /* free tail reference */ admin->head = NULL; admin->tail = NULL; } else { assert(c_refCount(sample) > 1); admin->head = sample->next; /* transfer refcount */ if (sample->next) { sample->next = NULL; admin->head->prev = NULL; /* or sample->next->prev = NULL */ } } c_free(sample); /* free head reference */ admin->sampleCount--; } else { if (sample == admin->tail) { assert(sample->prev); assert(c_refCount(sample) > 2); /* Both tail and next field from prev sample. */ assert(sample->next == NULL); c_free(admin->tail); admin->tail = c_keep(sample->prev); sample->prev = NULL; c_free(admin->tail->next); /* admin->tail->next == sample */ admin->tail->next = NULL; admin->sampleCount--; } else { if ((sample->next != NULL) && (sample->prev != NULL)) { assert(c_refCount(sample) > 1); assert(admin->sampleCount > 0); v_lifespanSample(sample->prev)->next = sample->next; /* transfer refcount */ sample->next->prev = sample->prev; sample->next = NULL; sample->prev = NULL; c_free(sample); admin->sampleCount--; } /* else sample not in admin, so no removing needed */ } } CHECK_ADMIN(admin, sample); }