});
}
+VsmStatus Client::vsm_lock_queue() noexcept
+{
+ return coverException([&] {
+ *mClient->callSync<api::Void, api::Void>(
+ vasum::api::ipc::METHOD_LOCK_QUEUE,
+ std::make_shared<api::Void>());
+ });
+}
+
+VsmStatus Client::vsm_unlock_queue() noexcept
+{
+ return coverException([&] {
+ *mClient->callSync<api::Void, api::Void>(
+ vasum::api::ipc::METHOD_UNLOCK_QUEUE,
+ std::make_shared<api::Void>());
+ });
+}
+
VsmStatus Client::vsm_get_zone_ids(VsmArrayString* array) noexcept
{
return coverException([&] {
VsmStatus vsm_get_zone_dbuses(VsmArrayString* keys, VsmArrayString* values) noexcept;
/**
+ * @see ::vsm_lock_queue
+ */
+ VsmStatus vsm_lock_queue() noexcept;
+
+ /**
+ * @see ::vsm_unlock_queue
+ */
+ VsmStatus vsm_unlock_queue() noexcept;
+
+ /**
* @see ::vsm_get_zone_ids
*/
VsmStatus vsm_get_zone_ids(VsmArrayString* array) noexcept;
} // namespace
+API VsmStatus vsm_lock_queue(VsmClient client)
+{
+ return getClient(client).vsm_lock_queue();
+}
+
+API VsmStatus vsm_unlock_queue(VsmClient client)
+{
+ return getClient(client).vsm_unlock_queue();
+}
+
API VsmStatus vsm_get_poll_fd(VsmClient client, int* fd)
{
return getClient(client).vsm_get_poll_fd(fd);
void* data);
/**
+ * Lock the command queue exclusively.
+ *
+ * @param[in] client vasum-server's client
+ * @return status of this function call
+ */
+VsmStatus vsm_lock_queue(VsmClient client);
+
+/**
+ * Unlock the command queue.
+ *
+ * @param[in] client vasum-server's client
+ * @return status of this function call
+ */
+VsmStatus vsm_unlock_queue(VsmClient client);
+
+/**
* Get dbus address of each zone.
*
* @param[in] client vasum-server's client
namespace vasum {
namespace api {
+const std::string DBUS_CONNECTION_PREFIX = "dbus://";
+
template<typename Data>
class DbusMethodResultBuilder: public MethodResultBuilder {
public:
void setImpl(const std::shared_ptr<void>& data) override;
void setVoid() override;
void setError(const std::string& name, const std::string& message) override;
+ std::string getID() const;
::dbus::MethodResultBuilder::Pointer mMethodResultBuilderPtr;
std::function<GVariant*(std::shared_ptr<void>)> mSerialize;
mMethodResultBuilderPtr->setError(name, message);
}
+template<typename Data>
+std::string DbusMethodResultBuilder<Data>::getID() const
+{
+ return DBUS_CONNECTION_PREFIX + mMethodResultBuilderPtr->getPeerName();
+}
+
} // namespace result
} // namespace vasum
mMethodResultPtr->setError(1, message);
}
+std::string IPCMethodResultBuilder::getID() const
+{
+ return IPC_CONNECTION_PREFIX + std::to_string(mMethodResultPtr->getPeerID());
+}
+
} // namespace result
} // namespace vasum
namespace vasum {
namespace api {
+const std::string IPC_CONNECTION_PREFIX = "ipc://";
+
class IPCMethodResultBuilder: public MethodResultBuilder {
public:
IPCMethodResultBuilder(const ipc::MethodResult::Pointer& methodResult);
void setImpl(const std::shared_ptr<void>& data) override;
void setVoid() override;
void setError(const std::string& name, const std::string& message) override;
+ std::string getID() const;
ipc::MethodResult::Pointer mMethodResultPtr;
};
virtual ~MethodResultBuilder() {}
virtual void setVoid() = 0;
virtual void setError(const std::string& name, const std::string& message) = 0;
+ virtual std::string getID() const = 0;
template<typename Data>
void set(const std::shared_ptr<Data>& data)
}
private:
- virtual void setImpl(const std::shared_ptr<void>& data) =0;
+ virtual void setImpl(const std::shared_ptr<void>& data) = 0;
};
g_dbus_method_invocation_return_dbus_error(mInvocation, name.c_str(), message.c_str());
mResultSet = true;
}
+ std::string getPeerName()
+ {
+ return std::string(g_dbus_method_invocation_get_sender(mInvocation));
+ }
private:
GDBusMethodInvocation* mInvocation;
bool mResultSet;
DbusConnection::~DbusConnection()
{
// Close connection in a glib thread (because of a bug in glib)
- GDBusConnection* connection = mConnection;
- guint nameId = mNameId;
+ auto closeConnection = [this]() {
+ for (auto client : mWatchedClients) {
+ LOGT("Stopped watching the client: " << client.first);
+ g_bus_unwatch_name(client.second);
+ }
- auto closeConnection = [=]() {
- if (nameId) {
- g_bus_unown_name(nameId);
+ if (mNameId) {
+ g_bus_unown_name(mNameId);
}
- g_object_unref(connection);
+ g_object_unref(mConnection);
LOGT("Connection deleted");
};
+
executeInGlibThread(closeConnection, mGuard);
}
void DbusConnection::registerObject(const std::string& objectPath,
const std::string& objectDefinitionXml,
- const MethodCallCallback& callback)
+ const MethodCallCallback& methodCall,
+ const ClientVanishedCallback& clientVanished)
{
ScopedGError error;
GDBusNodeInfo* nodeInfo = g_dbus_node_info_new_for_xml(objectDefinitionXml.c_str(), &error);
objectPath.c_str(),
interfaceInfo,
&vtable,
- createCallbackWrapper(callback, mGuard.spawn()),
- &deleteCallbackWrapper<MethodCallCallback>,
+ createCallbackWrapper(
+ MethodCallbacks(methodCall, clientVanished, this),
+ mGuard.spawn()),
+ &deleteCallbackWrapper<MethodCallbacks>,
&error);
g_dbus_node_info_unref(nodeInfo);
if (error) {
}
}
-void DbusConnection::onMethodCall(GDBusConnection*,
+void DbusConnection::onMethodCall(GDBusConnection* connection,
const gchar*,
const gchar* objectPath,
const gchar* interface,
GDBusMethodInvocation* invocation,
gpointer userData)
{
- const MethodCallCallback& callback = getCallbackFromPointer<MethodCallCallback>(userData);
+ const MethodCallbacks& callbacks = getCallbackFromPointer<MethodCallbacks>(userData);
LOGD("MethodCall: " << objectPath << "; " << interface << "; " << method);
+ const gchar *sender = g_dbus_method_invocation_get_sender(invocation);
+ ClientsMap &watchedClients = callbacks.dbusConn->mWatchedClients;
+
+ if (watchedClients.find(sender) == watchedClients.end()) {
+ LOGT("Watching the client: " << sender);
+ guint id = g_bus_watch_name_on_connection(connection,
+ sender,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ NULL,
+ &DbusConnection::onClientVanish,
+ createCallbackWrapper(
+ VanishedCallbacks(callbacks.clientVanished,
+ watchedClients),
+ callbacks.dbusConn->mGuard.spawn()),
+ &deleteCallbackWrapper<VanishedCallbacks>);
+
+ watchedClients[sender] = id;
+ }
+
MethodResultBuilder::Pointer resultBuilder(new MethodResultBuilderImpl(invocation));
- if (callback) {
- callback(objectPath, interface, method, parameters, resultBuilder);
+ if (callbacks.methodCall) {
+ callbacks.methodCall(objectPath, interface, method, parameters, resultBuilder);
+ }
+}
+
+void DbusConnection::onClientVanish(GDBusConnection*,
+ const gchar *name,
+ gpointer userData)
+{
+ const VanishedCallbacks& callbacks = getCallbackFromPointer<VanishedCallbacks>(userData);
+
+ LOGI("ClientVanished: " << name);
+
+ guint id = callbacks.watchedClients[name];
+ callbacks.watchedClients.erase(name);
+
+ if (callbacks.clientVanished) {
+ callbacks.clientVanished(name);
}
+
+ LOGT("Stopped watching the client: " << name);
+
+ // after this line we cannot use the *name pointer, this call frees it
+ g_bus_unwatch_name(id);
}
GVariantPtr DbusConnection::callMethod(const std::string& busName,
#include <memory>
#include <string>
#include <functional>
+#include <map>
#include <gio/gio.h>
virtual void set(GVariant* parameters) = 0;
virtual void setVoid() = 0;
virtual void setError(const std::string& name, const std::string& message) = 0;
+ virtual std::string getPeerName() = 0;
};
/**
MethodResultBuilder::Pointer result
)> MethodCallCallback;
+ typedef std::function<void(const std::string& name
+ )> ClientVanishedCallback;
+
typedef std::function<void(const std::string& senderBusName,
const std::string& objectPath,
const std::string& interface,
*/
void registerObject(const std::string& objectPath,
const std::string& objectDefinitionXml,
- const MethodCallCallback& callback);
+ const MethodCallCallback& method,
+ const ClientVanishedCallback& vanish);
/**
* Call a dbus method
: nameAcquired(acquired), nameLost(lost) {}
};
- utils::CallbackGuard mGuard;
+ typedef std::map<std::string, guint> ClientsMap;
+
+ struct MethodCallbacks {
+ MethodCallCallback methodCall;
+ ClientVanishedCallback clientVanished;
+ DbusConnection *dbusConn;
+
+ MethodCallbacks(const MethodCallCallback& method,
+ const ClientVanishedCallback& vanish,
+ DbusConnection *dbus)
+ : methodCall(method), clientVanished(vanish), dbusConn(dbus) {}
+ };
+
+ struct VanishedCallbacks {
+ ClientVanishedCallback clientVanished;
+ ClientsMap &watchedClients;
+
+ VanishedCallbacks(const ClientVanishedCallback& vanish, ClientsMap& clients)
+ : clientVanished(vanish), watchedClients(clients) {}
+ };
+
GDBusConnection* mConnection;
guint mNameId;
+ // It's only ever modified in the glib thread
+ ClientsMap mWatchedClients;
+ // Guard must be destroyed before objects it protects
+ // (e.g. all of the above, see the destructor)
+ utils::CallbackGuard mGuard;
DbusConnection(const std::string& address);
static void onAsyncReady(GObject* source,
GAsyncResult* asyncResult,
gpointer userData);
+ static void onClientVanish(GDBusConnection* connection,
+ const gchar *name,
+ gpointer userData);
};
mProcessor.sendError(mPeerID, mMessageID, code, message);
}
+PeerID MethodResult::getPeerID()
+{
+ return mPeerID;
+}
+
} // namespace ipc
void setVoid();
void setError(const int code, const std::string& message);
+ PeerID getPeerID();
private:
Processor& mProcessor;
const std::string ERROR_INTERNAL = "org.tizen.vasum.Error.Internal";
const std::string ERROR_ZONE_NOT_RUNNING = "org.tizen.vasum.Error.ZonesNotRunning";
const std::string ERROR_CREATE_FILE_FAILED = "org.tizen.vasum.Error.CreateFileFailed";
+const std::string ERROR_QUEUE = "org.tizen.vasum.Error.Queue";
///@}
} // namespace api
mDbusConnection->registerObject(api::dbus::OBJECT_PATH,
api::dbus::DEFINITION,
std::bind(&HostDbusConnection::onMessageCall,
- this, _1, _2, _3, _4, _5));
+ this, _1, _2, _3, _4, _5),
+ std::bind(&HostDbusConnection::onClientVanished,
+ this, _1));
mSubscriptionId = mDbusConnection->signalSubscribe(std::bind(&HostDbusConnection::onSignalCall,
this, _1, _2, _3, _4, _5),
return;
}
+ if (methodName == api::dbus::METHOD_LOCK_QUEUE) {
+ auto rb = std::make_shared<api::DbusMethodResultBuilder<api::Void>>(result);
+ mZonesManagerPtr->handleLockQueueCall(rb);
+ return;
+ }
+
+ if (methodName == api::dbus::METHOD_UNLOCK_QUEUE) {
+ auto rb = std::make_shared<api::DbusMethodResultBuilder<api::Void>>(result);
+ mZonesManagerPtr->handleUnlockQueueCall(rb);
+ return;
+ }
+
if (methodName == api::dbus::METHOD_GET_ZONE_ID_LIST) {
auto rb = std::make_shared<api::DbusMethodResultBuilder<api::ZoneIds>>(result);
mZonesManagerPtr->handleGetZoneIdsCall(rb);
mZonesManagerPtr->handleCreateFileCall(data, rb);
return;
}
+
+ if (methodName == api::dbus::METHOD_SWITCH_TO_DEFAULT) {
+ auto rb = std::make_shared<api::DbusMethodResultBuilder<api::Void>>(result);
+ mZonesManagerPtr->handleSwitchToDefaultCall(EMPTY_CALLER, rb);
+ return;
+ }
+}
+
+void HostDbusConnection::onClientVanished(const std::string& name)
+{
+ const std::string id = api::DBUS_CONNECTION_PREFIX + name;
+ mZonesManagerPtr->disconnectedCallback(id);
}
void HostDbusConnection::onSignalCall(const std::string& /* senderBusName */,
const std::string& objectPath,
const std::string& interface,
- const std::string& signalName,
+ const std::string& /* signalName */,
GVariant* /* parameters */)
{
if (objectPath != api::dbus::OBJECT_PATH || interface != api::dbus::INTERFACE) {
return;
}
-
- if (signalName == api::dbus::SIGNAL_SWITCH_TO_DEFAULT) {
- mZonesManagerPtr->handleSwitchToDefaultCall(EMPTY_CALLER);
- }
}
void HostDbusConnection::proxyCallAsync(const std::string& busName,
const std::string& methodName,
GVariant* parameters,
dbus::MethodResultBuilder::Pointer result);
+ void onClientVanished(const std::string& name);
void onSignalCall(const std::string& senderBusName,
const std::string& objectPath,
const std::string& interface,
const std::string METHOD_REVOKE_DEVICE = "RevokeDevice";
const std::string METHOD_PROXY_CALL = "ProxyCall";
const std::string METHOD_CREATE_FILE = "CreateFile";
+const std::string METHOD_LOCK_QUEUE = "LockQueue";
+const std::string METHOD_UNLOCK_QUEUE = "UnlockQueue";
+const std::string METHOD_SWITCH_TO_DEFAULT = "SwitchToDefault";
const std::string METHOD_NOTIFY_ACTIVE_ZONE = "NotifyActiveZone";
const std::string METHOD_FILE_MOVE_REQUEST = "FileMoveRequest";
const std::string SIGNAL_NOTIFICATION = "Notification";
-const std::string SIGNAL_SWITCH_TO_DEFAULT = "SwitchToDefault";
const std::string FILE_MOVE_DESTINATION_NOT_FOUND = "FILE_MOVE_DESTINATION_NOT_FOUND";
const std::string FILE_MOVE_WRONG_DESTINATION = "FILE_MOVE_WRONG_DESTINATION";
const std::string DEFINITION =
"<node>"
" <interface name='" + INTERFACE + "'>"
- " <method name='" + METHOD_PROXY_CALL + "'>"
- " <arg type='s' name='target' direction='in'/>"
- " <arg type='s' name='busName' direction='in'/>"
- " <arg type='s' name='objectPath' direction='in'/>"
- " <arg type='s' name='interface' direction='in'/>"
- " <arg type='s' name='method' direction='in'/>"
- " <arg type='v' name='parameters' direction='in'/>"
- " <arg type='v' name='result' direction='out'/>"
+ " <method name='" + METHOD_LOCK_QUEUE + "'>"
+ " </method>"
+ " <method name='" + METHOD_UNLOCK_QUEUE + "'>"
" </method>"
" <method name='" + METHOD_GET_ZONE_ID_LIST + "'>"
" <arg type='as' name='result' direction='out'/>"
" <arg type='v' name='parameters' direction='in'/>"
" <arg type='v' name='result' direction='out'/>"
" </method>"
+ " <method name='" + METHOD_SWITCH_TO_DEFAULT + "'>"
+ " </method>"
" <signal name='" + SIGNAL_NOTIFICATION + "'>"
" <arg type='s' name='zone'/>"
" <arg type='s' name='application'/>"
" <arg type='s' name='message'/>"
" </signal>"
- " <signal name='" + SIGNAL_SWITCH_TO_DEFAULT + "'>"
- " </signal>"
" </interface>"
"</node>";
: mZonesManagerPtr(zonesManagerPtr)
{
LOGT("Connecting to host IPC socket");
- mService.reset(new ipc::Service(mDispatcher.getPoll(), HOST_IPC_SOCKET));
+
+ ipc::PeerCallback removedCallback = [this](const ipc::PeerID peerID,
+ const ipc::FileDescriptor) {
+ std::string id = api::IPC_CONNECTION_PREFIX + std::to_string(peerID);
+ mZonesManagerPtr->disconnectedCallback(id);
+ };
+ mService.reset(new ipc::Service(mDispatcher.getPoll(), HOST_IPC_SOCKET,
+ nullptr, removedCallback));
using namespace std::placeholders;
+ setLockQueueCallback(std::bind(&ZonesManager::handleLockQueueCall,
+ mZonesManagerPtr, _1));
+
+ setUnlockQueueCallback(std::bind(&ZonesManager::handleUnlockQueueCall,
+ mZonesManagerPtr, _1));
+
setGetZoneIdsCallback(std::bind(&ZonesManager::handleGetZoneIdsCall,
mZonesManagerPtr, _1));
mZonesManagerPtr, "", _1, _2));
setSwitchToDefaultCallback(std::bind(&ZonesManager::handleSwitchToDefaultCall,
- mZonesManagerPtr, ""));
+ mZonesManagerPtr, "", _1));
setFileMoveCallback(std::bind(&ZonesManager::handleFileMoveCall,
mZonesManagerPtr, "", _1, _2));
LOGD("Connected");
}
+void HostIPCConnection::setLockQueueCallback(const Method<api::Void>::type& callback)
+{
+ typedef IPCMethodWrapper<api::Void> Callback;
+ mService->setMethodHandler<Callback::out, Callback::in>(
+ api::ipc::METHOD_LOCK_QUEUE,
+ Callback::getWrapper(callback));
+}
+
+void HostIPCConnection::setUnlockQueueCallback(const Method<api::Void>::type& callback)
+{
+ typedef IPCMethodWrapper<api::Void> Callback;
+ mService->setMethodHandler<Callback::out, Callback::in>(
+ api::ipc::METHOD_UNLOCK_QUEUE,
+ Callback::getWrapper(callback));
+}
+
void HostIPCConnection::setGetZoneIdsCallback(const Method<api::ZoneIds>::type& callback)
{
typedef IPCMethodWrapper<api::ZoneIds> Callback;
mService->setMethodHandler<Callback::out, Callback::in>(
api::ipc::METHOD_GET_ZONE_ID_LIST,
Callback::getWrapper(callback));
-
}
void HostIPCConnection::setGetActiveZoneIdCallback(const Method<api::ZoneId>::type& callback)
mService->setMethodHandler<Callback::out, Callback::in>(
api::ipc::METHOD_GET_ACTIVE_ZONE_ID,
Callback::getWrapper(callback));
-
}
void HostIPCConnection::setGetZoneInfoCallback(const Method<const api::ZoneId, api::ZoneInfoOut>::type& callback)
Method::getWrapper(callback));
}
-void HostIPCConnection::setSwitchToDefaultCallback(const Signal<const api::Void>::type& callback)
+void HostIPCConnection::setSwitchToDefaultCallback(const Method<api::Void>::type& callback)
{
- typedef IPCSignalWrapper<const api::Void> Signal;
- mService->setSignalHandler<Signal::in>(
- api::ipc::SIGNAL_SWITCH_TO_DEFAULT,
- Signal::getWrapper(callback));
+ typedef IPCMethodWrapper<api::Void> Callback;
+ mService->setMethodHandler<Callback::out, Callback::in>(
+ api::ipc::METHOD_SWITCH_TO_DEFAULT,
+ Callback::getWrapper(callback));
}
void HostIPCConnection::setFileMoveCallback(const Method<const api::FileMoveRequestIn,
void sendNotification(const api::Notification& notification);
private:
+ void setLockQueueCallback(const Method<api::Void>::type& callback);
+ void setUnlockQueueCallback(const Method<api::Void>::type& callback);
void setGetZoneIdsCallback(const Method<api::ZoneIds>::type& callback);
void setGetZoneConnectionsCallback(const Method<api::Connections>::type& callback);
void setGetActiveZoneIdCallback(const Method<api::ZoneId>::type& callback);
void setGrantDeviceCallback(const Method<const api::GrantDeviceIn>::type& callback);
void setRevokeDeviceCallback(const Method<const api::RevokeDeviceIn>::type& callback);
void setNotifyActiveZoneCallback(const Method<const vasum::api::NotifActiveZoneIn>::type& callback);
- void setSwitchToDefaultCallback(const Signal<const api::Void>::type& callback);
+ void setSwitchToDefaultCallback(const Method<api::Void>::type& callback);
void setFileMoveCallback(const Method<const api::FileMoveRequestIn,
api::FileMoveRequestStatus>::type& callback);
void setCreateFileCallback(const Method<const api::CreateFileIn, api::CreateFileOut>::type& callback);
const ::ipc::MethodID METHOD_GRANT_DEVICE = 25;
const ::ipc::MethodID METHOD_REVOKE_DEVICE = 26;
const ::ipc::MethodID METHOD_CREATE_FILE = 27;
+const ::ipc::MethodID METHOD_LOCK_QUEUE = 28;
+const ::ipc::MethodID METHOD_UNLOCK_QUEUE = 29;
+const ::ipc::MethodID METHOD_SWITCH_TO_DEFAULT = 30;
const ::ipc::MethodID METHOD_NOTIFY_ACTIVE_ZONE = 100;
const ::ipc::MethodID METHOD_FILE_MOVE_REQUEST = 101;
const ::ipc::MethodID SIGNAL_NOTIFICATION = 102;
-const ::ipc::MethodID SIGNAL_SWITCH_TO_DEFAULT = 103;
const std::string FILE_MOVE_DESTINATION_NOT_FOUND = "FILE_MOVE_DESTINATION_NOT_FOUND";
const std::string FILE_MOVE_WRONG_DESTINATION = "FILE_MOVE_WRONG_DESTINATION";
: mWorker(utils::Worker::create())
, mHostIPCConnection(this)
, mDetachOnExit(false)
+ , mExclusiveIDLock(INVALID_CONNECTION_ID)
#ifdef DBUS_CONNECTION
, mHostDbusConnection(this)
#endif
}
}
+void ZonesManager::tryAddTask(const utils::Worker::Task& task, api::MethodResultBuilder::Pointer result, bool wait)
+{
+ {
+ Lock lock(mExclusiveIDMutex);
+
+ if (mExclusiveIDLock != INVALID_CONNECTION_ID &&
+ mExclusiveIDLock != result->getID()) {
+ result->setError(api::ERROR_QUEUE, "Queue is locked by another client");
+ return;
+ }
+ }
+
+ if (wait) {
+ mWorker->addTaskAndWait(task);
+ } else {
+ mWorker->addTask(task);
+ }
+}
+
void ZonesManager::destroyZone(const std::string& zoneId)
{
Lock lock(mMutex);
}
}
-void ZonesManager::handleSwitchToDefaultCall(const std::string& /*caller*/)
+void ZonesManager::disconnectedCallback(const std::string& id)
+{
+ LOGD("Client Disconnected: " << id);
+
+ {
+ Lock lock(mExclusiveIDMutex);
+
+ if (mExclusiveIDLock == id) {
+ mExclusiveIDLock = INVALID_CONNECTION_ID;
+ }
+ }
+}
+
+void ZonesManager::handleSwitchToDefaultCall(const std::string& /*caller*/,
+ api::MethodResultBuilder::Pointer result)
{
auto handler = [&, this] {
// get config of currently set zone and switch if switchToDefaultAfterTimeout is true
LOGI("Switching to default zone " << mDynamicConfig.defaultId);
focusInternal(defaultIter);
}
+ result->setVoid();
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
#ifdef ZONE_CONNECTION
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleFileMoveCall(const std::string& srcZoneId,
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
#else
void ZonesManager::handleNotifyActiveZoneCall(const std::string& /* caller */,
result->set(retValue);
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
#ifdef DBUS_CONNECTION
asyncResultCallback);
};
+ // This call cannot be locked by lock/unlock queue
mWorker->addTaskAndWait(handler);
}
#endif //DBUS_CONNECTION
+void ZonesManager::handleLockQueueCall(api::MethodResultBuilder::Pointer result)
+{
+ Lock lock(mExclusiveIDMutex);
+ std::string id = result->getID();
+
+ LOGI("Lock Queue: " << id);
+
+ if (mExclusiveIDLock == id) {
+ result->setError(api::ERROR_QUEUE, "Queue already locked");
+ return;
+ }
+
+ if (mExclusiveIDLock != INVALID_CONNECTION_ID) {
+ result->setError(api::ERROR_QUEUE, "Queue locked by another connection");
+ return;
+ }
+
+ mExclusiveIDLock = id;
+ result->setVoid();
+}
+
+void ZonesManager::handleUnlockQueueCall(api::MethodResultBuilder::Pointer result)
+{
+ Lock lock(mExclusiveIDMutex);
+ std::string id = result->getID();
+
+ LOGI("Unlock Queue: " << id);
+
+ if (mExclusiveIDLock == INVALID_CONNECTION_ID) {
+ result->setError(api::ERROR_QUEUE, "Queue not locked");
+ return;
+ }
+
+ if (mExclusiveIDLock != id) {
+ result->setError(api::ERROR_QUEUE, "Queue locked by another connection");
+ return;
+ }
+
+ mExclusiveIDLock = INVALID_CONNECTION_ID;
+ result->setVoid();
+}
+
void ZonesManager::handleGetZoneIdsCall(api::MethodResultBuilder::Pointer result)
{
auto handler = [&, this] {
result->set(zoneIds);
};
+ // This call cannot be locked by lock/unlock queue
mWorker->addTaskAndWait(handler);
}
result->set(zoneId);
};
+ // This call cannot be locked by lock/unlock queue
mWorker->addTaskAndWait(handler);
}
result->set(zoneInfo);
};
+ // This call cannot be locked by lock/unlock queue
mWorker->addTaskAndWait(handler);
}
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleGetNetdevAttrsCall(const api::GetNetDevAttrsIn& data,
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleGetNetdevListCall(const api::ZoneId& zoneId,
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleCreateNetdevVethCall(const api::CreateNetDevVethIn& data,
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleCreateNetdevMacvlanCall(const api::CreateNetDevMacvlanIn& data,
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleCreateNetdevPhysCall(const api::CreateNetDevPhysIn& data,
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleDestroyNetdevCall(const api::DestroyNetDevIn& data,
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleDeleteNetdevIpAddressCall(const api::DeleteNetdevIpAddressIn& data,
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleDeclareFileCall(const api::DeclareFileIn& data,
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleDeclareMountCall(const api::DeclareMountIn& data,
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleDeclareLinkCall(const api::DeclareLinkIn& data,
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleGetDeclarationsCall(const api::ZoneId& zoneId,
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleRemoveDeclarationCall(const api::RemoveDeclarationIn& data,
}
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleSetActiveZoneCall(const api::ZoneId& zoneId,
result->setVoid();
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
}
};
- mWorker->addTaskAndWait(creator);
+ tryAddTask(creator, result, true);
}
void ZonesManager::handleDestroyZoneCall(const api::ZoneId& zoneId,
result->setVoid();
};
- mWorker->addTask(destroyer);
+ tryAddTask(destroyer, result, false);
}
void ZonesManager::handleShutdownZoneCall(const api::ZoneId& zoneId,
}
};
- mWorker->addTask(shutdown);
+ tryAddTask(shutdown, result, false);
}
void ZonesManager::handleStartZoneCall(const api::ZoneId& zoneId,
result->setError(api::ERROR_INTERNAL, "Failed to start zone");
}
};
- mWorker->addTask(startAsync);
+ tryAddTask(startAsync, result, false);
}
void ZonesManager::handleLockZoneCall(const api::ZoneId& zoneId,
result->setVoid();
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleUnlockZoneCall(const api::ZoneId& zoneId,
result->setVoid();
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleGrantDeviceCall(const api::GrantDeviceIn& data,
result->setVoid();
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
void ZonesManager::handleRevokeDeviceCall(const api::RevokeDeviceIn& data,
result->setVoid();
};
- mWorker->addTaskAndWait(handler);
+ tryAddTask(handler, result, true);
}
} // namespace vasum
namespace vasum {
+const std::string INVALID_CONNECTION_ID = "invalid://";
+
class ZonesManager final {
public:
*/
void setZonesDetachOnExit();
+ /**
+ * Callback on a client (ipc/dbus) disconnect
+ */
+ void disconnectedCallback(const std::string& id);
+
// Handlers --------------------------------------------------------
+ void handleLockQueueCall(api::MethodResultBuilder::Pointer result);
+ void handleUnlockQueueCall(api::MethodResultBuilder::Pointer result);
void handleGetZoneIdsCall(api::MethodResultBuilder::Pointer result);
void handleGetActiveZoneIdCall(api::MethodResultBuilder::Pointer result);
void handleGetZoneInfoCall(const api::ZoneId& data,
void handleNotifyActiveZoneCall(const std::string& caller,
const api::NotifActiveZoneIn& notif,
api::MethodResultBuilder::Pointer result);
- void handleSwitchToDefaultCall(const std::string& caller);
+ void handleSwitchToDefaultCall(const std::string& caller,
+ api::MethodResultBuilder::Pointer result);
void handleFileMoveCall(const std::string& srcZoneId,
const api::FileMoveRequestIn& request,
api::MethodResultBuilder::Pointer result);
Zones mZones;
std::string mActiveZoneId;
bool mDetachOnExit;
+ std::string mExclusiveIDLock;
+ Mutex mExclusiveIDMutex; // used to protect mExclusiveIDLock
Zones::iterator findZone(const std::string& id);
Zone& getZone(const std::string& id);
std::string getTemplatePathForExistingZone(const std::string& id);
int getVTForNewZone();
void insertZone(const std::string& zoneId, const std::string& templatePath);
+ void tryAddTask(const utils::Worker::Task& task, api::MethodResultBuilder::Pointer result, bool wait);
#ifdef DBUS_CONNECTION
HostDbusConnection mHostDbusConnection;
using namespace std::placeholders;
mConnection->registerObject(TESTAPI_OBJECT_PATH,
TESTAPI_DEFINITION,
- std::bind(&DbusTestServer::onMessageCall, this, _1, _2, _3, _4, _5));
+ std::bind(&DbusTestServer::onMessageCall, this, _1, _2, _3, _4, _5),
+ nullptr);
}
bool DbusTestServer::waitForName()
ScopedGlibLoop loop;
DbusConnection::Pointer conn = DbusConnection::create(DBUS_ADDRESS);
DbusConnection::MethodCallCallback callback;
- BOOST_CHECK_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, "<invalid", callback),
+ BOOST_CHECK_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, "<invalid", callback, nullptr),
DbusInvalidArgumentException);
- BOOST_CHECK_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, "", callback),
+ BOOST_CHECK_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, "", callback, nullptr),
DbusInvalidArgumentException);
- BOOST_CHECK_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, "<node></node>", callback),
+ BOOST_CHECK_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, "<node></node>", callback, nullptr),
DbusInvalidArgumentException);
- BOOST_CHECK_NO_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, callback));
+ BOOST_CHECK_NO_THROW(conn->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, callback, nullptr));
}
BOOST_AUTO_TEST_CASE(IntrospectSystem)
BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT));
conn1->registerObject(TESTAPI_OBJECT_PATH,
TESTAPI_DEFINITION,
- DbusConnection::MethodCallCallback());
+ DbusConnection::MethodCallCallback(),
+ nullptr);
std::string xml = conn2->introspect(TESTAPI_BUS_NAME, TESTAPI_OBJECT_PATH);
std::string iface = getInterfaceFromIntrospectionXML(xml, TESTAPI_INTERFACE);
BOOST_REQUIRE(!iface.empty());
result->setError("org.tizen.vasum.Error.Test", "msg: " + std::to_string(arg));
}
};
- conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler);
+ conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler, nullptr);
GVariantPtr result1 = conn2->callMethod(TESTAPI_BUS_NAME,
TESTAPI_OBJECT_PATH,
result->setError("org.tizen.vasum.Error.Test", "msg: " + std::to_string(arg));
}
};
- conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler);
+ conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler, nullptr);
auto asyncResult1 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) {
if (g_variant_is_of_type(asyncMethodCallResult.get(), G_VARIANT_TYPE_UNIT)) {
handlerDone.set();
}
};
- conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler);
+ conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler, nullptr);
auto asyncResult = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) {
const gchar* ret = NULL;
BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT));
conn1->registerObject(TESTAPI_OBJECT_PATH,
TESTAPI_DEFINITION,
- DbusConnection::MethodCallCallback());
+ DbusConnection::MethodCallCallback(),
+ nullptr);
BOOST_CHECK_THROW(conn2->callMethod(TESTAPI_BUS_NAME,
TESTAPI_OBJECT_PATH,
TESTAPI_INTERFACE,
mClient->signalSubscribe(handler, api::dbus::BUS_NAME);
}
- void signalSwitchToDefault()
+ void callSwitchToDefault()
{
- // emit signal from dbus connection
- mClient->emitSignal(api::dbus::OBJECT_PATH,
+ mClient->callMethod(api::dbus::BUS_NAME,
+ api::dbus::OBJECT_PATH,
api::dbus::INTERFACE,
- api::dbus::SIGNAL_SWITCH_TO_DEFAULT,
- nullptr);
+ api::dbus::METHOD_SWITCH_TO_DEFAULT,
+ NULL,
+ "()");
}
void callMethodNotify()
}
}
};
- mClient->registerObject(testapi::OBJECT_PATH, testapi::DEFINITION, handler);
+ mClient->registerObject(testapi::OBJECT_PATH, testapi::DEFINITION, handler, nullptr);
}
std::string testApiProxyCall(const std::string& target, const std::string& argument)
callbackWrapper);
}
- void signalSwitchToDefault()
+ void callSwitchToDefault()
{
- mClient.signal<api::Void>(api::ipc::SIGNAL_SWITCH_TO_DEFAULT, std::make_shared<api::Void>());
+ mClient.callSync<api::Void, api::Void>(api::ipc::METHOD_SWITCH_TO_DEFAULT,
+ std::make_shared<api::Void>(),
+ EVENT_TIMEOUT*10); //Prevent from IPCTimeoutException see LockUnlockZone
}
void callMethodNotify()
cm.focus("zone3");
- host.signalSwitchToDefault();
+ host.callSwitchToDefault();
// check if default zone has focus
BOOST_CHECK(spinWaitFor(EVENT_TIMEOUT, isDefaultFocused));
// focus non-default zone with allowed switching
cm.focus("zone3");
- host.signalSwitchToDefault();
+ host.callSwitchToDefault();
// check if default zone has focus
BOOST_CHECK(spinWaitFor(EVENT_TIMEOUT, isDefaultFocused));
// focus non-default zone with disabled switching
cm.focus("zone2");
- host.signalSwitchToDefault();
+ host.callSwitchToDefault();
// now default zone should not be focused
// TODO uncomment this after adding an api to change 'switchToDefaultAfterTimeout'
mDbusConnection->registerObject(zone_daemon::api::OBJECT_PATH,
zone_daemon::api::DEFINITION,
std::bind(&DaemonConnection::onMessageCall,
- this, _1, _2, _3, _4, _5));
+ this, _1, _2, _3, _4, _5),
+ nullptr);
LOGD("Connected");
}