Global nodes can mow be released by the teams which created them.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2923 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper 2003-03-16 03:52:52 +00:00
parent 2937222250
commit 54187cc6e8
13 changed files with 303 additions and 70 deletions

View File

@ -19,6 +19,7 @@
class _BSlaveNodeStorageP; class _BSlaveNodeStorageP;
namespace BPrivate { namespace media { namespace BPrivate { namespace media {
class BMediaRosterEx;
class TimeSourceObject; class TimeSourceObject;
class SystemTimeSourceObject; class SystemTimeSourceObject;
struct TimeSourceTransmit; struct TimeSourceTransmit;
@ -100,12 +101,9 @@ virtual status_t TimeSourceOp(
private: private:
friend class _BMediaRosterP;
friend class _BTimeSourceP;
friend class _SysTimeSource;
friend class BMediaNode; friend class BMediaNode;
friend class BMediaRoster; friend class BMediaRoster;
friend class _ServerApp; friend class BPrivate::media::BMediaRosterEx;
friend class BPrivate::media::TimeSourceObject; friend class BPrivate::media::TimeSourceObject;
friend class BPrivate::media::SystemTimeSourceObject; friend class BPrivate::media::SystemTimeSourceObject;

View File

@ -97,6 +97,8 @@ enum {
SERVER_REGISTER_BUFFER, SERVER_REGISTER_BUFFER,
SERVER_UNREGISTER_BUFFER, SERVER_UNREGISTER_BUFFER,
SERVER_RESCAN_DEFAULTS, SERVER_RESCAN_DEFAULTS,
SERVER_SET_NODE_CREATOR,
SERVER_CHANGE_DORMANT_NODE_USECOUNT,
SERVER_MESSAGE_END, SERVER_MESSAGE_END,
NODE_MESSAGE_START = 0x200, NODE_MESSAGE_START = 0x200,
@ -228,6 +230,7 @@ struct addonserver_instantiate_dormant_node_request : public request_data
{ {
media_addon_id addonid; media_addon_id addonid;
int32 flavorid; int32 flavorid;
team_id creator_team;
}; };
struct addonserver_instantiate_dormant_node_reply : public reply_data 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 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 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 struct server_get_live_node_info_request : public request_data

View File

@ -11,17 +11,27 @@
namespace BPrivate { namespace BPrivate {
namespace media { 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 class DormantNodeManager
{ {
public: public:
DormantNodeManager(); DormantNodeManager();
~DormantNodeManager(); ~DormantNodeManager();
// InstantiateDormantNode(const dormant_node_info & in_info, bool global, media_node * out_node); // Be careful, GetAddon and PutAddon[Delayed] must be balanced.
// Be careful, GetAddon and PutAddon must be balanced.
BMediaAddOn *GetAddon(media_addon_id id); BMediaAddOn *GetAddon(media_addon_id id);
void PutAddon(media_addon_id id); void PutAddon(media_addon_id id);
void PutAddonDelayed(media_addon_id id);
// For use by media_addon_server only // For use by media_addon_server only
media_addon_id RegisterAddon(const char *path); media_addon_id RegisterAddon(const char *path);

View File

@ -32,7 +32,16 @@ namespace BPrivate { namespace media {
class BMediaRosterEx : public BMediaRoster class BMediaRosterEx : public BMediaRoster
{ {
public: 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 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 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); status_t SetNode(node_type type, const media_node *node, const dormant_node_info *info = NULL, const media_input *input = NULL);

View File

@ -130,6 +130,15 @@ DormantNodeManager::GetAddon(media_addon_id id)
return addon; 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 void
DormantNodeManager::PutAddon(media_addon_id id) DormantNodeManager::PutAddon(media_addon_id id)

View File

@ -12,6 +12,7 @@
#include <FileInterface.h> #include <FileInterface.h>
#include <string.h> #include <string.h>
#include "debug.h" #include "debug.h"
#include "MediaRosterEx.h"
#include "DataExchange.h" #include "DataExchange.h"
#include "ServerInterface.h" #include "ServerInterface.h"
#include "Notifications.h" #include "Notifications.h"
@ -106,6 +107,7 @@ BMediaNode::~BMediaNode()
if (fTimeSource) { if (fTimeSource) {
fTimeSource->RemoveMe(this); fTimeSource->RemoveMe(this);
fTimeSource->Release(); fTimeSource->Release();
fTimeSource = NULL;
} }
// Attention! We do not unregister TimeSourceObject nodes, // Attention! We do not unregister TimeSourceObject nodes,
@ -136,7 +138,9 @@ BMediaNode *
BMediaNode::Release() BMediaNode::Release()
{ {
CALLED(); 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) { if (DeleteHook(this) != B_OK) {
FATAL("BMediaNode::Release(): DeleteHook failed\n"); FATAL("BMediaNode::Release(): DeleteHook failed\n");
return Acquire(); return Acquire();
@ -203,8 +207,8 @@ BMediaNode::TimeSource() const
// If the node hasn't been assigned a time source // If the node hasn't been assigned a time source
// so far, we assign the system time source. This // so far, we assign the system time source. This
// can't be done in the BMediaNode constructor, since // can't be done in the BMediaNode constructor, since
// a BTimeSource is also a BMediaNode that would be // a BTimeSource is also a BMediaNode and that would be
// a infinite loop... loop... loop... loop... // an infinite loop... loop... loop... loop...
BMediaRoster *roster = BMediaRoster::Roster(); BMediaRoster *roster = BMediaRoster::Roster();
status_t rv; status_t rv;

View File

@ -44,6 +44,57 @@ using namespace BPrivate::media;
// DefaultDeleter will delete the BMediaRoster object in it's destructor. // DefaultDeleter will delete the BMediaRoster object in it's destructor.
DefaultDeleter _deleter; 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 status_t
BMediaRosterEx::GetNode(node_type type, media_node * out_node, int32 * out_input_id, BString * out_input_name) 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 status_t
BMediaRoster::RegisterNode(BMediaNode * node) 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(); CALLED();
if (node == NULL) if (node == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
status_t rv; // some sanity check
BMediaAddOn *addon; // I'm not sure if the media kit warrants to call BMediaNode::AddOn() here.
int32 addon_flavor_id; // Perhaps we don't need it.
media_addon_id addon_id; {
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; status_t rv;
addon = node->AddOn(&addon_flavor_id);
addon_id = addon ? addon->AddonID() : -1;
server_register_node_request request; server_register_node_request request;
server_register_node_reply reply; server_register_node_reply reply;
request.addon_id = addon_id; request.addon_id = addonid;
request.addon_flavor_id = addon_flavor_id; request.addon_flavor_id = flavorid;
strcpy(request.name, node->Name()); strcpy(request.name, node->Name());
request.kinds = node->Kinds(); request.kinds = node->Kinds();
request.port = node->ControlPort(); 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); 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; 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) { if (node->ID() == NODE_UNREGISTERED_ID) {
FATAL("BMediaRoster::UnregisterNode: Warning node id %ld, name '%s' already unregistered\n", node->ID(), node->Name()); FATAL("BMediaRoster::UnregisterNode: Warning node id %ld, name '%s' already unregistered\n", node->ID(), node->Name());
return B_OK; 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_request request;
server_unregister_node_reply reply; server_unregister_node_reply reply;
status_t rv; status_t rv;
@ -1470,13 +1539,19 @@ BMediaRoster::UnregisterNode(BMediaNode * node)
return rv; return rv;
} }
if (reply.addon_id != -1) { if (reply.addonid != -1) {
// XXX This is a real big problem! // Small problem here, we can't use DormantNodeManager::PutAddon(), as
// XXX UnregisterNode is called by a dormant node itself, but UnregisterNode will // UnregisterNode() is called by a dormant node itself (by the destructor).
// XXX unload the dormant node image from memory when calling PutAddon // The add-on that contains the node needs to remain in memory until the
// _DormantNodeManager->PutAddon(reply.addon_id); // 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 // 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. * Checks concerning global/local are not done here.
*/ */
status_t 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 // This function is always called from the correct context, if the node
// either load the add-on from file and create a new BMediaAddOn class, or // is supposed to be global, it is called from the media_addon_server.
// 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
// if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that // if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that
// resides in the media_addon_server // resides in the media_addon_server
// RegisterNode() must be called for nodes instantiated from add-ons, // RegisterNode() must be called for nodes instantiated from add-ons,
// since the media kit warrants that it's done automatically. // 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. // addonid 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, // 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() int the // this is the number that was published by BMediaAddOn::GetFlavorAt() in the
// flavor_info::internal_id field. // 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); printf("BMediaRosterEx::InstantiateDormantNode: addon-id %ld, flavor_id %ld\n", addonid, flavorid);
// Get flavor_info from the server // Get flavor_info from the server
@ -1691,32 +1766,70 @@ BMediaRosterEx::InstantiateDormantNode(media_addon_id addonid, int32 flavorid, m
return B_ERROR; 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; 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; BMediaNode *node;
status_t out_error; status_t out_error;
out_error = B_OK;
node = addon->InstantiateNodeFor(&node_info, &config, &out_error); node = addon->InstantiateNodeFor(&node_info, &config, &out_error);
if (!node) { if (!node) {
FATAL("BMediaRosterEx::InstantiateDormantNode: InstantiateNodeFor failed\n"); FATAL("BMediaRosterEx::InstantiateDormantNode: InstantiateNodeFor failed\n");
// XXX do "possible_count" increment in the server. // Put the addon back into the pool
_DormantNodeManager->PutAddon(addonid); _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) { if (rv != B_OK) {
FATAL("BMediaRosterEx::InstantiateDormantNode: RegisterNode failed\n"); FATAL("BMediaRosterEx::InstantiateDormantNode: RegisterNode failed\n");
delete node; delete node;
// XXX do "possible_count" increment in the server. // Put the addon back into the pool
_DormantNodeManager->PutAddon(addonid); _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; return B_ERROR;
} }
// XXX we must remember in_info.addon and call if (creator != -1) {
// XXX _DormantNodeManager->PutAddon when the // send a message to the server to assign team "creator" as creator of node "node->ID()"
// XXX node is unregistered printf("!!! BMediaRosterEx::InstantiateDormantNode assigning team %ld as creator of node %ld\n", creator, node->ID());
// should be handled by RegisterNode() and UnregisterNode() now 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(); *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"); FATAL("BMediaRoster::InstantiateDormantNode Error: requested B_FLAVOR_IS_GLOBAL, but dormant node has B_FLAVOR_IS_LOCAL\n");
return B_BAD_VALUE; return B_BAD_VALUE;
} }
//#if 0
// If either the node, or the caller requested to make the instance global // 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 // we will do it by forwarding this request into the media_addon_server, which
// in turn will call BMediaRosterEx::InstantiateDormantNode to create the node // 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; status_t rv;
request.addonid = in_info.addon; request.addonid = in_info.addon;
request.flavorid = in_info.flavor_id; 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)); rv = QueryAddonServer(ADDONSERVER_INSTANTIATE_DORMANT_NODE, &request, sizeof(request), &reply, sizeof(reply));
if (rv == B_OK) { if (rv == B_OK) {
*out_node = reply.node; *out_node = reply.node;
@ -1802,10 +1916,9 @@ BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info,
} else { } 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; BMediaNode *node;
message->FindPointer("node", reinterpret_cast<void **>(&node)); message->FindPointer("node", reinterpret_cast<void **>(&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! node->DeleteHook(node); // we don't call Release(), see above!
return; return;
} }

View File

@ -217,6 +217,13 @@ void AppManager::TerminateAddonServer()
} }
} }
team_id
AppManager::AddonServer()
{
// XXX not sure about locking
return fAddonServer;
}
void AppManager::Dump() void AppManager::Dump()
{ {
BAutolock lock(fLocker); BAutolock lock(fLocker);

View File

@ -17,6 +17,7 @@ public:
bool HasTeam(team_id); bool HasTeam(team_id);
void StartAddonServer(); void StartAddonServer();
void TerminateAddonServer(); void TerminateAddonServer();
team_id AddonServer();
void Dump(); void Dump();

View File

@ -13,6 +13,9 @@
#include <MediaAddOn.h> #include <MediaAddOn.h>
#include "debug.h" #include "debug.h"
#include "NodeManager.h" #include "NodeManager.h"
#include "AppManager.h"
extern AppManager *gAppManager;
const char *get_node_type(node_type t); 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.kinds = kinds;
rn.port = port; rn.port = port;
rn.team = team; rn.team = team;
rn.creator = -1; // will be set later
rn.globalrefcount = 1; rn.globalrefcount = 1;
rn.teamrefcount.Insert(team, 1); rn.teamrefcount.Insert(team, 1);
@ -64,7 +68,7 @@ NodeManager::RegisterNode(media_node_id *nodeid, media_addon_id addon_id, int32
status_t 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); BAutolock lock(fLocker);
bool b; 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); FATAL("!!! NodeManager::UnregisterNode: Error: node %ld, team %ld, globalrefcount %ld\n", nodeid, team, rn->globalrefcount);
//return B_ERROR; //return B_ERROR;
} }
*addon_id = rn->addon_id; *addonid = rn->addon_id;
*flavorid = rn->addon_flavor_id;
b = fRegisteredNodeMap->Remove(nodeid); b = fRegisteredNodeMap->Remove(nodeid);
ASSERT(b); 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; return B_OK;
} }
@ -135,8 +140,20 @@ NodeManager::DecrementGlobalRefCount(media_node_id nodeid, team_id team)
int32 *count; int32 *count;
b = rn->teamrefcount.Get(team, &count); b = rn->teamrefcount.Get(team, &count);
if (!b) { if (!b) {
FATAL("!!! NodeManager::DecrementGlobalRefCount: Error: node %ld has no team %ld references\n", nodeid, team); // Normally it is an error to release a node in another team. But we make one
return B_ERROR; // 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; *count -= 1;
int32 debug_count = *count; int32 debug_count = *count;
@ -155,6 +172,30 @@ NodeManager::DecrementGlobalRefCount(media_node_id nodeid, team_id team)
return B_OK; 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 void
NodeManager::FinalReleaseNode(media_node_id nodeid) NodeManager::FinalReleaseNode(media_node_id nodeid)
@ -658,6 +699,11 @@ NodeManager::CleanupTeam(team_id team)
registered_node *rn; registered_node *rn;
for (fRegisteredNodeMap->Rewind(); fRegisteredNodeMap->GetNext(&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 the team hosting this node is gone, remove node from database
if (rn->team == team) { if (rn->team == team) {
FATAL("NodeManager::CleanupTeam: removing node id %ld, team %ld\n", rn->nodeid, team); FATAL("NodeManager::CleanupTeam: removing node id %ld, team %ld\n", rn->nodeid, team);

View File

@ -16,7 +16,8 @@ struct registered_node
char name[B_MEDIA_NAME_LENGTH]; char name[B_MEDIA_NAME_LENGTH];
uint64 kinds; uint64 kinds;
port_id port; 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; int32 globalrefcount;
Map<team_id, int32> teamrefcount; Map<team_id, int32> teamrefcount;
List<media_input> inputlist; List<media_input> inputlist;
@ -55,7 +56,7 @@ public:
/* Management of live nodes */ /* 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 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 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 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); 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 GetDormantNodeInfo(dormant_node_info *node_info, const media_node &node);
status_t IncrementGlobalRefCount(media_node_id nodeid, team_id team); status_t IncrementGlobalRefCount(media_node_id nodeid, team_id team);
status_t DecrementGlobalRefCount(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); void FinalReleaseNode(media_node_id nodeid);
/* Add media_node_id of all live nodes to the message /* Add media_node_id of all live nodes to the message

View File

@ -306,7 +306,7 @@ ServerApp::HandleMessage(int32 code, void *data, size_t size)
{ {
const server_unregister_node_request *request = reinterpret_cast<const server_unregister_node_request *>(data); const server_unregister_node_request *request = reinterpret_cast<const server_unregister_node_request *>(data);
server_unregister_node_reply reply; 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)); request->SendReply(rv, &reply, sizeof(reply));
break; break;
} }
@ -471,6 +471,15 @@ ServerApp::HandleMessage(int32 code, void *data, size_t size)
break; break;
} }
case SERVER_SET_NODE_CREATOR:
{
const server_set_node_creator_request *request = reinterpret_cast<const server_set_node_creator_request *>(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: case SERVER_GET_SHARED_BUFFER_AREA:
{ {
const server_get_shared_buffer_area_request *request = reinterpret_cast<const server_get_shared_buffer_area_request *>(data); const server_get_shared_buffer_area_request *request = reinterpret_cast<const server_get_shared_buffer_area_request *>(data);

View File

@ -86,7 +86,7 @@ MediaAddonServer::HandleMessage(int32 code, const void *data, size_t size)
const addonserver_instantiate_dormant_node_request *request = static_cast<const addonserver_instantiate_dormant_node_request *>(data); const addonserver_instantiate_dormant_node_request *request = static_cast<const addonserver_instantiate_dormant_node_request *>(data);
addonserver_instantiate_dormant_node_reply reply; addonserver_instantiate_dormant_node_reply reply;
status_t rv; 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)); request->SendReply(rv, &reply, sizeof(reply));
break; break;
} }