diff --git a/include/lgi/common/Thread.h b/include/lgi/common/Thread.h --- a/include/lgi/common/Thread.h +++ b/include/lgi/common/Thread.h @@ -1,164 +1,165 @@ #ifndef __GTHREAD_H #define __GTHREAD_H ////////////////////////////////////////////////////////////////////////// // Thread types are defined in LMutex.h #include "lgi/common/Mutex.h" class LgiClass LThread { public: enum ThreadState { THREAD_INIT = 1, THREAD_RUNNING = 2, THREAD_ASLEEP = 3, THREAD_EXITED = 4, THREAD_ERROR = 5 }; enum ThreadPriority { ThreadPriorityIdle, ThreadPriorityNormal, ThreadPriorityHigh, ThreadPriorityRealtime, }; + static const OsThread InvalidHandle; + static const OsThreadId InvalidId; + protected: - ThreadState State; - int ReturnValue; - OsThread hThread; + ThreadState State = THREAD_INIT; + ThreadPriority Priority = ThreadPriorityNormal; + OsThread hThread = InvalidHandle; + OsThreadId ThreadId = InvalidId; + + int ReturnValue = -1; LString Name; - ThreadPriority Priority; - OsThreadId ThreadId; #if defined WIN32 friend uint WINAPI ThreadEntryPoint(void *i); void Create(class LThread *Thread, OsThread &hThread, OsThreadId &ThreadId); #elif defined POSIX friend void *ThreadEntryPoint(void *i); #else friend int32 ThreadEntryPoint(void *i); #endif protected: /// Auto deletes the thread after ::Main has finished. - bool DeleteOnExit; + bool DeleteOnExit = false; /// Aka from LView::AddDispatch(). - int ViewHandle; + int ViewHandle = -1; public: - static const OsThread InvalidHandle; - static const OsThreadId InvalidId; - LThread( /// Name for the thread. const char *Name, /// [Optional] Handle from LView::AddDispatch() /// This enables the OnComplete event to be called /// from the GUI thread after the thread exits. int viewHandle = -1 ); virtual ~LThread(); // Properties OsThread Handle() { return hThread; } const char *GetName() { return Name; } OsThreadId GetId() { return ThreadId; } ThreadState GetState() { return State; } // Volatile at best... only use for 'debug' bool GetDeleteOnExit() { return DeleteOnExit; } virtual int ExitCode(); virtual bool IsExited(); // Methods virtual void Run(); virtual void Terminate(); virtual void WaitForExit(int WarnAfterMs = 2000); // Override to do something virtual int Main() = 0; // Events virtual void OnBeforeMain() {} virtual void OnAfterMain() {} /// This event runs after the thread has finished but /// is called from the main GUI thread. It requires a valid /// viewHandle to be passed to the constructor. Which can /// be aquired by calling LView::AddDispatch(). virtual void OnComplete() {} }; //////////////////////////////////////////////////////////////////////////////////////// class LThreadOwner; class LThreadTarget; class LThreadWorker; /// A generic threaded job parent class. class LgiClass LThreadJob { friend class LThreadWorker; LThreadTarget *Owner; public: LThreadJob(LThreadTarget *o) { Owner = o; } virtual ~LThreadJob() {} virtual void Do() {} }; /// The thread target is a virtual API to receive work units executed /// in the worker thread. class LgiClass LThreadTarget : public LMutex { friend class LThreadWorker; protected: /// The thread doing the work. LThreadWorker *Worker; public: LThreadTarget(); virtual ~LThreadTarget() {} virtual void SetWorker(LThreadWorker *w); virtual void Detach(); /// This function gets called when the job is finished virtual void OnDone(LAutoPtr j) {} }; #undef AddJob /// This parent class does the actual work of processing jobs. class LgiClass LThreadWorker : public LThread, public LMutex { LArray Owners; LArray Jobs; bool Loop; public: LThreadWorker(LThreadTarget *First, const char *ThreadName); virtual ~LThreadWorker(); void Stop(); void Attach(LThreadTarget *o); void Detach(LThreadTarget *o); virtual void AddJob(LThreadJob *j); virtual void DoJob(LThreadJob *j); int Main(); }; class LgiClass LThreadOwner : public LThreadTarget { public: virtual ~LThreadOwner(); }; #endif diff --git a/src/linux/Lgi/Thread.cpp b/src/linux/Lgi/Thread.cpp --- a/src/linux/Lgi/Thread.cpp +++ b/src/linux/Lgi/Thread.cpp @@ -1,142 +1,137 @@ #include #include #include #include "lgi/common/Lgi.h" #include "lgi/common/EventTargetThread.h" OsThreadId GetCurrentThreadId() { #ifdef SYS_gettid return syscall(SYS_gettid); #else LAssert(0); return 0; #endif } //////////////////////////////////////////////////////////////////////////// void *ThreadEntryPoint(void *i) { if (i) { LThread *Thread = (LThread*) i; Thread->ThreadId = GetCurrentThreadId(); // Make sure we have finished executing the setup while (Thread->State == LThread::THREAD_INIT) { LSleep(1); } pthread_detach(Thread->hThread); LString Nm = Thread->Name; if (Nm) pthread_setname_np(pthread_self(), Nm); // Do thread's work Thread->OnBeforeMain(); Thread->ReturnValue = Thread->Main(); Thread->OnAfterMain(); // Shutdown... Thread->State = LThread::THREAD_EXITED; bool DelayDelete = false; if (Thread->ViewHandle >= 0) { // If DeleteOnExit is set AND ViewHandle then the LView::OnEvent handle will // process the delete... don't do it here. DelayDelete = PostThreadEvent(Thread->ViewHandle, M_THREAD_COMPLETED, (LMessage::Param)Thread); // However if PostThreadEvent fails... do honour DeleteOnExit. } - if (Thread->DeleteOnExit) + if (!DelayDelete && Thread->DeleteOnExit) { DeleteObj(Thread); } pthread_exit(0); } return 0; } const OsThread LThread::InvalidHandle = 0; const OsThreadId LThread::InvalidId = 0; LThread::LThread(const char *ThreadName, int viewHandle) { Name = ThreadName; ViewHandle = viewHandle; - ThreadId = InvalidId; - State = LThread::THREAD_INIT; - ReturnValue = -1; - hThread = InvalidHandle; - DeleteOnExit = false; } LThread::~LThread() { if (!IsExited()) { Terminate(); } } int LThread::ExitCode() { return ReturnValue; } bool LThread::IsExited() { return State == LThread::THREAD_EXITED; } void LThread::Run() { Terminate(); if (!hThread) { State = LThread::THREAD_INIT; static int Creates = 0; int e; if (!(e = pthread_create(&hThread, NULL, ThreadEntryPoint, (void*)this))) { Creates++; State = LThread::THREAD_RUNNING; } else { const char *Err = "(unknown)"; switch (e) { case EAGAIN: Err = "EAGAIN"; break; case EINVAL: Err = "EINVAL"; break; case EPERM: Err = "EPERM"; break; case ENOMEM: Err = "ENOMEM"; break; } printf("%s,%i - pthread_create failed with the error %i (%s) (After %i creates)\n", __FILE__, __LINE__, e, Err, Creates); State = LThread::THREAD_EXITED; } } } void LThread::Terminate() { if (hThread && pthread_cancel(hThread) == 0) { State = LThread::THREAD_EXITED; hThread = 0; } } int LThread::Main() { return 0; }