diff --git a/headers/os/media/TimeSource.h b/headers/os/media/TimeSource.h index a2f0eb5157..956069e18f 100644 --- a/headers/os/media/TimeSource.h +++ b/headers/os/media/TimeSource.h @@ -19,6 +19,7 @@ class _BSlaveNodeStorageP; namespace BPrivate { namespace media { + class BMediaRosterEx; class TimeSourceObject; class SystemTimeSourceObject; struct TimeSourceTransmit; @@ -100,12 +101,9 @@ virtual status_t TimeSourceOp( private: - friend class _BMediaRosterP; - friend class _BTimeSourceP; - friend class _SysTimeSource; friend class BMediaNode; friend class BMediaRoster; - friend class _ServerApp; + friend class BPrivate::media::BMediaRosterEx; friend class BPrivate::media::TimeSourceObject; friend class BPrivate::media::SystemTimeSourceObject; diff --git a/headers/private/media/DataExchange.h b/headers/private/media/DataExchange.h index e87a42abdf..d80f597979 100644 --- a/headers/private/media/DataExchange.h +++ b/headers/private/media/DataExchange.h @@ -97,6 +97,8 @@ enum { SERVER_REGISTER_BUFFER, SERVER_UNREGISTER_BUFFER, SERVER_RESCAN_DEFAULTS, + SERVER_SET_NODE_CREATOR, + SERVER_CHANGE_DORMANT_NODE_USECOUNT, SERVER_MESSAGE_END, NODE_MESSAGE_START = 0x200, @@ -228,6 +230,7 @@ struct addonserver_instantiate_dormant_node_request : public request_data { media_addon_id addonid; int32 flavorid; + team_id creator_team; }; struct addonserver_instantiate_dormant_node_reply : public reply_data @@ -665,7 +668,26 @@ struct server_unregister_app_reply : public reply_data { }; +struct server_set_node_creator_request : public request_data +{ + media_node_id node; + team_id creator; +}; +struct server_set_node_creator_reply : public reply_data +{ +}; + +struct server_change_dormant_node_usecount_request : public request_data +{ + media_addon_id addon_id; + int32 addon_flavor_id; + int32 delta; +}; + +struct server_change_dormant_node_usecount_reply : public reply_data +{ +}; struct server_register_node_request : public request_data { @@ -690,7 +712,8 @@ struct server_unregister_node_request : public request_data struct server_unregister_node_reply : public reply_data { - media_addon_id addon_id; + media_addon_id addonid; + int32 flavorid; }; struct server_get_live_node_info_request : public request_data diff --git a/headers/private/media/DormantNodeManager.h b/headers/private/media/DormantNodeManager.h index 67e9328e42..6e3f5bab07 100644 --- a/headers/private/media/DormantNodeManager.h +++ b/headers/private/media/DormantNodeManager.h @@ -11,17 +11,27 @@ namespace BPrivate { namespace media { +// To instantiate a dormant node in the current address space, we need to +// either load the add-on from file and create a new BMediaAddOn class and +// cache the BMediaAddOn after that for later reuse, or reuse the cached +// BMediaAddOn if we already have one. +// This is handled by the DormantNodeManager. +// +// GetAddon() will provide a ready to use BMediaAddOn, while +// PutAddonDelayed() will unload it when it's no longer needed, +// but will delay the unloading slightly, because it is called +// from a node destructor of the loaded add-on. + class DormantNodeManager { public: DormantNodeManager(); ~DormantNodeManager(); -// InstantiateDormantNode(const dormant_node_info & in_info, bool global, media_node * out_node); - - // Be careful, GetAddon and PutAddon must be balanced. + // Be careful, GetAddon and PutAddon[Delayed] must be balanced. BMediaAddOn *GetAddon(media_addon_id id); void PutAddon(media_addon_id id); + void PutAddonDelayed(media_addon_id id); // For use by media_addon_server only media_addon_id RegisterAddon(const char *path); diff --git a/headers/private/media/MediaRosterEx.h b/headers/private/media/MediaRosterEx.h index e926b1c00e..376ce2513e 100644 --- a/headers/private/media/MediaRosterEx.h +++ b/headers/private/media/MediaRosterEx.h @@ -32,7 +32,16 @@ namespace BPrivate { namespace media { class BMediaRosterEx : public BMediaRoster { public: - status_t InstantiateDormantNode(media_addon_id addonid, int32 flavorid, media_node *out_node); + status_t SaveNodeConfiguration(BMediaNode *node); + status_t LoadNodeConfiguration(media_addon_id addonid, int32 flavorid, BMessage *out_msg); + + status_t IncrementDormantNodeUseCount(media_addon_id addonid, int32 flavorid); + status_t DecrementDormantNodeUseCount(media_addon_id addonid, int32 flavorid); + + status_t SetNodeCreator(media_node_id node, team_id creator); + + status_t RegisterNode(BMediaNode * node, media_addon_id addonid, int32 flavorid); + status_t InstantiateDormantNode(media_addon_id addonid, int32 flavorid, team_id creator, media_node *out_node); status_t GetDormantFlavorInfo(media_addon_id addonid, int32 flavorid, dormant_flavor_info *out_flavor); status_t GetNode(node_type type, media_node * out_node, int32 * out_input_id = NULL, BString * out_input_name = NULL); status_t SetNode(node_type type, const media_node *node, const dormant_node_info *info = NULL, const media_input *input = NULL); diff --git a/src/kits/media/DormantNodeManager.cpp b/src/kits/media/DormantNodeManager.cpp index 4dfbc3b400..3fc32fe409 100644 --- a/src/kits/media/DormantNodeManager.cpp +++ b/src/kits/media/DormantNodeManager.cpp @@ -130,6 +130,15 @@ DormantNodeManager::GetAddon(media_addon_id id) return addon; } +void +DormantNodeManager::PutAddonDelayed(media_addon_id id) +{ + // Called from a node destructor of the loaded media-add-on. + // We must make sure that the media-add-on stays in memory + // a couple of seconds longer. + + UNIMPLEMENTED(); +} void DormantNodeManager::PutAddon(media_addon_id id) diff --git a/src/kits/media/MediaNode.cpp b/src/kits/media/MediaNode.cpp index 91dcbe33c9..5777025b78 100644 --- a/src/kits/media/MediaNode.cpp +++ b/src/kits/media/MediaNode.cpp @@ -12,6 +12,7 @@ #include #include #include "debug.h" +#include "MediaRosterEx.h" #include "DataExchange.h" #include "ServerInterface.h" #include "Notifications.h" @@ -106,6 +107,7 @@ BMediaNode::~BMediaNode() if (fTimeSource) { fTimeSource->RemoveMe(this); fTimeSource->Release(); + fTimeSource = NULL; } // Attention! We do not unregister TimeSourceObject nodes, @@ -136,7 +138,9 @@ BMediaNode * BMediaNode::Release() { CALLED(); - if (atomic_add(&fRefCount,-1) == 1) { + if (atomic_add(&fRefCount, -1) == 1) { + TRACE("BMediaNode::Release() saving node %ld configuration\n", fNodeID); + MediaRosterEx(BMediaRoster::Roster())->SaveNodeConfiguration(this); if (DeleteHook(this) != B_OK) { FATAL("BMediaNode::Release(): DeleteHook failed\n"); return Acquire(); @@ -203,8 +207,8 @@ BMediaNode::TimeSource() const // If the node hasn't been assigned a time source // so far, we assign the system time source. This // can't be done in the BMediaNode constructor, since - // a BTimeSource is also a BMediaNode that would be - // a infinite loop... loop... loop... loop... + // a BTimeSource is also a BMediaNode and that would be + // an infinite loop... loop... loop... loop... BMediaRoster *roster = BMediaRoster::Roster(); status_t rv; diff --git a/src/kits/media/MediaRoster.cpp b/src/kits/media/MediaRoster.cpp index 2d7c6c2b62..1a251c0150 100644 --- a/src/kits/media/MediaRoster.cpp +++ b/src/kits/media/MediaRoster.cpp @@ -44,6 +44,57 @@ using namespace BPrivate::media; // DefaultDeleter will delete the BMediaRoster object in it's destructor. DefaultDeleter _deleter; +status_t +BMediaRosterEx::SaveNodeConfiguration(BMediaNode *node) +{ + BMediaAddOn *addon; + media_addon_id addonid; + int32 flavorid; + addon = node->AddOn(&flavorid); + if (!addon) { + FATAL("BMediaRosterEx::SaveNodeConfiguration node %ld not instantiated from BMediaAddOn!\n"); + return B_ERROR; + } + addonid = addon->AddonID(); + + // XXX fix this + printf("### BMediaRosterEx::SaveNodeConfiguration should save addon-id %ld, flavor-id %ld config NOW!\n", addonid, flavorid); + return B_OK; +} + +status_t +BMediaRosterEx::LoadNodeConfiguration(media_addon_id addonid, int32 flavorid, BMessage *out_msg) +{ + // XXX fix this + out_msg->MakeEmpty(); // to be fully R5 compliant + printf("### BMediaRosterEx::LoadNodeConfiguration should load addon-id %ld, flavor-id %ld config NOW!\n", addonid, flavorid); + return B_OK; +} + +status_t +BMediaRosterEx::IncrementDormantNodeUseCount(media_addon_id addonid, int32 flavorid) +{ + //perhaps rename all this from dormantnode into addon-flavor or instance + return B_OK; +} + +status_t +BMediaRosterEx::DecrementDormantNodeUseCount(media_addon_id addonid, int32 flavorid) +{ + return B_OK; +} + +status_t +BMediaRosterEx::SetNodeCreator(media_node_id node, team_id creator) +{ + server_set_node_creator_request request; + server_set_node_creator_reply reply; + + request.node = node; + request.creator = creator; + return QueryServer(SERVER_SET_NODE_CREATOR, &request, sizeof(request), &reply, sizeof(reply)); +} + status_t BMediaRosterEx::GetNode(node_type type, media_node * out_node, int32 * out_input_id, BString * out_input_name) { @@ -1354,25 +1405,39 @@ BMediaRoster::StopWatching(const BMessenger & where, status_t BMediaRoster::RegisterNode(BMediaNode * node) { - printf("BMediaRoster::RegisterNode %p\n", node); + CALLED(); + // addon-id = -1 (unused), addon-flavor-id = 0 (unused, too) + return MediaRosterEx(this)->RegisterNode(node, -1, 0); +} + + +status_t +BMediaRosterEx::RegisterNode(BMediaNode * node, media_addon_id addonid, int32 flavorid) +{ CALLED(); if (node == NULL) return B_BAD_VALUE; - status_t rv; - BMediaAddOn *addon; - int32 addon_flavor_id; - media_addon_id addon_id; + // some sanity check + // I'm not sure if the media kit warrants to call BMediaNode::AddOn() here. + // Perhaps we don't need it. + { + BMediaAddOn *addon; + int32 addon_flavor_id; + media_addon_id addon_id; + addon_flavor_id = 0; + addon = node->AddOn(&addon_flavor_id); + addon_id = addon ? addon->AddonID() : -1; + ASSERT(addonid == addon_id); + ASSERT(flavorid == addon_flavor_id); + } - addon_flavor_id = 0; - addon = node->AddOn(&addon_flavor_id); - addon_id = addon ? addon->AddonID() : -1; - + status_t rv; server_register_node_request request; server_register_node_reply reply; - request.addon_id = addon_id; - request.addon_flavor_id = addon_flavor_id; + request.addon_id = addonid; + request.addon_flavor_id = flavorid; strcpy(request.name, node->Name()); request.kinds = node->Kinds(); request.port = node->ControlPort(); @@ -1444,16 +1509,20 @@ BMediaRoster::UnregisterNode(BMediaNode * node) printf("BMediaRoster::UnregisterNode, trying to unregister reference counting disabled timesource, node %ld, port %ld, team %ld\n", node->ID(), node->ControlPort(), team); return B_OK; } - - if (node->fRefCount != 0) { - FATAL("BMediaRoster::UnregisterNode: Warning node id %ld, name '%s' has local reference count of %ld\n", node->ID(), node->Name(), node->fRefCount); - // no return here, we continue and unregister! - } if (node->ID() == NODE_UNREGISTERED_ID) { FATAL("BMediaRoster::UnregisterNode: Warning node id %ld, name '%s' already unregistered\n", node->ID(), node->Name()); return B_OK; } - + if (node->fRefCount != 0) { + FATAL("BMediaRoster::UnregisterNode: Warning node id %ld, name '%s' has local reference count of %ld\n", node->ID(), node->Name(), node->fRefCount); + // no return here, we continue and unregister! + } + + // Calling BMediaAddOn::GetConfigurationFor(BMediaNode *node, BMessage *config) + // if this node was instanciated by an add-on needs to be done *somewhere* + // We can't do it here because it is already to late (destructor of the node + // might have been called). + server_unregister_node_request request; server_unregister_node_reply reply; status_t rv; @@ -1470,13 +1539,19 @@ BMediaRoster::UnregisterNode(BMediaNode * node) return rv; } - if (reply.addon_id != -1) { - // XXX This is a real big problem! - // XXX UnregisterNode is called by a dormant node itself, but UnregisterNode will - // XXX unload the dormant node image from memory when calling PutAddon -// _DormantNodeManager->PutAddon(reply.addon_id); + if (reply.addonid != -1) { + // Small problem here, we can't use DormantNodeManager::PutAddon(), as + // UnregisterNode() is called by a dormant node itself (by the destructor). + // The add-on that contains the node needs to remain in memory until the + // destructor execution is finished. + // DormantNodeManager::PutAddonDelayed() will delay unloading. + _DormantNodeManager->PutAddonDelayed(reply.addonid); - // XXX do "possible_count" increment in the server. + rv = MediaRosterEx(this)->DecrementDormantNodeUseCount(reply.addonid, reply.flavorid); + if (rv != B_OK) { + FATAL("BMediaRoster::UnregisterNode: DecrementDormantNodeUseCount failed\n"); + // this is really a problem, but we can't fail now + } } // we are a friend class of BMediaNode and invalidate this member variable @@ -1651,25 +1726,25 @@ BMediaRoster::GetDormantNodes(dormant_node_info * out_info, * Checks concerning global/local are not done here. */ status_t -BMediaRosterEx::InstantiateDormantNode(media_addon_id addonid, int32 flavorid, media_node *out_node) +BMediaRosterEx::InstantiateDormantNode(media_addon_id addonid, int32 flavorid, team_id creator, media_node *out_node) { - // to instantiate a dormant node in the current address space, we need to - // either load the add-on from file and create a new BMediaAddOn class, or - // reuse the cached BMediaAddOn from a previous call - // call BMediaAddOn::InstantiateNodeFor() - // and cache the BMediaAddOn after that for later reuse. - // BeOS R5 does not seem to delete it when the application quits + // This function is always called from the correct context, if the node + // is supposed to be global, it is called from the media_addon_server. + // if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that // resides in the media_addon_server // RegisterNode() must be called for nodes instantiated from add-ons, // since the media kit warrants that it's done automatically. - // dormant_node_info::addon Indicates the ID number of the media add-on in which the node resides. - // dormant_node_info::flavor_id Indicates the internal ID number that the add-on uses to identify the flavor, - // this is the number that was published by BMediaAddOn::GetFlavorAt() int the - // flavor_info::internal_id field. - + // addonid Indicates the ID number of the media add-on in which the node resides. + // flavorid Indicates the internal ID number that the add-on uses to identify the flavor, + // this is the number that was published by BMediaAddOn::GetFlavorAt() in the + // flavor_info::internal_id field. + // creator The creator team is -1 if nodes are created locally. If created globally, + // it will contain (while called in media_addon_server context) the team-id of + // the team that requested the instantiation. + printf("BMediaRosterEx::InstantiateDormantNode: addon-id %ld, flavor_id %ld\n", addonid, flavorid); // Get flavor_info from the server @@ -1691,32 +1766,70 @@ BMediaRosterEx::InstantiateDormantNode(media_addon_id addonid, int32 flavorid, m return B_ERROR; } + // Now we need to try to increment the use count of this addon flavor + // in the server. This can fail if the total number instances of this + // flavor is limited. + rv = IncrementDormantNodeUseCount(addonid, flavorid); + if (rv != B_OK) { + FATAL("BMediaRosterEx::InstantiateDormantNode error: can't create more nodes for addon-id %ld, flavour-id %ld\n", addonid, flavorid); + // Put the addon back into the pool + _DormantNodeManager->PutAddon(addonid); + return B_ERROR; + } + BMessage config; - // XXX get configuration from server and do "possible_count" decrement in the server. + rv = LoadNodeConfiguration(addonid, flavorid, &config); + if (rv != B_OK) { + FATAL("BMediaRosterEx::InstantiateDormantNode: couldn't load configuration for addon-id %ld, flavor-id %ld\n", addonid, flavorid); + // do not return, this is a minor problem, not a reason to fail + } BMediaNode *node; status_t out_error; + out_error = B_OK; node = addon->InstantiateNodeFor(&node_info, &config, &out_error); if (!node) { FATAL("BMediaRosterEx::InstantiateDormantNode: InstantiateNodeFor failed\n"); - // XXX do "possible_count" increment in the server. + // Put the addon back into the pool _DormantNodeManager->PutAddon(addonid); - return B_ERROR; + // We must decrement the use count of this addon flavor in the + // server to compensate the increment done in the beginning. + rv = DecrementDormantNodeUseCount(addonid, flavorid); + if (rv != B_OK) { + FATAL("BMediaRosterEx::InstantiateDormantNode: DecrementDormantNodeUseCount failed\n"); + } + return (out_error != B_OK) ? out_error : B_ERROR; } - rv = RegisterNode(node); + + rv = RegisterNode(node, addonid, flavorid); if (rv != B_OK) { FATAL("BMediaRosterEx::InstantiateDormantNode: RegisterNode failed\n"); delete node; - // XXX do "possible_count" increment in the server. + // Put the addon back into the pool _DormantNodeManager->PutAddon(addonid); + // We must decrement the use count of this addon flavor in the + // server to compensate the increment done in the beginning. + rv = DecrementDormantNodeUseCount(addonid, flavorid); + if (rv != B_OK) { + FATAL("BMediaRosterEx::InstantiateDormantNode: DecrementDormantNodeUseCount failed\n"); + } return B_ERROR; } - // XXX we must remember in_info.addon and call - // XXX _DormantNodeManager->PutAddon when the - // XXX node is unregistered - // should be handled by RegisterNode() and UnregisterNode() now + if (creator != -1) { + // send a message to the server to assign team "creator" as creator of node "node->ID()" + printf("!!! BMediaRosterEx::InstantiateDormantNode assigning team %ld as creator of node %ld\n", creator, node->ID()); + rv = MediaRosterEx(this)->SetNodeCreator(node->ID(), creator); + if (rv != B_OK) { + FATAL("BMediaRosterEx::InstantiateDormantNode failed to assign team %ld as creator of node %ld\n", creator, node->ID()); + // do not return, this is a minor problem, not a reason to fail + } + } + + // RegisterNode() does remember the add-on id in the server + // and UnregisterNode() will call DormantNodeManager::PutAddon() + // when the node is unregistered. *out_node = node->Node(); @@ -1778,7 +1891,7 @@ BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info, FATAL("BMediaRoster::InstantiateDormantNode Error: requested B_FLAVOR_IS_GLOBAL, but dormant node has B_FLAVOR_IS_LOCAL\n"); return B_BAD_VALUE; } -//#if 0 + // If either the node, or the caller requested to make the instance global // we will do it by forwarding this request into the media_addon_server, which // in turn will call BMediaRosterEx::InstantiateDormantNode to create the node @@ -1792,6 +1905,7 @@ BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info, status_t rv; request.addonid = in_info.addon; request.flavorid = in_info.flavor_id; + request.creator_team = team; // creator team is allowed to also release global nodes rv = QueryAddonServer(ADDONSERVER_INSTANTIATE_DORMANT_NODE, &request, sizeof(request), &reply, sizeof(reply)); if (rv == B_OK) { *out_node = reply.node; @@ -1802,10 +1916,9 @@ BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info, } else { - return MediaRosterEx(this)->InstantiateDormantNode(in_info.addon, in_info.flavor_id, out_node); + // creator team = -1, as this is a local node + return MediaRosterEx(this)->InstantiateDormantNode(in_info.addon, in_info.flavor_id, -1, out_node); } -//#endif -// return MediaRosterEx(this)->InstantiateDormantNode(in_info.addon, in_info.flavor_id, out_node); } @@ -2175,8 +2288,10 @@ BMediaRoster::MessageReceived(BMessage * message) BMediaNode *node; message->FindPointer("node", reinterpret_cast(&node)); - TRACE("BMediaRoster::MessageReceived NODE_FINAL_RELEASE releasing node %p\n", node); + TRACE("BMediaRoster::MessageReceived NODE_FINAL_RELEASE saving node %ld configuration\n", node->ID()); + MediaRosterEx(BMediaRoster::Roster())->SaveNodeConfiguration(node); + TRACE("BMediaRoster::MessageReceived NODE_FINAL_RELEASE releasing node %ld\n", node->ID()); node->DeleteHook(node); // we don't call Release(), see above! return; } diff --git a/src/servers/media/AppManager.cpp b/src/servers/media/AppManager.cpp index fd3e42088d..aadaeefc6f 100644 --- a/src/servers/media/AppManager.cpp +++ b/src/servers/media/AppManager.cpp @@ -217,6 +217,13 @@ void AppManager::TerminateAddonServer() } } +team_id +AppManager::AddonServer() +{ + // XXX not sure about locking + return fAddonServer; +} + void AppManager::Dump() { BAutolock lock(fLocker); diff --git a/src/servers/media/AppManager.h b/src/servers/media/AppManager.h index 06bb8411ac..fed4d23ed3 100644 --- a/src/servers/media/AppManager.h +++ b/src/servers/media/AppManager.h @@ -17,6 +17,7 @@ public: bool HasTeam(team_id); void StartAddonServer(); void TerminateAddonServer(); + team_id AddonServer(); void Dump(); diff --git a/src/servers/media/NodeManager.cpp b/src/servers/media/NodeManager.cpp index 61aa148940..6bacaad3b4 100644 --- a/src/servers/media/NodeManager.cpp +++ b/src/servers/media/NodeManager.cpp @@ -13,6 +13,9 @@ #include #include "debug.h" #include "NodeManager.h" +#include "AppManager.h" + +extern AppManager *gAppManager; const char *get_node_type(node_type t); @@ -51,6 +54,7 @@ NodeManager::RegisterNode(media_node_id *nodeid, media_addon_id addon_id, int32 rn.kinds = kinds; rn.port = port; rn.team = team; + rn.creator = -1; // will be set later rn.globalrefcount = 1; rn.teamrefcount.Insert(team, 1); @@ -64,7 +68,7 @@ NodeManager::RegisterNode(media_node_id *nodeid, media_addon_id addon_id, int32 status_t -NodeManager::UnregisterNode(media_addon_id *addon_id, media_node_id nodeid, team_id team) +NodeManager::UnregisterNode(media_addon_id *addonid, int32 *flavorid, media_node_id nodeid, team_id team) { BAutolock lock(fLocker); bool b; @@ -83,10 +87,11 @@ NodeManager::UnregisterNode(media_addon_id *addon_id, media_node_id nodeid, team FATAL("!!! NodeManager::UnregisterNode: Error: node %ld, team %ld, globalrefcount %ld\n", nodeid, team, rn->globalrefcount); //return B_ERROR; } - *addon_id = rn->addon_id; + *addonid = rn->addon_id; + *flavorid = rn->addon_flavor_id; b = fRegisteredNodeMap->Remove(nodeid); ASSERT(b); - TRACE("NodeManager::UnregisterNode leave: node %ld, addon_id %ld, team %ld\n", nodeid, *addon_id, team); + TRACE("NodeManager::UnregisterNode leave: node %ld, addon_id %ld, flavor_id %ld team %ld\n", nodeid, *addonid, *flavorid, team); return B_OK; } @@ -135,8 +140,20 @@ NodeManager::DecrementGlobalRefCount(media_node_id nodeid, team_id team) int32 *count; b = rn->teamrefcount.Get(team, &count); if (!b) { - FATAL("!!! NodeManager::DecrementGlobalRefCount: Error: node %ld has no team %ld references\n", nodeid, team); - return B_ERROR; + // Normally it is an error to release a node in another team. But we make one + // exception. If the node is global, and the creator team tries to release it, + // we will release it in the the media_addon_server. + team_id addon_server_team; + addon_server_team = gAppManager->AddonServer(); + if (rn->creator == team && rn->teamrefcount.Get(addon_server_team, &count)) { + printf("!!! NodeManager::DecrementGlobalRefCount doing global release!\n"); + rn->creator = -1; //invalidate! + team = addon_server_team; //redirect! + // the count variable was already redirected in if() statement above. + } else { + FATAL("!!! NodeManager::DecrementGlobalRefCount: Error: node %ld has no team %ld references\n", nodeid, team); + return B_ERROR; + } } *count -= 1; int32 debug_count = *count; @@ -155,6 +172,30 @@ NodeManager::DecrementGlobalRefCount(media_node_id nodeid, team_id team) return B_OK; } +status_t +NodeManager::SetNodeCreator(media_node_id nodeid, team_id creator) +{ + BAutolock lock(fLocker); + registered_node *rn; + bool b; + status_t rv; + + TRACE("NodeManager::SetNodeCreator node %ld, creator %ld\n", nodeid, creator); + + b = fRegisteredNodeMap->Get(nodeid, &rn); + if (!b) { + FATAL("NodeManager::SetNodeCreator: Error: node %ld not found\n", nodeid); + return B_ERROR; + } + + if (rn->creator != -1) { + FATAL("NodeManager::SetNodeCreator: Error: node %ld is already assigned creator %ld\n", nodeid, rn->creator); + return B_ERROR; + } + + rn->creator = creator; + return B_OK; +} void NodeManager::FinalReleaseNode(media_node_id nodeid) @@ -658,6 +699,11 @@ NodeManager::CleanupTeam(team_id team) registered_node *rn; for (fRegisteredNodeMap->Rewind(); fRegisteredNodeMap->GetNext(&rn); ) { + // if the gone team was the creator of some global dormant node instance, we now invalidate that + if (rn->creator == team) { + rn->creator = -1; + // fall through + } // if the team hosting this node is gone, remove node from database if (rn->team == team) { FATAL("NodeManager::CleanupTeam: removing node id %ld, team %ld\n", rn->nodeid, team); diff --git a/src/servers/media/NodeManager.h b/src/servers/media/NodeManager.h index 6f2420a089..fd65957ee0 100644 --- a/src/servers/media/NodeManager.h +++ b/src/servers/media/NodeManager.h @@ -16,7 +16,8 @@ struct registered_node char name[B_MEDIA_NAME_LENGTH]; uint64 kinds; port_id port; - team_id team; + team_id creator; // team that created the node + team_id team; // team that contains the node object int32 globalrefcount; Map teamrefcount; List inputlist; @@ -55,7 +56,7 @@ public: /* Management of live nodes */ status_t RegisterNode(media_node_id *nodeid, media_addon_id addon_id, int32 addon_flavor_id, const char *name, uint64 kinds, port_id port, team_id team); - status_t UnregisterNode(media_addon_id *addon_id, media_node_id nodeid, team_id team); + status_t UnregisterNode(media_addon_id *addonid, int32 *flavorid, media_node_id nodeid, team_id team); status_t GetCloneForId(media_node *node, media_node_id nodeid, team_id team); status_t GetClone(media_node *node, char *input_name, int32 *input_id, node_type type, team_id team); status_t ReleaseNode(const media_node &node, team_id team); @@ -68,6 +69,7 @@ public: status_t GetDormantNodeInfo(dormant_node_info *node_info, const media_node &node); status_t IncrementGlobalRefCount(media_node_id nodeid, team_id team); status_t DecrementGlobalRefCount(media_node_id nodeid, team_id team); + status_t SetNodeCreator(media_node_id nodeid, team_id creator); void FinalReleaseNode(media_node_id nodeid); /* Add media_node_id of all live nodes to the message diff --git a/src/servers/media/media_server.cpp b/src/servers/media/media_server.cpp index 64f82baaa2..a1745161b5 100644 --- a/src/servers/media/media_server.cpp +++ b/src/servers/media/media_server.cpp @@ -306,7 +306,7 @@ ServerApp::HandleMessage(int32 code, void *data, size_t size) { const server_unregister_node_request *request = reinterpret_cast(data); server_unregister_node_reply reply; - rv = gNodeManager->UnregisterNode(&reply.addon_id, request->nodeid, request->team); + rv = gNodeManager->UnregisterNode(&reply.addonid, &reply.flavorid, request->nodeid, request->team); request->SendReply(rv, &reply, sizeof(reply)); break; } @@ -471,6 +471,15 @@ ServerApp::HandleMessage(int32 code, void *data, size_t size) break; } + case SERVER_SET_NODE_CREATOR: + { + const server_set_node_creator_request *request = reinterpret_cast(data); + server_set_node_creator_reply reply; + rv = gNodeManager->SetNodeCreator(request->node, request->creator); + request->SendReply(rv, &reply, sizeof(reply)); + break; + } + case SERVER_GET_SHARED_BUFFER_AREA: { const server_get_shared_buffer_area_request *request = reinterpret_cast(data); diff --git a/src/servers/media_addon/main.cpp b/src/servers/media_addon/main.cpp index 65023c02db..4349e76361 100644 --- a/src/servers/media_addon/main.cpp +++ b/src/servers/media_addon/main.cpp @@ -86,7 +86,7 @@ MediaAddonServer::HandleMessage(int32 code, const void *data, size_t size) const addonserver_instantiate_dormant_node_request *request = static_cast(data); addonserver_instantiate_dormant_node_reply reply; status_t rv; - rv = MediaRosterEx(mediaroster)->InstantiateDormantNode(request->addonid, request->flavorid, &reply.node); + rv = MediaRosterEx(mediaroster)->InstantiateDormantNode(request->addonid, request->flavorid, request->creator_team, &reply.node); request->SendReply(rv, &reply, sizeof(reply)); break; }