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 21 AbstractProcess::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 33 AbstractProcess::~AbstractProcess() 34 { 35 } 36 37 38 void 39 AbstractProcess::SetListener(ProcessListener* listener) 40 { 41 if (fListener != listener) { 42 AutoLocker<BLocker> locker(&fLock); 43 fListener = listener; 44 } 45 } 46 47 48 status_t 49 AbstractProcess::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 96 bool 97 AbstractProcess::WasStopped() 98 { 99 AutoLocker<BLocker> locker(&fLock); 100 return fWasStopped; 101 } 102 103 104 status_t 105 AbstractProcess::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 119 status_t 120 AbstractProcess::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 146 status_t 147 AbstractProcess::StopInternal() 148 { 149 return B_NOT_ALLOWED; 150 } 151 152 153 bool 154 AbstractProcess::IsRunning() 155 { 156 return ProcessState() == PROCESS_RUNNING; 157 } 158 159 160 process_state 161 AbstractProcess::ProcessState() 162 { 163 AutoLocker<BLocker> locker(&fLock); 164 return fProcessState; 165 } 166 167 168 float 169 AbstractProcess::Progress() 170 { 171 return kProgressIndeterminate; 172 } 173 174 175 void 176 AbstractProcess::_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 188 BString 189 AbstractProcess::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 200 AbstractProcess::_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 }