inline
    int UserInfoCache::updateUserInfo(int userId, UserInfo *userInfo)
    {
        int ret = 1;
//..
// Although we intend to update the information, we first acquire a *read*
// *lock* to locate the item.  This allows other threads to read the list while
// we find the item.  If we do not locate the item we can simply release the
// *read* *lock* and return an error without causing any other *reading* thread
// to block.  (Again, other writers *will* block until this *read* *lock* is
// released.)
//..
        d_lock.lockRead();
        InfoMap::iterator it = d_infoMap.find(userId);
        if (d_infoMap.end() != it) {
//..
// Since 'it != end()', we found the item.  Now we need to upgrade to a *write*
// *lock*.  If we can't do this atomically, then we need to locate the item
// again.  This is because another thread may have changed 'd_infoMap' during
// the time between our *read* and *write* locks.
//..
            if (d_lock.upgradeToWriteLock()) {
                it = d_infoMap.find(userId);
            }
//..
// This is a little more costly, but since we don't expect many concurrent
// writes, it should not happen often.  In the (likely) event that we do
// upgrade to a *write* *lock* atomically, then the second lookup above is not
// performed.  In any case, we can now update the information and release the
// lock, since we already have a pointer to the item and we know that the list
// could not have been changed by anyone else.
//..
            if (d_infoMap.end() != it) {
                it->second = *userInfo;
                ret = 0;
            }
            d_lock.unlock();
        }
        else {
            d_lock.unlock();
        }
        return ret;
    }
    inline
    int UserInfoCache::getUserInfo(int userId, UserInfo *userInfo)
    {
        int ret = 1;
//..
// Getting the user info does not require any write access.  We do, however,
// need read access to 'd_infoMap', which is controlled by 'd_lock'.  (Note
// that writers *will* block until this *read* *lock* is released, but
// concurrent reads are allowed.)  The user info is copied into the
// caller-owned location 'userInfo'.
//..
        d_lock.lockRead();
        InfoMap::iterator it = d_infoMap.find(userId);
        if (d_infoMap.end() != it) {
            *userInfo = it->second;
            ret = 0;
        }
        d_lock.unlock();
        return ret;
    }
