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:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user