Skip to content

Commit

Permalink
iox-#27 Add BaseServer for typed and untyped API
Browse files Browse the repository at this point in the history
  • Loading branch information
elBoberido committed Feb 11, 2022
1 parent 6dcb9ef commit 601edf6
Show file tree
Hide file tree
Showing 3 changed files with 362 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ namespace iox
error(POPO__BASE_SUBSCRIBER_OVERRIDING_WITH_STATE_SINCE_HAS_DATA_OR_DATA_RECEIVED_ALREADY_ATTACHED) \
error(POPO__BASE_CLIENT_OVERRIDING_WITH_EVENT_SINCE_HAS_RESPONSE_OR_RESPONSE_RECEIVED_ALREADY_ATTACHED) \
error(POPO__BASE_CLIENT_OVERRIDING_WITH_STATE_SINCE_HAS_RESPONSE_OR_RESPONSE_RECEIVED_ALREADY_ATTACHED) \
error(POPO__BASE_SERVER_OVERRIDING_WITH_EVENT_SINCE_HAS_REQUEST_OR_REQUEST_RECEIVED_ALREADY_ATTACHED) \
error(POPO__BASE_SERVER_OVERRIDING_WITH_STATE_SINCE_HAS_REQUEST_OR_REQUEST_RECEIVED_ALREADY_ATTACHED) \
error(POPO__CHUNK_QUEUE_POPPER_CHUNK_WITH_INCOMPATIBLE_CHUNK_HEADER_VERSION) \
error(POPO__CHUNK_DISTRIBUTOR_OVERFLOW_OF_QUEUE_CONTAINER) \
error(POPO__CHUNK_DISTRIBUTOR_CLEANUP_DEADLOCK_BECAUSE_BAD_APPLICATION_TERMINATION) \
Expand Down
155 changes: 155 additions & 0 deletions iceoryx_posh/include/iceoryx_posh/internal/popo/base_server.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2020 - 2022 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

#ifndef IOX_POSH_POPO_BASE_SERVER_HPP
#define IOX_POSH_POPO_BASE_SERVER_HPP

#include "iceoryx_hoofs/cxx/expected.hpp"
#include "iceoryx_posh/capro/service_description.hpp"
#include "iceoryx_posh/internal/popo/ports/server_port_user.hpp"
#include "iceoryx_posh/popo/server_options.hpp"
#include "iceoryx_posh/popo/trigger_handle.hpp"
#include "iceoryx_posh/runtime/posh_runtime.hpp"

