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