BMediaRoster: Reintroduce the undertaker class

* This has been necessary due to the undefined call order of
of static objects. Fixes #12315.
* The bug has been caused by the linker which free unused resources,
making the BMediaRoster to run in a zombie state. In this state
anything such as a message could make the looper to crash.
* The class is reintroduced with some differences though, we are
going to protect it from another thread calling Roster() while the
BMediaRoster is quitting and implement BMediaRosterEx::Quit.
* Unregister registrar notifications before we quit our thread. Avoid
to uninitialize anything from QuitRequested as it may cause problems.
This commit is contained in:
Dario Casalinuovo 2015-09-01 13:02:07 +02:00
parent a33d19b0a4
commit 7d337b23b7
2 changed files with 33 additions and 9 deletions

View File

@ -37,6 +37,8 @@ public:
BMediaRosterEx(status_t* out_error);
virtual ~BMediaRosterEx();
virtual void Quit();
status_t SaveNodeConfiguration(BMediaNode* node);
status_t LoadNodeConfiguration(media_addon_id addonid,
int32 flavorid, BMessage* out_msg);

View File

@ -86,6 +86,22 @@ static bool sServerIsUp = false;
static List<RosterNotification> sNotificationList;
static BLocker sInitLocker("BMediaRoster::Roster locker");
class MediaRosterUndertaker {
public:
~MediaRosterUndertaker()
{
BAutolock _(sInitLocker);
if (BMediaRoster::CurrentRoster() != NULL
&& BMediaRoster::CurrentRoster()->Lock()) {
BMediaRoster::CurrentRoster()->Quit();
}
}
};
static MediaRosterUndertaker sMediaRosterUndertaker;
} // namespace media
} // namespace BPrivate
@ -96,8 +112,8 @@ BMediaRosterEx::BMediaRosterEx(status_t* _error)
:
BMediaRoster()
{
gDormantNodeManager = new DormantNodeManager;
gTimeSourceObjectManager = new TimeSourceObjectManager;
gDormantNodeManager = new DormantNodeManager();
gTimeSourceObjectManager = new TimeSourceObjectManager();
*_error = BuildConnections();
@ -111,6 +127,19 @@ BMediaRosterEx::BMediaRosterEx(status_t* _error)
}
void
BMediaRosterEx::Quit()
{
if (be_roster->StopWatching(BMessenger(this, this)) != B_OK)
TRACE("Can't unregister roster notifications");
if (sNotificationList.CountItems() != 0)
sNotificationList.MakeEmpty();
BMediaRoster::Quit();
}
status_t
BMediaRosterEx::BuildConnections()
{
@ -3474,13 +3503,6 @@ bool
BMediaRoster::QuitRequested()
{
CALLED();
if (be_roster->StopWatching(BMessenger(this, this)) != B_OK)
TRACE("Can't unregister roster notifications");
if (sNotificationList.CountItems() != 0)
sNotificationList.MakeEmpty();
return true;
}