hrev48657 adds 3 changesets to branch 'master' old head: d52ab7d045a9bedb40509bf7fd67d45c46a507fe new head: 84316965edb8b5280b5ab8997cae7240ef3526e0 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=8431696+%5Ed52ab7d ---------------------------------------------------------------------------- 05bffa6: HaikuDepot: Check thread ids before waiting for threads. These threads are not created if creating a semaphore failed, so it's not fixing a bug which anyone has likely encountered. 09f8290: HaikuDepot: Always init the thread ids... ... also in case creating the semaphores fails. 8431696: HaikuDepot: Populate package contents asynchronously Also remove debugging output with O(n*n) runtime. The problem for which I write this is already understood, but it is not yet fixed. [ Stephan Aßmus <superstippi@xxxxxx> ] ---------------------------------------------------------------------------- 4 files changed, 212 insertions(+), 57 deletions(-) src/apps/haikudepot/ui/MainWindow.cpp | 14 +- src/apps/haikudepot/ui/PackageContentsView.cpp | 212 +++++++++++++++++---- src/apps/haikudepot/ui/PackageContentsView.h | 23 ++- src/apps/haikudepot/ui/PackageInfoView.cpp | 20 +- ############################################################################ Commit: 05bffa62e63aa5c4fcbb3c69cf5d2a8017482289 URL: http://cgit.haiku-os.org/haiku/commit/?id=05bffa6 Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Jan 10 22:08:52 2015 UTC HaikuDepot: Check thread ids before waiting for threads. These threads are not created if creating a semaphore failed, so it's not fixing a bug which anyone has likely encountered. ---------------------------------------------------------------------------- diff --git a/src/apps/haikudepot/ui/MainWindow.cpp b/src/apps/haikudepot/ui/MainWindow.cpp index 7549490..f2fa790 100644 --- a/src/apps/haikudepot/ui/MainWindow.cpp +++ b/src/apps/haikudepot/ui/MainWindow.cpp @@ -266,14 +266,16 @@ MainWindow::~MainWindow() BPackageRoster().StopWatching(this); fTerminating = true; - if (fModelWorker > 0) + if (fModelWorker >= 0) wait_for_thread(fModelWorker, NULL); delete_sem(fPendingActionsSem); - wait_for_thread(fPendingActionsWorker, NULL); + if (fPendingActionsWorker >= 0) + wait_for_thread(fPendingActionsWorker, NULL); delete_sem(fPackageToPopulateSem); - wait_for_thread(fPopulatePackageWorker, NULL); + if (fPopulatePackageWorker >= 0) + wait_for_thread(fPopulatePackageWorker, NULL); if (fScreenshotWindow != NULL && fScreenshotWindow->Lock()) fScreenshotWindow->Quit(); ############################################################################ Commit: 09f8290534c965883f44bb0917249b760b08baa6 URL: http://cgit.haiku-os.org/haiku/commit/?id=09f8290 Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Jan 10 22:19:25 2015 UTC HaikuDepot: Always init the thread ids... ... also in case creating the semaphores fails. ---------------------------------------------------------------------------- diff --git a/src/apps/haikudepot/ui/MainWindow.cpp b/src/apps/haikudepot/ui/MainWindow.cpp index f2fa790..742348f 100644 --- a/src/apps/haikudepot/ui/MainWindow.cpp +++ b/src/apps/haikudepot/ui/MainWindow.cpp @@ -611,7 +611,8 @@ MainWindow::_InitWorkerThreads() "Planet Express", B_NORMAL_PRIORITY, this); if (fPendingActionsWorker >= 0) resume_thread(fPendingActionsWorker); - } + } else + fPendingActionsWorker = -1; fPackageToPopulateSem = create_sem(0, "PopulatePackage"); if (fPackageToPopulateSem >= 0) { @@ -619,7 +620,8 @@ MainWindow::_InitWorkerThreads() "Package Populator", B_NORMAL_PRIORITY, this); if (fPopulatePackageWorker >= 0) resume_thread(fPopulatePackageWorker); - } + } else + fPopulatePackageWorker = -1; } ############################################################################ Revision: hrev48657 Commit: 84316965edb8b5280b5ab8997cae7240ef3526e0 URL: http://cgit.haiku-os.org/haiku/commit/?id=8431696 Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Jan 10 22:37:19 2015 UTC HaikuDepot: Populate package contents asynchronously Also remove debugging output with O(n*n) runtime. The problem for which I write this is already understood, but it is not yet fixed. ---------------------------------------------------------------------------- diff --git a/src/apps/haikudepot/ui/PackageContentsView.cpp b/src/apps/haikudepot/ui/PackageContentsView.cpp index e508df3..ebd8949 100644 --- a/src/apps/haikudepot/ui/PackageContentsView.cpp +++ b/src/apps/haikudepot/ui/PackageContentsView.cpp @@ -10,21 +10,23 @@ #include <Autolock.h> #include <Catalog.h> +#include <FindDirectory.h> #include <MessageFormat.h> -#include <ScrollBar.h> -#include <Window.h> #include <LayoutBuilder.h> #include <LayoutUtils.h> #include <OutlineListView.h> #include <Path.h> +#include <ScrollBar.h> #include <ScrollView.h> +#include <StringItem.h> -#include <package/hpkg/PackageReader.h> +#include <package/PackageDefs.h> #include <package/hpkg/NoErrorOutput.h> #include <package/hpkg/PackageContentHandler.h> #include <package/hpkg/PackageEntry.h> -#include "MainWindow.h" -#include "PackageAction.h" +#include <package/hpkg/PackageReader.h> + +using namespace BPackageKit; using BPackageKit::BHPKG::BNoErrorOutput; using BPackageKit::BHPKG::BPackageContentHandler; @@ -81,6 +83,7 @@ public: BStringItem(entry->Name()), fEntry(entry) { + printf("PackageEntryItem(%s)\n", entry->Name()); } inline const BPackageEntry* PackageEntry() const @@ -96,45 +99,70 @@ private: // #pragma mark - PackageContentOutliner -class PackageContentsView::PackageContentOutliner - : public BPackageContentHandler { - +class PackageContentOutliner : public BPackageContentHandler { public: - PackageContentOutliner(BOutlineListView* listView) + PackageContentOutliner(BOutlineListView* listView, + const PackageInfo* packageInfo, + BLocker& packageLock, PackageInfoRef& packageInfoRef) : fListView(listView), fLastParentEntry(NULL), fLastParentItem(NULL), fLastEntry(NULL), - fLastItem(NULL) + fLastItem(NULL), + + fPackageInfoToPopulate(packageInfo), + fPackageLock(packageLock), + fPackageInfoRef(packageInfoRef) { } virtual status_t HandleEntry(BPackageEntry* entry) { + printf("HandleEntry(%s/%s)\n", + entry->Parent() != NULL ? entry->Parent()->Name() : "NULL", + entry->Name()); + + { + // Check if we are still supposed to popuplate the list + BAutolock lock(&fPackageLock); + if (fPackageInfoRef.Get() != fPackageInfoToPopulate) + return B_ERROR; + } + + if (!fListView->LockLooper()) + return B_ERROR; + PackageEntryItem* item = new PackageEntryItem(entry); if (entry->Parent() == NULL) { + printf(" adding root entry\n"); fListView->AddItem(item); + fLastParentEntry = NULL; + fLastParentItem = NULL; } else if (entry->Parent() == fLastEntry) { + printf(" adding to last entry %s\n", fLastEntry->Name()); fListView->AddUnder(item, fLastItem); fLastParentEntry = fLastEntry; fLastParentItem = fLastItem; } else if (entry->Parent() == fLastParentEntry) { + printf(" adding to last parent %s\n", fLastParentEntry->Name()); fListView->AddUnder(item, fLastParentItem); } else { // Not the last parent entry, need to search for the parent // among the already added list items. bool foundParent = false; - for (int32 i = 0; i < fListView->CountItems(); i++) { + for (int32 i = 0; i < fListView->FullListCountItems(); i++) { PackageEntryItem* listItem - = dynamic_cast<PackageEntryItem*>(fListView->ItemAt(i)); + = dynamic_cast<PackageEntryItem*>( + fListView->FullListItemAt(i)); if (listItem == NULL) continue; if (listItem->PackageEntry() == entry->Parent()) { fLastParentEntry = listItem->PackageEntry(); fLastParentItem = listItem; - fListView->AddUnder(item, fLastParentItem); + printf(" found parent %s\n", listItem->Text()); + fListView->AddUnder(item, listItem); foundParent = true; break; } @@ -145,12 +173,16 @@ public: printf("Did not find parent entry for %s (%s)!\n", entry->Name(), entry->Parent()->Name()); fListView->AddItem(item); + fLastParentEntry = NULL; + fLastParentItem = NULL; } } fLastEntry = entry; fLastItem = item; + fListView->UnlockLooper(); + return B_OK; } @@ -183,6 +215,10 @@ private: const BPackageEntry* fLastEntry; PackageEntryItem* fLastItem; + + const PackageInfo* fPackageInfoToPopulate; + BLocker& fPackageLock; + PackageInfoRef& fPackageInfoRef; }; @@ -192,7 +228,7 @@ private: PackageContentsView::PackageContentsView(const char* name) : BView("package_contents_view", B_WILL_DRAW), - fLayout(new BGroupLayout(B_HORIZONTAL)) + fPackageLock("package contents populator lock") { fContentListView = new BOutlineListView("content list view", B_SINGLE_SELECTION_LIST); @@ -204,12 +240,18 @@ PackageContentsView::PackageContentsView(const char* name) .Add(scrollView, 1.0f) .SetInsets(0.0f, -1.0f, -1.0f, -1.0f) ; + + _InitContentPopulator(); } PackageContentsView::~PackageContentsView() { Clear(); + + delete_sem(fContentPopulatorSem); + if (fContentPopulator >= 0) + wait_for_thread(fContentPopulator, NULL); } @@ -228,39 +270,135 @@ PackageContentsView::AllAttached() void -PackageContentsView::SetPackage(const PackageInfo& package) +PackageContentsView::SetPackage(const PackageInfoRef& package) { + if (fPackage == package) + return; + + printf("PackageContentsView::SetPackage(%s)\n", + package.Get() != NULL ? package->Title().String() : "NULL"); + Clear(); - if (package.IsLocalFile() ) { + { + BAutolock lock(&fPackageLock); + fPackage = package; + } + release_sem_etc(fContentPopulatorSem, 1, 0); +} + + +void +PackageContentsView::Clear() +{ + { + BAutolock lock(&fPackageLock); + fPackage.Unset(); + } + + fContentListView->MakeEmpty(); +} + + +// #pragma mark - private + + +void +PackageContentsView::_InitContentPopulator() +{ + fContentPopulatorSem = create_sem(0, "PopulatePackageContents"); + if (fContentPopulatorSem >= 0) { + fContentPopulator = spawn_thread(&_ContentPopulatorThread, + "Package Contents Populator", B_NORMAL_PRIORITY, this); + if (fContentPopulator >= 0) + resume_thread(fContentPopulator); + } else + fContentPopulator = -1; +} + + +/*static*/ int32 +PackageContentsView::_ContentPopulatorThread(void* arg) +{ + PackageContentsView* view = reinterpret_cast<PackageContentsView*>(arg); + + while (acquire_sem(view->fContentPopulatorSem) == B_OK) { + PackageInfoRef package; + { + BAutolock lock(&view->fPackageLock); + package = view->fPackage; + } + + if (package.Get() != NULL) + view->_PopuplatePackageContens(*package.Get()); + } + + return 0; +} + + +void +PackageContentsView::_PopuplatePackageContens(const PackageInfo& package) +{ + BPath packagePath; + + // Obtain path to the package file + if (package.IsLocalFile()) { BString pathString = package.LocalFilePath(); - BPath packagePath; packagePath.SetTo(pathString.String()); - - BNoErrorOutput errorOutput; - BPackageReader reader(&errorOutput); - - status_t status = reader.Init(packagePath.Path()); - if (status != B_OK) { - printf("PackageContentsView::SetPackage(): failed to init " - "BPackageReader(%s): %s\n", - packagePath.Path(), strerror(status)); + } else { + int32 installLocation = _InstallLocation(package); + if (installLocation == B_PACKAGE_INSTALLATION_LOCATION_SYSTEM) { + if (find_directory(B_SYSTEM_PACKAGES_DIRECTORY, &packagePath) + != B_OK) { + return; + } + } else if (installLocation == B_PACKAGE_INSTALLATION_LOCATION_HOME) { + if (find_directory(B_USER_PACKAGES_DIRECTORY, &packagePath) + != B_OK) { + return; + } + } else { + printf("PackageContentsView::_PopuplatePackageContens(): " + "unknown install location"); return; } - - // Scan package contents and populate list - PackageContentOutliner contentHandler(fContentListView); - status = reader.ParseContent(&contentHandler); - if (status != B_OK) { - printf("PackageContentsView::SetPackage(): " - "failed parse package contents: %s\n", strerror(status)); - } + + packagePath.Append(package.FileName()); + } + + // Setup a BPackageReader + BNoErrorOutput errorOutput; + BPackageReader reader(&errorOutput); + + status_t status = reader.Init(packagePath.Path()); + if (status != B_OK) { + printf("PackageContentsView::_PopuplatePackageContens(): " + "failed to init BPackageReader(%s): %s\n", + packagePath.Path(), strerror(status)); + return; + } + + // Scan package contents and populate list + PackageContentOutliner contentHandler(fContentListView, &package, + fPackageLock, fPackage); + status = reader.ParseContent(&contentHandler); + if (status != B_OK) { + printf("PackageContentsView::SetPackage(): " + "failed parse package contents: %s\n", strerror(status)); } } -void -PackageContentsView::Clear() +int32 +PackageContentsView::_InstallLocation(const PackageInfo& package) const { - fContentListView->MakeEmpty(); + const PackageInstallationLocationSet& locations + = package.InstallationLocations(); + + // If the package is already installed, return its first installed location + if (locations.size() != 0) + return *locations.begin(); + + return B_PACKAGE_INSTALLATION_LOCATION_SYSTEM; } diff --git a/src/apps/haikudepot/ui/PackageContentsView.h b/src/apps/haikudepot/ui/PackageContentsView.h index d311c2a..b80fe71 100644 --- a/src/apps/haikudepot/ui/PackageContentsView.h +++ b/src/apps/haikudepot/ui/PackageContentsView.h @@ -5,10 +5,13 @@ #ifndef PACKAGE_CONTENTS_VIEW_H #define PACKAGE_CONTENTS_VIEW_H -#include <OutlineListView.h> +#include <Locker.h> #include <View.h> + #include "PackageInfo.h" -#include "ScrollableGroupView.h" + +class BOutlineListView; + class PackageContentsView : public BView { public: @@ -18,14 +21,24 @@ public: virtual void AttachedToWindow(); virtual void AllAttached(); - void SetPackage(const PackageInfo& package); + void SetPackage(const PackageInfoRef& package); void Clear(); private: - class PackageContentOutliner; + void _InitContentPopulator(); + static int32 _ContentPopulatorThread(void* arg); + void _PopuplatePackageContens( + const PackageInfo& package); + int32 _InstallLocation( + const PackageInfo& package) const; - BGroupLayout* fLayout; +private: BOutlineListView* fContentListView; + + thread_id fContentPopulator; + sem_id fContentPopulatorSem; + BLocker fPackageLock; + PackageInfoRef fPackage; }; #endif // PACKAGE_CONTENTS_VIEW_H diff --git a/src/apps/haikudepot/ui/PackageInfoView.cpp b/src/apps/haikudepot/ui/PackageInfoView.cpp index 95e615b..821406a 100644 --- a/src/apps/haikudepot/ui/PackageInfoView.cpp +++ b/src/apps/haikudepot/ui/PackageInfoView.cpp @@ -1191,7 +1191,7 @@ public: { } - void SetPackage(const PackageInfo& package) + void SetPackage(const PackageInfoRef& package) { fPackageContents->SetPackage(package); } @@ -1294,13 +1294,13 @@ public: Clear(); } - void SetPackage(const PackageInfo& package, bool switchToDefaultTab) + void SetPackage(const PackageInfoRef& package, bool switchToDefaultTab) { if (switchToDefaultTab) Select(0); - fAboutView->SetPackage(package); - fUserRatingsView->SetPackage(package); - fChangelogView->SetPackage(package); + fAboutView->SetPackage(*package.Get()); + fUserRatingsView->SetPackage(*package.Get()); + fChangelogView->SetPackage(*package.Get()); fContentsView->SetPackage(package); } @@ -1404,8 +1404,8 @@ PackageInfoView::MessageReceived(BMessage* message) break; } - const PackageInfo& package = *fPackageListener->Package().Get(); - if (package.Title() != title) + const PackageInfoRef& package = fPackageListener->Package(); + if (package->Title() != title) break; BAutolock _(fModelLock); @@ -1417,11 +1417,11 @@ PackageInfoView::MessageReceived(BMessage* message) if ((changes & PKG_CHANGED_RATINGS) != 0) { fPagesView->SetPackage(package, false); - fTitleView->SetPackage(package); + fTitleView->SetPackage(*package.Get()); } if ((changes & PKG_CHANGED_STATE) != 0) { - fPackageActionView->SetPackage(package); + fPackageActionView->SetPackage(*package.Get()); } break; @@ -1445,7 +1445,7 @@ PackageInfoView::SetPackage(const PackageInfoRef& packageRef) fTitleView->SetPackage(package); fPackageActionView->SetPackage(package); - fPagesView->SetPackage(package, switchToDefaultTab); + fPagesView->SetPackage(packageRef, switchToDefaultTab); fCardLayout->SetVisibleItem(1);