void v_leaseManagerDeinit( v_leaseManager _this) { v_leaseAction lease; assert(C_TYPECHECK(_this, v_leaseManager)); c_mutexLock(&_this->mutex); c_free(_this->firstLeaseToExpire); _this->firstLeaseToExpire = NULL; lease = v_leaseAction(c_take(_this->leases)); while (lease != NULL) { c_free(lease); lease = v_leaseAction(c_take(_this->leases)); } c_free(_this->leases); _this->leases = NULL; _this->quit = TRUE; c_condBroadcast(&_this->cond); c_mutexUnlock(&_this->mutex); /* Note the condition _this->cond is deinitalised via c_free */ }
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; }
void v_networkQueueTrigger( v_networkQueue queue) { c_mutexLock(&queue->mutex); queue->triggered = 1; if (queue->threadWaiting) { c_condBroadcast(&queue->cv); } c_mutexUnlock(&queue->mutex); }
void v_participantResendManagerQuit( v_participant p) { assert(C_TYPECHECK(p,v_participant)); c_mutexLock(&p->resendMutex); p->resendQuit = TRUE; c_condBroadcast(&p->resendCond); c_mutexUnlock(&p->resendMutex); }
void v_observerFree( v_observer o) { assert(C_TYPECHECK(o,v_observer)); c_mutexLock(&o->mutex); o->eventFlags |= V_EVENT_OBJECT_DESTROYED; c_condBroadcast(&o->cv); c_mutexUnlock(&o->mutex); v_observableFree(v_observable(o)); }
void v_readerNotifyHistoricalDataAvailable( v_reader _this) { assert(C_TYPECHECK(_this, v_reader)); if(_this){ V_READER_LOCK(_this); _this->historicalDataComplete = TRUE; c_condBroadcast(&_this->historicalDataCondition); V_READER_UNLOCK(_this); } return; }
void v_participantResendManagerAddWriter( v_participant p, v_writer w) { v_proxy wp, found; assert(C_TYPECHECK(p,v_participant)); wp = v_proxyNew(v_objectKernel(w), v_publicHandle(v_public(w)), NULL); c_mutexLock(&p->resendMutex); found = c_insert(p->resendWriters, wp); assert((found->source.index == wp->source.index) && (found->source.serial == wp->source.serial)); c_condBroadcast(&p->resendCond); c_mutexUnlock(&p->resendMutex); c_free(wp); }
void v_listenerFree( v_listener _this) { v_participant p; v_listenerEvent event; os_duration delay; assert(_this != NULL); assert(C_TYPECHECK(_this,v_listener)); p = v_participant(_this->participant); assert(p != NULL); c_mutexLock(&_this->mutex); /* wakeup blocking threads to evaluate new condition. */ /* remove all events */ while (_this->eventList != NULL) { event = _this->eventList; _this->eventList = event->next; v_listenerEventDeinit(event); c_free(event); } _this->eventList = NULL; c_free(_this->lastEvent); _this->lastEvent = NULL; _this->terminate = TRUE; c_condBroadcast(&_this->cv); c_mutexUnlock(&_this->mutex); delay = OS_DURATION_INIT(0, 1000); while (_this->waitCount > 0 && !p->processIsZombie) { ospl_os_sleep(delay); } v_participantRemove(p, v_object(_this)); _this->participant = NULL; v_publicFree(v_public(_this)); }
void v_listenerFlush( v_listener _this, v_eventMask events, c_voidp userData) { v_listenerEvent event, *prev; if (_this == NULL) { return; } assert(C_TYPECHECK(_this,v_listener)); c_mutexLock(&_this->mutex); /* wakeup blocking threads to evaluate new condition. */ /* remove all events */ prev = &_this->eventList; event = _this->eventList; while (event != NULL) { if (event->userData == userData) { event->kind &= ~events; } if (event->kind == 0) { if (event == _this->lastEvent) { _this->lastEvent = c_keep(_this->lastEvent->next); v_listenerEventDeinit(event); c_free(event); } *prev = event->next; v_listenerEventDeinit(event); c_free(event); event = *prev; } else { prev = &event->next; event = event->next; } } c_condBroadcast(&_this->cv); c_mutexUnlock(&_this->mutex); }
void v_listenerNotify( v_listener _this, v_event e, v_entity listener) { /* The userData argument is typical the user layer entity to which * this listener is attached. * The userData is passed to the v_listenerWait operation. * The eventData is optional for passing additional data, * typically status information is passed. */ v_listenerEvent event,found; v_status status; assert(_this != NULL); assert(C_TYPECHECK(_this,v_listener)); c_mutexLock(&_this->mutex); if (e != NULL) { found = NULL; event = NULL; if (_this->combine && ((e->kind & V_EVENT_DATA_AVAILABLE) || (e->kind & V_EVENT_ON_DATA_ON_READERS)) ) { /* Optimization for data availability: look for pending event and combine * to avoid triggering after data is already read on behalf of the first * trigger. */ c_voidp source = v_publicGetUserData(v_public(e->source)); found = _this->eventList; while (found != NULL) { if ((found->source == source) && (found->kind == e->kind)) { break; } else { found = found->next; } } } if (found == NULL) { event = c_new(v_kernelType(v_objectKernel(_this),K_LISTENEREVENT)); event->next = NULL; event->kind = e->kind; event->source = v_publicGetUserData(v_public(e->source)); /* For all events except for data availability * copy the entity status to keep the actual value until the * data is processed. The aforementioned events do not affect * status, so there is no need to copy the value nor reset any * counters. */ if (event->kind == V_EVENT_DATA_AVAILABLE) { c_free(event->eventData); event->eventData = c_keep(e->data); } else { status = v_entityStatus(v_entity(e->source)); c_free(event->eventData); event->eventData = v_statusCopyOut(status); v_statusResetCounters(status, e->kind); c_free(status); } } } else { event = c_new(v_kernelType(v_objectKernel(_this),K_LISTENEREVENT)); event->next = NULL; event->kind = V_EVENT_TRIGGER; event->source = NULL; event->eventData = NULL; } if (event) { /* insert constructed listener event in the listeners event list. */ if (_this->lastEvent) { _this->lastEvent->next = c_keep(event); c_free(_this->lastEvent); } else { assert(_this->eventList == NULL); _this->eventList = c_keep(event); } _this->lastEvent = event /* transfer ref */; if (listener) { event->listenerData = listener->listenerData; event->userData = v_publicGetUserData(v_public(listener)); /* Typical the language binding entity */ } else { event->listenerData = NULL; event->userData = NULL; /* Typical the language binding entity */ } } _TRACE_EVENTS_("v_listenerNotify: listener 0x%x, events 0x%x\n", _this, (e?e->kind:V_EVENT_TRIGGER)); c_condBroadcast(&_this->cv); c_mutexUnlock(&_this->mutex); }
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; }
/** * PRE: v_observerLock has been called. * * When the text 'intentionally no break' is set after a case label * the class specified by the label has not implemented the notify * method. */ void v_observerNotify( v_observer _this, v_event event, c_voidp userData) { /* This Notify method is part of the observer-observable pattern. * It is designed to be invoked when _this object as observer receives * an event from an observable object. * It must be possible to pass the event to the subclass of itself by * calling <subclass>Notify(_this, event, userData). * This implies that _this cannot be locked within any Notify method * to avoid deadlocks. * For consistency _this must be locked by v_observerLock(_this) before * calling this method. */ c_ulong trigger; assert(_this != NULL); assert(C_TYPECHECK(_this,v_observer)); /* The observer will be made insensitive to event as soon as the * observer is deinitialized. However it may be that destruction * of the observer has started before the deinit of the observer * is called. In that case the V_EVENT_OBJECT_DESTROYED flag will * be set to avoid processing of incomming events. */ if ((_this->eventFlags & V_EVENT_OBJECT_DESTROYED) == 0) { /* The observer is valid so the event can be processed. */ if (event != NULL ) { trigger = event->kind & _this->eventMask; } else { /* NULL-event always notifies observers */ trigger = V_EVENT_TRIGGER; } /* The following code invokes the observers subclass specific * notification method. * This is a bit strange that the observer has knowledge about * the subclass notification methods, a better model is that * subclasses register the notification method to the observer * instead. The reason for this model is that registering a * function pointer is only valid in the process scope and this * method will typically be called from another process. */ if (trigger != 0) { switch (v_objectKind(_this)) { case K_DATAREADER: v_dataReaderNotify(v_dataReader(_this), event, userData); break; case K_WAITSET: v_waitsetNotify(v_waitset(_this), event, userData); break; case K_PARTICIPANT: v_participantNotify(v_participant(_this), event, userData); break; case K_TOPIC: v_topicNotify(v_topic(_this), event, userData); break; case K_QUERY: /* v_queryNotify(v_query(_this), event, userData); */ break; case K_SPLICED: /* intentionally no break */ case K_SERVICE: case K_NETWORKING: case K_DURABILITY: case K_CMSOAP: v_serviceNotify(v_service(_this), event, userData); break; case K_SERVICEMANAGER: v_serviceManagerNotify(v_serviceManager(_this), event, userData); break; case K_WRITER: /* no action for the following observers */ case K_PUBLISHER: case K_SUBSCRIBER: case K_GROUPQUEUE: break; default: OS_REPORT_1(OS_INFO,"Kernel Observer",0, "Notify an unknown observer type: %d", v_objectKind(_this)); break; } /* * Only trigger condition variable if at least * one thread is waiting AND the event is seen for the first time. */ if ((_this->waitCount > 0) && ((trigger == V_EVENT_TRIGGER) || (~_this->eventFlags & trigger))) { _this->eventFlags |= trigger; /* store event */ c_condBroadcast(&_this->cv); } else { _this->eventFlags |= trigger; /* store event */ } } } /* else observer object destroyed, skip notification */ }
/************************************************************** * 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; }