namespace iox
{
namespace popo
{
using uid_t = UniquePortId;

/// @brief The BaseServer class contains the common implementation for the different server
/// @param[in] Port type of the underlying port, required for testing specializations.
template <typename Port = ServerPortUser>
class BaseServer
{
public:
virtual ~BaseServer() noexcept;

BaseServer(const BaseServer& other) = delete;
BaseServer& operator=(const BaseServer&) = delete;
BaseServer(BaseServer&& rhs) = delete;
BaseServer& operator=(BaseServer&& rhs) = delete;

///
/// @brief Get the UID of the server.
/// @return The server's UID.
///
uid_t getUid() const noexcept;

///
/// @brief Get the service description of the server.
/// @return The service description.
///
capro::ServiceDescription getServiceDescription() const noexcept;

///
/// @brief Offer the service to be connected to.
///
void offer() noexcept;

///
/// @brief Stop offering the service.
///
void stopOffer() noexcept;

///
/// @brief Check if the server is offering.
/// @return True if service is currently being offered.
///
bool isOffered() const noexcept;

///
/// @brief Check if the server has clients
/// @return True if currently has subscribers to the service.
///
bool hasClients() const noexcept;

///
/// @brief Check if requests are available.
/// @return True if requests are available.
///
bool hasRequests() const noexcept;

///
/// @brief Check if requests has been missed since the last call of this method.
/// @return True if requests has been missed.
/// @details Requests may be missed due to overflowing receive queue.
///
bool hasMissedRequests() noexcept;

/// @brief Releases any unread queued requests.
void releaseQueuedRequests() noexcept;

friend class NotificationAttorney;

protected:
using SelfType = BaseServer<Port>;
using PortType = Port;

BaseServer() noexcept = default; // Required for testing.
BaseServer(const capro::ServiceDescription& service, const ServerOptions& serverOptions) noexcept;

/// @brief Only usable by the WaitSet, not for public use. Invalidates the internal triggerHandle.
/// @param[in] uniqueTriggerId the id of the corresponding trigger
void invalidateTrigger(const uint64_t uniqueTriggerId) noexcept;

/// @brief Only usable by the WaitSet, not for public use. Attaches the triggerHandle to the internal trigger.
/// @param[in] triggerHandle rvalue reference to the triggerHandle. This class takes the ownership of that handle.
/// @param[in] serverState the state which should be attached
void enableState(iox::popo::TriggerHandle&& triggerHandle, const ServerState serverState) noexcept;

/// @brief Only usable by the WaitSet, not for public use. Returns method pointer to the event corresponding
/// hasTriggered method callback
/// @param[in] serverState the state to which the hasTriggeredCallback is required
WaitSetIsConditionSatisfiedCallback
getCallbackForIsStateConditionSatisfied(const ServerState serverState) const noexcept;

/// @brief Only usable by the WaitSet, not for public use. Resets the internal triggerHandle
/// @param[in] serverState the state which should be detached
void disableState(const ServerState serverState) noexcept;

/// @brief Only usable by the WaitSet, not for public use. Attaches the triggerHandle to the internal trigger.
/// @param[in] triggerHandle rvalue reference to the triggerHandle. This class takes the ownership of that handle.
/// @param[in] serverEvent the event which should be attached
void enableEvent(iox::popo::TriggerHandle&& triggerHandle, const ServerEvent serverEvent) noexcept;

/// @brief Only usable by the WaitSet, not for public use. Resets the internal triggerHandle
/// @param[in] serverEvent the event which should be detached
void disableEvent(const ServerEvent serverEvent) noexcept;

///
/// @brief port
/// @return const accessor of the underlying port
///
const Port& port() const noexcept;

///
/// @brief port
/// @return accessor of the underlying port
///
Port& port() noexcept;

Port m_port{nullptr}; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
TriggerHandle m_trigger; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
};

} // namespace popo
} // namespace iox

#include "iceoryx_posh/internal/popo/base_server.inl"

#endif // IOX_POSH_POPO_BASE_SERVER_HPP
205 changes: 205 additions & 0 deletions iceoryx_posh/include/iceoryx_posh/internal/popo/base_server.inl
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2020 - 2022 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

#ifndef IOX_POSH_POPO_BASE_SERVER_INL
#define IOX_POSH_POPO_BASE_SERVER_INL

#include "iceoryx_posh/internal/popo/base_server.hpp"

