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 15 #include "HaikuDepotConstants.h" 16 #include "Logger.h" 17 #include "ProcessListener.h" 18 19 20 AbstractProcess::AbstractProcess() 21 : 22 fLock(), 23 fListener(NULL), 24 fWasStopped(false), 25 fProcessState(PROCESS_INITIAL), 26 fErrorStatus(B_OK) 27 { 28 } 29 30 31 AbstractProcess::~AbstractProcess() 32 { 33 } 34 35 36 void 37 AbstractProcess::SetListener(ProcessListener* listener) 38 { 39 if (fListener != listener) { 40 AutoLocker<BLocker> locker(&fLock); 41 fListener = listener; 42 } 43 } 44 45 46 status_t 47 AbstractProcess::Run() 48 { 49 ProcessListener* listener; 50 51 { 52 AutoLocker<BLocker> locker(&fLock); 53 54 if (ProcessState() != PROCESS_INITIAL) { 55 HDINFO("cannot start process as it is not idle"); 56 return B_NOT_ALLOWED; 57 } 58 59 if (fWasStopped) { 60 HDINFO("cannot start process as it was stopped"); 61 return B_CANCELED; 62 } 63 64 fProcessState = PROCESS_RUNNING; 65 listener = fListener; 66 } 67 68 if (listener != NULL) 69 listener->ProcessChanged(); 70 71 status_t runResult = RunInternal(); 72 73 if (runResult != B_OK) 74 HDERROR("[%s] an error has arisen; %s", Name(), strerror(runResult)); 75 76 { 77 AutoLocker<BLocker> locker(&fLock); 78 fProcessState = PROCESS_COMPLETE; 79 fErrorStatus = runResult; 80 } 81 82 // this process may be part of a larger bulk-load process and 83 // if so, the process orchestration needs to know when this 84 // process has completed. 85 if (listener != NULL) 86 listener->ProcessChanged(); 87 88 return runResult; 89 } 90 91 92 bool 93 AbstractProcess::WasStopped() 94 { 95 AutoLocker<BLocker> locker(&fLock); 96 return fWasStopped; 97 } 98 99 100 status_t 101 AbstractProcess::ErrorStatus() 102 { 103 AutoLocker<BLocker> locker(&fLock); 104 return fErrorStatus; 105 } 106 107 108 /*! This method will stop the process. The actual process may carry on to 109 perform some tidy-ups on its thread so this does not stop the thread or 110 change the state of the process; just indicates to the running thread that 111 it should stop. If it has not yet been started then it will be put into 112 finished state. 113 */ 114 115 status_t 116 AbstractProcess::Stop() 117 { 118 status_t result = B_CANCELED; 119 ProcessListener* listener = NULL; 120 121 { 122 AutoLocker<BLocker> locker(&fLock); 123 124 if (!fWasStopped) { 125 fWasStopped = true; 126 result = StopInternal(); 127 128 if (fProcessState == PROCESS_INITIAL) { 129 listener = fListener; 130 fProcessState = PROCESS_COMPLETE; 131 } 132 } 133 } 134 135 if (listener != NULL) 136 listener->ProcessChanged(); 137 138 return result; 139 } 140 141 142 status_t 143 AbstractProcess::StopInternal() 144 { 145 return B_NOT_ALLOWED; 146 } 147 148 149 bool 150 AbstractProcess::IsRunning() 151 { 152 return ProcessState() == PROCESS_RUNNING; 153 } 154 155 156 process_state 157 AbstractProcess::ProcessState() 158 { 159 AutoLocker<BLocker> locker(&fLock); 160 return fProcessState; 161 } 162 163 164 float 165 AbstractProcess::Progress() 166 { 167 return kProgressIndeterminate; 168 } 169 170 171 void 172 AbstractProcess::_NotifyChanged() 173 { 174 ProcessListener* listener = NULL; 175 { 176 AutoLocker<BLocker> locker(&fLock); 177 listener = fListener; 178 } 179 if (listener != NULL) 180 listener->ProcessChanged(); 181 } 182