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