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; }
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); }
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() }
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); }