Пример #1
0
/**************************************************************
 * 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);
}
Пример #2
0
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);
}
Пример #3
0
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;
}
Пример #4
0
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;
        }
    }
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
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);
                }
            }
        }
    }
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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;
}
Пример #11
0
/* 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);
                }
            }
        }
    }
}
Пример #12
0
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;
}
Пример #13
0
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;
}
Пример #14
0
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;
}
Пример #15
0
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;
}    
Пример #16
0
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 = &currentMarker->next;
                currentMarker = *currentMarkerPtr;
            break;
            case C_EQ:
                if (priorityLookingFor < currentMarker->priority) {
                    currentMarkerPtr = &currentMarker->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;
}
Пример #17
0
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;
}    
Пример #18
0
/**************************************************************
 * 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;
}
Пример #19
0
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);
        }
    }
}
Пример #20
0
/**************************************************************
 * 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);
}
Пример #21
0
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;
}
Пример #22
0
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;
}
Пример #23
0
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;
}
Пример #24
0
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);
}