sdbus-cpp: emit signal on io queue

Else, we can see several deadlock (closeVideoInput() will wait
forever, because a signal is emitted before the method is finished
causing a deadlock in sdbus-cpp)

Change-Id: I87d5a5d51e80f3b75e60354595f8c618def361ff
This commit is contained in:
Sébastien Blin
2023-05-31 14:24:22 -04:00
parent c83a427001
commit e4cca14861
7 changed files with 175 additions and 83 deletions

View File

@ -463,56 +463,56 @@ private:
{
using namespace std::placeholders;
using libjami::exportable_callback;
using libjami::exportable_serialized_callback;
using libjami::CallSignal;
using SharedCallback = std::shared_ptr<libjami::CallbackWrapperBase>;
const std::map<std::string, SharedCallback> callEvHandlers
= {exportable_callback<CallSignal::StateChange>(
= {exportable_serialized_callback<CallSignal::StateChange>(
std::bind(&DBusCallManager::emitCallStateChanged, this, _1, _2, _3, _4)),
exportable_callback<CallSignal::TransferFailed>(
exportable_serialized_callback<CallSignal::TransferFailed>(
std::bind(&DBusCallManager::emitTransferFailed, this)),
exportable_callback<CallSignal::TransferSucceeded>(
exportable_serialized_callback<CallSignal::TransferSucceeded>(
std::bind(&DBusCallManager::emitTransferSucceeded, this)),
exportable_callback<CallSignal::RecordPlaybackStopped>(
exportable_serialized_callback<CallSignal::RecordPlaybackStopped>(
std::bind(&DBusCallManager::emitRecordPlaybackStopped, this, _1)),
exportable_callback<CallSignal::VoiceMailNotify>(
exportable_serialized_callback<CallSignal::VoiceMailNotify>(
std::bind(&DBusCallManager::emitVoiceMailNotify, this, _1, _2, _3, _4)),
exportable_callback<CallSignal::IncomingMessage>(
exportable_serialized_callback<CallSignal::IncomingMessage>(
std::bind(&DBusCallManager::emitIncomingMessage, this, _1, _2, _3, _4)),
exportable_callback<CallSignal::IncomingCall>(
exportable_serialized_callback<CallSignal::IncomingCall>(
std::bind(&DBusCallManager::emitIncomingCall, this, _1, _2, _3)),
exportable_callback<CallSignal::IncomingCallWithMedia>(
exportable_serialized_callback<CallSignal::IncomingCallWithMedia>(
std::bind(&DBusCallManager::emitIncomingCallWithMedia, this, _1, _2, _3, _4)),
exportable_callback<CallSignal::MediaChangeRequested>(
exportable_serialized_callback<CallSignal::MediaChangeRequested>(
std::bind(&DBusCallManager::emitMediaChangeRequested, this, _1, _2, _3)),
exportable_callback<CallSignal::RecordPlaybackFilepath>(
exportable_serialized_callback<CallSignal::RecordPlaybackFilepath>(
std::bind(&DBusCallManager::emitRecordPlaybackFilepath, this, _1, _2)),
exportable_callback<CallSignal::ConferenceCreated>(
exportable_serialized_callback<CallSignal::ConferenceCreated>(
std::bind(&DBusCallManager::emitConferenceCreated, this, _1, _2)),
exportable_callback<CallSignal::ConferenceChanged>(
exportable_serialized_callback<CallSignal::ConferenceChanged>(
std::bind(&DBusCallManager::emitConferenceChanged, this, _1, _2, _3)),
exportable_callback<CallSignal::UpdatePlaybackScale>(
exportable_serialized_callback<CallSignal::UpdatePlaybackScale>(
std::bind(&DBusCallManager::emitUpdatePlaybackScale, this, _1, _2, _3)),
exportable_callback<CallSignal::ConferenceRemoved>(
exportable_serialized_callback<CallSignal::ConferenceRemoved>(
std::bind(&DBusCallManager::emitConferenceRemoved, this, _1, _2)),
exportable_callback<CallSignal::RecordingStateChanged>(
exportable_serialized_callback<CallSignal::RecordingStateChanged>(
std::bind(&DBusCallManager::emitRecordingStateChanged, this, _1, _2)),
exportable_callback<CallSignal::RtcpReportReceived>(
exportable_serialized_callback<CallSignal::RtcpReportReceived>(
std::bind(&DBusCallManager::emitOnRtcpReportReceived, this, _1, _2)),
exportable_callback<CallSignal::OnConferenceInfosUpdated>(
exportable_serialized_callback<CallSignal::OnConferenceInfosUpdated>(
std::bind(&DBusCallManager::emitOnConferenceInfosUpdated, this, _1, _2)),
exportable_callback<CallSignal::PeerHold>(
exportable_serialized_callback<CallSignal::PeerHold>(
std::bind(&DBusCallManager::emitPeerHold, this, _1, _2)),
exportable_callback<CallSignal::AudioMuted>(
exportable_serialized_callback<CallSignal::AudioMuted>(
std::bind(&DBusCallManager::emitAudioMuted, this, _1, _2)),
exportable_callback<CallSignal::VideoMuted>(
exportable_serialized_callback<CallSignal::VideoMuted>(
std::bind(&DBusCallManager::emitVideoMuted, this, _1, _2)),
exportable_callback<CallSignal::SmartInfo>(
exportable_serialized_callback<CallSignal::SmartInfo>(
std::bind(&DBusCallManager::emitSmartInfo, this, _1)),
exportable_callback<CallSignal::RemoteRecordingChanged>(
exportable_serialized_callback<CallSignal::RemoteRecordingChanged>(
std::bind(&DBusCallManager::emitRemoteRecordingChanged, this, _1, _2, _3)),
exportable_callback<CallSignal::MediaNegotiationStatus>(
exportable_serialized_callback<CallSignal::MediaNegotiationStatus>(
std::bind(&DBusCallManager::emitMediaNegotiationStatus, this, _1, _2, _3))
};

View File

@ -1019,7 +1019,7 @@ private:
{
using namespace std::placeholders;
using libjami::exportable_callback;
using libjami::exportable_serialized_callback;
using libjami::ConfigurationSignal;
using libjami::AudioSignal;
using libjami::DataTransferSignal;
@ -1028,105 +1028,105 @@ private:
// Configuration event handlers
const std::map<std::string, SharedCallback> configEvHandlers = {
exportable_callback<ConfigurationSignal::VolumeChanged>(
exportable_serialized_callback<ConfigurationSignal::VolumeChanged>(
std::bind(&DBusConfigurationManager::emitVolumeChanged, this, _1, _2)),
exportable_callback<ConfigurationSignal::AccountsChanged>(
exportable_serialized_callback<ConfigurationSignal::AccountsChanged>(
std::bind(&DBusConfigurationManager::emitAccountsChanged, this)),
exportable_callback<ConfigurationSignal::AccountDetailsChanged>(
exportable_serialized_callback<ConfigurationSignal::AccountDetailsChanged>(
std::bind(&DBusConfigurationManager::emitAccountDetailsChanged, this, _1, _2)),
exportable_callback<ConfigurationSignal::StunStatusFailed>(
exportable_serialized_callback<ConfigurationSignal::StunStatusFailed>(
std::bind(&DBusConfigurationManager::emitStunStatusFailure, this, _1)),
exportable_callback<ConfigurationSignal::RegistrationStateChanged>(
exportable_serialized_callback<ConfigurationSignal::RegistrationStateChanged>(
std::bind(&DBusConfigurationManager::emitRegistrationStateChanged, this, _1, _2, _3, _4)),
exportable_callback<ConfigurationSignal::VolatileDetailsChanged>(
exportable_serialized_callback<ConfigurationSignal::VolatileDetailsChanged>(
std::bind(&DBusConfigurationManager::emitVolatileAccountDetailsChanged, this, _1, _2)),
exportable_callback<ConfigurationSignal::Error>(
exportable_serialized_callback<ConfigurationSignal::Error>(
std::bind(&DBusConfigurationManager::emitErrorAlert, this, _1)),
exportable_callback<ConfigurationSignal::IncomingAccountMessage>(
exportable_serialized_callback<ConfigurationSignal::IncomingAccountMessage>(
std::bind(&DBusConfigurationManager::emitIncomingAccountMessage, this, _1, _2, _3, _4)),
exportable_callback<ConfigurationSignal::AccountMessageStatusChanged>(
exportable_serialized_callback<ConfigurationSignal::AccountMessageStatusChanged>(
std::bind(&DBusConfigurationManager::emitAccountMessageStatusChanged, this, _1, _2, _3, _4, _5)),
exportable_callback<ConfigurationSignal::ProfileReceived>(
exportable_serialized_callback<ConfigurationSignal::ProfileReceived>(
std::bind(&DBusConfigurationManager::emitProfileReceived, this, _1, _2, _3)),
exportable_callback<ConfigurationSignal::ActiveCallsChanged>(
exportable_serialized_callback<ConfigurationSignal::ActiveCallsChanged>(
std::bind(&DBusConfigurationManager::emitActiveCallsChanged, this, _1, _2, _3)),
exportable_callback<ConfigurationSignal::ComposingStatusChanged>(
exportable_serialized_callback<ConfigurationSignal::ComposingStatusChanged>(
std::bind(&DBusConfigurationManager::emitComposingStatusChanged, this, _1, _2, _3, _4)),
exportable_callback<ConfigurationSignal::IncomingTrustRequest>(
exportable_serialized_callback<ConfigurationSignal::IncomingTrustRequest>(
std::bind(&DBusConfigurationManager::emitIncomingTrustRequest, this, _1, _2, _3, _4, _5)),
exportable_callback<ConfigurationSignal::ContactAdded>(
exportable_serialized_callback<ConfigurationSignal::ContactAdded>(
std::bind(&DBusConfigurationManager::emitContactAdded, this, _1, _2, _3)),
exportable_callback<ConfigurationSignal::ContactRemoved>(
exportable_serialized_callback<ConfigurationSignal::ContactRemoved>(
std::bind(&DBusConfigurationManager::emitContactRemoved, this, _1, _2, _3)),
exportable_callback<ConfigurationSignal::ExportOnRingEnded>(
exportable_serialized_callback<ConfigurationSignal::ExportOnRingEnded>(
std::bind(&DBusConfigurationManager::emitExportOnRingEnded, this, _1, _2, _3)),
exportable_callback<ConfigurationSignal::KnownDevicesChanged>(
exportable_serialized_callback<ConfigurationSignal::KnownDevicesChanged>(
std::bind(&DBusConfigurationManager::emitKnownDevicesChanged, this, _1, _2)),
exportable_callback<ConfigurationSignal::NameRegistrationEnded>(
exportable_serialized_callback<ConfigurationSignal::NameRegistrationEnded>(
std::bind(&DBusConfigurationManager::emitNameRegistrationEnded, this, _1, _2, _3)),
exportable_callback<ConfigurationSignal::UserSearchEnded>(
exportable_serialized_callback<ConfigurationSignal::UserSearchEnded>(
std::bind(&DBusConfigurationManager::emitUserSearchEnded, this, _1, _2, _3, _4)),
exportable_callback<ConfigurationSignal::RegisteredNameFound>(
exportable_serialized_callback<ConfigurationSignal::RegisteredNameFound>(
std::bind(&DBusConfigurationManager::emitRegisteredNameFound, this, _1, _2, _3, _4)),
exportable_callback<ConfigurationSignal::DeviceRevocationEnded>(
exportable_serialized_callback<ConfigurationSignal::DeviceRevocationEnded>(
std::bind(&DBusConfigurationManager::emitDeviceRevocationEnded, this, _1, _2, _3)),
exportable_callback<ConfigurationSignal::AccountProfileReceived>(
exportable_serialized_callback<ConfigurationSignal::AccountProfileReceived>(
std::bind(&DBusConfigurationManager::emitAccountProfileReceived, this, _1, _2, _3)),
exportable_callback<ConfigurationSignal::CertificatePinned>(
exportable_serialized_callback<ConfigurationSignal::CertificatePinned>(
std::bind(&DBusConfigurationManager::emitCertificatePinned, this, _1)),
exportable_callback<ConfigurationSignal::CertificatePathPinned>(
exportable_serialized_callback<ConfigurationSignal::CertificatePathPinned>(
std::bind(&DBusConfigurationManager::emitCertificatePathPinned, this, _1, _2)),
exportable_callback<ConfigurationSignal::CertificateExpired>(
exportable_serialized_callback<ConfigurationSignal::CertificateExpired>(
std::bind(&DBusConfigurationManager::emitCertificateExpired, this, _1)),
exportable_callback<ConfigurationSignal::CertificateStateChanged>(
exportable_serialized_callback<ConfigurationSignal::CertificateStateChanged>(
std::bind(&DBusConfigurationManager::emitCertificateStateChanged, this, _1, _2, _3)),
exportable_callback<ConfigurationSignal::MediaParametersChanged>(
exportable_serialized_callback<ConfigurationSignal::MediaParametersChanged>(
std::bind(&DBusConfigurationManager::emitMediaParametersChanged, this, _1)),
exportable_callback<ConfigurationSignal::MigrationEnded>(
exportable_serialized_callback<ConfigurationSignal::MigrationEnded>(
std::bind(&DBusConfigurationManager::emitMigrationEnded, this, _1, _2)),
exportable_callback<ConfigurationSignal::HardwareDecodingChanged>(
exportable_serialized_callback<ConfigurationSignal::HardwareDecodingChanged>(
std::bind(&DBusConfigurationManager::emitHardwareDecodingChanged, this, _1)),
exportable_callback<ConfigurationSignal::HardwareEncodingChanged>(
exportable_serialized_callback<ConfigurationSignal::HardwareEncodingChanged>(
std::bind(&DBusConfigurationManager::emitHardwareEncodingChanged, this, _1)),
exportable_callback<ConfigurationSignal::MessageSend>(
exportable_serialized_callback<ConfigurationSignal::MessageSend>(
std::bind(&DBusConfigurationManager::emitMessageSend, this, _1)),
};
// Audio event handlers
const std::map<std::string, SharedCallback> audioEvHandlers = {
exportable_callback<AudioSignal::DeviceEvent>(
exportable_serialized_callback<AudioSignal::DeviceEvent>(
std::bind(&DBusConfigurationManager::emitAudioDeviceEvent, this)),
exportable_callback<AudioSignal::AudioMeter>(
exportable_serialized_callback<AudioSignal::AudioMeter>(
std::bind(&DBusConfigurationManager::emitAudioMeter, this, _1, _2)),
};
const std::map<std::string, SharedCallback> dataXferEvHandlers = {
exportable_callback<DataTransferSignal::DataTransferEvent>(
exportable_serialized_callback<DataTransferSignal::DataTransferEvent>(
std::bind(&DBusConfigurationManager::emitDataTransferEvent, this, _1, _2, _3, _4, _5)),
};
const std::map<std::string, SharedCallback> convEvHandlers = {
exportable_callback<ConversationSignal::ConversationLoaded>(
exportable_serialized_callback<ConversationSignal::ConversationLoaded>(
std::bind(&DBusConfigurationManager::emitConversationLoaded, this, _1, _2, _3, _4)),
exportable_callback<ConversationSignal::MessagesFound>(
exportable_serialized_callback<ConversationSignal::MessagesFound>(
std::bind(&DBusConfigurationManager::emitMessagesFound, this, _1, _2, _3, _4)),
exportable_callback<ConversationSignal::MessageReceived>(
exportable_serialized_callback<ConversationSignal::MessageReceived>(
std::bind(&DBusConfigurationManager::emitMessageReceived, this, _1, _2, _3)),
exportable_callback<ConversationSignal::ConversationProfileUpdated>(
exportable_serialized_callback<ConversationSignal::ConversationProfileUpdated>(
std::bind(&DBusConfigurationManager::emitConversationProfileUpdated, this, _1, _2, _3)),
exportable_callback<ConversationSignal::ConversationRequestReceived>(
exportable_serialized_callback<ConversationSignal::ConversationRequestReceived>(
std::bind(&DBusConfigurationManager::emitConversationRequestReceived, this, _1, _2, _3)),
exportable_callback<ConversationSignal::ConversationRequestDeclined>(
exportable_serialized_callback<ConversationSignal::ConversationRequestDeclined>(
std::bind(&DBusConfigurationManager::emitConversationRequestDeclined, this, _1, _2)),
exportable_callback<ConversationSignal::ConversationReady>(
exportable_serialized_callback<ConversationSignal::ConversationReady>(
std::bind(&DBusConfigurationManager::emitConversationReady, this, _1, _2)),
exportable_callback<ConversationSignal::ConversationRemoved>(
exportable_serialized_callback<ConversationSignal::ConversationRemoved>(
std::bind(&DBusConfigurationManager::emitConversationRemoved, this, _1, _2)),
exportable_callback<ConversationSignal::ConversationMemberEvent>(
exportable_serialized_callback<ConversationSignal::ConversationMemberEvent>(
std::bind(&DBusConfigurationManager::emitConversationMemberEvent, this, _1, _2, _3, _4)),
exportable_callback<ConversationSignal::OnConversationError>(
exportable_serialized_callback<ConversationSignal::OnConversationError>(
std::bind(&DBusConfigurationManager::emitOnConversationError, this, _1, _2, _3, _4)),
exportable_callback<ConversationSignal::ConversationPreferencesUpdated>(
exportable_serialized_callback<ConversationSignal::ConversationPreferencesUpdated>(
std::bind(&DBusConfigurationManager::emitConversationPreferencesUpdated, this, _1, _2, _3)),
};

View File

@ -208,11 +208,11 @@ private:
{
using namespace std::placeholders;
using libjami::exportable_callback;
using libjami::exportable_serialized_callback;
using SharedCallback = std::shared_ptr<libjami::CallbackWrapperBase>;
const std::map<std::string, SharedCallback> pluginEvHandlers = {
exportable_callback<libjami::PluginSignal::WebViewMessageReceived>(
exportable_serialized_callback<libjami::PluginSignal::WebViewMessageReceived>(
std::bind(&DBusPluginManagerInterface::emitWebViewMessageReceived, this, _1, _2, _3, _4)),
};

View File

@ -76,20 +76,20 @@ private:
{
using namespace std::placeholders;
using libjami::exportable_callback;
using libjami::exportable_serialized_callback;
using libjami::PresenceSignal;
using SharedCallback = std::shared_ptr<libjami::CallbackWrapperBase>;
const std::map<std::string, SharedCallback> presEvHandlers = {
exportable_callback<PresenceSignal::NewServerSubscriptionRequest>(
exportable_serialized_callback<PresenceSignal::NewServerSubscriptionRequest>(
std::bind(&DBusPresenceManager::emitNewServerSubscriptionRequest, this, _1)),
exportable_callback<PresenceSignal::ServerError>(
exportable_serialized_callback<PresenceSignal::ServerError>(
std::bind(&DBusPresenceManager::emitServerError, this, _1, _2, _3)),
exportable_callback<PresenceSignal::NewBuddyNotification>(
exportable_serialized_callback<PresenceSignal::NewBuddyNotification>(
std::bind(&DBusPresenceManager::emitNewBuddyNotification, this, _1, _2, _3, _4)),
exportable_callback<PresenceSignal::NearbyPeerNotification>(
exportable_serialized_callback<PresenceSignal::NearbyPeerNotification>(
std::bind(&DBusPresenceManager::emitNearbyPeerNotification, this, _1, _2, _3, _4)),
exportable_callback<PresenceSignal::SubscriptionStateChanged>(
exportable_serialized_callback<PresenceSignal::SubscriptionStateChanged>(
std::bind(&DBusPresenceManager::emitSubscriptionStateChanged, this, _1, _2, _3)),
};

View File

@ -158,16 +158,16 @@ private:
{
using namespace std::placeholders;
using libjami::exportable_callback;
using libjami::exportable_serialized_callback;
using libjami::VideoSignal;
using SharedCallback = std::shared_ptr<libjami::CallbackWrapperBase>;
const std::map<std::string, SharedCallback> videoEvHandlers = {
exportable_callback<VideoSignal::DeviceEvent>(
exportable_serialized_callback<VideoSignal::DeviceEvent>(
std::bind(&DBusVideoManager::emitDeviceEvent, this)),
exportable_callback<VideoSignal::DecodingStarted>(
exportable_serialized_callback<VideoSignal::DecodingStarted>(
std::bind(&DBusVideoManager::emitDecodingStarted, this, _1, _2, _3, _4, _5)),
exportable_callback<VideoSignal::DecodingStopped>(
exportable_serialized_callback<VideoSignal::DecodingStopped>(
std::bind(&DBusVideoManager::emitDecodingStopped, this, _1, _2, _3)),
};

View File

@ -106,7 +106,13 @@ LIBJAMI_PUBLIC void logging(const std::string& whom, const std::string& action)
* See CallbackWrapper template for details.
*/
class LIBJAMI_PUBLIC CallbackWrapperBase
{};
{
protected:
// Because post() needs Manager, it should be defined in a .cpp
// so not in a templated class.
// Also we do not want this method to be public in the API.
void post(std::function<void()> cb);
};
/* Concrete class of CallbackWrapperBase.
* This class wraps callbacks of a specific signature.
@ -160,6 +166,74 @@ public:
constexpr explicit operator bool() const noexcept { return static_cast<bool>(cb_); }
};
/* Concrete class of CallbackWrapperBase.
* This class wraps callbacks of a specific signature.
* Used to retrigger callbacks on a io context to avoid lock if signals cannot
* be emitted while a method is called.
* Also used to obtain the user callback from a CallbackWrapperBase shared ptr.
*
* This class is CopyConstructible, CopyAssignable, MoveConstructible
* and MoveAssignable.
*/
template<typename TProto>
class SerializedCallbackWrapper : public CallbackWrapperBase
{
private:
using TFunc = std::function<TProto>;
TFunc cb_; // The user-callback
// This is quite a ugly method used to transmit templated TFunc with their arguments in the
// ioContext of the manager to avoid locks for signals.
template <typename TCallback>
auto ioContextWrapper(TCallback&& fun)
{
return [this, fun{std::move(fun)}](auto&&... args) -> decltype(fun(std::forward<decltype(args)>(args)...))
{
post([fun{std::move(fun)}, forwardArgs=std::make_tuple(std::move(args)...)]() mutable {
std::apply(std::move(fun), std::move(forwardArgs));
});
};
}
public:
const char* file_;
uint32_t linum_;
// Empty wrapper: no callback associated.
// Used to initialize internal callback arrays.
SerializedCallbackWrapper() noexcept {}
// Create and initialize a wrapper to given callback.
SerializedCallbackWrapper(TFunc&& func, const char* filename, uint32_t linum) noexcept
: file_(filename)
, linum_(linum)
{
cb_ = ioContextWrapper(func);
}
// Create and initialize a wrapper from a generic CallbackWrapperBase
// shared pointer.
// Note: the given callback is copied into internal storage.
SerializedCallbackWrapper(const std::shared_ptr<CallbackWrapperBase>& p) noexcept
{
if (p) {
auto other = (CallbackWrapper<TProto>*) p.get();
cb_ = ioContextWrapper(other.cb_);
file_ = other->file_;
linum_ = other->linum_;
}
}
// Return user-callback reference.
// The returned std::function can be null-initialized if no callback
// has been set.
constexpr const TFunc& operator*() const noexcept { return cb_; }
// Return boolean true value if a non-null callback has been set
constexpr explicit operator bool() const noexcept { return static_cast<bool>(cb_); }
};
/**
* Return an exportable callback object.
* This object is a std::pair of a string and a CallbackWrapperBase shared_ptr.
@ -177,6 +251,17 @@ exportable_callback(std::function<typename Ts::cb_type>&& func,
std::forward<std::function<typename Ts::cb_type>>(func), file, linum));
}
template<typename Ts>
std::pair<std::string, std::shared_ptr<CallbackWrapperBase>>
exportable_serialized_callback(std::function<typename Ts::cb_type>&& func,
const char* file = CURRENT_FILENAME(),
uint32_t linum = CURRENT_LINE())
{
return std::make_pair((const std::string&) Ts::name,
std::make_shared<SerializedCallbackWrapper<typename Ts::cb_type>>(
std::forward<std::function<typename Ts::cb_type>>(func), file, linum));
}
LIBJAMI_PUBLIC void registerSignalHandlers(
const std::map<std::string, std::shared_ptr<CallbackWrapperBase>>&);
LIBJAMI_PUBLIC void unregisterSignalHandlers();

View File

@ -18,6 +18,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <asio.hpp>
#include <string>
#include <vector>
#include <map>
@ -121,4 +122,10 @@ logging(const std::string& whom, const std::string& action) noexcept
}
}
void
CallbackWrapperBase::post(std::function<void()> cb)
{
jami::Manager::instance().ioContext()->post(std::move(cb));
}
} // namespace libjami