c_bool v_waitsetDetach ( v_waitset _this, v_observable o) { c_bool result; v_proxy found; findProxyArgument arg; void* userDataRemoved = NULL; assert(_this != NULL); assert(C_TYPECHECK(_this,v_waitset)); arg.observable = v_publicHandle(v_public(o)); arg.proxy = NULL; v_waitsetLock(_this); c_setWalk(_this->observables,findProxy,&arg); if (arg.proxy != NULL) { /* proxy to the observer found */ found = c_remove(_this->observables,arg.proxy,NULL,NULL); assert(found == arg.proxy); c_free(found); } v_waitsetUnlock(_this); result = v_observableRemoveObserver(o,v_observer(_this), &userDataRemoved); v_waitsetClearRemovedObserverPendingEvents(_this, userDataRemoved); /* wakeup blocking threads to evaluate new condition. */ if (v_observerWaitCount(_this)) { v_waitsetTrigger(_this, NULL); } return result; }
c_bool v_waitsetAttach ( v_waitset _this, v_observable o, c_voidp userData) { c_bool result; v_proxy proxy; findProxyArgument arg; assert(_this != NULL); assert(C_TYPECHECK(_this,v_waitset)); arg.observable = v_publicHandle(v_public(o)); arg.proxy = NULL; v_waitsetLock(_this); c_setWalk(_this->observables, findProxy,&arg); if (arg.proxy == NULL) { /* no proxy to the observer exists */ proxy = v_proxyNew(v_objectKernel(_this), arg.observable, userData); c_insert(_this->observables,proxy); c_free(proxy); } v_waitsetUnlock(_this); result = v_observableAddObserver(o,v_observer(_this), userData); /* wakeup blocking threads to evaluate new condition. */ if (v_observerWaitCount(_this)) { v_waitsetTrigger(_this, NULL); } return result; }
void v_subscriberUnSubscribe( v_subscriber s, const c_char *partitionExpr) { v_partition d; v_dataReaderConnectionChanges arg; v_partitionPolicy old; assert(s != NULL); assert(C_TYPECHECK(s,v_subscriber)); arg.addedPartitions = NULL; c_lockWrite(&s->lock); arg.removedPartitions = v_partitionAdminRemove(s->partitions, partitionExpr); old = s->qos->partition; s->qos->partition = v_partitionPolicyRemove(old, partitionExpr, c_getBase(c_object(s))); c_free(old); c_setWalk(s->readers, qosChangedAction, &arg); d = v_partition(c_iterTakeFirst(arg.removedPartitions)); while (d != NULL) { c_free(d); d = v_partition(c_iterTakeFirst(arg.removedPartitions)); } c_iterFree(arg.removedPartitions); c_lockUnlock(&s->lock); }
void v_subscriberConnectNewGroup( v_subscriber s, v_group g) { c_bool connect; c_iter addedPartitions; v_partition d; c_lockWrite(&s->lock); connect = v_partitionAdminFitsInterest(s->partitions, g->partition); if (connect) { addedPartitions = v_partitionAdminAdd(s->partitions, v_partitionName(g->partition)); d = v_partition(c_iterTakeFirst(addedPartitions)); while (d != NULL) { c_free(d); d = v_partition(c_iterTakeFirst(addedPartitions)); } c_iterFree(addedPartitions); c_setWalk(s->readers, (c_action)v_readerSubscribeGroup, g); } else { /* * Check if group fits interest. This extra steps are needed because * the groupActionStream does not create the groups that match the * subscriber qos partition expression on creation. It only needs to * connect to new groups once they are created. This is a different * approach then for a data reader. */ /* * Because already existing partitions are created and added to the * subscriber of the groupActionStream at creation time, these * partitions can be resolved from the subscriber. This is necessary to * determine whether the groupActionStream should connect to the new * group or if it is already connected. */ if (v_partitionAdminExists(s->partitions, v_partitionName(g->partition))) { c_setWalk(s->readers, (c_action)notifyGroupQueues, g); } } c_lockUnlock(&s->lock); }
c_bool v_readerWalkEntries( v_reader r, c_action action, c_voidp arg) { c_bool result; assert(C_TYPECHECK(r,v_reader)); v_readerEntrySetLock(r); result = c_setWalk(r->entrySet.entries, action, arg); v_readerEntrySetUnlock(r); return result; }
static void getStatusMask( v_entity e, c_voidp arg) { c_long *mask = (c_long *)arg; if ( v_objectKind(e) == K_SUBSCRIBER ) { if ( !c_setWalk(v_subscriber(e)->readers, (c_action)readerHasDataAvailable, NULL) ) { *mask = V_EVENT_DATA_AVAILABLE; } else { *mask = 0; } } else { *mask = v_statusGetMask(e->status); } }
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; }
c_iter v_subscriberLookupReadersByTopic( v_subscriber s, const c_char *topicName) { struct lookupReaderByTopicArg arg; assert(s != NULL); arg.list = NULL; arg.topicName = topicName; c_lockRead(&s->lock); c_setWalk(s->readers, (c_action)lookupReaderByTopic, &arg); c_lockUnlock(&s->lock); return arg.list; }
/************************************************************** * 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); }
void v_leaseManagerDeregister( v_leaseManager _this, v_lease lease) { struct findLeaseActionArg arg; v_leaseAction found; c_bool removed; assert(_this != NULL); assert(C_TYPECHECK(_this, v_leaseManager)); if (lease != NULL) { assert(C_TYPECHECK(lease, v_lease)); /* Step 1: Locate the leaseAction object based on the lease object */ c_mutexLock(&_this->mutex); arg.lease = lease; arg.action = NULL; c_setWalk(_this->leases, findLeaseAction, &arg); if(arg.action) { /* step 2a: If we found the action object, then remove it */ found = c_setRemove(_this->leases, arg.action, NULL, NULL); assert(found == arg.action); /* Step 2b: Remove the leaseManager from the list of observers of the * lease object. Using explicit lock operations, to keep the * v_leaseRemoveObserverNoLock operation consistent with the * v_leaseAddObserverNoLock operation. */ v_leaseLock(lease); removed = v_leaseRemoveObserverNoLock(lease, _this); v_leaseUnlock(lease); if(removed == FALSE) { OS_REPORT_2(OS_ERROR, "v_leaseManagerDeregister",0, "Failed to remove leaseManager %p from the list of " "observers of lease %p, while the lease WAS contained in " "the list of leases managed by the leaseManager. This means " "the administration has become inconsistent internally. " "This is not a fatal error in itself, but points towards " "a bug that could affect behaviour of OpenSpliceDDS", _this, lease); } /* else everything is ok */ /* step 3: If the removed action was the 'firstLeaseToExpire' then we need * to redetermine the new 'firstLeaseToExpire'. Take note that no broadcast is done * on the condition. Because the new 'firstLeaseToExpire' will always have a later * expiry time, otherwise the one removed would not have been the first to expire. * So as a result of not doing the broadcast the leaseManager will wake up and find no * lease to be expired and continue as normal */ if (arg.action == _this->firstLeaseToExpire) { c_free(_this->firstLeaseToExpire); _this->firstLeaseToExpire = NULL; c_setWalk(_this->leases, determineFirstLeaseToExpire, _this); } c_free(found); /* delete local reference */ c_free(arg.action); }/* else the lease was not contained, so do nothing */ c_mutexUnlock(&_this->mutex); } }
v_result v_subscriberSetQos( v_subscriber s, v_subscriberQos qos) { v_result result; v_qosChangeMask cm; v_dataReaderConnectionChanges arg; v_partition d; v_accessMode access; assert(s != NULL); arg.addedPartitions = NULL; arg.removedPartitions = NULL; c_lockWrite(&s->lock); /* ES, dds1576: When the QoS is being set we have to verify that the partitions * listed in the qos do not have an invalid access mode set. For a subscriber * an invalid mode is characterized as 'write' mode. If the partitionAccess * check returns ok, then everything continue as normal. If the * partitionAccess check returns something else, then the setQos operation * is aborted. Please see the partitionAccess check operation to know when * a partition expression is not allowed. */ if(qos && qos->partition) { access = v_kernelPartitionAccessMode(v_objectKernel(s), qos->partition); } else { access = V_ACCESS_MODE_READ_WRITE;/* default */ } if(access == V_ACCESS_MODE_READ_WRITE || access == V_ACCESS_MODE_READ) { result = v_subscriberQosSet(s->qos, qos, v_entity(s)->enabled, &cm); if ((result == V_RESULT_OK) && (cm != 0)) { c_lockUnlock(&s->lock); /* since creation builtin topic might lock subscriber again. */ if (cm & V_POLICY_BIT_PARTITION) { /* partition policy has changed! */ v_partitionAdminSet(s->partitions, s->qos->partition, &arg.addedPartitions, &arg.removedPartitions); } c_setWalk(s->readers, qosChangedAction, &arg); d = v_partition(c_iterTakeFirst(arg.addedPartitions)); while (d != NULL) { c_free(d); d = v_partition(c_iterTakeFirst(arg.addedPartitions)); } c_iterFree(arg.addedPartitions); d = v_partition(c_iterTakeFirst(arg.removedPartitions)); while (d != NULL) { c_free(d); d = v_partition(c_iterTakeFirst(arg.removedPartitions)); } c_iterFree(arg.removedPartitions); } else { c_lockUnlock(&s->lock); } } else { result = V_RESULT_PRECONDITION_NOT_MET; c_lockUnlock(&s->lock); } return result; }