/* * Copyright 2018-2022, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "AbstractProcess.h" #include #include #include #include #include #include #include #include "HaikuDepotConstants.h" #include "Logger.h" #include "ProcessListener.h" AbstractProcess::AbstractProcess() : fLock(), fListener(NULL), fWasStopped(false), fProcessState(PROCESS_INITIAL), fErrorStatus(B_OK), fDurationSeconds(0.0) { } AbstractProcess::~AbstractProcess() { } void AbstractProcess::SetListener(ProcessListener* listener) { if (fListener != listener) { AutoLocker locker(&fLock); fListener = listener; } } status_t AbstractProcess::Run() { ProcessListener* listener; { AutoLocker locker(&fLock); if (ProcessState() != PROCESS_INITIAL) { HDINFO("cannot start process as it is not idle"); return B_NOT_ALLOWED; } if (fWasStopped) { HDINFO("cannot start process as it was stopped"); return B_CANCELED; } fProcessState = PROCESS_RUNNING; listener = fListener; } if (listener != NULL) listener->ProcessChanged(); BStopWatch stopWatch("process", true); status_t runResult = RunInternal(); fDurationSeconds = ((double) stopWatch.ElapsedTime() / 1000000.0); if (runResult != B_OK) HDERROR("[%s] an error has arisen; %s", Name(), strerror(runResult)); { AutoLocker locker(&fLock); fProcessState = PROCESS_COMPLETE; fErrorStatus = runResult; } // 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 != NULL) listener->ProcessChanged(); return runResult; } bool AbstractProcess::WasStopped() { AutoLocker locker(&fLock); return fWasStopped; } status_t AbstractProcess::ErrorStatus() { AutoLocker locker(&fLock); return fErrorStatus; } /*! This method will stop the process. The actual process may carry on to perform some tidy-ups on its thread so this does not stop the thread or change the state of the process; just indicates to the running thread that it should stop. If it has not yet been started then it will be put into finished state. */ status_t AbstractProcess::Stop() { status_t result = B_CANCELED; ProcessListener* listener = NULL; { AutoLocker locker(&fLock); if (!fWasStopped) { fWasStopped = true; result = StopInternal(); if (fProcessState == PROCESS_INITIAL) { listener = fListener; fProcessState = PROCESS_COMPLETE; } } } if (listener != NULL) listener->ProcessChanged(); return result; } status_t AbstractProcess::StopInternal() { return B_NOT_ALLOWED; } bool AbstractProcess::IsRunning() { return ProcessState() == PROCESS_RUNNING; } process_state AbstractProcess::ProcessState() { AutoLocker locker(&fLock); return fProcessState; } float AbstractProcess::Progress() { return kProgressIndeterminate; } void AbstractProcess::_NotifyChanged() { ProcessListener* listener = NULL; { AutoLocker locker(&fLock); listener = fListener; } if (listener != NULL) listener->ProcessChanged(); } BString AbstractProcess::LogReport() { BString result; AutoLocker locker(&fLock); result.SetToFormat("%s [%c] %6.3f", Name(), _ProcessStateIdentifier(ProcessState()), fDurationSeconds); return result; } /*static*/ char AbstractProcess::_ProcessStateIdentifier(process_state value) { switch (value) { case PROCESS_INITIAL: return 'I'; case PROCESS_RUNNING: return 'R'; case PROCESS_COMPLETE: return 'C'; default: return '?'; } }