示例#3
0
void
MediaAddonServer::_AddOnRemoved(ino_t fileNode)
{
	// TODO: locking?

	FileMap::iterator foundFile = fFileMap.find(fileNode);
	if (foundFile == fFileMap.end()) {
		ERROR("MediaAddonServer::_AddOnRemoved: inode %Ld removed, but no "
			"media add-on found\n", fileNode);
		return;
	}

	media_addon_id id = foundFile->second;
	fFileMap.erase(foundFile);

	int32 oldFlavorCount;
	InfoMap::iterator foundInfo = fInfoMap.find(id);

	if (foundInfo == fInfoMap.end()) {
		ERROR("MediaAddonServer::_AddOnRemoved: couldn't get addon info for "
			"add-on %ld\n", id);
		oldFlavorCount = 1000;
	} else {
		AddOnInfo& info = foundInfo->second;
		oldFlavorCount = info.flavor_count;

		_DestroyInstantiatedFlavors(info);
		_PutAddonIfPossible(info);

		if (info.addon) {
			ERROR("MediaAddonServer::_AddOnRemoved: couldn't unload addon "
				"%ld since flavors are in use\n", id);
		}

		fInfoMap.erase(foundInfo);
	}

	gDormantNodeManager->UnregisterAddOn(id);

	BPrivate::media::notifications::FlavorsChanged(id, 0, oldFlavorCount);
}
示例#4
0
void
MediaAddonServer::_AddOnAdded(const char* path, ino_t fileNode)
{
	TRACE("\n\nMediaAddonServer::_AddOnAdded: path %s\n", path);

	media_addon_id id = gDormantNodeManager->RegisterAddOn(path);
	if (id <= 0) {
		ERROR("MediaAddonServer::_AddOnAdded: failed to register add-on %s\n",
			path);
		return;
	}

	TRACE("MediaAddonServer::_AddOnAdded: loading addon %ld now...\n", id);

	BMediaAddOn* addon = gDormantNodeManager->GetAddOn(id);
	if (addon == NULL) {
		ERROR("MediaAddonServer::_AddOnAdded: failed to get add-on %s\n", path);
		gDormantNodeManager->UnregisterAddOn(id);
		return;
	}

	TRACE("MediaAddonServer::_AddOnAdded: loading finished, id %ld\n", id);

	try {
		// put file's inode and addon's id into map
		fFileMap.insert(std::make_pair(fileNode, id));

		AddOnInfo info;
		fInfoMap.insert(std::make_pair(id, info));
	} catch (std::bad_alloc& exception) {
		fFileMap.erase(fileNode);
		return;
	}

	InfoMap::iterator found = fInfoMap.find(id);
	AddOnInfo& info = found->second;

	info.id = id;
	info.wants_autostart = false; // temporary default
	info.flavor_count = 0;
	info.addon = addon;

	// scan the flavors
	_ScanAddOnFlavors(addon);

	// need to call BMediaNode::WantsAutoStart()
	// after the flavors have been scanned
	info.wants_autostart = addon->WantsAutoStart();

	if (info.wants_autostart)
		TRACE("add-on %ld WantsAutoStart!\n", id);

	// During startup, first all add-ons are loaded, then all
	// nodes (flavors) representing physical inputs and outputs
	// are instantiated. Next, all add-ons that need autostart
	// will be autostarted. Finally, add-ons that don't have
	// any active nodes (flavors) will be unloaded.

	// After startup is done, we simply do it for each new
	// loaded add-on, too.
	if (!fStartup) {
		_InstantiatePhysicalInputsAndOutputs(info);
		_InstantiateAutostartFlavors(info);
		_PutAddonIfPossible(info);

		// since something might have changed
		server_rescan_defaults_command cmd;
		SendToServer(SERVER_RESCAN_DEFAULTS, &cmd, sizeof(cmd));
	}

	// we do not call gDormantNodeManager->PutAddOn(id)
	// since it is done by _PutAddonIfPossible()
}
示例#5
0
void
MediaAddonServer::_ScanAddOnFlavors(BMediaAddOn* addon)
{
	ASSERT(addon->AddonID() > 0);

	TRACE("MediaAddonServer::_ScanAddOnFlavors: id %ld\n", addon->AddonID());

	// cache the media_addon_id in a local variable to avoid
	// calling BMediaAddOn::AddonID() too often
	media_addon_id addonID = addon->AddonID();

	// update the cached flavor count, get oldflavorcount and newflavorcount

	InfoMap::iterator found = fInfoMap.find(addonID);
	ASSERT(found != fInfoMap.end());

	AddOnInfo& info = found->second;
	int32 oldFlavorCount = info.flavor_count;
	int32 newFlavorCount = addon->CountFlavors();
	info.flavor_count = newFlavorCount;

	TRACE("%ld old flavors, %ld new flavors\n", oldflavorcount, newFlavorCount);

	// during the first update (i == 0), the server removes old dormant_flavor_infos
	for (int i = 0; i < newFlavorCount; i++) {
		const flavor_info* flavorInfo;
		TRACE("flavor %d:\n", i);
		if (addon->GetFlavorAt(i, &flavorInfo) != B_OK) {
			ERROR("MediaAddonServer::_ScanAddOnFlavors GetFlavorAt failed for "
				"index %d!\n", i);
			continue;
		}

#if DEBUG >= 2
		DumpFlavorInfo(flavorInfo);
#endif

		dormant_flavor_info dormantFlavorInfo;
		dormantFlavorInfo = *flavorInfo;
		dormantFlavorInfo.node_info.addon = addonID;
		dormantFlavorInfo.node_info.flavor_id = flavorInfo->internal_id;
		strlcpy(dormantFlavorInfo.node_info.name, flavorInfo->name,
			B_MEDIA_NAME_LENGTH);

		size_t flattenedSize = dormantFlavorInfo.FlattenedSize();
		size_t messageSize = flattenedSize
			+ sizeof(server_register_dormant_node_command);
		server_register_dormant_node_command* message
			= (server_register_dormant_node_command*)malloc(messageSize);
		if (message == NULL)
			break;

		// The server should remove previously registered "dormant_flavor_info"s
		// during the first update, but after  the first iteration, we don't
		// want the server to anymore remove old dormant_flavor_infos
		message->purge_id = i == 0 ? addonID : 0;

		message->type = dormantFlavorInfo.TypeCode();
		message->flattened_size = flattenedSize;
		dormantFlavorInfo.Flatten(message->flattened_data, flattenedSize);

		status_t status = SendToServer(SERVER_REGISTER_DORMANT_NODE,
			message, messageSize);
		if (status != B_OK) {
			ERROR("MediaAddonServer::_ScanAddOnFlavors: couldn't register "
				"dormant node: %s\n", strerror(status));
		}

		free(message);
	}

	// TODO: we currently pretend that all old flavors have been removed, this
	// could probably be done in a smarter way
	BPrivate::media::notifications::FlavorsChanged(addonID, newFlavorCount,
		oldFlavorCount);
}