Browse Source

Add new thread class file

gh-pages
falkTX 10 years ago
parent
commit
755d7f31a3
1 changed files with 291 additions and 0 deletions
  1. +291
    -0
      distrho/extra/d_thread.hpp

+ 291
- 0
distrho/extra/d_thread.hpp View File

@@ -0,0 +1,291 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DISTRHO_THREAD_HPP_INCLUDED
#define DISTRHO_THREAD_HPP_INCLUDED

#include "d_mutex.hpp"
#include "d_sleep.hpp"
#include "d_string.hpp"

#if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012
// has pthread_setname_np
#elif defined(DISTRHO_OS_LINUX)
# include <sys/prctl.h>
#endif

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------
// Thread class

class Thread
{
protected:
/*
* Constructor.
*/
Thread(const char* const threadName = nullptr) noexcept
: fLock(),
fName(threadName),
#ifdef PTW32_DLLPORT
fHandle({nullptr, 0}),
#else
fHandle(0),
#endif
fShouldExit(false) {}

/*
* Destructor.
*/
virtual ~Thread() /*noexcept*/
{
DISTRHO_SAFE_ASSERT(! isThreadRunning());

stopThread(-1);
}

/*
* Virtual function to be implemented by the subclass.
*/
virtual void run() = 0;

// -------------------------------------------------------------------

public:
/*
* Check if the thread is running.
*/
bool isThreadRunning() const noexcept
{
#ifdef PTW32_DLLPORT
return (fHandle.p != nullptr);
#else
return (fHandle != 0);
#endif
}

/*
* Check if the thread should exit.
*/
bool shouldThreadExit() const noexcept
{
return fShouldExit;
}

/*
* Start the thread.
*/
bool startThread() noexcept
{
// check if already running
DISTRHO_SAFE_ASSERT_RETURN(! isThreadRunning(), true);

const MutexLocker cml(fLock);

fShouldExit = false;

pthread_t handle;

if (pthread_create(&handle, nullptr, _entryPoint, this) == 0)
{
#ifdef PTW32_DLLPORT
DISTRHO_SAFE_ASSERT_RETURN(handle.p != nullptr, false);
#else
DISTRHO_SAFE_ASSERT_RETURN(handle != 0, false);
#endif
pthread_detach(handle);
_copyFrom(handle);

// wait for thread to start
fLock.lock();

return true;
}

return false;
}

/*
* Stop the thread.
* In the 'timeOutMilliseconds':
* = 0 -> no wait
* > 0 -> wait timeout value
* < 0 -> wait forever
*/
bool stopThread(const int timeOutMilliseconds) noexcept
{
const MutexLocker cml(fLock);

if (isThreadRunning())
{
signalThreadShouldExit();

if (timeOutMilliseconds != 0)
{
// Wait for the thread to stop
int timeOutCheck = (timeOutMilliseconds == 1 || timeOutMilliseconds == -1) ? timeOutMilliseconds : timeOutMilliseconds/2;

for (; isThreadRunning();)
{
d_msleep(2);

if (timeOutCheck < 0)
continue;

if (timeOutCheck > 0)
timeOutCheck -= 1;
else
break;
}
}

if (isThreadRunning())
{
// should never happen!
d_stderr2("Carla assertion failure: \"! isThreadRunning()\" in file %s, line %i", __FILE__, __LINE__);

// copy thread id so we can clear our one
pthread_t threadId;
_copyTo(threadId);
_init();

try {
pthread_cancel(threadId);
} DISTRHO_SAFE_EXCEPTION("pthread_cancel");

return false;
}
}

return true;
}

/*
* Tell the thread to stop as soon as possible.
*/
void signalThreadShouldExit() noexcept
{
fShouldExit = true;
}

// -------------------------------------------------------------------

/*
* Returns the name of the thread.
* This is the name that gets set in the constructor.
*/
const d_string& getThreadName() const noexcept
{
return fName;
}

/*
* Changes the name of the caller thread.
*/
static void setCurrentThreadName(const char* const name) noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',);

#if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012
pthread_setname_np(pthread_self(), name);
#elif defined(DISTRHO_OS_LINUX)
prctl(PR_SET_NAME, name, 0, 0, 0);
#endif
}

// -------------------------------------------------------------------

private:
Mutex fLock; // Thread lock
const d_string fName; // Thread name
volatile pthread_t fHandle; // Handle for this thread
volatile bool fShouldExit; // true if thread should exit

/*
* Init pthread type.
*/
void _init() noexcept
{
#ifdef PTW32_DLLPORT
fHandle.p = nullptr;
fHandle.x = 0;
#else
fHandle = 0;
#endif
}

/*
* Copy our pthread type from another var.
*/
void _copyFrom(const pthread_t& handle) noexcept
{
#ifdef PTW32_DLLPORT
fHandle.p = handle.p;
fHandle.x = handle.x;
#else
fHandle = handle;
#endif
}

/*
* Copy our pthread type to another var.
*/
void _copyTo(volatile pthread_t& handle) const noexcept
{
#ifdef PTW32_DLLPORT
handle.p = fHandle.p;
handle.x = fHandle.x;
#else
handle = fHandle;
#endif
}

/*
* Thread entry point.
*/
void _runEntryPoint() noexcept
{
// report ready
fLock.unlock();

setCurrentThreadName(fName);

try {
run();
} catch(...) {}

// done
_init();
}

/*
* Thread entry point.
*/
static void* _entryPoint(void* userData) noexcept
{
static_cast<Thread*>(userData)->_runEntryPoint();
return nullptr;
}

DISTRHO_DECLARE_NON_COPY_CLASS(Thread)
};

// -----------------------------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // DISTRHO_THREAD_HPP_INCLUDED

Loading…
Cancel
Save