namespace iox
{
namespace popo
{
template <typename Port>
inline BaseServer<Port>::BaseServer(const capro::ServiceDescription& service,
const ServerOptions& serverOptions) noexcept
: m_port(*iox::runtime::PoshRuntime::getInstance().getMiddlewareServer(service, serverOptions))
{
}

template <typename Port>
inline BaseServer<Port>::~BaseServer() noexcept
{
m_port.destroy();
}

template <typename Port>
inline uid_t BaseServer<Port>::getUid() const noexcept
{
return m_port.getUniqueID();
}

template <typename Port>
inline capro::ServiceDescription BaseServer<Port>::getServiceDescription() const noexcept
{
return m_port.getCaProServiceDescription();
}

template <typename Port>
inline void BaseServer<Port>::offer() noexcept
{
m_port.offer();
}

template <typename Port>
inline void BaseServer<Port>::stopOffer() noexcept
{
m_port.stopOffer();
}

template <typename Port>
inline bool BaseServer<Port>::isOffered() const noexcept
{
return m_port.isOffered();
}

template <typename Port>
inline bool BaseServer<Port>::hasClients() const noexcept
{
return m_port.hasClients();
}

template <typename Port>
inline bool BaseServer<Port>::hasRequests() const noexcept
{
return m_port.hasNewRequests();
}

template <typename Port>
inline bool BaseServer<Port>::hasMissedRequests() noexcept
{
return m_port.hasLostRequestsSinceLastCall();
}

template <typename Port>
inline void BaseServer<Port>::releaseQueuedRequests() noexcept
{
m_port.releaseQueuedRequests();
}

template <typename Port>
inline void BaseServer<Port>::invalidateTrigger(const uint64_t uniqueTriggerId) noexcept
{
if (m_trigger.getUniqueId() == uniqueTriggerId)
{
m_port.unsetConditionVariable();
m_trigger.invalidate();
}
}

template <typename Port>
inline void BaseServer<Port>::enableState(iox::popo::TriggerHandle&& triggerHandle,
const ServerState serverState) noexcept
{
switch (serverState)
{
case ServerState::HAS_REQUEST:
if (m_trigger)
{
LogWarn()
<< "The server is already attached with either the ServerState::HAS_REQUEST or "
"ServerEvent::REQUEST_RECEIVED to a WaitSet/Listener. Detaching it from previous one and "
"attaching it to the new one with ServerState::HAS_REQUEST. Best practice is to call detach first.";

errorHandler(
Error::kPOPO__BASE_SERVER_OVERRIDING_WITH_STATE_SINCE_HAS_REQUEST_OR_REQUEST_RECEIVED_ALREADY_ATTACHED,
nullptr,
ErrorLevel::MODERATE);
}
m_trigger = std::move(triggerHandle);
m_port.setConditionVariable(*m_trigger.getConditionVariableData(), m_trigger.getUniqueId());
break;
}
}

template <typename Port>
inline WaitSetIsConditionSatisfiedCallback
BaseServer<Port>::getCallbackForIsStateConditionSatisfied(const ServerState serverState) const noexcept
{
switch (serverState)
{
case ServerState::HAS_REQUEST:
return {*this, &SelfType::hasRequests};
}
return {};
}

template <typename Port>
inline void BaseServer<Port>::disableState(const ServerState serverState) noexcept
{
switch (serverState)
{
case ServerState::HAS_REQUEST:
m_trigger.reset();
m_port.unsetConditionVariable();
break;
}
}

template <typename Port>
inline void BaseServer<Port>::enableEvent(iox::popo::TriggerHandle&& triggerHandle,
const ServerEvent serverEvent) noexcept
{
switch (serverEvent)
{
case ServerEvent::REQUEST_RECEIVED:
if (m_trigger)
{
LogWarn()
<< "The server is already attached with either the ServerState::HAS_REQUEST or "
"ServerEvent::REQUEST_RECEIVED to a WaitSet/Listener. Detaching it from previous one and "
"attaching it to the new one with ServerEvent::REQUEST_RECEIVED. Best practice is to call detach "
"first.";
errorHandler(
Error::kPOPO__BASE_SERVER_OVERRIDING_WITH_EVENT_SINCE_HAS_REQUEST_OR_REQUEST_RECEIVED_ALREADY_ATTACHED,
nullptr,
ErrorLevel::MODERATE);
}
m_trigger = std::move(triggerHandle);
m_port.setConditionVariable(*m_trigger.getConditionVariableData(), m_trigger.getUniqueId());
break;
}
}

template <typename Port>
inline void BaseServer<Port>::disableEvent(const ServerEvent serverEvent) noexcept
{
switch (serverEvent)
{
case ServerEvent::REQUEST_RECEIVED:
m_trigger.reset();
m_port.unsetConditionVariable();
break;
}
}

template <typename Port>
const Port& BaseServer<Port>::port() const noexcept
{
return m_port;
}

template <typename Port>
Port& BaseServer<Port>::port() noexcept
{
return m_port;
}

} // namespace popo
} // namespace iox

#endif // IOX_POSH_POPO_BASE_SERVER_INL

0 comments on commit 601edf6

Please sign in to comment.