/*
    PIP - Platform Independent Primitives
    Thread
    Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "pithread.h"

#include "piincludes_p.h"
#include "piintrospection_threads.h"
#include "piliterals_time.h"
#include "pitime.h"
#include "pitranslator.h"
#ifndef MICRO_PIP
#  include "pisystemtests.h"
#endif
#ifdef WINDOWS
#  include <ioapiset.h>
#endif
#include <signal.h>
#if defined(WINDOWS)
#  define __THREAD_FUNC_RET__ uint __stdcall
#elif defined(FREERTOS)
#  define __THREAD_FUNC_RET__ void
#else
#  define __THREAD_FUNC_RET__ void *
#endif
#ifndef FREERTOS
#  define __THREAD_FUNC_END__ 0
#else
#  define __THREAD_FUNC_END__
#endif
#if defined(LINUX)
#  include <sys/syscall.h>
#  define gettid() syscall(SYS_gettid)
#endif
#if defined(MAC_OS) || defined(BLACKBERRY)
#  include <pthread.h>
#endif
__THREAD_FUNC_RET__ thread_function(void * t) {
	((PIThread *)t)->__thread_func__();
	return __THREAD_FUNC_END__;
}
__THREAD_FUNC_RET__ thread_function_once(void * t) {
	((PIThread *)t)->__thread_func_once__();
	return __THREAD_FUNC_END__;
}

#ifndef MICRO_PIP
#  define REGISTER_THREAD(t)   __PIThreadCollection::instance()->registerThread(t)
#  define UNREGISTER_THREAD(t) __PIThreadCollection::instance()->unregisterThread(t)
#else
#  define REGISTER_THREAD(t)
#  define UNREGISTER_THREAD(t)
#endif

//! \addtogroup Thread
//! \{
//! \class PIThread pithread.h
//! \~\brief
//! \~english Thread class
//! \~russian Класс потока
//!
//! \~\details
//! \~english
//! This class allow you exec your code in separate thread.
//!
//! \~russian
//! Этот класс позволяет выполнять код из параллельного потока.
//!
//!
//! \~english \section PIThread_sec0 Synopsis
//! \~russian \section PIThread_sec0 Краткий обзор
//! \~english
//! Multithreading allow you to execute code
//! in several threads simultaneously. This trend allow you to use all
//! cores of modern processors, but there are many dangers.
//!
//! This class provide virtual functions \a begin(), \a run() and \a end(),
//! which describes start, execution and finish work of some process.
//! These functions executes in \b separate thread. When you execute
//! \a start(int), %PIThread create separate system thread and sequentially
//! executes function \a begin(), \a run() and \a end(). You can
//! reimplement each function and write your own code to execute.
//!
//! Scheme of functions executing:
//!
//! \~russian
//! Многопоточность позволяет исполнять код в нескольких потоках
//! одновременно и использовать все ядра современных процессоров.
//! Однако это таит в себе опасности.
//!
//! Этот класс предоставляет виртуальные методы \a begin(), \a run() и \a end(),
//! которые описывают старт, выполнение и завершение потоковой задачи.
//! Все эти методы исполняются в \b отдельном потоке. Когда выполняется
//! \a start(int), %PIThread создает отдельный поток средствами ОС и последовательно
//! выполняет \a begin(), \a run() и \a end(). Можно переопределить каждый метод
//! для реализации нужной задачи.
//!
//! Схема выполнения методов:
//!
//! \~\code{.cpp}
//! virtual begin()
//! event started()
//! while (isRunning()) {     // while not stop()
//!     virtual run()
//!     ThreadFunc()          // Slot or lambda
//!     piMSleep(loop_delay)  // if loop_delay > 0
//! }
//! event stopped()
//! virtual end()
//! \endcode
//!
//! \~english
//! If no internal loop needed, you can use \a startOnce() method instead of \a start(int).
//!
//! In this case scheme is next:
//!
//! \~russian
//! Если внутренний цикл не нужен, то можно использовать метод \a startOnce() вместо \a start(int).
//!
//! В этом случает схема выполнения следущая:
//!
//! \~\code{.cpp}
//! virtual begin()
//! event started()
//! virtual run()
//! ThreadFunc()    // Slot or lambda
//! event stopped()
//! virtual end()
//! \endcode
//!
//! \~english
//! Unlike from directly using "pthread" or some similar you doesn`t need
//! to write your own main thread cycle and sleep at every cycle end.
//! %PIThread make it for you, and your job is to set sleep value from
//! contructor or when starting thread, and reimplement \a begin(), \a run()
//! and \a end() functions.
//!
//! \~russian
//! В отличии от прямого использования "pthread" или похожих механизмов
//! нет необходимости писать свой цикл внутри поточного метода и ожидать
//! в его теле. %PIThread уже рализует такой цикл, необходимо лишь
//! установить значение ожидания в конструкторе или при запуске потока,
//! и переопределить методы \a begin(), \a run() и \a end().
//!
//! \~english Using with internal loop
//! \~russian Использование с внутренним циклом
//! \~\code{.cpp}
//! class MyThread: public PIThread {
//! 	PIOBJECT_SUBCLASS(MyThread, PIThread)
//! public:
//! 	void begin() override {piCout << "thread begin";}
//! 	void run() override {piCout << "thread run" << ++cnt;}
//! 	void end() override {piCout << "thread end";}
//! private:
//! 	int cnt = 0;
//! };
//!
//! int main(int argc, char * argv[]) {
//! 	MyThread mt;
//! 	mt.start(100);
//! 	piMSleep(500);
//! 	mt.stop(true);
//! 	return 0;
//! }
//!
//! // thread begin
//! // thread run 1
//! // thread run 2
//! // thread run 3
//! // thread run 4
//! // thread run 5
//! // thread end
//! \endcode
//!
//! \~english Using without internal loop
//! \~russian Использование без внутреннего цикла
//! \~\code{.cpp}
//! class MyThread: public PIThread {
//! 	PIOBJECT_SUBCLASS(MyThread, PIThread)
//! public:
//! 	void begin() override {piCout << "thread begin";}
//! 	void run() override {piCout << "thread run" << ++cnt;}
//! 	void end() override {piCout << "thread end";}
//! private:
//! 	int cnt = 0;
//! };
//!
//! int main(int argc, char * argv[]) {
//! 	MyThread mt;
//! 	mt.startOnce();
//! 	piMSleep(500);
//! 	mt.stop(true);
//! 	return 0;
//! }
//!
//! // thread begin
//! // thread run 1
//! // thread end
//! \endcode
//!
//!
//! \~english \section PIThread_sec1 Using without subclassing
//! \~russian \section PIThread_sec1 Использование без наследования
//! \~english
//! You can use %PIThread without subclassing by using "ThreadFunc" pointer
//! that can be set from constructor or by overloaded function \a start(ThreadFunc func, int loop_delay).
//! If "func" if not null this function will be executed after \a run().
//!
//! ThreadFunc is any static function with format "void func(void * data)", or
//! [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) with format [...]( ){...}.
//! "Data" is custom data set from constructor or with \a setData() function.
//!
//! Also you can connect to event \a started(), but in this case you should to white
//! your thread main cycle, because this event raised only one time after thread start.
//!
//! \~russian
//! Возможно использовать %PIThread без наследования. Можно передать ему в конструкторе
//! или при запуске указатель на внешний метод "ThreadFunc". В основном цикле потока,
//! если "ThreadFunc" существует, он будет вызываться после \a run().
//!
//! ThreadFunc может быть любым статическим методом в формате "void func(void * data)", либо
//! [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) в формате [...]( ){...}.
//! "Data" является произвольным указателем, задаваемым в конструкторе или методом \a setData().
//!
//! Также можно присоединиться к событию \a started(), но в этом случае надо будет своими силами
//! реализовать весь цикл, т.к. это событие вызывается один раз после запуска потока.
//!
//! \~english Using with internal loop
//! \~russian Использование с внутренним циклом
//! \~\code{.cpp}
//! void myThreadFunc(void * d) {
//! 	int * cnt = (int*)d;
//! 	piCout << "thread run" << ++(*cnt);
//! }
//!
//! int main(int argc, char * argv[]) {
//! 	int cnt = 0;
//! 	PIThread mt;
//! 	mt.setData(&cnt);
//! 	mt.start(myThreadFunc, 100);
//! 	piMSleep(500);
//! 	mt.stop(true);
//! 	return 0;
//! }
//!
//! // thread run 1
//! // thread run 2
//! // thread run 3
//! // thread run 4
//! // thread run 5
//! \endcode
//!
//! \~english Using without internal loop
//! \~russian Использование без внутреннего цикла
//! \~\code{.cpp}
//! void myThreadFunc(void * d) {
//! 	int * cnt = (int*)d;
//! 	piCout << "thread run" << ++(*cnt);
//! }
//!
//! int main(int argc, char * argv[]) {
//! 	int cnt = 0;
//! 	PIThread mt;
//! 	mt.setData(&cnt);
//! 	mt.startOnce(myThreadFunc);
//! 	piMSleep(500);
//! 	mt.stop(true);
//! 	return 0;
//! }
//!
//! // thread run 1
//! \endcode
//!
//! \~english Using with [lambda expression](https://en.cppreference.com/w/cpp/language/lambda)
//! \~russian Использование с [лямбда-выражением](https://ru.cppreference.com/w/cpp/language/lambda)
//! \~\code{.cpp}
//! int main(int argc, char * argv[]) {
//! 	int cnt = 0;
//! 	PIThread mt;
//! 	mt.start([&cnt](){
//! 		piCout << "thread run" << ++cnt;
//! 	}, 100);
//! 	piMSleep(500);
//! 	mt.stop(true);
//! 	return 0;
//! }
//!
//! // thread run 1
//! // thread run 2
//! // thread run 3
//! // thread run 4
//! // thread run 5
//! \endcode
//!
//! \~english Using with event
//! \~russian Использование с событием
//! \~\code{.cpp}
//! class MyObj: public PIObject {
//! 	PIOBJECT(MyObj)
//! public:
//! 	EVENT_HANDLER(void, threadRun) {
//! 		piForTimes (5) {
//! 			piCout << "threadRun" << ++cnt;
//! 			piMSleep(100);
//! 		}
//! 	};
//! private:
//! 	int cnt = 0;
//! };
//!
//! int main(int argc, char * argv[]) {
//! 	MyObj mo;
//! 	PIThread mt;
//! 	CONNECTU(&mt, started, &mo, threadRun);
//! 	mt.startOnce();
//! 	mt.stop(true);
//! 	return 0;
//! }
//!
//! // threadRun 1
//! // threadRun 2
//! // threadRun 3
//! // threadRun 4
//! // threadRun 5
//! \endcode
//!
//! \~english \section PIThread_sec2 Locking
//! \~russian \section PIThread_sec2 Блокировки
//! \~english
//! %PIThread has inrternal mutex that can be locked and unlocked every \a run() if you set this flag
//! with function \a needLockRun(true). Also you can access to this mutex by functions \a lock(), \a unlock()
//! and \a mutex(). Using this functions outside of thread together with \a needLockRun(true) can defend
//! your data.
//!
//! \~russian
//! %PIThread имеет встроенный мьютекс, который может блокироваться и разблокироваться каждый \a run()
//! при установленном \a needLockRun(true). К нему есть доступ через методы \a lock(), \a unlock() и \a mutex().
//! Использование этих методов вне потока совместно с \a needLockRun(true) поможет защитить данные.
//!
//! \}
//!


//! \fn bool PIThread::start(int loop_delay = -1)
//! \~\details
//! \~english
//! Start execution of \a run() in internal loop with
//! "loop_delay" delay in milliseconds. If "loop_delay" <= 0
//! this is no delay in loop. Thread also exec external function
//! set by \a setSlot() if it`s not null.
//! \return \c false if thread already started or can`t start thread
//!
//! \~russian
//! Начинает выполнение \a run() во внутреннем цикле
//! с задержкой "loop_delay" миллисекунд. Если "loop_delay" <= 0
//! то задержки не будет. Также поток вызывает внешний метод,
//! заданный через \a setSlot(), если он существует.
//! \return \c false если поток уже запущен или не может запуститься


//! \fn bool PIThread::startOnce()
//! \~\details
//! \~english
//! Start execution of \a run() once. Thread also exec
//! external function set by \a setSlot() if it`s not null.
//! \return \c false if thread already started or can`t start thread
//!
//! \~russian
//! Начинает выполнение \a run() один раз. Также поток вызывает
//! внешний метод, заданный через \a setSlot(), если он существует.
//! \return \c false если поток уже запущен или не может запуститься


//! \fn bool PIThread::startOnce(ThreadFunc func)
//! \~\details
//! \~english
//! Overloaded function. Set external function "func" before start.
//! \return \c false if thread already started or can`t start thread
//!
//! \~russian
//! Перегрузка метода, устанавливает внешний метод в "func" перед запуском.
//! \return \c false если поток уже запущен или не может запуститься


//! \fn void PIThread::stop(bool wait = false)
//! \~\details
//! \~english
//! Mark thread to stop execution and wait for finish
//! if "wait" is \c true. Thread can be stopped only outside of
//! \a run() or external method.
//! \warning This function can block for infinite
//! time if "wait" is \c true and any of thread function is
//! busy forever.
//!
//! \~russian
//! Помечает поток на остановку и ожидает завершения если
//! "wait" \c true. Поток может быть остановлен только вне
//! \a run() или внешнего метода.
//! \warning Этот метод может ожидать бесконечно если
//! "wait" \c true и любой из потоковых методов занят навечно.


//! \fn void PIThread::terminate()
//! \~\details
//! \~english
//! Stop execution of thread immediately.
//! \warning Memory can be corrupted, try not to use this method!
//!
//! \~russian
//! Немедленно останавливает поток.
//! \warning Это может повредить память, старайтесь не использовать этот метод!


//! \fn bool PIThread::waitForStart(int timeout_msecs = -1)
//! \~\details
//! \~english
//! Block until thread start within "timeout_msecs"
//! or forever if "timeout_msecs" < 0
//! \return \c true if thread started less than timeout
//! \return \c false if timeout is exceeded
//!
//! \~russian
//! Блокирует до тех пор, пока поток не запустится в течении
//! "timeout_msecs", или бесконечно, если "timeout_msecs" < 0
//! \return \c true если поток запустился менее чем за таймаут
//! \return \c false если таймаут истёк


//! \fn bool PIThread::waitForFinish(int timeout_msecs = -1)
//! \~\details
//! \~english
//! Block until thread finish for "timeout_msecs"
//! or forever if "timeout_msecs" < 0
//! \return \c true if thread finished less than timeout
//! \return \c false if timeout is exceeded
//!
//! \~russian
//! Блокирует до тех пор, пока поток не завершится в течении
//! "timeout_msecs", или бесконечно, если "timeout_msecs" < 0
//! \return \c true если поток завершился менее чем за таймаут
//! \return \c false если таймаут истёк


#ifndef MICRO_PIP

__PIThreadCollection * __PIThreadCollection::instance() {
	return __PIThreadCollection_Initializer__::__instance__;
}


void __PIThreadCollection::registerThread(PIThread * t) {
	lock();
	if (!threads_.contains(t)) threads_ << t;
	unlock();
}


void __PIThreadCollection::unregisterThread(PIThread * t) {
	lock();
	threads_.removeAll(t);
	unlock();
}


PIVector<PIThread *> __PIThreadCollection::threads() const {
	return threads_;
}


void __PIThreadCollection::startedAuto(PIThread * t) {
	PIMutexLocker _ml(auto_mutex);
	auto_threads_ << t;
}


void __PIThreadCollection::stoppedAuto() {
	PIThread * t = emitter()->cast<PIThread>();
	if (!t) return;
	auto_mutex.lock();
	auto_threads_.removeAll(t);
	auto_mutex.unlock();
	t->deleteLater();
}


int __PIThreadCollection_Initializer__::count_(0);
__PIThreadCollection * __PIThreadCollection_Initializer__::__instance__(0);


__PIThreadCollection_Initializer__::__PIThreadCollection_Initializer__() {
	count_++;
	// PICout(PICoutManipulators::DefaultControls) << "try create Core" << count_;
	if (count_ > 1) return;
	// PICout(PICoutManipulators::DefaultControls) << "create Core";
	__instance__ = new __PIThreadCollection();
}


__PIThreadCollection_Initializer__::~__PIThreadCollection_Initializer__() {
	count_--;
	// PICout(PICoutManipulators::DefaultControls) << "try delete Core" << count_;
	if (count_ > 0) return;
	// PICout(PICoutManipulators::DefaultControls) << "delete Core";
	if (__instance__ != 0) {
		delete __instance__;
		__instance__ = 0;
	}
}

#endif // MICRO_PIP


PRIVATE_DEFINITION_START(PIThread)
#if defined(WINDOWS)
	void * thread = nullptr;
#elif defined(FREERTOS)
	TaskHandle_t thread;
#else
	pthread_t thread = 0;
	sched_param sparam;
#endif
PRIVATE_DEFINITION_END(PIThread)


PIThread::PIThread(void * data, ThreadFunc func, bool startNow, PISystemTime loop_delay): PIObject() {
	PIINTROSPECTION_THREAD_NEW(this);
	data_       = data;
	ret_func    = std::move(func);
	terminating = running_ = lockRun = false;
	priority_                        = piNormal;
	delay_                           = loop_delay;
	if (startNow) start();
}


PIThread::PIThread(std::function<void()> func, bool startNow, PISystemTime loop_delay) {
	PIINTROSPECTION_THREAD_NEW(this);
	ret_func    = [func](void *) { func(); };
	terminating = running_ = lockRun = false;
	priority_                        = piNormal;
	delay_                           = loop_delay;
	if (startNow) start();
}


PIThread::PIThread(bool startNow, PISystemTime loop_delay): PIObject() {
	PIINTROSPECTION_THREAD_NEW(this);
	terminating = running_ = lockRun = false;
	priority_                        = piNormal;
	delay_                           = loop_delay;
	if (startNow) start();
}


PIThread::~PIThread() {
	PIINTROSPECTION_THREAD_DELETE(this);
	if (!running_ || PRIVATE->thread == 0) return;
	piCout << "[PIThread \"%1\"] Warning, terminate on destructor!"_tr("PIThread").arg(name());
#ifdef FREERTOS
	// void * ret(0);
	// PICout(PICoutManipulators::DefaultControls) << "~PIThread" << PRIVATE->thread;
	// PICout(PICoutManipulators::DefaultControls) << pthread_join(PRIVATE->thread, 0);
	PICout(PICoutManipulators::DefaultControls) << "FreeRTOS can't terminate pthreads! waiting for stop";
	stopAndWait();
	// PICout(PICoutManipulators::DefaultControls) << "stopped!";
#else
#  ifndef WINDOWS
#	ifdef ANDROID
	pthread_kill(PRIVATE->thread, SIGTERM);
#	else
	pthread_cancel(PRIVATE->thread);
#	endif
#  else
	TerminateThread(PRIVATE->thread, 0);
	CloseHandle(PRIVATE->thread);
#  endif
#endif
	UNREGISTER_THREAD(this);
	PIINTROSPECTION_THREAD_STOP(this);
	terminating = running_ = false;
}


bool PIThread::start() {
	if (running_) return false;
	return _startThread((void *)thread_function);
}


bool PIThread::start(PISystemTime loop_delay) {
	delay_ = loop_delay;
	return start();
}


bool PIThread::start(ThreadFunc func) {
	ret_func = std::move(func);
	return start();
}


bool PIThread::start(ThreadFunc func, PISystemTime loop_delay) {
	ret_func = std::move(func);
	delay_   = loop_delay;
	return start();
}


bool PIThread::start(std::function<void()> func) {
	ret_func = [func](void *) { func(); };
	return start();
}


bool PIThread::start(std::function<void()> func, PISystemTime loop_delay) {
	ret_func = [func](void *) { func(); };
	delay_   = loop_delay;
	return start();
}


bool PIThread::startOnce() {
	if (running_) return false;
	return _startThread((void *)thread_function_once);
}


bool PIThread::startOnce(ThreadFunc func) {
	ret_func = std::move(func);
	return startOnce();
}


bool PIThread::startOnce(std::function<void()> func) {
	ret_func = [func](void *) { func(); };
	return startOnce();
}


bool PIThread::stopAndWait(PISystemTime timeout) {
	stop();
	return waitForFinish(timeout);
}


void PIThread::stop() {
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop ..." << running_ << wait;
	terminating = true;
}


void PIThread::terminate() {
	piCoutObj << "Warning, terminate!"_tr("PIThread");
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "terminate ..." << running_;
#ifdef FREERTOS
	PICout(PICoutManipulators::DefaultControls) << "FreeRTOS can't terminate pthreads! waiting for stop";
	stop(true);
	// PICout(PICoutManipulators::DefaultControls) << "stopped!";
#else
	if (PRIVATE->thread == 0) return;
	UNREGISTER_THREAD(this);
	terminating = running_ = false;
	tid_                   = -1;
	// PICout(PICoutManipulators::DefaultControls) << "terminate" << PRIVATE->thread;
#  ifndef WINDOWS
#	ifdef ANDROID
	pthread_kill(PRIVATE->thread, SIGTERM);
#	else
	// pthread_kill(PRIVATE->thread, SIGKILL);
	// void * ret(0);
	pthread_cancel(PRIVATE->thread);
	// pthread_join(PRIVATE->thread, &ret);
#	endif
#  else
	TerminateThread(PRIVATE->thread, 0);
	CloseHandle(PRIVATE->thread);
#  endif
	PRIVATE->thread = 0;
	end();
#endif // FREERTOS
	PIINTROSPECTION_THREAD_STOP(this);
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "terminate ok" << running_;
}


int PIThread::priority2System(PIThread::Priority p) {
	switch (p) {
#if defined(QNX)
	case piLowerst: return 8;
	case piLow: return 9;
	case piNormal: return 10;
	case piHigh: return 11;
	case piHighest: return 12;
#elif defined(WINDOWS)
	case piLowerst: return -2;
	case piLow: return -1;
	case piNormal: return 0;
	case piHigh: return 1;
	case piHighest: return 2;
#elif defined(FREERTOS)
	case piLowerst: return 2;
	case piLow: return 3;
	case piNormal: return 4;
	case piHigh: return 5;
	case piHighest: return 6;
#else
	case piLowerst: return 2;
	case piLow: return 1;
	case piNormal: return 0;
	case piHigh: return -1;
	case piHighest: return -2;
#endif
	default: return 0;
	}
	return 0;
}


bool PIThread::_startThread(void * func) {
	terminating = false;
	running_    = true;

#ifdef FREERTOS

	auto name_ba = createThreadName();
	if (xTaskCreate((__THREAD_FUNC_RET__(*)(void *))func,
	                (const char *)name_ba.data(), // A name just for humans
	                128,                          // This stack size can be checked & adjusted by reading the Stack Highwater
	                this,
	                priority_,
	                &PRIVATE->thread) == pdPASS) {
		tid_ = (llong)PRIVATE->thread;
		return true;
	}

#elif defined(WINDOWS)

	if (PRIVATE->thread) CloseHandle(PRIVATE->thread);
#  ifdef CC_GCC
	PRIVATE->thread = (void *)_beginthreadex(0, 0, (__THREAD_FUNC_RET__(*)(void *))func, this, CREATE_SUSPENDED, 0);
#  else
	PRIVATE->thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)func, this, CREATE_SUSPENDED, 0);
#  endif
	if (PRIVATE->thread != 0) {
		ResumeThread(PRIVATE->thread);
		return true;
	}

#else

	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	int ret = pthread_create(&PRIVATE->thread, &attr, (__THREAD_FUNC_RET__(*)(void *))func, this);
	pthread_attr_destroy(&attr);
	// PICout(PICoutManipulators::DefaultControls) << "pthread_create" << PRIVATE->thread;
	// piCout << "started" << PRIVATE->thread;
	if (ret == 0) {
		return true;
	}

#endif

	running_        = false;
	PRIVATE->thread = 0;
	piCoutObj << "Error: Can`t start new thread: %1"_tr("PIThread").arg(errorString());
	return false;
}


void PIThread::setPriority(PIThread::Priority prior) {
	priority_ = prior;
	if (!running_ || (PRIVATE->thread == 0)) return;
#ifdef FREERTOS
	vTaskPrioritySet(PRIVATE->thread, priority2System(priority_));
#else
#  ifndef WINDOWS
	// PICout(PICoutManipulators::DefaultControls) << "setPriority" << PRIVATE->thread;
	int policy_ = 0;
	piZeroMemory(PRIVATE->sparam);
	pthread_getschedparam(PRIVATE->thread, &policy_, &(PRIVATE->sparam));
	PRIVATE->sparam.
#	ifndef LINUX
		sched_priority
#	else
		__sched_priority
#	endif
		= priority2System(priority_);
	pthread_setschedparam(PRIVATE->thread, policy_, &(PRIVATE->sparam));
#  else
	SetThreadPriority(PRIVATE->thread, priority2System(priority_));
#  endif
#endif // FREERTOS
}


#ifdef WINDOWS
bool isExists(HANDLE hThread) {
	// errorClear();
	// piCout << "isExists" << hThread;
	DWORD dw = 0;
	GetExitCodeThread(hThread, &dw);
	// piCout << ret << dw << errorString();
	if (dw == STILL_ACTIVE) return true;
	// piCout << errorString();
	return false;
}
#endif


bool PIThread::waitForFinish(PISystemTime timeout) {
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "PIThread::waitForFinish" << running_ << terminating <<
	// timeout_msecs;
	if (!running_) return true;
	if (timeout.isNull()) {
		for (;;) {
			if (_waitForFinish(PISystemTime::fromMilliseconds(PIP_MIN_MSLEEP))) break;
		}
		return true;
	}
	PITimeMeasurer tm;
	while (tm.elapsed() < timeout) {
		if (_waitForFinish(PISystemTime::fromMilliseconds(PIP_MIN_MSLEEP))) return true;
	}
	return tm.elapsed() < timeout;
}


bool PIThread::waitForStart(PISystemTime timeout) {
	if (running_) return true;
	if (timeout.isNull()) {
		while (!running_)
			piMinSleep();
		return true;
	}
	PITimeMeasurer tm;
	while (!running_ && tm.elapsed() < timeout)
		piMinSleep();
	return tm.elapsed() < timeout;
}


void PIThread::_beginThread() {
#ifndef WINDOWS
#  if !defined(ANDROID) && !defined(FREERTOS)
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, 0);
#  endif
#endif
#ifdef WINDOWS
	tid_ = GetCurrentThreadId();
#endif
#ifdef LINUX
	tid_ = gettid();
#endif
	setPriority(priority_);
	setThreadName();
	PIINTROSPECTION_THREAD_START(this);
	REGISTER_THREAD(this);
	running_ = true;
	if (lockRun) thread_mutex.lock();
	begin();
	if (lockRun) thread_mutex.unlock();
	started();
}


void PIThread::_runThread() {
	PIINTROSPECTION_THREAD_RUN(this);
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "...";
	if (lockRun) thread_mutex.lock();
		// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "ok";
		// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "run" << "...";
#ifdef PIP_INTROSPECTION
	PITimeMeasurer _tm;
#endif
	run();
#ifdef PIP_INTROSPECTION
	PIINTROSPECTION_THREAD_RUN_DONE(this, ullong(_tm.elapsed_u()));
#endif
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "run" << "ok";
	// printf("thread %p tick\n", this);
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "ret_func" << "...";
	if (ret_func != 0) ret_func(data_);
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "ret_func" << "ok";
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "...";
	if (lockRun) thread_mutex.unlock();
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "ok";
}


void PIThread::_endThread() {
	PIScopeExitCall ec([this] {
		terminating = running_ = false;
		tid_                   = -1;
		state_notifier.notify();
	});
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "...";
	stopped();
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
	if (lockRun) thread_mutex.lock();
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "end" << "...";
	end();
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
	if (lockRun) thread_mutex.unlock();
	// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "exit";
	// cout << "thread " << t << " exiting ... " << endl;
	// PICout(PICoutManipulators::DefaultControls) << "pthread_exit" << (__privateinitializer__.p)->thread;
	UNREGISTER_THREAD(this);
	PIINTROSPECTION_THREAD_STOP(this);
#if defined(WINDOWS)
	ec.callAndCancel();
#  ifdef CC_GCC
	_endthreadex(0);
#  else
	ExitThread(0);
#  endif
#elif defined(FREERTOS)
	PRIVATE->thread = 0;
#else
	PRIVATE->thread = 0;
	ec.callAndCancel();
	pthread_exit(0);
#endif
}


void PIThread::__thread_func__() {
	_beginThread();
	while (!terminating) {
		// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "queued" << "...";
		maybeCallQueuedEvents();
		// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "queued" << "ok";
		_runThread();
		// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "wait" << "...";
		PIINTROSPECTION_THREAD_WAIT(this);
		if (delay_.isNotNull()) {
			PITimeMeasurer tm;
			double sl(0.);
			while (1) {
				sl = piMind(delay_.toMilliseconds() - tm.elapsed_m(), PIP_MIN_MSLEEP);
				if (terminating) break;
				if (sl <= 0.) break;
				piMSleep(sl);
			}
		}
		// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "wait" << "ok";
	}
	_endThread();
}


void PIThread::__thread_func_once__() {
	_beginThread();
	_runThread();
	_endThread();
}


//! \~\details
//! \~english
//! This method create %PIThread with name "name" and execute
//! event handler "handler" of object "object" in this thread.\n
//! This %PIThread automatically delete on function finish.
//!
//! \~russian
//! Этот метод создает %PIThread с именем "name" и выполняет
//! обработчик "handler" объекта "object" в этом потоке.\n
//! %PIThread автоматически удаляется после завершения обработчика.
//!
//! \~\code
//! class MyObj: public PIObject {
//! 	PIOBJECT(MyObj)
//! public:
//! 	EVENT_HANDLER(void, threadRun) {
//! 		piForTimes (5) {
//! 			piCout << "threadRun";
//! 			piMSleep(100);
//! 		}
//! 	};
//! };
//!
//! int main(int argc, char * argv[]) {
//! 	MyObj mo;
//! 	PIThread::runOnce(&mo, "threadRun");
//! 	piMSleep(1000); // wait for thread finish
//! 	return 0;
//! }
//! \endcode
void PIThread::runOnce(PIObject * object, const char * handler, const PIString & name) {
	PIThread * t = new PIThread();
	t->setName(name);
	if (!PIObject::piConnectU(t, PIStringAscii("started"), object, object, PIStringAscii(handler), "PIThread::runOnce").isValid()) {
		delete t;
		return;
	}
#ifndef MICRO_PIP
	__PIThreadCollection::instance()->startedAuto(t);
	CONNECT0(void, t, stopped, __PIThreadCollection::instance(), stoppedAuto);
#endif
	t->startOnce();
}


//! \~\details
//! \~english
//! This method create %PIThread with name "name" and execute
//! [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) "func" in this thread.\n
//! This %PIThread automatically delete on function finish.\n
//! "func" shouldn`t have arguments.
//!
//! \~russian
//! Этот метод создает %PIThread с именем "name" и выполняет
//! [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) "func" в этом потоке.\n
//! %PIThread автоматически удаляется после завершения функции.\n
//! "func" не должна иметь аргументов.
//!
//! \~\code
//! PIThread::runOnce([](){
//! 	piForTimes(5) {
//! 		piCout << "thread func";
//! 		piMSleep(100);
//! 	}
//! });
//! piMSleep(1000);
//! \endcode
void PIThread::runOnce(std::function<void()> func, const PIString & name) {
	PIThread * t = new PIThread();
	t->setName(name);
	t->setSlot(std::move(func));
#ifndef MICRO_PIP
	__PIThreadCollection::instance()->startedAuto(t);
	CONNECT0(void, t, stopped, __PIThreadCollection::instance(), stoppedAuto);
#endif
	t->startOnce();
}


PIByteArray PIThread::createThreadName(int size) const {
	PIString tname = name().simplified();
	tname.elide(size - 1, 0.4f).resize(size - 1, PIChar('\0'));
	PIByteArray ret = tname.toAscii();
	ret.resize(size);
	ret.back() = 0;
	return ret;
}


void PIThread::setThreadName() {
#ifndef WINDOWS
	auto name_ba = createThreadName();
#  ifdef MAC_OS
	pthread_setname_np((const char *)name_ba.data());
	pthread_threadid_np(PRIVATE->thread, (__uint64_t *)&tid_);
#  else
	pthread_setname_np(PRIVATE->thread, (const char *)name_ba.data());
#  endif
#endif
}


bool PIThread::_waitForFinish(PISystemTime max_tm) {
	if (!running_) return true;
	state_notifier.waitFor(max_tm);
	if (!running_) return true;
#ifdef WINDOWS
	if (!isExists(PRIVATE->thread)) {
		return true;
	}
#endif
	return false;
}
