Changed the somewhat bold BLocker usage to a more straight forward semaphore

based mechanism to pause and eventually cancel the WorkerThread. This also works
now when the CopyEngine is still collecting file informartion (ticket #4153).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31912 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2009-07-29 15:04:02 +00:00
parent 4bfd2003b4
commit d7737cc84f
6 changed files with 104 additions and 60 deletions
+58 -15
View File
@@ -26,6 +26,39 @@
using std::nothrow; using std::nothrow;
// SemaphoreLocking
class SemaphoreLocking {
public:
inline bool Lock(sem_id* lockable)
{
return acquire_sem(*lockable) == B_OK;
}
inline void Unlock(sem_id* lockable)
{
release_sem(*lockable);
}
};
// SemaphoreLocker
class SemaphoreLocker : public AutoLocker<sem_id, SemaphoreLocking> {
public:
inline SemaphoreLocker(sem_id semaphore, bool alreadyLocked = false,
bool lockIfNotLocked = true)
:
AutoLocker<sem_id, SemaphoreLocking>(),
fSem(semaphore)
{
SetTo(&fSem, alreadyLocked, lockIfNotLocked);
}
private:
sem_id fSem;
};
CopyEngine::CopyEngine(const BMessenger& messenger, BMessage* message) CopyEngine::CopyEngine(const BMessenger& messenger, BMessage* message)
: :
fBufferQueue(), fBufferQueue(),
@@ -102,16 +135,16 @@ CopyEngine::ResetTargets()
status_t status_t
CopyEngine::CollectTargets(const char* source) CopyEngine::CollectTargets(const char* source, sem_id cancelSemaphore)
{ {
int32 level = 0; int32 level = 0;
return _CollectCopyInfo(source, level); return _CollectCopyInfo(source, level, cancelSemaphore);
} }
status_t status_t
CopyEngine::CopyFolder(const char* source, const char* destination, CopyEngine::CopyFolder(const char* source, const char* destination,
BLocker* locker) sem_id cancelSemaphore)
{ {
printf("%lld bytes to read in %lld files\n", fBytesToCopy, fItemsToCopy); printf("%lld bytes to read in %lld files\n", fBytesToCopy, fItemsToCopy);
@@ -122,16 +155,16 @@ CopyEngine::CopyFolder(const char* source, const char* destination,
} }
int32 level = 0; int32 level = 0;
return _CopyFolder(source, destination, level, locker); return _CopyFolder(source, destination, level, cancelSemaphore);
} }
status_t status_t
CopyEngine::CopyFile(const BEntry& _source, const BEntry& _destination, CopyEngine::CopyFile(const BEntry& _source, const BEntry& _destination,
BLocker* locker) sem_id cancelSemaphore)
{ {
AutoLocker<BLocker> lock(locker); SemaphoreLocker lock(cancelSemaphore);
if (locker != NULL && !lock.IsLocked()) { if (cancelSemaphore >= 0 && !lock.IsLocked()) {
// We are supposed to quit // We are supposed to quit
printf("CopyFile - cancled\n"); printf("CopyFile - cancled\n");
return B_CANCELED; return B_CANCELED;
@@ -210,7 +243,8 @@ printf("CopyFile - cancled\n");
status_t status_t
CopyEngine::_CollectCopyInfo(const char* _source, int32& level) CopyEngine::_CollectCopyInfo(const char* _source, int32& level,
sem_id cancelSemaphore)
{ {
level++; level++;
@@ -221,6 +255,12 @@ CopyEngine::_CollectCopyInfo(const char* _source, int32& level)
BEntry entry; BEntry entry;
while (source.GetNextEntry(&entry) == B_OK) { while (source.GetNextEntry(&entry) == B_OK) {
SemaphoreLocker lock(cancelSemaphore);
if (cancelSemaphore >= 0 && !lock.IsLocked()) {
// We are supposed to quit
return B_CANCELED;
}
struct stat statInfo; struct stat statInfo;
entry.GetStat(&statInfo); entry.GetStat(&statInfo);
@@ -239,7 +279,10 @@ CopyEngine::_CollectCopyInfo(const char* _source, int32& level)
if (ret < B_OK) if (ret < B_OK)
return ret; return ret;
ret = _CollectCopyInfo(srcFolder.Path(), level); if (cancelSemaphore >= 0)
lock.Unlock();
ret = _CollectCopyInfo(srcFolder.Path(), level, cancelSemaphore);
if (ret < B_OK) if (ret < B_OK)
return ret; return ret;
} else if (S_ISLNK(statInfo.st_mode)) { } else if (S_ISLNK(statInfo.st_mode)) {
@@ -259,7 +302,7 @@ CopyEngine::_CollectCopyInfo(const char* _source, int32& level)
status_t status_t
CopyEngine::_CopyFolder(const char* _source, const char* _destination, CopyEngine::_CopyFolder(const char* _source, const char* _destination,
int32& level, BLocker* locker) int32& level, sem_id cancelSemaphore)
{ {
level++; level++;
fCurrentTargetFolder = _destination; fCurrentTargetFolder = _destination;
@@ -283,8 +326,8 @@ CopyEngine::_CopyFolder(const char* _source, const char* _destination,
BEntry entry; BEntry entry;
while (source.GetNextEntry(&entry) == B_OK) { while (source.GetNextEntry(&entry) == B_OK) {
AutoLocker<BLocker> lock(locker); SemaphoreLocker lock(cancelSemaphore);
if (locker != NULL && !lock.IsLocked()) { if (cancelSemaphore >= 0 && !lock.IsLocked()) {
// We are supposed to quit // We are supposed to quit
return B_CANCELED; return B_CANCELED;
} }
@@ -341,15 +384,15 @@ CopyEngine::_CopyFolder(const char* _source, const char* _destination,
if (ret < B_OK) if (ret < B_OK)
return ret; return ret;
if (locker != NULL) if (cancelSemaphore >= 0)
lock.Unlock(); lock.Unlock();
ret = _CopyFolder(srcFolder.Path(), dstFolder.Path(), level, ret = _CopyFolder(srcFolder.Path(), dstFolder.Path(), level,
locker); cancelSemaphore);
if (ret < B_OK) if (ret < B_OK)
return ret; return ret;
if (locker != NULL && !lock.Lock()) { if (cancelSemaphore >= 0 && !lock.Lock()) {
// We are supposed to quit // We are supposed to quit
return B_CANCELED; return B_CANCELED;
} }
+6 -7
View File
@@ -15,7 +15,6 @@
#include "BlockingQueue.h" #include "BlockingQueue.h"
class BFile; class BFile;
class BLocker;
class BMessage; class BMessage;
class BMessenger; class BMessenger;
@@ -26,23 +25,23 @@ public:
virtual ~CopyEngine(); virtual ~CopyEngine();
void ResetTargets(); void ResetTargets();
status_t CollectTargets(const char* source); status_t CollectTargets(const char* source,
sem_id cancelSemaphore = -1);
status_t CopyFolder(const char* source, status_t CopyFolder(const char* source,
const char* destination, const char* destination,
BLocker* locker = NULL); sem_id cancelSemaphore = -1);
status_t CopyFile(const BEntry& entry, status_t CopyFile(const BEntry& entry,
const BEntry& destination, const BEntry& destination,
BLocker* locker = NULL); sem_id cancelSemaphore = -1);
private: private:
status_t _CollectCopyInfo(const char* source, status_t _CollectCopyInfo(const char* source,
int32& level); int32& level, sem_id cancelSemaphore);
status_t _CopyFolder(const char* source, status_t _CopyFolder(const char* source,
const char* destination, const char* destination,
int32& level, int32& level, sem_id cancelSemaphore);
BLocker* locker = NULL);
bool _ShouldCopyEntry(const char* name, bool _ShouldCopyEntry(const char* name,
const struct stat& statInfo, const struct stat& statInfo,
+28 -27
View File
@@ -149,7 +149,7 @@ InstallerWindow::InstallerWindow()
fDriveSetupLaunched(false), fDriveSetupLaunched(false),
fInstallStatus(kReadyForInstall), fInstallStatus(kReadyForInstall),
fWorkerThread(new WorkerThread(this)), fWorkerThread(new WorkerThread(this)),
fCopyEngineLock(NULL) fCopyEngineCancelSemaphore(-1)
{ {
LogoView* logoView = new LogoView(); LogoView* logoView = new LogoView();
@@ -271,6 +271,7 @@ InstallerWindow::InstallerWindow()
InstallerWindow::~InstallerWindow() InstallerWindow::~InstallerWindow()
{ {
_SetCopyEngineCancelSemaphore(-1);
be_roster->StopWatching(this); be_roster->StopWatching(this);
} }
@@ -299,8 +300,7 @@ InstallerWindow::MessageReceived(BMessage *msg)
switch (msg->what) { switch (msg->what) {
case MSG_RESET: case MSG_RESET:
{ {
delete fCopyEngineLock; _SetCopyEngineCancelSemaphore(-1);
fCopyEngineLock = NULL;
status_t error; status_t error;
if (msg->FindInt32("error", &error) == B_OK) { if (msg->FindInt32("error", &error) == B_OK) {
@@ -326,12 +326,13 @@ InstallerWindow::MessageReceived(BMessage *msg)
switch (fInstallStatus) { switch (fInstallStatus) {
case kReadyForInstall: case kReadyForInstall:
{ {
delete fCopyEngineLock; _SetCopyEngineCancelSemaphore(create_sem(1,
fCopyEngineLock = new BLocker("copy engine lock"); "copy engine cancel"));
BList* list = new BList(); BList* list = new BList();
int32 size = 0; int32 size = 0;
fPackagesView->GetPackagesToInstall(list, &size); fPackagesView->GetPackagesToInstall(list, &size);
fWorkerThread->SetLock(fCopyEngineLock); fWorkerThread->SetLock(fCopyEngineCancelSemaphore);
fWorkerThread->SetPackagesList(list); fWorkerThread->SetPackagesList(list);
fWorkerThread->SetSpaceRequired(size); fWorkerThread->SetSpaceRequired(size);
fInstallStatus = kInstalling; fInstallStatus = kInstalling;
@@ -415,8 +416,8 @@ InstallerWindow::MessageReceived(BMessage *msg)
} }
case MSG_INSTALL_FINISHED: case MSG_INSTALL_FINISHED:
{ {
delete fCopyEngineLock;
fCopyEngineLock = NULL; _SetCopyEngineCancelSemaphore(-1);
fBeginButton->SetLabel("Quit"); fBeginButton->SetLabel("Quit");
@@ -688,14 +689,27 @@ InstallerWindow::_SetStatusMessage(const char *text)
} }
void
InstallerWindow::_SetCopyEngineCancelSemaphore(sem_id id, bool alreadyLocked)
{
if (fCopyEngineCancelSemaphore >= 0) {
if (!alreadyLocked)
acquire_sem(fCopyEngineCancelSemaphore);
delete_sem(fCopyEngineCancelSemaphore);
}
fCopyEngineCancelSemaphore = id;
}
void void
InstallerWindow::_QuitCopyEngine(bool askUser) InstallerWindow::_QuitCopyEngine(bool askUser)
{ {
if (fCopyEngineLock == NULL) if (fCopyEngineCancelSemaphore < 0)
return; return;
// first of all block the copy engine // First of all block the copy engine, so that it doesn't continue
fCopyEngineLock->Lock(); // while the alert is showing, which would be irritating.
acquire_sem(fCopyEngineCancelSemaphore);
bool quit = true; bool quit = true;
if (askUser) { if (askUser) {
@@ -706,23 +720,10 @@ InstallerWindow::_QuitCopyEngine(bool askUser)
} }
if (quit) { if (quit) {
int32 tries = 0; // Make it quit by having it's lock fail...
// wait until the engine blocks _SetCopyEngineCancelSemaphore(-1, true);
while (fCopyEngineLock->CountLockRequests() < 2) {
// TODO: There is a race here, the copy engine
// may have finished before we locked the engine
// lock. That's why we limit the number of tries
// here.
tries++;
if (tries > 100)
break;
snooze(3000);
}
// make it quit by having it's lock fail
delete fCopyEngineLock;
fCopyEngineLock = NULL;
} else } else
fCopyEngineLock->Unlock(); release_sem(fCopyEngineCancelSemaphore);
} }
+3 -2
View File
@@ -16,7 +16,6 @@ using namespace BPrivate;
class BButton; class BButton;
class BLayoutItem; class BLayoutItem;
class BLocker;
class BMenu; class BMenu;
class BMenuField; class BMenuField;
class BStatusBar; class BStatusBar;
@@ -61,6 +60,8 @@ private:
void _PublishPackages(); void _PublishPackages();
void _SetStatusMessage(const char* text); void _SetStatusMessage(const char* text);
void _SetCopyEngineCancelSemaphore(sem_id id,
bool alreadyLocked = false);
void _QuitCopyEngine(bool askUser); void _QuitCopyEngine(bool askUser);
static int _ComparePackages(const void* firstArg, static int _ComparePackages(const void* firstArg,
@@ -95,7 +96,7 @@ private:
WorkerThread* fWorkerThread; WorkerThread* fWorkerThread;
BString fLastStatus; BString fLastStatus;
BLocker* fCopyEngineLock; sem_id fCopyEngineCancelSemaphore;
}; };
#endif // INSTALLER_WINDOW_H #endif // INSTALLER_WINDOW_H
+6 -5
View File
@@ -77,7 +77,8 @@ WorkerThread::WorkerThread(InstallerWindow *window)
: BLooper("copy_engine"), : BLooper("copy_engine"),
fWindow(window), fWindow(window),
fPackages(NULL), fPackages(NULL),
fSpaceRequired(0) fSpaceRequired(0),
fCancelSemaphore(-1)
{ {
Run(); Run();
} }
@@ -398,7 +399,7 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
// let the engine collect information for the progress bar later on // let the engine collect information for the progress bar later on
engine.ResetTargets(); engine.ResetTargets();
err = engine.CollectTargets(srcDirectory.Path()); err = engine.CollectTargets(srcDirectory.Path(), fCancelSemaphore);
if (err != B_OK) if (err != B_OK)
goto error; goto error;
@@ -409,7 +410,7 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
Package *p = static_cast<Package*>(fPackages->ItemAt(i)); Package *p = static_cast<Package*>(fPackages->ItemAt(i));
BPath packageDir(pkgRootDir.Path(), p->Folder()); BPath packageDir(pkgRootDir.Path(), p->Folder());
err = engine.CollectTargets(packageDir.Path()); err = engine.CollectTargets(packageDir.Path(), fCancelSemaphore);
if (err != B_OK) if (err != B_OK)
goto error; goto error;
} }
@@ -417,7 +418,7 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
// copy source volume // copy source volume
err = engine.CopyFolder(srcDirectory.Path(), targetDirectory.Path(), err = engine.CopyFolder(srcDirectory.Path(), targetDirectory.Path(),
fCancelLock); fCancelSemaphore);
if (err != B_OK) if (err != B_OK)
goto error; goto error;
@@ -429,7 +430,7 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
Package *p = static_cast<Package*>(fPackages->ItemAt(i)); Package *p = static_cast<Package*>(fPackages->ItemAt(i));
BPath packageDir(pkgRootDir.Path(), p->Folder()); BPath packageDir(pkgRootDir.Path(), p->Folder());
err = engine.CopyFolder(packageDir.Path(), targetDirectory.Path(), err = engine.CopyFolder(packageDir.Path(), targetDirectory.Path(),
fCancelLock); fCancelSemaphore);
if (err != B_OK) if (err != B_OK)
goto error; goto error;
} }
+3 -4
View File
@@ -14,7 +14,6 @@
#include <Volume.h> #include <Volume.h>
class BList; class BList;
class BLocker;
class BMenu; class BMenu;
class InstallerWindow; class InstallerWindow;
@@ -32,8 +31,8 @@ public:
{ fSpaceRequired = bytes; }; { fSpaceRequired = bytes; };
bool Cancel(); bool Cancel();
void SetLock(BLocker* lock) void SetLock(sem_id cancelSemaphore)
{ fCancelLock = lock; } { fCancelSemaphore = cancelSemaphore; }
void StartInstall(); void StartInstall();
void WriteBootSector(BMenu* dstMenu); void WriteBootSector(BMenu* dstMenu);
@@ -50,7 +49,7 @@ private:
BDiskDeviceRoster fDDRoster; BDiskDeviceRoster fDDRoster;
BList* fPackages; BList* fPackages;
off_t fSpaceRequired; off_t fSpaceRequired;
BLocker* fCancelLock; sem_id fCancelSemaphore;
}; };
#endif // WORKER_THREAD_H #endif // WORKER_THREAD_H