Implemented loading/unloading of add-ons.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22544 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2007-10-13 23:17:44 +00:00
parent 445e975fda
commit ade9d403d4
2 changed files with 187 additions and 9 deletions

View File

@ -5,9 +5,17 @@
#include "DiskSystemAddOnManager.h"
#include <exception>
#include <set>
#include <string>
#include <Directory.h>
#include <Entry.h>
#include <image.h>
#include <Path.h>
#include <AppMisc.h>
#include <AutoDeleter.h>
#include <AutoLocker.h>
#include <DiskSystemAddOn.h>
@ -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<std::string> {
};
// Default
DiskSystemAddOnManager*
DiskSystemAddOnManager::Default()
@ -74,15 +104,27 @@ DiskSystemAddOnManager::Unlock()
// LoadDiskSystems
void
status_t
DiskSystemAddOnManager::LoadDiskSystems()
{
AutoLocker<BLocker> _(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<BLocker> _(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<AddOnImage> 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;
}

View File

@ -5,6 +5,7 @@
#ifndef _DISK_SYSTEM_ADD_ON_MANAGER_H
#define _DISK_SYSTEM_ADD_ON_MANAGER_H
#include <FindDirectory.h>
#include <List.h>
#include <Locker.h>
@ -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;