1 // ==============================================================
2 //	This file is part of Glest Shared Library (www.glest.org)
3 //
4 //	Copyright (C) 2009-2010 Titus Tscharntke (info@titusgames.de) and
5 //                          Mark Vejvoda (mark_vejvoda@hotmail.com)
6 //
7 //	You can redistribute this code and/or modify it under
8 //	the terms of the GNU General Public License as published
9 //	by the Free Software Foundation; either version 2 of the
10 //	License, or (at your option) any later version
11 // ==============================================================
12 
13 #include "base_thread.h"
14 #include "platform_common.h"
15 #include "util.h"
16 #include "conversion.h"
17 #include "platform_util.h"
18 #include <time.h>
19 
20 using namespace Shared::Util;
21 
22 namespace Shared { namespace PlatformCommon {
23 
24 Mutex BaseThread::mutexMasterThreadList;
25 std::map<void *,int> BaseThread::masterThreadList;
26 
BaseThread()27 BaseThread::BaseThread() : Thread(),
28 		mutexRunning(new Mutex(CODE_AT_LINE)),
29 		mutexQuit(new Mutex(CODE_AT_LINE)),
30 		mutexBeginExecution(new Mutex(CODE_AT_LINE)),
31 		mutexDeleteSelfOnExecutionDone(new Mutex(CODE_AT_LINE)),
32 	    mutexThreadObjectAccessor(new Mutex(CODE_AT_LINE)),
33 	    mutexThreadOwnerValid(new Mutex(CODE_AT_LINE)),
34 		mutexExecutingTask(new Mutex(CODE_AT_LINE)),
35 		mutexStarted(new Mutex(CODE_AT_LINE)),
36 		ptr(NULL), genericData(NULL) {
37 
38 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
39 
40 	ptr = this;
41 	MutexSafeWrapper safeMutexMasterList(&mutexMasterThreadList);
42 	masterThreadList[ptr]++;
43 	safeMutexMasterList.ReleaseLock();
44 
45 	uniqueID = "base_thread";
46 
47 	setQuitStatus(false);
48 	setRunningStatus(false);
49 	setStarted(false);
50 	setHasBeginExecution(false);
51 	setExecutingTask(false);
52 	setDeleteSelfOnExecutionDone(false);
53 	setThreadOwnerValid(true);
54 
55 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
56 }
57 
getMutexThreadObjectAccessor()58 Mutex * BaseThread::getMutexThreadObjectAccessor() {
59 	return mutexThreadObjectAccessor;
60 }
61 
~BaseThread()62 BaseThread::~BaseThread() {
63 
64 	//printf("In ~BaseThread Line: %d uniqueID [%s]\n",__LINE__,uniqueID.c_str());
65 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s]\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str());
66 
67 	//BaseThread *base_thread = dynamic_cast<BaseThread *>(this);
68 	if(this->getStarted() == false) {
69 		time_t elapsed = time(NULL);
70 		for(;this->getStarted() == false &&
71     		difftime((long int)time(NULL),elapsed) <= 3;) {
72 			sleep(5);
73 		}
74 	}
75 
76 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s]\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str());
77 	bool ret = shutdownAndWait();
78 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s] ret [%d] END\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str(),ret);
79 
80 	//printf("In ~BaseThread Line: %d uniqueID [%s]\n",__LINE__,uniqueID.c_str());
81 
82 	MutexSafeWrapper safeMutexMasterList(&mutexMasterThreadList);
83 
84 	//printf("In ~BaseThread Line: %d uniqueID [%s]\n",__LINE__,uniqueID.c_str());
85 
86 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s] ret [%d] END\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str(),ret);
87 
88 	//printf("In ~BaseThread Line: %d uniqueID [%s]\n",__LINE__,uniqueID.c_str());
89 
90 	if(masterThreadList.find(this) == masterThreadList.end()) {
91 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s] ret [%d] END\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str(),ret);
92 
93 		char szBuf[8096]="";
94 		snprintf(szBuf,8096,"invalid thread delete for ptr: %p",this);
95 		throw megaglest_runtime_error(szBuf);
96 	}
97 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s] ret [%d] END\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str(),ret);
98 
99 	//printf("In ~BaseThread Line: %d uniqueID [%s]\n",__LINE__,uniqueID.c_str());
100 
101 	masterThreadList[this]--;
102 	if(masterThreadList[this] <= 0) {
103 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s] ret [%d] END\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str(),ret);
104 		masterThreadList.erase(this);
105 	}
106 
107 	//printf("In ~BaseThread Line: %d uniqueID [%s]\n",__LINE__,uniqueID.c_str());
108 
109 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s] ret [%d] END\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str(),ret);
110 
111 	safeMutexMasterList.ReleaseLock();
112 
113 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s] ret [%d] END\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str(),ret);
114 
115 
116 	delete mutexRunning;
117 	mutexRunning = NULL;
118 	delete mutexQuit;
119 	mutexQuit = NULL;
120 	delete mutexBeginExecution;
121 	mutexBeginExecution = NULL;
122 	delete mutexDeleteSelfOnExecutionDone;
123 	mutexDeleteSelfOnExecutionDone = NULL;
124 	delete mutexThreadObjectAccessor;
125 	mutexThreadObjectAccessor = NULL;
126     delete mutexThreadOwnerValid;
127     mutexThreadOwnerValid = NULL;
128     delete mutexExecutingTask;
129     mutexExecutingTask = NULL;
130 	delete mutexStarted;
131 	mutexStarted = NULL;
132 
133 	//printf("In ~BaseThread Line: %d uniqueID [%s] [%p]\n",__LINE__,uniqueID.c_str(),this);
134 }
135 
getStarted()136 bool BaseThread::getStarted() {
137 	static string mutexOwnerId = CODE_AT_LINE;
138 	MutexSafeWrapper safeMutex(mutexStarted,mutexOwnerId);
139 	mutexStarted->setOwnerId(mutexOwnerId);
140 	bool retval = started;
141 	safeMutex.ReleaseLock();
142 
143 	return retval;
144 }
145 
setStarted(bool value)146 void BaseThread::setStarted(bool value) {
147 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s]\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str());
148 
149 	static string mutexOwnerId = CODE_AT_LINE;
150 	MutexSafeWrapper safeMutex(mutexStarted,mutexOwnerId);
151 	mutexStarted->setOwnerId(mutexOwnerId);
152 	started = value;
153 	safeMutex.ReleaseLock();
154 
155 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s]\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str());
156 }
157 
isThreadDeleted(void * ptr)158 bool BaseThread::isThreadDeleted(void *ptr) {
159 	bool result = false;
160 	MutexSafeWrapper safeMutexMasterList(&mutexMasterThreadList);
161 	if(masterThreadList.find(ptr) != masterThreadList.end()) {
162 		result = (masterThreadList[ptr] <= 0);
163 	}
164 	safeMutexMasterList.ReleaseLock();
165 	return result;
166 }
167 
getMutexThreadOwnerValid()168 Mutex * BaseThread::getMutexThreadOwnerValid() {
169 	if(getThreadOwnerValid() == true) {
170 	    return mutexThreadOwnerValid;
171 	}
172     return NULL;
173 }
174 
setThreadOwnerValid(bool value)175 void BaseThread::setThreadOwnerValid(bool value) {
176 	static string mutexOwnerId = CODE_AT_LINE;
177 	MutexSafeWrapper safeMutex(mutexThreadOwnerValid,mutexOwnerId);
178 	mutexThreadOwnerValid->setOwnerId(mutexOwnerId);
179 	threadOwnerValid = value;
180 	safeMutex.ReleaseLock();
181 }
182 
getThreadOwnerValid()183 bool BaseThread::getThreadOwnerValid() {
184 	//bool ret = false;
185 	static string mutexOwnerId = CODE_AT_LINE;
186 	MutexSafeWrapper safeMutex(mutexThreadOwnerValid,mutexOwnerId);
187 	//mutexThreadOwnerValid.setOwnerId(mutexOwnerId);
188 	bool ret = threadOwnerValid;
189 	safeMutex.ReleaseLock();
190 
191 	return ret;
192 }
193 
signalQuit()194 void BaseThread::signalQuit() {
195 	setQuitStatus(true);
196 }
197 
setQuitStatus(bool value)198 void BaseThread::setQuitStatus(bool value) {
199 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s]\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str());
200 
201 	static string mutexOwnerId = CODE_AT_LINE;
202 	MutexSafeWrapper safeMutex(mutexQuit,mutexOwnerId);
203 	mutexQuit->setOwnerId(mutexOwnerId);
204 	quit = value;
205 	safeMutex.ReleaseLock();
206 
207 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s]\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str());
208 }
209 
getQuitStatus()210 bool BaseThread::getQuitStatus() {
211 	//bool retval = false;
212 	static string mutexOwnerId = CODE_AT_LINE;
213 	MutexSafeWrapper safeMutex(mutexQuit,mutexOwnerId);
214 	//mutexQuit.setOwnerId(mutexOwnerId);
215 	bool retval = quit;
216 	safeMutex.ReleaseLock();
217 
218 	return retval;
219 }
220 
getHasBeginExecution()221 bool BaseThread::getHasBeginExecution() {
222 	//bool retval = false;
223 	static string mutexOwnerId = CODE_AT_LINE;
224 	MutexSafeWrapper safeMutex(mutexBeginExecution,mutexOwnerId);
225 	//mutexBeginExecution.setOwnerId(mutexOwnerId);
226 	bool retval = hasBeginExecution;
227 	safeMutex.ReleaseLock();
228 
229 	return retval;
230 }
231 
setHasBeginExecution(bool value)232 void BaseThread::setHasBeginExecution(bool value) {
233 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s]\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str());
234 
235 	static string mutexOwnerId = CODE_AT_LINE;
236 	MutexSafeWrapper safeMutex(mutexBeginExecution,mutexOwnerId);
237 	mutexBeginExecution->setOwnerId(mutexOwnerId);
238 	hasBeginExecution = value;
239 	safeMutex.ReleaseLock();
240 
241 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s]\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str());
242 }
243 
getRunningStatus()244 bool BaseThread::getRunningStatus() {
245 	//bool retval = false;
246 
247 	static string mutexOwnerId = CODE_AT_LINE;
248 	MutexSafeWrapper safeMutex(mutexRunning,mutexOwnerId);
249 	bool retval = running;
250 	safeMutex.ReleaseLock();
251 
252 	if(retval == false) {
253 		retval = !getHasBeginExecution();
254 	}
255 
256 	return retval;
257 }
258 
setRunningStatus(bool value)259 void BaseThread::setRunningStatus(bool value) {
260 	static string mutexOwnerId = CODE_AT_LINE;
261 	MutexSafeWrapper safeMutex(mutexRunning,mutexOwnerId);
262 	mutexRunning->setOwnerId(mutexOwnerId);
263 	running = value;
264 	if(value == true) {
265 		setHasBeginExecution(true);
266 	}
267 	safeMutex.ReleaseLock();
268 }
269 
setExecutingTask(bool value)270 void BaseThread::setExecutingTask(bool value) {
271 	static string mutexOwnerId = CODE_AT_LINE;
272 	MutexSafeWrapper safeMutex(mutexExecutingTask,mutexOwnerId);
273 	mutexExecutingTask->setOwnerId(mutexOwnerId);
274 	executingTask = value;
275 	safeMutex.ReleaseLock();
276 }
277 
getExecutingTask()278 bool BaseThread::getExecutingTask() {
279 	//bool retval = false;
280 	static string mutexOwnerId = CODE_AT_LINE;
281 	MutexSafeWrapper safeMutex(mutexExecutingTask,mutexOwnerId);
282 	bool retval = executingTask;
283 	safeMutex.ReleaseLock();
284 
285 	return retval;
286 }
287 
getDeleteSelfOnExecutionDone()288 bool BaseThread::getDeleteSelfOnExecutionDone() {
289     //bool retval = false;
290     static string mutexOwnerId = CODE_AT_LINE;
291     MutexSafeWrapper safeMutex(mutexDeleteSelfOnExecutionDone,mutexOwnerId);
292     bool retval = deleteSelfOnExecutionDone;
293     safeMutex.ReleaseLock();
294 
295     return retval;
296 }
297 
setDeleteSelfOnExecutionDone(bool value)298 void BaseThread::setDeleteSelfOnExecutionDone(bool value) {
299 	static string mutexOwnerId = CODE_AT_LINE;
300     MutexSafeWrapper safeMutex(mutexDeleteSelfOnExecutionDone,mutexOwnerId);
301     mutexDeleteSelfOnExecutionDone->setOwnerId(mutexOwnerId);
302     deleteSelfOnExecutionDone = value;
303 }
304 
deleteSelfIfRequired()305 void BaseThread::deleteSelfIfRequired() {
306     if(getDeleteSelfOnExecutionDone() == true) {
307     	if(isThreadDeleted(this->ptr) == false) {
308     		this->setDeleteAfterExecute(true);
309     	}
310         return;
311     }
312 }
313 
canShutdown(bool deleteSelfIfShutdownDelayed)314 bool BaseThread::canShutdown(bool deleteSelfIfShutdownDelayed) {
315     return true;
316 }
317 
shutdownAndWait(BaseThread * pThread)318 bool BaseThread::shutdownAndWait(BaseThread *pThread) {
319 	bool ret = false;
320 	if(pThread != NULL) {
321 		ret = pThread->shutdownAndWait();
322 	}
323 
324 	return ret;
325 }
326 
shutdownAndWait()327 bool BaseThread::shutdownAndWait() {
328 	bool ret = true;
329 	BaseThread *pThread = this;
330 	//string uniqueID = (pThread != NULL ? pThread->getUniqueID() : "?");
331 	string uniqueID = pThread->getUniqueID();
332 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s]\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str());
333 
334 	//if(pThread != NULL) {
335 		if(pThread->getRunningStatus() == true) {
336 			if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s]\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str());
337 
338 			pThread->signalQuit();
339 			sleep(0);
340 			ret = false;
341 
342 			int maxWaitSeconds = 5;
343 			if(pThread->canShutdown() == false) {
344 				maxWaitSeconds = 2;
345 			}
346 
347 			for( time_t elapsed = time(NULL); difftime(time(NULL),elapsed) <= maxWaitSeconds; ) {
348 				if(pThread->getRunningStatus() == false) {
349 					ret = true;
350 					break;
351 				}
352 
353 				sleep(0);
354 			}
355 			if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s]\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str());
356 			sleep(0);
357 		}
358 	//}
359 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] uniqueID [%s] ret [%d] END\n",__FILE__,__FUNCTION__,__LINE__,uniqueID.c_str(),ret);
360 	return ret;
361 }
362 
363 }}//end namespace
364