

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of CMSDK version 2.0.0.170915_Beta4 (15 September 2017)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2017
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  and is released under the following
//_/_/  
//_/_/  EXTENDED BSD License
//_/_/
//_/_/  Redistribution and use in source and binary forms, with or without
//_/_/  modification, is permitted provided that the following conditions 
//_/_/  are met:
//_/_/
//_/_/  - Redistributions of source code must retain the above copyright 
//_/_/    and collaboration notice, this list of conditions and the following 
//_/_/    disclaimer.
//_/_/
//_/_/  - Redistributions in binary form must reproduce the above copyright 
//_/_/    notice, this list of conditions and the following disclaimer in the 
//_/_/    documentation and/or other materials provided with the distribution.
//_/_/
//_/_/  - Neither the name of its copyright holders nor the names of its 
//_/_/    contributors may be used to endorse or promote products derived from 
//_/_/    this software without specific prior written permission.
//_/_/
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license. The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#if !defined(_THREADMANAGER_H_)
#define _THREADMANAGER_H_

#include "MemoryManager.h"

namespace cmlabs {

struct ThreadStats {
	uint32 id;				// ID of the thread
	uint64 created;			// Thread creation time
	uint32 status;			// Status of the thread
	uint32 osID;			// OS id of thread
	ThreadHandle hThread;	// Thread handle
	THREAD_FUNCTION func;	// Function to run
	void* args;				// Function argument
	uint64 time[10];		// Last 10 timestamps
	uint64 currentCPUTicks[10];	// Last 10 CPU usage readings
};

struct ThreadDataHeader {
	uint32 size;			// Total size of data in bytes
	uint32 count;			// Number of thread stats
	uint32 activeCount;		// Number of thread stats
	uint32 statColPolicy;	// How statistics are collected
	uint64 time[10];		// Last 10 timestamps
	uint64 currentCPUTicks[10];	// Last 10 CPU usage readings
	uint32 bitFieldSize;	// Number of bytes in the bitfield
	// Bitfield
	// Stats1, Stats2, ...
};


class Runnable {
public:
	Runnable() {threadID = 0; shouldContinue = true; isRunning = false;}
	virtual ~Runnable() {
		stop();
	}
	virtual bool stop(uint32 timeout = 200) {
		shouldContinue = false;
		int32 timeleft = (int32)timeout;
		while (isRunning) {
			utils::Sleep(5);
			if ( (timeleft -= 5) <= 0) {
				LogPrint(0,LOG_SYSTEM,0,"Thread id %u didn't terminate...\n", threadID);
				return false;
			}
		}
		return true;
	}

protected:
	uint32 threadID;
	bool shouldContinue;
	bool isRunning;
};

#define GETTHREADSTATS(data,id) (ThreadStats*)(data + sizeof(ThreadDataHeader) + ((ThreadDataHeader*)data)->bitFieldSize + id*sizeof(ThreadStats))

class ThreadManager : public Runnable {
public:
	static ThreadManager* Singleton;

	// Create the ThreadManager Singleton
	static bool CreateThreadManager();
	// Create a new thread and start it
	static bool CreateThread(THREAD_FUNCTION func, void* args, uint32& newID, uint32 reqID = 0);
	// Pause the thread wherever it is now
	static bool PauseThread(uint32 id);
	// Allow the thread to continue running
	static bool ContinueThread(uint32 id);
	// Terminate the thread and restart it from its base location
	static bool InterruptThread(uint32 id);
	// Terminate and destroy the thread
	static bool TerminateThread(uint32 id);
	// Has thread terminated / exited
	static bool IsThreadRunning(uint32 id);

	// Add thread stats for local thread - needed for pthreads
	static bool AddLocalThreadStats();
	// Add thread stats for local thread - needed for pthreads
	static bool GetLocalThreadID(uint32& id);

	// Get the statistics for local thread
	static ThreadStats GetLocalThreadStats();
	// Get the statistics for a thread
	static ThreadStats GetThreadStats(uint32 id);
	// Get the statistics for all threads
	static ThreadStats* GetAllThreadStats(uint32& count);

	// Shutdown and delete the ThreadManager
	static bool Shutdown();

	ThreadManager();
	~ThreadManager();
	bool init();
	bool shutdown();

	int32 threadMonitoring();

protected:
	// Create a new thread and start it
	bool createThread(THREAD_FUNCTION func, void* args, uint32& newID, uint32 reqID);
	// Pause the thread wherever it is now
	bool pauseThread(uint32 id);
	// Allow the thread to continue running
	bool continueThread(uint32 id);
	// Terminate the thread and restart it from its base location
	bool interruptThread(uint32 id);
	// Terminate and destroy the thread
	bool terminateThread(uint32 id);
	// Has thread terminated / exited
	bool isThreadRunning(uint32 id);

	// Add thread stats for local thread - needed for pthreads
	bool addLocalThreadStats();
	// Get the local thread ID
	bool getLocalThreadID(uint32& id);

	// Get the statistics for a thread
	ThreadStats getThreadStats(uint32 id);
	// Get the statistics for all threads
	ThreadStats* getAllThreadStats(uint32& count);

	// Resize the ThreadStats storage to be able to contain more threads
	bool resizeThreadStorage(uint32 newCount);

	utils::Mutex mutex;
	unsigned char* data;
};

bool TestThreadManager();

static THREAD_RET THREAD_FUNCTION_CALL ThreadMonitoring(void* arg);


} // namespace cmlabs

#endif //_THREADMANAGER_H_

