xref: /haiku/src/apps/haikudepot/process/AbstractProcess.cpp (revision 68f76d61d74f9f73085105d541b4d0a5e7df0317)
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 }