|
- /*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-10 by Raw Material Software Ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the GNU General
- Public License (Version 2), as published by the Free Software Foundation.
- A copy of the license is included in the JUCE distribution, or can be found
- online at www.gnu.org/licenses.
-
- JUCE 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 General Public License for more details.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.rawmaterialsoftware.com/juce for more information.
-
- ==============================================================================
- */
-
- #include "../core/juce_StandardHeader.h"
-
- BEGIN_JUCE_NAMESPACE
-
- #include "juce_Thread.h"
- #include "juce_ScopedLock.h"
- #include "../core/juce_Time.h"
-
-
- // these functions are implemented in the platform-specific code.
- void* juce_createThread (void* userData);
- void juce_killThread (void* handle);
- bool juce_setThreadPriority (void* handle, int priority);
- void juce_setCurrentThreadName (const String& name);
- #if JUCE_WINDOWS
- void juce_CloseThreadHandle (void* handle);
- #endif
-
-
- //==============================================================================
- void Thread::threadEntryPoint (Thread* const thread)
- {
- {
- const ScopedLock sl (runningThreadsLock);
- runningThreads.add (thread);
- }
-
- JUCE_TRY
- {
- thread->threadId_ = Thread::getCurrentThreadId();
-
- if (thread->threadName_.isNotEmpty())
- juce_setCurrentThreadName (thread->threadName_);
-
- if (thread->startSuspensionEvent_.wait (10000))
- {
- if (thread->affinityMask_ != 0)
- setCurrentThreadAffinityMask (thread->affinityMask_);
-
- thread->run();
- }
- }
- JUCE_CATCH_ALL_ASSERT
-
- {
- const ScopedLock sl (runningThreadsLock);
-
- jassert (runningThreads.contains (thread));
- runningThreads.removeValue (thread);
- }
-
- #if JUCE_WINDOWS
- juce_CloseThreadHandle (thread->threadHandle_);
- #endif
-
- thread->threadHandle_ = 0;
- thread->threadId_ = 0;
- }
-
- // used to wrap the incoming call from the platform-specific code
- void JUCE_API juce_threadEntryPoint (void* userData)
- {
- Thread::threadEntryPoint (static_cast <Thread*> (userData));
- }
-
-
- //==============================================================================
- Thread::Thread (const String& threadName)
- : threadName_ (threadName),
- threadHandle_ (0),
- threadPriority_ (5),
- threadId_ (0),
- affinityMask_ (0),
- threadShouldExit_ (false)
- {
- }
-
- Thread::~Thread()
- {
- /* If your thread class's destructor has been called without first stopping the thread, that
- means that this partially destructed object is still performing some work - and that's not
- unlikely to be a safe approach to take!
-
- To avoid this type of nastiness, always make sure you call stopThread() before or during
- your subclass's destructor.
- */
- jassert (! isThreadRunning());
-
- stopThread (100);
- }
-
- //==============================================================================
- void Thread::startThread()
- {
- const ScopedLock sl (startStopLock);
-
- threadShouldExit_ = false;
-
- if (threadHandle_ == 0)
- {
- threadHandle_ = juce_createThread (this);
- juce_setThreadPriority (threadHandle_, threadPriority_);
- startSuspensionEvent_.signal();
- }
- }
-
- void Thread::startThread (const int priority)
- {
- const ScopedLock sl (startStopLock);
-
- if (threadHandle_ == 0)
- {
- threadPriority_ = priority;
- startThread();
- }
- else
- {
- setPriority (priority);
- }
- }
-
- bool Thread::isThreadRunning() const
- {
- return threadHandle_ != 0;
- }
-
- //==============================================================================
- void Thread::signalThreadShouldExit()
- {
- threadShouldExit_ = true;
- }
-
- bool Thread::waitForThreadToExit (const int timeOutMilliseconds) const
- {
- // Doh! So how exactly do you expect this thread to wait for itself to stop??
- jassert (getThreadId() != getCurrentThreadId());
-
- const int sleepMsPerIteration = 5;
- int count = timeOutMilliseconds / sleepMsPerIteration;
-
- while (isThreadRunning())
- {
- if (timeOutMilliseconds > 0 && --count < 0)
- return false;
-
- sleep (sleepMsPerIteration);
- }
-
- return true;
- }
-
- void Thread::stopThread (const int timeOutMilliseconds)
- {
- // agh! You can't stop the thread that's calling this method! How on earth
- // would that work??
- jassert (getCurrentThreadId() != getThreadId());
-
- const ScopedLock sl (startStopLock);
-
- if (isThreadRunning())
- {
- signalThreadShouldExit();
- notify();
-
- if (timeOutMilliseconds != 0)
- waitForThreadToExit (timeOutMilliseconds);
-
- if (isThreadRunning())
- {
- // very bad karma if this point is reached, as
- // there are bound to be locks and events left in
- // silly states when a thread is killed by force..
- jassertfalse;
- Logger::writeToLog ("!! killing thread by force !!");
-
- juce_killThread (threadHandle_);
- threadHandle_ = 0;
- threadId_ = 0;
-
- const ScopedLock sl2 (runningThreadsLock);
- runningThreads.removeValue (this);
- }
- }
- }
-
- //==============================================================================
- bool Thread::setPriority (const int priority)
- {
- const ScopedLock sl (startStopLock);
-
- const bool worked = juce_setThreadPriority (threadHandle_, priority);
-
- if (worked)
- threadPriority_ = priority;
-
- return worked;
- }
-
- bool Thread::setCurrentThreadPriority (const int priority)
- {
- return juce_setThreadPriority (0, priority);
- }
-
- void Thread::setAffinityMask (const uint32 affinityMask)
- {
- affinityMask_ = affinityMask;
- }
-
- //==============================================================================
- bool Thread::wait (const int timeOutMilliseconds) const
- {
- return defaultEvent_.wait (timeOutMilliseconds);
- }
-
- void Thread::notify() const
- {
- defaultEvent_.signal();
- }
-
- //==============================================================================
- int Thread::getNumRunningThreads()
- {
- return runningThreads.size();
- }
-
- Thread* Thread::getCurrentThread()
- {
- const ThreadID thisId = getCurrentThreadId();
-
- const ScopedLock sl (runningThreadsLock);
-
- for (int i = runningThreads.size(); --i >= 0;)
- {
- Thread* const t = runningThreads.getUnchecked(i);
-
- if (t->threadId_ == thisId)
- return t;
- }
-
- return 0;
- }
-
- void Thread::stopAllThreads (const int timeOutMilliseconds)
- {
- {
- const ScopedLock sl (runningThreadsLock);
-
- for (int i = runningThreads.size(); --i >= 0;)
- runningThreads.getUnchecked(i)->signalThreadShouldExit();
- }
-
- for (;;)
- {
- Thread* firstThread;
-
- {
- const ScopedLock sl (runningThreadsLock);
- firstThread = runningThreads.getFirst();
- }
-
- if (firstThread == 0)
- break;
-
- firstThread->stopThread (timeOutMilliseconds);
- }
- }
-
- Array<Thread*> Thread::runningThreads;
- CriticalSection Thread::runningThreadsLock;
-
-
- END_JUCE_NAMESPACE
|