1/* 2 * Copyright 2018-2022, Andrew Lindesay <apl@lindesay.co.nz>. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5#include "AbstractProcess.h" 6 7#include <unistd.h> 8#include <errno.h> 9#include <string.h> 10 11#include <AutoDeleter.h> 12#include <AutoLocker.h> 13#include <Locker.h> 14#include <StopWatch.h> 15 16#include "HaikuDepotConstants.h" 17#include "Logger.h" 18#include "ProcessListener.h" 19 20 21AbstractProcess::AbstractProcess() 22 : 23 fLock(), 24 fListener(NULL), 25 fWasStopped(false), 26 fProcessState(PROCESS_INITIAL), 27 fErrorStatus(B_OK), 28 fDurationSeconds(0.0) 29{ 30} 31 32 33AbstractProcess::~AbstractProcess() 34{ 35} 36 37 38void 39AbstractProcess::SetListener(ProcessListener* listener) 40{ 41 if (fListener != listener) { 42 AutoLocker<BLocker> locker(&fLock); 43 fListener = listener; 44 } 45} 46 47 48status_t 49AbstractProcess::Run() 50{ 51 ProcessListener* listener; 52 53 { 54 AutoLocker<BLocker> locker(&fLock); 55 56 if (ProcessState() != PROCESS_INITIAL) { 57 HDINFO("cannot start process as it is not idle"); 58 return B_NOT_ALLOWED; 59 } 60 61 if (fWasStopped) { 62 HDINFO("cannot start process as it was stopped"); 63 return B_CANCELED; 64 } 65 66 fProcessState = PROCESS_RUNNING; 67 listener = fListener; 68 } 69 70 if (listener != NULL) 71 listener->ProcessChanged(); 72 73 BStopWatch stopWatch("process", true); 74 status_t runResult = RunInternal(); 75 fDurationSeconds = ((double) stopWatch.ElapsedTime() / 1000000.0); 76 77 if (runResult != B_OK) 78 HDERROR("[%s] an error has arisen; %s", Name(), strerror(runResult)); 79 80 { 81 AutoLocker<BLocker> locker(&fLock); 82 fProcessState = PROCESS_COMPLETE; 83 fErrorStatus = runResult; 84 } 85 86 // this process may be part of a larger bulk-load process and 87 // if so, the process orchestration needs to know when this 88 // process has completed. 89 if (listener != NULL) 90 listener->ProcessChanged(); 91 92 return runResult; 93} 94 95 96bool 97AbstractProcess::WasStopped() 98{ 99 AutoLocker<BLocker> locker(&fLock); 100 return fWasStopped; 101} 102 103 104status_t 105AbstractProcess::ErrorStatus() 106{ 107 AutoLocker<BLocker> locker(&fLock); 108 return fErrorStatus; 109} 110 111 112/*! This method will stop the process. The actual process may carry on to 113 perform some tidy-ups on its thread so this does not stop the thread or 114 change the state of the process; just indicates to the running thread that 115 it should stop. If it has not yet been started then it will be put into 116 finished state. 117*/ 118 119status_t 120AbstractProcess::Stop() 121{ 122 status_t result = B_CANCELED; 123 ProcessListener* listener = NULL; 124 125 { 126 AutoLocker<BLocker> locker(&fLock); 127 128 if (!fWasStopped) { 129 fWasStopped = true; 130 result = StopInternal(); 131 132 if (fProcessState == PROCESS_INITIAL) { 133 listener = fListener; 134 fProcessState = PROCESS_COMPLETE; 135 } 136 } 137 } 138 139 if (listener != NULL) 140 listener->ProcessChanged(); 141 142 return result; 143} 144 145 146status_t 147AbstractProcess::StopInternal() 148{ 149 return B_NOT_ALLOWED; 150} 151 152 153bool 154AbstractProcess::IsRunning() 155{ 156 return ProcessState() == PROCESS_RUNNING; 157} 158 159 160process_state 161AbstractProcess::ProcessState() 162{ 163 AutoLocker<BLocker> locker(&fLock); 164 return fProcessState; 165} 166 167 168float 169AbstractProcess::Progress() 170{ 171 return kProgressIndeterminate; 172} 173 174 175void 176AbstractProcess::_NotifyChanged() 177{ 178 ProcessListener* listener = NULL; 179 { 180 AutoLocker<BLocker> locker(&fLock); 181 listener = fListener; 182 } 183 if (listener != NULL) 184 listener->ProcessChanged(); 185} 186 187 188BString 189AbstractProcess::LogReport() 190{ 191 BString result; 192 AutoLocker<BLocker> locker(&fLock); 193 result.SetToFormat("%s [%c] %6.3f", Name(), _ProcessStateIdentifier(ProcessState()), 194 fDurationSeconds); 195 return result; 196} 197 198 199/*static*/ char 200AbstractProcess::_ProcessStateIdentifier(process_state value) 201{ 202 switch (value) { 203 case PROCESS_INITIAL: 204 return 'I'; 205 case PROCESS_RUNNING: 206 return 'R'; 207 case PROCESS_COMPLETE: 208 return 'C'; 209 default: 210 return '?'; 211 } 212}