From ade9d403d429947e2c74e0fb645e7c1b3199fb7c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 13 Oct 2007 23:17:44 +0000 Subject: [PATCH] Implemented loading/unloading of add-ons. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22544 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kits/storage/DiskSystemAddOnManager.cpp | 187 +++++++++++++++++++- src/kits/storage/DiskSystemAddOnManager.h | 9 +- 2 files changed, 187 insertions(+), 9 deletions(-) diff --git a/src/kits/storage/DiskSystemAddOnManager.cpp b/src/kits/storage/DiskSystemAddOnManager.cpp index 07d3e8fa03..7287397f2f 100644 --- a/src/kits/storage/DiskSystemAddOnManager.cpp +++ b/src/kits/storage/DiskSystemAddOnManager.cpp @@ -5,9 +5,17 @@ #include "DiskSystemAddOnManager.h" +#include +#include +#include + +#include +#include #include +#include #include +#include #include #include @@ -19,6 +27,17 @@ DiskSystemAddOnManager* DiskSystemAddOnManager::sManager = NULL; // AddOnImage struct DiskSystemAddOnManager::AddOnImage { + AddOnImage(image_id image) + : image(image), + refCount(0) + { + } + + ~AddOnImage() + { + unload_add_on(image); + } + image_id image; int32 refCount; }; @@ -26,12 +45,23 @@ struct DiskSystemAddOnManager::AddOnImage { // AddOn struct DiskSystemAddOnManager::AddOn { + AddOn(AddOnImage* image, BDiskSystemAddOn* addOn) + : image(image), + addOn(addOn) + { + } + AddOnImage* image; BDiskSystemAddOn* addOn; int32 refCount; }; +// StringSet +struct DiskSystemAddOnManager::StringSet : std::set { +}; + + // Default DiskSystemAddOnManager* DiskSystemAddOnManager::Default() @@ -74,15 +104,27 @@ DiskSystemAddOnManager::Unlock() // LoadDiskSystems -void +status_t DiskSystemAddOnManager::LoadDiskSystems() { AutoLocker _(fLock); if (++fLoadCount > 1) - return; + return B_OK; - // TODO: Load the add-ons ... + StringSet alreadyLoaded; + status_t error = _LoadAddOns(alreadyLoaded, B_USER_ADDONS_DIRECTORY); + + if (error == B_OK) + error = _LoadAddOns(alreadyLoaded, B_COMMON_ADDONS_DIRECTORY); + + if (error == B_OK) + error = _LoadAddOns(alreadyLoaded, B_BEOS_ADDONS_DIRECTORY); + + if (error != B_OK) + UnloadDiskSystems(); + + return error; } @@ -92,10 +134,16 @@ DiskSystemAddOnManager::UnloadDiskSystems() { AutoLocker _(fLock); - if (--fLoadCount == 0) + if (fLoadCount == 0 || --fLoadCount > 0) return; - // TODO: Unload the add-ons ... + fAddOnsToBeUnloaded.AddList(&fAddOns); + fAddOns.MakeEmpty(); + + // put all add-ons -- that will cause them to be deleted as soon as they're + // unused + for (int32 i = fAddOnsToBeUnloaded.CountItems() - 1; i >= 0; i--) + _PutAddOn(i); } @@ -147,13 +195,24 @@ DiskSystemAddOnManager::PutAddOn(BDiskSystemAddOn* _addOn) for (int32 i = 0; AddOn* addOn = _AddOnAt(i); i++) { if (_addOn == addOn->addOn) { - if (addOn->refCount == 0) - debugger("DiskSystemAddOnManager: unbalanced PutAddOn()"); - else + if (addOn->refCount > 1) { addOn->refCount--; + } else { + debugger("Unbalanced call to " + "DiskSystemAddOnManager::PutAddOn()"); + } + return; + } + + for (int32 i = 0; + AddOn* addOn = (AddOn*)fAddOnsToBeUnloaded.ItemAt(i); i++) { + if (_addOn == addOn->addOn) + _PutAddOn(i); return; } } + + debugger("DiskSystemAddOnManager::PutAddOn(): disk system not found"); } @@ -161,6 +220,7 @@ DiskSystemAddOnManager::PutAddOn(BDiskSystemAddOn* _addOn) DiskSystemAddOnManager::DiskSystemAddOnManager() : fLock("disk system add-ons manager"), fAddOns(), + fAddOnsToBeUnloaded(), fLoadCount(0) { } @@ -173,3 +233,114 @@ DiskSystemAddOnManager::_AddOnAt(int32 index) const return (AddOn*)fAddOns.ItemAt(index); } + +// _PutAddOn +void +DiskSystemAddOnManager::_PutAddOn(int32 index) +{ + AddOn* addOn = (AddOn*)fAddOnsToBeUnloaded.ItemAt(index); + if (!addOn) + return; + + if (--addOn->refCount == 0) { + if (--addOn->image->refCount == 0) + delete addOn->image; + + fAddOnsToBeUnloaded.RemoveItem(index); + delete addOn; + } +} + + +// _LoadAddOns +status_t +DiskSystemAddOnManager::_LoadAddOns(StringSet& alreadyLoaded, + directory_which addOnDir) +{ + // get the add-on directory path + BPath path; + status_t error = find_directory(addOnDir, &path, false); + if (error != B_OK) + return error; + + error = path.Append("disk_systems"); + if (error != B_OK) + return error; + + if (!BEntry(path.Path()).Exists()) + return B_OK; + + // open the directory and iterate through its entries + BDirectory directory; + error = directory.SetTo(path.Path()); + if (error != B_OK) + return error; + + entry_ref ref; + while (directory.GetNextRef(&ref) == B_OK) { + // skip, if already loaded + if (alreadyLoaded.find(ref.name) != alreadyLoaded.end()) + continue; + + // get the entry path + BPath entryPath; + error = entryPath.SetTo(&ref); + if (error != B_OK) { + if (error == B_NO_MEMORY) + return error; + continue; + } + + // load the add-on + image_id image = load_add_on(entryPath.Path()); + if (image < 0) + continue; + + AddOnImage* addOnImage = new(nothrow) AddOnImage(image); + if (!addOnImage) { + unload_add_on(image); + return B_NO_MEMORY; + } + ObjectDeleter addOnImageDeleter(addOnImage); + + // get the add-on objects + status_t (*getAddOns)(BList*); + error = get_image_symbol(image, "get_disk_system_add_ons", + B_SYMBOL_TYPE_TEXT, (void**)&getAddOns); + if (error != B_OK) + continue; + + BList addOns; + error = getAddOns(&addOns); + if (error != B_OK || addOns.IsEmpty()) + continue; + + // create and add AddOn objects + int32 count = addOns.CountItems(); + for (int32 i = 0; i < count; i++) { + BDiskSystemAddOn* diskSystemAddOn + = (BDiskSystemAddOn*)addOns.ItemAt(i); + AddOn* addOn = new(nothrow) AddOn(addOnImage, diskSystemAddOn); + if (!addOn) + return B_NO_MEMORY; + + if (fAddOns.AddItem(addOn)) { + addOnImage->refCount++; + addOnImageDeleter.Detach(); + } else { + delete addOn; + return B_NO_MEMORY; + } + } + + // add the add-on name to the set of already loaded add-ons + try { + alreadyLoaded.insert(ref.name); + } catch (std::bad_alloc& exception) { + return B_NO_MEMORY; + } + } + + return B_OK; +} + diff --git a/src/kits/storage/DiskSystemAddOnManager.h b/src/kits/storage/DiskSystemAddOnManager.h index a75ef0e25e..65fe70c45b 100644 --- a/src/kits/storage/DiskSystemAddOnManager.h +++ b/src/kits/storage/DiskSystemAddOnManager.h @@ -5,6 +5,7 @@ #ifndef _DISK_SYSTEM_ADD_ON_MANAGER_H #define _DISK_SYSTEM_ADD_ON_MANAGER_H +#include #include #include @@ -23,7 +24,7 @@ public: void Unlock(); // load/unload all disk system add-ons - void LoadDiskSystems(); + status_t LoadDiskSystems(); void UnloadDiskSystems(); // manager must be locked @@ -37,14 +38,20 @@ public: private: struct AddOnImage; struct AddOn; + struct StringSet; DiskSystemAddOnManager(); AddOn* _AddOnAt(int32 index) const; + void _PutAddOn(int32 index); + + status_t _LoadAddOns(StringSet& alreadyLoaded, + directory_which directory); private: mutable BLocker fLock; BList fAddOns; + BList fAddOnsToBeUnloaded; int32 fLoadCount; static DiskSystemAddOnManager* sManager;