* Use ref counting to determine when to unload a replicants add_on image, fixes #2712.
* Don't delete fStream if we don't own it, would crash ShelfTest on quit. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29439 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,14 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2001-2007, Haiku Inc.
|
* Copyright 2001-2009, Haiku Inc.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef _SHELF_H
|
#ifndef _SHELF_H
|
||||||
#define _SHELF_H
|
#define _SHELF_H
|
||||||
|
|
||||||
|
|
||||||
#include <Dragger.h>
|
#include <Dragger.h>
|
||||||
#include <Handler.h>
|
#include <Handler.h>
|
||||||
#include <List.h>
|
#include <List.h>
|
||||||
|
#include <Locker.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
class BDataIO;
|
class BDataIO;
|
||||||
class BPoint;
|
class BPoint;
|
||||||
@@ -123,6 +127,10 @@ class BShelf : public BHandler {
|
|||||||
bool fAllowZombies;
|
bool fAllowZombies;
|
||||||
bool fTypeEnforced;
|
bool fTypeEnforced;
|
||||||
|
|
||||||
|
typedef std::map<BString, std::pair<image_id, int32> > LoadedImageMap;
|
||||||
|
static LoadedImageMap sLoadedImages;
|
||||||
|
static BLocker sLoadedImageMapLocker;
|
||||||
|
|
||||||
uint32 _reserved[8];
|
uint32 _reserved[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2001-2008, Haiku.
|
* Copyright 2001-2009, Haiku.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -7,11 +7,12 @@
|
|||||||
* Axel Dörfler, [email protected]
|
* Axel Dörfler, [email protected]
|
||||||
* Jérôme Duval
|
* Jérôme Duval
|
||||||
* René Gollent
|
* René Gollent
|
||||||
|
* Alexandre Deckner, [email protected]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! BShelf stores replicant views that are dropped onto it */
|
/*! BShelf stores replicant views that are dropped onto it */
|
||||||
|
|
||||||
|
#include <AutoLock.h>
|
||||||
#include <Beep.h>
|
#include <Beep.h>
|
||||||
#include <Dragger.h>
|
#include <Dragger.h>
|
||||||
#include <Entry.h>
|
#include <Entry.h>
|
||||||
@@ -103,7 +104,7 @@ namespace BPrivate {
|
|||||||
|
|
||||||
struct replicant_data {
|
struct replicant_data {
|
||||||
replicant_data(BMessage *message, BView *view, BDragger *dragger,
|
replicant_data(BMessage *message, BView *view, BDragger *dragger,
|
||||||
BDragger::relation relation, unsigned long id, image_id image);
|
BDragger::relation relation, unsigned long id);
|
||||||
replicant_data();
|
replicant_data();
|
||||||
~replicant_data();
|
~replicant_data();
|
||||||
|
|
||||||
@@ -122,7 +123,6 @@ struct replicant_data {
|
|||||||
BDragger* dragger;
|
BDragger* dragger;
|
||||||
BDragger::relation relation;
|
BDragger::relation relation;
|
||||||
unsigned long id;
|
unsigned long id;
|
||||||
image_id image;
|
|
||||||
status_t error;
|
status_t error;
|
||||||
BView* zombie_view;
|
BView* zombie_view;
|
||||||
};
|
};
|
||||||
@@ -201,14 +201,13 @@ find_replicant(BList &list, const char *className, const char *addOn)
|
|||||||
|
|
||||||
|
|
||||||
replicant_data::replicant_data(BMessage *_message, BView *_view, BDragger *_dragger,
|
replicant_data::replicant_data(BMessage *_message, BView *_view, BDragger *_dragger,
|
||||||
BDragger::relation _relation, unsigned long _id, image_id _image)
|
BDragger::relation _relation, unsigned long _id)
|
||||||
:
|
:
|
||||||
message(_message),
|
message(_message),
|
||||||
view(_view),
|
view(_view),
|
||||||
dragger(NULL),
|
dragger(NULL),
|
||||||
relation(_relation),
|
relation(_relation),
|
||||||
id(_id),
|
id(_id),
|
||||||
image(_image),
|
|
||||||
error(B_OK),
|
error(B_OK),
|
||||||
zombie_view(NULL)
|
zombie_view(NULL)
|
||||||
{
|
{
|
||||||
@@ -222,7 +221,6 @@ replicant_data::replicant_data()
|
|||||||
dragger(NULL),
|
dragger(NULL),
|
||||||
relation(BDragger::TARGET_UNKNOWN),
|
relation(BDragger::TARGET_UNKNOWN),
|
||||||
id(0),
|
id(0),
|
||||||
image(-1),
|
|
||||||
error(B_ERROR),
|
error(B_ERROR),
|
||||||
zombie_view(NULL)
|
zombie_view(NULL)
|
||||||
{
|
{
|
||||||
@@ -231,12 +229,6 @@ replicant_data::replicant_data()
|
|||||||
replicant_data::~replicant_data()
|
replicant_data::~replicant_data()
|
||||||
{
|
{
|
||||||
delete message;
|
delete message;
|
||||||
// we can't delete the view or image here since
|
|
||||||
// 1 - the view may already have been deleted and thus our pointer is invalid
|
|
||||||
// and 2 - we don't know what order they will be deleted in, so we can't unload the image yet
|
|
||||||
// since the destructor code for the view might still be needed if it has not been destroyed yet.
|
|
||||||
// this does mean we technically leak add-on images on exit, but I don't see a way around that,
|
|
||||||
// and in theory they should be unloaded by team cleanup on exit anyways.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
@@ -463,6 +455,9 @@ ReplicantViewFilter::Filter(BMessage *message, BHandler **handler)
|
|||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
BShelf::LoadedImageMap BShelf::sLoadedImages;
|
||||||
|
BLocker BShelf::sLoadedImageMapLocker("BShelf loaded image map");
|
||||||
|
|
||||||
|
|
||||||
BShelf::BShelf(BView *view, bool allowDrags, const char *shelfType)
|
BShelf::BShelf(BView *view, bool allowDrags, const char *shelfType)
|
||||||
: BHandler(shelfType)
|
: BHandler(shelfType)
|
||||||
@@ -498,8 +493,11 @@ BShelf::~BShelf()
|
|||||||
{
|
{
|
||||||
Save();
|
Save();
|
||||||
|
|
||||||
delete fEntry;
|
// we own fStream only when fEntry is set
|
||||||
delete fStream;
|
if (fEntry) {
|
||||||
|
delete fEntry;
|
||||||
|
delete fStream;
|
||||||
|
}
|
||||||
|
|
||||||
while (fReplicants.CountItems() > 0) {
|
while (fReplicants.CountItems() > 0) {
|
||||||
replicant_data *data = (replicant_data *)fReplicants.ItemAt(0);
|
replicant_data *data = (replicant_data *)fReplicants.ItemAt(0);
|
||||||
@@ -1135,8 +1133,6 @@ BShelf::_InitData(BEntry *entry, BDataIO *stream, BView *view,
|
|||||||
status_t
|
status_t
|
||||||
BShelf::_DeleteReplicant(replicant_data* item)
|
BShelf::_DeleteReplicant(replicant_data* item)
|
||||||
{
|
{
|
||||||
bool loadedImage = item->message->FindBool("_loaded_image_");
|
|
||||||
|
|
||||||
BView *view = item->view;
|
BView *view = item->view;
|
||||||
if (view == NULL)
|
if (view == NULL)
|
||||||
view = item->zombie_view;
|
view = item->zombie_view;
|
||||||
@@ -1162,14 +1158,26 @@ BShelf::_DeleteReplicant(replicant_data* item)
|
|||||||
delete item->dragger;
|
delete item->dragger;
|
||||||
}
|
}
|
||||||
|
|
||||||
image_id image = item->image;
|
// Update use count for image and unload if necessary
|
||||||
|
const char* signature = NULL;
|
||||||
|
if (item->message->FindString("add_on", &signature) == B_OK
|
||||||
|
&& signature != NULL) {
|
||||||
|
AutoLock<BLocker> lock(sLoadedImageMapLocker);
|
||||||
|
if (lock.IsLocked()) {
|
||||||
|
LoadedImageMap::iterator it = sLoadedImages.find(BString(signature));
|
||||||
|
|
||||||
|
if (it != sLoadedImages.end()) {
|
||||||
|
(*it).second.second -= 1;
|
||||||
|
if ((*it).second.second <= 0) {
|
||||||
|
unload_add_on((*it).second.first);
|
||||||
|
sLoadedImages.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delete item;
|
delete item;
|
||||||
|
|
||||||
if (loadedImage && image >= 0)
|
|
||||||
unload_add_on(image);
|
|
||||||
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1218,8 +1226,24 @@ BShelf::_AddReplicant(BMessage *data, BPoint *location, uint32 uniqueID)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Instantiate the object, if this fails we have a zombie
|
// Instantiate the object, if this fails we have a zombie
|
||||||
image_id image;
|
image_id image = -1;
|
||||||
BArchivable *archivable = _InstantiateObject(data, &image);
|
BArchivable *archivable = _InstantiateObject(data, &image);
|
||||||
|
|
||||||
|
// Update use count for image
|
||||||
|
const char* signature = NULL;
|
||||||
|
if (data->FindString("add_on", &signature) == B_OK && signature != NULL) {
|
||||||
|
AutoLock<BLocker> lock(sLoadedImageMapLocker);
|
||||||
|
if (lock.IsLocked()) {
|
||||||
|
LoadedImageMap::iterator it = sLoadedImages.find(BString(signature));
|
||||||
|
|
||||||
|
if (it == sLoadedImages.end())
|
||||||
|
sLoadedImages.insert(LoadedImageMap::value_type(
|
||||||
|
BString(signature), std::pair<image_id, int>(image, 1)));
|
||||||
|
else
|
||||||
|
(*it).second.second += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BView *view = dynamic_cast<BView*>(archivable);
|
BView *view = dynamic_cast<BView*>(archivable);
|
||||||
if (archivable != NULL && view == NULL) {
|
if (archivable != NULL && view == NULL) {
|
||||||
printf("Replicant was rejected: it's not a view!");
|
printf("Replicant was rejected: it's not a view!");
|
||||||
@@ -1247,11 +1271,8 @@ BShelf::_AddReplicant(BMessage *data, BPoint *location, uint32 uniqueID)
|
|||||||
data->RemoveName("_drop_point_");
|
data->RemoveName("_drop_point_");
|
||||||
data->RemoveName("_drop_offset_");
|
data->RemoveName("_drop_offset_");
|
||||||
|
|
||||||
if (image >= 0)
|
|
||||||
data->AddBool("_loaded_image_", true);
|
|
||||||
|
|
||||||
replicant_data *item = new replicant_data(data, replicant, dragger,
|
replicant_data *item = new replicant_data(data, replicant, dragger,
|
||||||
relation, uniqueID, image);
|
relation, uniqueID);
|
||||||
|
|
||||||
item->error = B_OK;
|
item->error = B_OK;
|
||||||
item->zombie_view = zombie;
|
item->zombie_view = zombie;
|
||||||
|
|||||||
Reference in New Issue
Block a user