HaikuDepot: Fix Crash on Shutdown
The MainWindow itself was a BReferencable via a listener virtual class. It looks like the error has come from a conflict between the MainWindow's own deletion and the state of the reference count. This change moves the listener / BReferencable out of the MainWindow so that the lifecycle of the BReferenable can be managed correctly. A further problem here is that the new listener was leaked from the MainWindow class on shutdown. To resolve this problem requires a considerable change to the "process coordinator" system. Fixes #17689 Change-Id: I7230843ba05537015f4a597b4a616b96c6db3dde Reviewed-on: https://review.haiku-os.org/c/haiku/+/5285 Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org> Reviewed-by: Andrew Lindesay <apl@lindesay.co.nz>
This commit is contained in:
parent
26f691760c
commit
409af93462
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2020, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2017-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef LOGGER_H
|
||||
@ -14,6 +14,9 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#define MILLIS_IN_DAY (1000 * 60 * 60 * 24)
|
||||
|
||||
|
||||
// These macros allow for standardized logging to be output.
|
||||
// The use of macros in this way means that the use of the log is concise where
|
||||
// it is used and also because the macro unwraps to a block contained with a
|
||||
@ -23,7 +26,11 @@
|
||||
// conditional clauses in the code to prevent this otherwise would be
|
||||
// cumbersome.
|
||||
|
||||
#define HDLOGPREFIX(L) printf("{%c} ", toupper(Logger::NameForLevel(L)[0]));
|
||||
#define HDLOGPREFIX(L) printf("@%08" B_PRId64 " {%c} <t:%" B_PRId32 "> ", \
|
||||
((system_time() / 1000) % MILLIS_IN_DAY), \
|
||||
toupper(Logger::NameForLevel(L)[0]), \
|
||||
abs(find_thread(NULL) % 1000) \
|
||||
);
|
||||
|
||||
#define HDLOG(L, M...) do { if (Logger::IsLevelEnabled(L)) { \
|
||||
HDLOGPREFIX(L) \
|
||||
|
@ -519,6 +519,8 @@ Model::CanPopulatePackage(const PackageInfoRef& package)
|
||||
void
|
||||
Model::PopulatePackage(const PackageInfoRef& package, uint32 flags)
|
||||
{
|
||||
HDTRACE("will populate package for [%s]", package->Name().String());
|
||||
|
||||
if (!CanPopulatePackage(package)) {
|
||||
HDINFO("unable to populate package [%s]", package->Name().String());
|
||||
return;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2018-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "AbstractProcess.h"
|
||||
@ -14,6 +14,7 @@
|
||||
|
||||
#include "HaikuDepotConstants.h"
|
||||
#include "Logger.h"
|
||||
#include "ProcessListener.h"
|
||||
|
||||
|
||||
AbstractProcess::AbstractProcess()
|
||||
@ -33,16 +34,20 @@ AbstractProcess::~AbstractProcess()
|
||||
|
||||
|
||||
void
|
||||
AbstractProcess::SetListener(AbstractProcessListener* listener)
|
||||
AbstractProcess::SetListener(ProcessListener* listener)
|
||||
{
|
||||
AutoLocker<BLocker> locker(&fLock);
|
||||
fListener = BReference<AbstractProcessListener>(listener);
|
||||
if (fListener != listener) {
|
||||
AutoLocker<BLocker> locker(&fLock);
|
||||
fListener = listener;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AbstractProcess::Run()
|
||||
{
|
||||
ProcessListener* listener;
|
||||
|
||||
{
|
||||
AutoLocker<BLocker> locker(&fLock);
|
||||
|
||||
@ -57,26 +62,27 @@ AbstractProcess::Run()
|
||||
}
|
||||
|
||||
fProcessState = PROCESS_RUNNING;
|
||||
listener = fListener;
|
||||
}
|
||||
|
||||
if (listener != NULL)
|
||||
listener->ProcessChanged();
|
||||
|
||||
status_t runResult = RunInternal();
|
||||
|
||||
if (runResult != B_OK)
|
||||
HDERROR("[%s] an error has arisen; %s", Name(), strerror(runResult));
|
||||
|
||||
BReference<AbstractProcessListener> listener;
|
||||
|
||||
{
|
||||
AutoLocker<BLocker> locker(&fLock);
|
||||
fProcessState = PROCESS_COMPLETE;
|
||||
fErrorStatus = runResult;
|
||||
listener = fListener;
|
||||
}
|
||||
|
||||
// this process may be part of a larger bulk-load process and
|
||||
// if so, the process orchestration needs to know when this
|
||||
// process has completed.
|
||||
if (listener.IsSet())
|
||||
if (listener != NULL)
|
||||
listener->ProcessChanged();
|
||||
|
||||
return runResult;
|
||||
@ -110,7 +116,7 @@ status_t
|
||||
AbstractProcess::Stop()
|
||||
{
|
||||
status_t result = B_CANCELED;
|
||||
BReference<AbstractProcessListener> listener = NULL;
|
||||
ProcessListener* listener = NULL;
|
||||
|
||||
{
|
||||
AutoLocker<BLocker> locker(&fLock);
|
||||
@ -126,7 +132,7 @@ AbstractProcess::Stop()
|
||||
}
|
||||
}
|
||||
|
||||
if (listener.IsSet())
|
||||
if (listener != NULL)
|
||||
listener->ProcessChanged();
|
||||
|
||||
return result;
|
||||
@ -165,11 +171,11 @@ AbstractProcess::Progress()
|
||||
void
|
||||
AbstractProcess::_NotifyChanged()
|
||||
{
|
||||
BReference<AbstractProcessListener> listener = NULL;
|
||||
ProcessListener* listener = NULL;
|
||||
{
|
||||
AutoLocker<BLocker> locker(&fLock);
|
||||
listener = fListener;
|
||||
}
|
||||
if (listener.IsSet())
|
||||
if (listener != NULL)
|
||||
listener->ProcessChanged();
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
/*
|
||||
* Copyright 2018-2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2018-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef ABSTRACT_PROCESS_H
|
||||
#define ABSTRACT_PROCESS_H
|
||||
|
||||
#include <String.h>
|
||||
#include <Referenceable.h>
|
||||
#include <Url.h>
|
||||
|
||||
#include "StandardMetaData.h"
|
||||
@ -20,15 +19,7 @@ typedef enum process_state {
|
||||
} process_state;
|
||||
|
||||
|
||||
/*! Clients are able to subclass from this 'interface' in order to accept
|
||||
call-backs when a process has exited; either through success or through
|
||||
failure.
|
||||
*/
|
||||
|
||||
class AbstractProcessListener : public BReferenceable {
|
||||
public:
|
||||
virtual void ProcessChanged() = 0;
|
||||
};
|
||||
class ProcessListener;
|
||||
|
||||
|
||||
/*! This is the superclass of all Processes. */
|
||||
@ -47,7 +38,8 @@ public:
|
||||
bool IsRunning();
|
||||
bool WasStopped();
|
||||
process_state ProcessState();
|
||||
void SetListener(AbstractProcessListener* listener);
|
||||
|
||||
void SetListener(ProcessListener* listener);
|
||||
|
||||
protected:
|
||||
virtual status_t RunInternal() = 0;
|
||||
@ -58,8 +50,7 @@ protected:
|
||||
BLocker fLock;
|
||||
|
||||
private:
|
||||
BReference<AbstractProcessListener>
|
||||
fListener;
|
||||
ProcessListener* fListener;
|
||||
bool fWasStopped;
|
||||
process_state fProcessState;
|
||||
status_t fErrorStatus;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2021-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@ -21,6 +21,8 @@
|
||||
|
||||
AbstractProcessNode::AbstractProcessNode(AbstractProcess* process)
|
||||
:
|
||||
fLock(),
|
||||
fListener(NULL),
|
||||
fProcess(process)
|
||||
{
|
||||
}
|
||||
@ -39,6 +41,23 @@ AbstractProcessNode::Process() const
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AbstractProcessNode::IsRunning()
|
||||
{
|
||||
return Process()->ProcessState() != PROCESS_COMPLETE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AbstractProcessNode::SetListener(ProcessListener* listener)
|
||||
{
|
||||
if (fListener != listener) {
|
||||
AutoLocker<BLocker> locker(&fLock);
|
||||
fListener = listener;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! This method will spin-lock the thread until the process is in one of the
|
||||
states defined by the mask.
|
||||
*/
|
||||
|
@ -1,16 +1,19 @@
|
||||
/*
|
||||
* Copyright 2018-2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2018-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef ABSTRACT_PROCESS_NODE_H
|
||||
#define ABSTRACT_PROCESS_NODE_H
|
||||
|
||||
|
||||
#include <AutoLocker.h>
|
||||
#include <Locker.h>
|
||||
#include <ObjectList.h>
|
||||
#include <OS.h>
|
||||
|
||||
|
||||
class AbstractProcess;
|
||||
class ProcessListener;
|
||||
|
||||
|
||||
/*! This class is designed to be used by the ProcessCoordinator class. The
|
||||
@ -26,6 +29,7 @@ public:
|
||||
AbstractProcess* Process() const;
|
||||
virtual status_t Start() = 0;
|
||||
virtual status_t RequestStop() = 0;
|
||||
virtual bool IsRunning();
|
||||
|
||||
void AddPredecessor(AbstractProcessNode* node);
|
||||
int32 CountPredecessors() const;
|
||||
@ -37,11 +41,17 @@ public:
|
||||
AbstractProcessNode*
|
||||
SuccessorAt(int32 index) const;
|
||||
|
||||
virtual void SetListener(ProcessListener* listener);
|
||||
|
||||
protected:
|
||||
status_t _SpinUntilProcessState(
|
||||
uint32 desiredStatesMask,
|
||||
int32 timeoutSeconds);
|
||||
|
||||
protected:
|
||||
BLocker fLock;
|
||||
ProcessListener* fListener;
|
||||
|
||||
private:
|
||||
void _AddSuccessor(AbstractProcessNode* node);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2020, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2018-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include <AutoLocker.h>
|
||||
#include <Catalog.h>
|
||||
#include <StringFormat.h>
|
||||
#include <Uuid.h>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
@ -16,15 +17,54 @@
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "ProcessCoordinator"
|
||||
|
||||
#define LOCK_TIMEOUT_MICROS (1000 * 1000)
|
||||
|
||||
// These are keys that are used to store the ProcessCoordinatorState data into
|
||||
// a BMessage instance.
|
||||
|
||||
#define KEY_PROCESS_COORDINATOR_IDENTIFIER "processCoordinatorIdentifier"
|
||||
#define KEY_PROGRESS "progress"
|
||||
#define KEY_MESSAGE "message"
|
||||
#define KEY_IS_RUNNING "isRunning"
|
||||
#define KEY_ERROR_STATUS "errorStatus"
|
||||
|
||||
|
||||
// #pragma mark - ProcessCoordinatorState implementation
|
||||
|
||||
|
||||
ProcessCoordinatorState::ProcessCoordinatorState(BMessage* from)
|
||||
{
|
||||
if (from->FindString(KEY_PROCESS_COORDINATOR_IDENTIFIER,
|
||||
&fProcessCoordinatorIdentifier) != B_OK) {
|
||||
HDFATAL("unable to find the key [%s]",
|
||||
KEY_PROCESS_COORDINATOR_IDENTIFIER);
|
||||
}
|
||||
|
||||
if (from->FindFloat(KEY_PROGRESS, &fProgress) != B_OK) {
|
||||
HDFATAL("unable to find the key [%s]", KEY_PROGRESS);
|
||||
}
|
||||
|
||||
if (from->FindString(KEY_MESSAGE, &fMessage) != B_OK) {
|
||||
HDFATAL("unable to find the key [%s]", KEY_MESSAGE);
|
||||
}
|
||||
|
||||
if (from->FindBool(KEY_IS_RUNNING, &fIsRunning) != B_OK) {
|
||||
HDFATAL("unable to find the key [%s]", KEY_IS_RUNNING);
|
||||
}
|
||||
|
||||
int64 errorStatusNumeric;
|
||||
if (from->FindInt64(KEY_ERROR_STATUS, &errorStatusNumeric) != B_OK) {
|
||||
HDFATAL("unable to find the key [%s]", KEY_ERROR_STATUS);
|
||||
}
|
||||
fErrorStatus = static_cast<status_t>(errorStatusNumeric);
|
||||
}
|
||||
|
||||
|
||||
ProcessCoordinatorState::ProcessCoordinatorState(
|
||||
const ProcessCoordinator* processCoordinator, float progress,
|
||||
const BString& message, bool isRunning, status_t errorStatus)
|
||||
:
|
||||
fProcessCoordinator(processCoordinator),
|
||||
fProcessCoordinatorIdentifier(processCoordinator->Identifier()),
|
||||
fProgress(progress),
|
||||
fMessage(message),
|
||||
fIsRunning(isRunning),
|
||||
@ -38,10 +78,10 @@ ProcessCoordinatorState::~ProcessCoordinatorState()
|
||||
}
|
||||
|
||||
|
||||
const ProcessCoordinator*
|
||||
ProcessCoordinatorState::Coordinator() const
|
||||
const BString
|
||||
ProcessCoordinatorState::ProcessCoordinatorIdentifier() const
|
||||
{
|
||||
return fProcessCoordinator;
|
||||
return fProcessCoordinatorIdentifier;
|
||||
}
|
||||
|
||||
|
||||
@ -73,15 +113,39 @@ ProcessCoordinatorState::ErrorStatus() const
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ProcessCoordinatorState::Archive(BMessage* into, bool deep) const
|
||||
{
|
||||
status_t result = B_OK;
|
||||
if (result == B_OK) {
|
||||
result = into->AddString(KEY_PROCESS_COORDINATOR_IDENTIFIER,
|
||||
fProcessCoordinatorIdentifier);
|
||||
}
|
||||
if (result == B_OK)
|
||||
result = into->AddFloat(KEY_PROGRESS, fProgress);
|
||||
if (result == B_OK)
|
||||
result = into->AddString(KEY_MESSAGE, fMessage);
|
||||
if (result == B_OK)
|
||||
result = into->AddBool(KEY_IS_RUNNING, fIsRunning);
|
||||
if (result == B_OK)
|
||||
result = into->AddInt64(KEY_ERROR_STATUS, static_cast<int64>(fErrorStatus));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - ProcessCoordinator implementation
|
||||
|
||||
|
||||
ProcessCoordinator::ProcessCoordinator(const char* name, BMessage* message)
|
||||
:
|
||||
fName(name),
|
||||
fLock(),
|
||||
fCoordinateAndCallListenerRerun(false),
|
||||
fCoordinateAndCallListenerRerunLock(),
|
||||
fListener(NULL),
|
||||
fMessage(message),
|
||||
fWasStopped(false)
|
||||
fWasStopped(false),
|
||||
fIdentifier(BUuid().ToString())
|
||||
{
|
||||
}
|
||||
|
||||
@ -97,9 +161,15 @@ ProcessCoordinator::~ProcessCoordinator()
|
||||
delete fMessage;
|
||||
}
|
||||
|
||||
const BString&
|
||||
ProcessCoordinator::Identifier() const
|
||||
{
|
||||
return fIdentifier;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ProcessCoordinator::SetListener(ProcessCoordinatorListener *listener)
|
||||
ProcessCoordinator::SetListener(ProcessCoordinatorListener* listener)
|
||||
{
|
||||
fListener = listener;
|
||||
}
|
||||
@ -110,6 +180,7 @@ ProcessCoordinator::AddNode(AbstractProcessNode* node)
|
||||
{
|
||||
AutoLocker<BLocker> locker(&fLock);
|
||||
fNodes.AddItem(node);
|
||||
node->SetListener(this);
|
||||
node->Process()->SetListener(this);
|
||||
}
|
||||
|
||||
@ -126,7 +197,8 @@ ProcessCoordinator::IsRunning()
|
||||
{
|
||||
AutoLocker<BLocker> locker(&fLock);
|
||||
for (int32 i = 0; i < fNodes.CountItems(); i++) {
|
||||
if (_IsRunning(fNodes.ItemAt(i)))
|
||||
AbstractProcessNode* node = fNodes.ItemAt(i);
|
||||
if (node->IsRunning())
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -237,13 +309,15 @@ ProcessCoordinator::_CreateStatusMessage()
|
||||
|
||||
for (int32 i = fNodes.CountItems() - 1; i >= 0; i--) {
|
||||
AbstractProcess* process = fNodes.ItemAt(i)->Process();
|
||||
|
||||
if (process->ProcessState() == PROCESS_RUNNING) {
|
||||
if (firstProcessDescription.IsEmpty()) {
|
||||
firstProcessDescription = process->Description();
|
||||
} else {
|
||||
additionalRunningProcesses++;
|
||||
if (strlen(process->Description()) != 0)
|
||||
firstProcessDescription = process->Description();
|
||||
else
|
||||
additionalRunningProcesses++;
|
||||
}
|
||||
else
|
||||
additionalRunningProcesses++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,13 +348,40 @@ ProcessCoordinator::_CreateStatus()
|
||||
}
|
||||
|
||||
|
||||
/*! This will try to obtain the lock and if it cannot obtain the lock then
|
||||
it will flag that when the coordinator has finished its current
|
||||
coordination, it should initiate another coordination.
|
||||
*/
|
||||
void
|
||||
ProcessCoordinator::_CoordinateAndCallListener()
|
||||
{
|
||||
if (fLock.LockWithTimeout(LOCK_TIMEOUT_MICROS) != B_OK) {
|
||||
HDDEBUG("[Coordinator] would coordinate nodes, but coordination is "
|
||||
"in progress - will defer");
|
||||
AutoLocker<BLocker> locker(&fCoordinateAndCallListenerRerunLock);
|
||||
fCoordinateAndCallListenerRerun = true;
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessCoordinatorState state = _Coordinate();
|
||||
|
||||
if (fListener != NULL)
|
||||
fListener->CoordinatorChanged(state);
|
||||
|
||||
fLock.Unlock();
|
||||
|
||||
bool coordinateAndCallListenerRerun = false;
|
||||
|
||||
{
|
||||
AutoLocker<BLocker> locker(&fCoordinateAndCallListenerRerunLock);
|
||||
coordinateAndCallListenerRerun = fCoordinateAndCallListenerRerun;
|
||||
fCoordinateAndCallListenerRerun = false;
|
||||
}
|
||||
|
||||
if (coordinateAndCallListenerRerun) {
|
||||
HDDEBUG("[Coordinator] will run deferred coordination");
|
||||
_CoordinateAndCallListener();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -347,13 +448,6 @@ ProcessCoordinator::_StopSuccessorNodes(AbstractProcessNode* predecessorNode)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ProcessCoordinator::_IsRunning(AbstractProcessNode* node)
|
||||
{
|
||||
return node->Process()->ProcessState() != PROCESS_COMPLETE;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
ProcessCoordinator::_CountNodesCompleted()
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2020, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2018-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PROCESS_COORDINATOR_H
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
#include "AbstractProcess.h"
|
||||
#include "AbstractProcessNode.h"
|
||||
#include "ProcessListener.h"
|
||||
|
||||
|
||||
class ProcessCoordinator;
|
||||
@ -20,8 +21,9 @@ class ProcessCoordinator;
|
||||
it can be dealt with atomically without having call back to the coordinator.
|
||||
*/
|
||||
|
||||
class ProcessCoordinatorState {
|
||||
class ProcessCoordinatorState : public BArchivable {
|
||||
public:
|
||||
ProcessCoordinatorState(BMessage* from);
|
||||
ProcessCoordinatorState(
|
||||
const ProcessCoordinator*
|
||||
processCoordinator,
|
||||
@ -29,14 +31,15 @@ public:
|
||||
bool isRunning, status_t errorStatus);
|
||||
virtual ~ProcessCoordinatorState();
|
||||
|
||||
const ProcessCoordinator* Coordinator() const;
|
||||
const BString ProcessCoordinatorIdentifier() const;
|
||||
float Progress() const;
|
||||
BString Message() const;
|
||||
bool IsRunning() const;
|
||||
status_t ErrorStatus() const;
|
||||
|
||||
status_t Archive(BMessage* into, bool deep = true) const;
|
||||
private:
|
||||
const ProcessCoordinator* fProcessCoordinator;
|
||||
BString fProcessCoordinatorIdentifier;
|
||||
float fProgress;
|
||||
BString fMessage;
|
||||
bool fIsRunning;
|
||||
@ -80,20 +83,22 @@ public:
|
||||
list of ProcessNode-s so that they are all completed in the correct order.
|
||||
*/
|
||||
|
||||
class ProcessCoordinator : public AbstractProcessListener {
|
||||
class ProcessCoordinator : public ProcessListener {
|
||||
public:
|
||||
ProcessCoordinator(
|
||||
const char* name,
|
||||
BMessage* message = NULL);
|
||||
virtual ~ProcessCoordinator();
|
||||
|
||||
const BString& Identifier() const;
|
||||
|
||||
void SetListener(
|
||||
ProcessCoordinatorListener *listener);
|
||||
|
||||
void AddNode(AbstractProcessNode* nodes);
|
||||
|
||||
void ProcessChanged();
|
||||
// AbstractProcessListener
|
||||
// ProcessListener
|
||||
|
||||
bool IsRunning();
|
||||
|
||||
@ -108,7 +113,6 @@ public:
|
||||
BMessage* Message() const;
|
||||
|
||||
private:
|
||||
bool _IsRunning(AbstractProcessNode* node);
|
||||
void _CoordinateAndCallListener();
|
||||
ProcessCoordinatorState
|
||||
_Coordinate();
|
||||
@ -122,12 +126,15 @@ private:
|
||||
private:
|
||||
BString fName;
|
||||
BLocker fLock;
|
||||
bool fCoordinateAndCallListenerRerun;
|
||||
BLocker fCoordinateAndCallListenerRerunLock;
|
||||
BObjectList<AbstractProcessNode>
|
||||
fNodes;
|
||||
ProcessCoordinatorListener*
|
||||
fListener;
|
||||
BMessage* fMessage;
|
||||
bool fWasStopped;
|
||||
BString fIdentifier;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2018-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@ -68,7 +68,7 @@ ProcessCoordinatorFactory::CreateUserDetailVerifierCoordinator(
|
||||
|
||||
/* static */ ProcessCoordinator*
|
||||
ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
|
||||
PackageInfoListener *packageInfoListener,
|
||||
PackageInfoListenerRef packageInfoListener,
|
||||
Model* model, bool forceLocalUpdate)
|
||||
{
|
||||
bool areWorkingFilesAvailable = StorageUtils::AreWorkingFilesAvailable();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2018-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PROCESS_COORDINATOR_FACTORY_H
|
||||
@ -25,7 +25,7 @@ public:
|
||||
const PackageInfoRef package);
|
||||
|
||||
static ProcessCoordinator* CreateBulkLoadCoordinator(
|
||||
PackageInfoListener *packageInfoListener,
|
||||
PackageInfoListenerRef packageInfoListener,
|
||||
Model* model, bool forceLocalUpdate);
|
||||
|
||||
static ProcessCoordinator* CreateUserDetailVerifierCoordinator(
|
||||
|
20
src/apps/haikudepot/process/ProcessListener.h
Normal file
20
src/apps/haikudepot/process/ProcessListener.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PROCESS_LISTENER_H
|
||||
#define PROCESS_LISTENER_H
|
||||
|
||||
#include <Referenceable.h>
|
||||
|
||||
/*! Clients are able to subclass from this 'interface' in order to accept
|
||||
call-backs when a process has exited; either through success or through
|
||||
failure.
|
||||
*/
|
||||
|
||||
class ProcessListener {
|
||||
public:
|
||||
virtual void ProcessChanged() = 0;
|
||||
};
|
||||
|
||||
#endif // PROCESS_LISTENER_H
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2021-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
#include "AbstractProcess.h"
|
||||
#include "Logger.h"
|
||||
#include "ProcessListener.h"
|
||||
|
||||
|
||||
#define TIMEOUT_UNTIL_STARTED_SECS_DEFAULT 10
|
||||
@ -37,6 +38,28 @@ ThreadedProcessNode::ThreadedProcessNode(AbstractProcess* process)
|
||||
|
||||
ThreadedProcessNode::~ThreadedProcessNode()
|
||||
{
|
||||
if (IsRunning()) {
|
||||
HDFATAL("the process node is being deleted while the thread is"
|
||||
"still running");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ThreadedProcessNode::IsRunning()
|
||||
{
|
||||
if (!AbstractProcessNode::IsRunning()) {
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
if (fWorker == B_BAD_THREAD_ID)
|
||||
return false;
|
||||
thread_info ti;
|
||||
status_t status = get_thread_info(fWorker, &ti);
|
||||
if (status != B_OK)
|
||||
// implies that the thread has stopped
|
||||
return false;
|
||||
HDTRACE("[Node<%s>] thread still running...", Process()->Name());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -46,13 +69,14 @@ ThreadedProcessNode::~ThreadedProcessNode()
|
||||
status_t
|
||||
ThreadedProcessNode::Start()
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
if (fWorker != B_BAD_THREAD_ID)
|
||||
return B_BUSY;
|
||||
|
||||
HDINFO("[Node<%s>] initiating threaded", Process()->Name());
|
||||
|
||||
fWorker = spawn_thread(&_StartProcess, Process()->Name(),
|
||||
B_NORMAL_PRIORITY, Process());
|
||||
fWorker = spawn_thread(&_RunProcessThreadEntry, Process()->Name(),
|
||||
B_NORMAL_PRIORITY, this);
|
||||
|
||||
if (fWorker >= 0) {
|
||||
resume_thread(fWorker);
|
||||
@ -71,20 +95,53 @@ ThreadedProcessNode::RequestStop()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ThreadedProcessNode::_RunProcessStart()
|
||||
{
|
||||
if (fListener != NULL) {
|
||||
if (on_exit_thread(&_RunProcessThreadExit, this) != B_OK) {
|
||||
HDFATAL("unable to setup 'on exit' for thread");
|
||||
}
|
||||
}
|
||||
|
||||
AbstractProcess* process = Process();
|
||||
|
||||
if (process == NULL)
|
||||
HDFATAL("the process node must have a process defined");
|
||||
|
||||
bigtime_t start = system_time();
|
||||
HDINFO("[Node<%s>] starting process in thread", process->Name());
|
||||
process->Run();
|
||||
HDINFO("[Node<%s>] finished process in thread %f seconds", process->Name(),
|
||||
(system_time() - start) / 1000000.0);
|
||||
}
|
||||
|
||||
|
||||
/*! This method is the initial function that is invoked on starting a new
|
||||
thread. It will start a process that is part of the bulk-load.
|
||||
*/
|
||||
|
||||
/*static*/ status_t
|
||||
ThreadedProcessNode::_StartProcess(void* cookie)
|
||||
ThreadedProcessNode::_RunProcessThreadEntry(void* cookie)
|
||||
{
|
||||
AbstractProcess* process = static_cast<AbstractProcess*>(cookie);
|
||||
bigtime_t start = system_time();
|
||||
|
||||
HDINFO("[Node<%s>] starting process in thread", process->Name());
|
||||
process->Run();
|
||||
HDINFO("[Node<%s>] finished process in thread %f seconds", process->Name(),
|
||||
(system_time() - start) / 1000000.0);
|
||||
|
||||
static_cast<ThreadedProcessNode*>(cookie)->_RunProcessStart();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ThreadedProcessNode::_RunProcessExit()
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
fWorker = B_BAD_THREAD_ID;
|
||||
HDTRACE("[Node<%s>] compute complete", Process()->Name());
|
||||
if (fListener != NULL)
|
||||
fListener->ProcessChanged();
|
||||
}
|
||||
|
||||
|
||||
/*static*/ void
|
||||
ThreadedProcessNode::_RunProcessThreadExit(void* cookie)
|
||||
{
|
||||
static_cast<ThreadedProcessNode*>(cookie)->_RunProcessExit();
|
||||
}
|
||||
|
@ -1,17 +1,13 @@
|
||||
/*
|
||||
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2021-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef THREADED_PROCESS_NODE_H
|
||||
#define THREADED_PROCESS_NODE_H
|
||||
|
||||
|
||||
#include "AbstractProcessNode.h"
|
||||
|
||||
|
||||
class AbstractProcess;
|
||||
|
||||
|
||||
class ThreadedProcessNode : public AbstractProcessNode {
|
||||
public:
|
||||
ThreadedProcessNode(AbstractProcess* process,
|
||||
@ -21,13 +17,16 @@ public:
|
||||
|
||||
virtual status_t Start();
|
||||
virtual status_t RequestStop();
|
||||
virtual bool IsRunning();
|
||||
|
||||
private:
|
||||
static status_t _StartProcess(void* cookie);
|
||||
void _RunProcessStart();
|
||||
void _RunProcessExit();
|
||||
static status_t _RunProcessThreadEntry(void* cookie);
|
||||
static void _RunProcessThreadExit(void* cookie);
|
||||
|
||||
thread_id fWorker;
|
||||
int32 fStartTimeoutSeconds;
|
||||
};
|
||||
|
||||
|
||||
#endif // THREADED_PROCESS_NODE_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2020, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2017-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@ -84,6 +84,7 @@ AbstractSingleFileServerProcess::RunInternal()
|
||||
HDINFO("[%s] did process data", Name());
|
||||
break;
|
||||
default:
|
||||
HDERROR("[%s] failed processing data", Name());
|
||||
MoveDamagedFileAside(localPath);
|
||||
break;
|
||||
}
|
||||
@ -97,4 +98,4 @@ status_t
|
||||
AbstractSingleFileServerProcess::GetStandardMetaDataPath(BPath& path) const
|
||||
{
|
||||
return GetLocalPath(path);
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
|
||||
IncrementViewCounterProcess::IncrementViewCounterProcess(
|
||||
Model* model, const PackageInfoRef package)
|
||||
Model* model, const PackageInfoRef& package)
|
||||
:
|
||||
fPackage(package),
|
||||
fModel(model)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2021-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef INCREMENT_VIEW_COUNTER_PROCESS_H
|
||||
@ -17,7 +17,7 @@ class IncrementViewCounterProcess : public AbstractProcess {
|
||||
public:
|
||||
IncrementViewCounterProcess(
|
||||
Model* model,
|
||||
const PackageInfoRef package);
|
||||
const PackageInfoRef& package);
|
||||
virtual ~IncrementViewCounterProcess();
|
||||
|
||||
const char* Name() const;
|
||||
|
@ -57,7 +57,7 @@ typedef std::map<BString, PackageInfoRef> PackageInfoMap;
|
||||
*/
|
||||
|
||||
LocalPkgDataLoadProcess::LocalPkgDataLoadProcess(
|
||||
PackageInfoListener* packageInfoListener,
|
||||
PackageInfoListenerRef packageInfoListener,
|
||||
Model *model, bool force)
|
||||
:
|
||||
AbstractProcess(),
|
||||
|
@ -32,7 +32,7 @@ class PkgDataLoadState;
|
||||
class LocalPkgDataLoadProcess : public AbstractProcess {
|
||||
public:
|
||||
LocalPkgDataLoadProcess(
|
||||
PackageInfoListener* packageInfoListener,
|
||||
PackageInfoListenerRef packageInfoListener,
|
||||
Model *model, bool force = false);
|
||||
virtual ~LocalPkgDataLoadProcess();
|
||||
|
||||
@ -49,7 +49,7 @@ private:
|
||||
private:
|
||||
Model* fModel;
|
||||
bool fForce;
|
||||
PackageInfoListener*
|
||||
PackageInfoListenerRef
|
||||
fPackageInfoListener;
|
||||
};
|
||||
|
||||
|
@ -914,6 +914,9 @@ WebAppInterface::_SendRawGetRequest(const BString urlPathComponents,
|
||||
{
|
||||
BUrl url = ServerSettings::CreateFullUrl(urlPathComponents);
|
||||
|
||||
HDDEBUG("http-get; will make request to [%s]",
|
||||
url.UrlString().String());
|
||||
|
||||
ProtocolListener listener;
|
||||
|
||||
BHttpHeaders headers;
|
||||
@ -934,6 +937,9 @@ WebAppInterface::_SendRawGetRequest(const BString urlPathComponents,
|
||||
|
||||
int32 statusCode = result.StatusCode();
|
||||
|
||||
HDDEBUG("http-get; did receive http-status [%" B_PRId32 "] from [%s]",
|
||||
statusCode, url.UrlString().String());
|
||||
|
||||
if (statusCode == 200)
|
||||
return B_OK;
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* Copyright 2013, Rene Gollent, rene@gollent.com.
|
||||
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Copyright 2016-2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2016-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
@ -68,6 +68,7 @@ enum {
|
||||
MSG_AUTHORIZATION_CHANGED = 'athc',
|
||||
MSG_CATEGORIES_LIST_CHANGED = 'clic',
|
||||
MSG_PACKAGE_CHANGED = 'pchd',
|
||||
MSG_PROCESS_COORDINATOR_CHANGED = 'pccd',
|
||||
MSG_WORK_STATUS_CHANGE = 'wsch',
|
||||
MSG_WORK_STATUS_CLEAR = 'wscl',
|
||||
|
||||
@ -128,6 +129,30 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class MainWindowPackageInfoListener : public PackageInfoListener {
|
||||
public:
|
||||
MainWindowPackageInfoListener(MainWindow* mainWindow)
|
||||
:
|
||||
fMainWindow(mainWindow)
|
||||
{
|
||||
}
|
||||
|
||||
~MainWindowPackageInfoListener()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
// PackageInfoListener
|
||||
virtual void PackageChanged(const PackageInfoEvent& event)
|
||||
{
|
||||
fMainWindow->PackageChanged(event);
|
||||
}
|
||||
|
||||
private:
|
||||
MainWindow* fMainWindow;
|
||||
};
|
||||
|
||||
|
||||
MainWindow::MainWindow(const BMessage& settings)
|
||||
:
|
||||
BWindow(BRect(50, 50, 650, 550), B_TRANSLATE_SYSTEM_NAME("HaikuDepot"),
|
||||
@ -147,6 +172,9 @@ MainWindow::MainWindow(const BMessage& settings)
|
||||
if ((fCoordinatorRunningSem = create_sem(1, "ProcessCoordinatorSem")) < B_OK)
|
||||
debugger("unable to create the process coordinator semaphore");
|
||||
|
||||
fPackageInfoListener = PackageInfoListenerRef(
|
||||
new MainWindowPackageInfoListener(this), true);
|
||||
|
||||
BMenuBar* menuBar = new BMenuBar("Main Menu");
|
||||
_BuildMenu(menuBar);
|
||||
|
||||
@ -242,6 +270,9 @@ MainWindow::MainWindow(const BMessage& settings, PackageInfoRef& package)
|
||||
if ((fCoordinatorRunningSem = create_sem(1, "ProcessCoordinatorSem")) < B_OK)
|
||||
debugger("unable to create the process coordinator semaphore");
|
||||
|
||||
fPackageInfoListener = PackageInfoListenerRef(
|
||||
new MainWindowPackageInfoListener(this), true);
|
||||
|
||||
fFilterView = new FilterView();
|
||||
fPackageInfoView = new PackageInfoView(&fModel, this);
|
||||
fWorkStatusView = new WorkStatusView("work status");
|
||||
@ -317,7 +348,7 @@ MainWindow::QuitRequested()
|
||||
AutoLocker<BLocker> lock(&fCoordinatorLock);
|
||||
fShouldCloseWhenNoProcessesToCoordinate = true;
|
||||
|
||||
if (fCoordinator.IsSet()) {
|
||||
if (fCoordinator != NULL) {
|
||||
HDINFO("a coordinator is running --> will wait before quitting...");
|
||||
|
||||
if (fShuttingDownWindow == NULL)
|
||||
@ -545,6 +576,13 @@ MainWindow::MessageReceived(BMessage* message)
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_PROCESS_COORDINATOR_CHANGED:
|
||||
{
|
||||
ProcessCoordinatorState state(message);
|
||||
_HandleProcessCoordinatorChanged(state);
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_RATE_PACKAGE:
|
||||
_RatePackage();
|
||||
break;
|
||||
@ -927,10 +965,8 @@ MainWindow::_AddRemovePackageFromLists(const PackageInfoRef& package)
|
||||
|
||||
|
||||
void
|
||||
MainWindow::_IncrementViewCounter(const PackageInfoRef& package)
|
||||
MainWindow::_IncrementViewCounter(const PackageInfoRef package)
|
||||
{
|
||||
// Temporarily disabled, see tickets #16879 and #17689.
|
||||
#if 0
|
||||
bool shouldIncrementViewCounter = false;
|
||||
|
||||
{
|
||||
@ -948,7 +984,6 @@ MainWindow::_IncrementViewCounter(const PackageInfoRef& package)
|
||||
&fModel, package);
|
||||
_AddProcessCoordinator(incrementViewCoordinator);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -988,9 +1023,7 @@ MainWindow::_StartBulkLoad(bool force)
|
||||
fRefreshRepositoriesItem->SetEnabled(false);
|
||||
ProcessCoordinator* bulkLoadCoordinator =
|
||||
ProcessCoordinatorFactory::CreateBulkLoadCoordinator(
|
||||
this,
|
||||
// PackageInfoListener
|
||||
&fModel, force);
|
||||
fPackageInfoListener, &fModel, force);
|
||||
_AddProcessCoordinator(bulkLoadCoordinator);
|
||||
}
|
||||
|
||||
@ -1422,7 +1455,6 @@ MainWindow::_HandleUserUsageConditionsNotLatest(
|
||||
void
|
||||
MainWindow::_AddProcessCoordinator(ProcessCoordinator* item)
|
||||
{
|
||||
BReference<ProcessCoordinator> itemRef(item, true);
|
||||
AutoLocker<BLocker> lock(&fCoordinatorLock);
|
||||
|
||||
if (fShouldCloseWhenNoProcessesToCoordinate) {
|
||||
@ -1433,12 +1465,13 @@ MainWindow::_AddProcessCoordinator(ProcessCoordinator* item)
|
||||
|
||||
item->SetListener(this);
|
||||
|
||||
if (!fCoordinator.IsSet()) {
|
||||
if (fCoordinator == NULL) {
|
||||
if (acquire_sem(fCoordinatorRunningSem) != B_OK)
|
||||
debugger("unable to acquire the process coordinator sem");
|
||||
HDINFO("adding and starting a process coordinator [%s]",
|
||||
item->Name().String());
|
||||
fCoordinator = itemRef;
|
||||
delete fCoordinator;
|
||||
fCoordinator = item;
|
||||
fCoordinator->Start();
|
||||
} else {
|
||||
HDINFO("adding process coordinator [%s] to the queue",
|
||||
@ -1458,7 +1491,7 @@ MainWindow::_SpinUntilProcessCoordinatorComplete()
|
||||
debugger("unable to release the process coordinator sem");
|
||||
{
|
||||
AutoLocker<BLocker> lock(&fCoordinatorLock);
|
||||
if (!fCoordinator.IsSet())
|
||||
if (fCoordinator == NULL)
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1472,14 +1505,15 @@ MainWindow::_StopProcessCoordinators()
|
||||
AutoLocker<BLocker> lock(&fCoordinatorLock);
|
||||
|
||||
while (!fCoordinatorQueue.empty()) {
|
||||
BReference<ProcessCoordinator> processCoordinator
|
||||
ProcessCoordinator* processCoordinator
|
||||
= fCoordinatorQueue.front();
|
||||
HDINFO("will drop queued process coordinator [%s]",
|
||||
processCoordinator->Name().String());
|
||||
fCoordinatorQueue.pop();
|
||||
delete processCoordinator;
|
||||
}
|
||||
|
||||
if (fCoordinator.IsSet())
|
||||
if (fCoordinator != NULL)
|
||||
fCoordinator->RequestStop();
|
||||
}
|
||||
|
||||
@ -1492,10 +1526,23 @@ MainWindow::_StopProcessCoordinators()
|
||||
|
||||
void
|
||||
MainWindow::CoordinatorChanged(ProcessCoordinatorState& coordinatorState)
|
||||
{
|
||||
BMessage message(MSG_PROCESS_COORDINATOR_CHANGED);
|
||||
if (coordinatorState.Archive(&message, true) != B_OK) {
|
||||
HDFATAL("unable to archive message when the process coordinator"
|
||||
" has changed");
|
||||
}
|
||||
BMessenger(this).SendMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWindow::_HandleProcessCoordinatorChanged(ProcessCoordinatorState& coordinatorState)
|
||||
{
|
||||
AutoLocker<BLocker> lock(&fCoordinatorLock);
|
||||
|
||||
if (fCoordinator.Get() == coordinatorState.Coordinator()) {
|
||||
if (fCoordinator->Identifier()
|
||||
== coordinatorState.ProcessCoordinatorIdentifier()) {
|
||||
if (!coordinatorState.IsRunning()) {
|
||||
if (release_sem(fCoordinatorRunningSem) != B_OK)
|
||||
debugger("unable to release the process coordinator sem");
|
||||
@ -1511,9 +1558,8 @@ MainWindow::CoordinatorChanged(ProcessCoordinatorState& coordinatorState)
|
||||
messenger.SendMessage(message);
|
||||
}
|
||||
|
||||
fCoordinator = BReference<ProcessCoordinator>(NULL);
|
||||
// will delete the old process coordinator if it is not used
|
||||
// elsewhere.
|
||||
delete fCoordinator;
|
||||
fCoordinator = NULL;
|
||||
|
||||
// now schedule the next one.
|
||||
if (!fCoordinatorQueue.empty()) {
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* Copyright 2013, Rene Gollent <rene@gollent.com>.
|
||||
* Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>.
|
||||
* Copyright 2017-2021, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2017-2022, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef MAIN_WINDOW_H
|
||||
@ -35,7 +35,7 @@ class ShuttingDownWindow;
|
||||
class WorkStatusView;
|
||||
|
||||
|
||||
class MainWindow : private PackageInfoListener,
|
||||
class MainWindow :
|
||||
private ProcessCoordinatorConsumer, public ProcessCoordinatorListener,
|
||||
public UserDetailVerifierListener, public BWindow {
|
||||
public:
|
||||
@ -61,9 +61,9 @@ public:
|
||||
virtual void UserCredentialsFailed();
|
||||
virtual void UserUsageConditionsNotLatest(
|
||||
const UserDetail& userDetail);
|
||||
private:
|
||||
// PackageInfoListener
|
||||
virtual void PackageChanged(
|
||||
|
||||
// services PackageInfoListener via MainWindowPackageInfoListener
|
||||
void PackageChanged(
|
||||
const PackageInfoEvent& event);
|
||||
|
||||
private:
|
||||
@ -99,7 +99,7 @@ private:
|
||||
void _ClearPackage();
|
||||
|
||||
void _IncrementViewCounter(
|
||||
const PackageInfoRef& package);
|
||||
const PackageInfoRef package);
|
||||
|
||||
void _PopulatePackageAsync(bool forcePopulate);
|
||||
void _StartBulkLoad(bool force = false);
|
||||
@ -118,6 +118,9 @@ private:
|
||||
|
||||
void _HandleChangePackageListViewMode();
|
||||
|
||||
void _HandleProcessCoordinatorChanged(
|
||||
ProcessCoordinatorState& coordinatorState);
|
||||
|
||||
static status_t _RefreshModelThreadWorker(void* arg);
|
||||
static status_t _PopulatePackageWorker(void* arg);
|
||||
static status_t _PackagesToShowWorker(void* arg);
|
||||
@ -165,10 +168,9 @@ private:
|
||||
Model fModel;
|
||||
ModelListenerRef fModelListener;
|
||||
|
||||
std::queue<BReference<ProcessCoordinator> >
|
||||
std::queue<ProcessCoordinator*>
|
||||
fCoordinatorQueue;
|
||||
BReference<ProcessCoordinator>
|
||||
fCoordinator;
|
||||
ProcessCoordinator* fCoordinator;
|
||||
BLocker fCoordinatorLock;
|
||||
sem_id fCoordinatorRunningSem;
|
||||
bool fShouldCloseWhenNoProcessesToCoordinate;
|
||||
@ -180,6 +182,11 @@ private:
|
||||
bool fForcePopulatePackage;
|
||||
BLocker fPackageToPopulateLock;
|
||||
sem_id fPackageToPopulateSem;
|
||||
|
||||
PackageInfoListenerRef
|
||||
fPackageInfoListener;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // MAIN_WINDOW_H
|
||||
|
Loading…
Reference in New Issue
Block a user