mirror of
https://github.com/MCLx86/xtreemtest.git
synced 2025-12-06 23:45:32 +01:00
Initial commit
This commit is contained in:
6
src/threading/CMakeLists.txt
Normal file
6
src/threading/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
set(JTHREAD_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/event.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/thread.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/semaphore.cpp
|
||||
PARENT_SCOPE)
|
||||
|
||||
44
src/threading/event.cpp
Normal file
44
src/threading/event.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
This file is a part of the JThread package, which contains some object-
|
||||
oriented thread wrappers for different thread implementations.
|
||||
|
||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "threading/event.h"
|
||||
#include "threading/mutex_auto_lock.h"
|
||||
|
||||
void Event::wait()
|
||||
{
|
||||
MutexAutoLock lock(mutex);
|
||||
while (!notified) {
|
||||
cv.wait(lock);
|
||||
}
|
||||
notified = false;
|
||||
}
|
||||
|
||||
|
||||
void Event::signal()
|
||||
{
|
||||
MutexAutoLock lock(mutex);
|
||||
notified = true;
|
||||
cv.notify_one();
|
||||
}
|
||||
46
src/threading/event.h
Normal file
46
src/threading/event.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
This file is a part of the JThread package, which contains some object-
|
||||
oriented thread wrappers for different thread implementations.
|
||||
|
||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
|
||||
/** A syncronization primitive that will wake up one waiting thread when signaled.
|
||||
* Calling @c signal() multiple times before a waiting thread has had a chance
|
||||
* to notice the signal will wake only one thread. Additionally, if no threads
|
||||
* are waiting on the event when it is signaled, the next call to @c wait()
|
||||
* will return (almost) immediately.
|
||||
*/
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
void wait();
|
||||
void signal();
|
||||
|
||||
private:
|
||||
std::condition_variable cv;
|
||||
std::mutex mutex;
|
||||
bool notified = false;
|
||||
};
|
||||
30
src/threading/mutex_auto_lock.h
Normal file
30
src/threading/mutex_auto_lock.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
This file is a part of the JThread package, which contains some object-
|
||||
oriented thread wrappers for different thread implementations.
|
||||
|
||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
using MutexAutoLock = std::unique_lock<std::mutex>;
|
||||
using RecursiveMutexAutoLock = std::unique_lock<std::recursive_mutex>;
|
||||
167
src/threading/semaphore.cpp
Normal file
167
src/threading/semaphore.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 sapier <sapier AT gmx DOT net>
|
||||
|
||||
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 2.1 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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "threading/semaphore.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
#define UNUSED(expr) do { (void)(expr); } while (0)
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <climits>
|
||||
#define MAX_SEMAPHORE_COUNT LONG_MAX - 1
|
||||
#else
|
||||
#include <cerrno>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
#if defined(__MACH__) && defined(__APPLE__)
|
||||
#include <mach/mach.h>
|
||||
#include <mach/task.h>
|
||||
#include <mach/semaphore.h>
|
||||
#include <sys/semaphore.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#undef sem_t
|
||||
#undef sem_init
|
||||
#undef sem_wait
|
||||
#undef sem_post
|
||||
#undef sem_destroy
|
||||
#define sem_t semaphore_t
|
||||
#define sem_init(s, p, c) semaphore_create(mach_task_self(), (s), 0, (c))
|
||||
#define sem_wait(s) semaphore_wait(*(s))
|
||||
#define sem_post(s) semaphore_signal(*(s))
|
||||
#define sem_destroy(s) semaphore_destroy(mach_task_self(), *(s))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
Semaphore::Semaphore(int val)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
semaphore = CreateSemaphore(NULL, val, MAX_SEMAPHORE_COUNT, NULL);
|
||||
#else
|
||||
int ret = sem_init(&semaphore, 0, val);
|
||||
assert(!ret);
|
||||
UNUSED(ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Semaphore::~Semaphore()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CloseHandle(semaphore);
|
||||
#else
|
||||
int ret = sem_destroy(&semaphore);
|
||||
#ifdef __ANDROID__
|
||||
// Workaround for broken bionic semaphore implementation!
|
||||
assert(!ret || errno == EBUSY);
|
||||
#else
|
||||
assert(!ret);
|
||||
#endif
|
||||
UNUSED(ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Semaphore::post(unsigned int num)
|
||||
{
|
||||
assert(num > 0);
|
||||
#ifdef _WIN32
|
||||
ReleaseSemaphore(semaphore, num, NULL);
|
||||
#else
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
int ret = sem_post(&semaphore);
|
||||
assert(!ret);
|
||||
UNUSED(ret);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Semaphore::wait()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WaitForSingleObject(semaphore, INFINITE);
|
||||
#else
|
||||
int ret = sem_wait(&semaphore);
|
||||
assert(!ret);
|
||||
UNUSED(ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool Semaphore::wait(unsigned int time_ms)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
unsigned int ret = WaitForSingleObject(semaphore, time_ms);
|
||||
|
||||
if (ret == WAIT_OBJECT_0) {
|
||||
return true;
|
||||
} else {
|
||||
assert(ret == WAIT_TIMEOUT);
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
# if defined(__MACH__) && defined(__APPLE__)
|
||||
mach_timespec_t wait_time;
|
||||
wait_time.tv_sec = time_ms / 1000;
|
||||
wait_time.tv_nsec = 1000000 * (time_ms % 1000);
|
||||
|
||||
errno = 0;
|
||||
int ret = semaphore_timedwait(semaphore, wait_time);
|
||||
switch (ret) {
|
||||
case KERN_OPERATION_TIMED_OUT:
|
||||
errno = ETIMEDOUT;
|
||||
break;
|
||||
case KERN_ABORTED:
|
||||
errno = EINTR;
|
||||
break;
|
||||
default:
|
||||
if (ret)
|
||||
errno = EINVAL;
|
||||
}
|
||||
# else
|
||||
int ret;
|
||||
if (time_ms > 0) {
|
||||
struct timespec wait_time;
|
||||
struct timeval now;
|
||||
|
||||
if (gettimeofday(&now, NULL) == -1) {
|
||||
std::cerr << "Semaphore::wait(ms): Unable to get time with gettimeofday!" << std::endl;
|
||||
abort();
|
||||
}
|
||||
|
||||
wait_time.tv_nsec = ((time_ms % 1000) * 1000 * 1000) + (now.tv_usec * 1000);
|
||||
wait_time.tv_sec = (time_ms / 1000) + (wait_time.tv_nsec / (1000 * 1000 * 1000)) + now.tv_sec;
|
||||
wait_time.tv_nsec %= 1000 * 1000 * 1000;
|
||||
|
||||
ret = sem_timedwait(&semaphore, &wait_time);
|
||||
} else {
|
||||
ret = sem_trywait(&semaphore);
|
||||
}
|
||||
# endif
|
||||
|
||||
assert(!ret || (errno == ETIMEDOUT || errno == EINTR || errno == EAGAIN));
|
||||
return !ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
52
src/threading/semaphore.h
Normal file
52
src/threading/semaphore.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 sapier <sapier AT gmx DOT net>
|
||||
|
||||
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 2.1 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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(__MACH__) && defined(__APPLE__)
|
||||
#include <mach/semaphore.h>
|
||||
#else
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
|
||||
#include "util/basic_macros.h"
|
||||
|
||||
class Semaphore
|
||||
{
|
||||
public:
|
||||
Semaphore(int val = 0);
|
||||
~Semaphore();
|
||||
|
||||
DISABLE_CLASS_COPY(Semaphore);
|
||||
|
||||
void post(unsigned int num = 1);
|
||||
void wait();
|
||||
bool wait(unsigned int time_ms);
|
||||
|
||||
private:
|
||||
#if defined(WIN32)
|
||||
HANDLE semaphore;
|
||||
#elif defined(__MACH__) && defined(__APPLE__)
|
||||
semaphore_t semaphore;
|
||||
#else
|
||||
sem_t semaphore;
|
||||
#endif
|
||||
};
|
||||
347
src/threading/thread.cpp
Normal file
347
src/threading/thread.cpp
Normal file
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
This file is a part of the JThread package, which contains some object-
|
||||
oriented thread wrappers for different thread implementations.
|
||||
|
||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "threading/thread.h"
|
||||
#include "threading/mutex_auto_lock.h"
|
||||
#include "log.h"
|
||||
#include "porting.h"
|
||||
|
||||
// for setName
|
||||
#if defined(__linux__)
|
||||
#include <sys/prctl.h>
|
||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
#include <pthread_np.h>
|
||||
#elif defined(__NetBSD__)
|
||||
#include <sched.h>
|
||||
#elif defined(_MSC_VER)
|
||||
struct THREADNAME_INFO {
|
||||
DWORD dwType; // Must be 0x1000
|
||||
LPCSTR szName; // Pointer to name (in user addr space)
|
||||
DWORD dwThreadID; // Thread ID (-1=caller thread)
|
||||
DWORD dwFlags; // Reserved for future use, must be zero
|
||||
};
|
||||
#endif
|
||||
|
||||
// for bindToProcessor
|
||||
#if __FreeBSD_version >= 702106
|
||||
typedef cpuset_t cpu_set_t;
|
||||
#elif defined(__sun) || defined(sun)
|
||||
#include <sys/types.h>
|
||||
#include <sys/processor.h>
|
||||
#include <sys/procset.h>
|
||||
#elif defined(_AIX)
|
||||
#include <sys/processor.h>
|
||||
#include <sys/thread.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/thread_act.h>
|
||||
#endif
|
||||
|
||||
|
||||
Thread::Thread(const std::string &name) :
|
||||
m_name(name),
|
||||
m_request_stop(false),
|
||||
m_running(false)
|
||||
{
|
||||
#ifdef _AIX
|
||||
m_kernel_thread_id = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
// kill the thread if running
|
||||
if (!m_running) {
|
||||
wait();
|
||||
} else {
|
||||
|
||||
m_running = false;
|
||||
|
||||
#if defined(_WIN32)
|
||||
// See https://msdn.microsoft.com/en-us/library/hh920601.aspx#thread__native_handle_method
|
||||
TerminateThread((HANDLE) m_thread_obj->native_handle(), 0);
|
||||
CloseHandle((HANDLE) m_thread_obj->native_handle());
|
||||
#else
|
||||
// We need to pthread_kill instead on Android since NDKv5's pthread
|
||||
// implementation is incomplete.
|
||||
# ifdef __ANDROID__
|
||||
pthread_kill(getThreadHandle(), SIGKILL);
|
||||
# else
|
||||
pthread_cancel(getThreadHandle());
|
||||
# endif
|
||||
wait();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Make sure start finished mutex is unlocked before it's destroyed
|
||||
if (m_start_finished_mutex.try_lock())
|
||||
m_start_finished_mutex.unlock();
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool Thread::start()
|
||||
{
|
||||
MutexAutoLock lock(m_mutex);
|
||||
|
||||
if (m_running)
|
||||
return false;
|
||||
|
||||
m_request_stop = false;
|
||||
|
||||
// The mutex may already be locked if the thread is being restarted
|
||||
m_start_finished_mutex.try_lock();
|
||||
|
||||
try {
|
||||
m_thread_obj = new std::thread(threadProc, this);
|
||||
} catch (const std::system_error &e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (!m_running)
|
||||
sleep_ms(1);
|
||||
|
||||
// Allow spawned thread to continue
|
||||
m_start_finished_mutex.unlock();
|
||||
|
||||
m_joinable = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Thread::stop()
|
||||
{
|
||||
m_request_stop = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Thread::wait()
|
||||
{
|
||||
MutexAutoLock lock(m_mutex);
|
||||
|
||||
if (!m_joinable)
|
||||
return false;
|
||||
|
||||
|
||||
m_thread_obj->join();
|
||||
|
||||
delete m_thread_obj;
|
||||
m_thread_obj = nullptr;
|
||||
|
||||
assert(m_running == false);
|
||||
m_joinable = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Thread::getReturnValue(void **ret)
|
||||
{
|
||||
if (m_running)
|
||||
return false;
|
||||
|
||||
*ret = m_retval;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Thread::threadProc(Thread *thr)
|
||||
{
|
||||
#ifdef _AIX
|
||||
thr->m_kernel_thread_id = thread_self();
|
||||
#endif
|
||||
|
||||
thr->setName(thr->m_name);
|
||||
|
||||
g_logger.registerThread(thr->m_name);
|
||||
thr->m_running = true;
|
||||
|
||||
// Wait for the thread that started this one to finish initializing the
|
||||
// thread handle so that getThreadId/getThreadHandle will work.
|
||||
thr->m_start_finished_mutex.lock();
|
||||
|
||||
thr->m_retval = thr->run();
|
||||
|
||||
thr->m_running = false;
|
||||
// Unlock m_start_finished_mutex to prevent data race condition on Windows.
|
||||
// On Windows with VS2017 build TerminateThread is called and this mutex is not
|
||||
// released. We try to unlock it from caller thread and it's refused by system.
|
||||
thr->m_start_finished_mutex.unlock();
|
||||
g_logger.deregisterThread();
|
||||
}
|
||||
|
||||
|
||||
void Thread::setName(const std::string &name)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
|
||||
// It would be cleaner to do this with pthread_setname_np,
|
||||
// which was added to glibc in version 2.12, but some major
|
||||
// distributions are still runing 2.11 and previous versions.
|
||||
prctl(PR_SET_NAME, name.c_str());
|
||||
|
||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
|
||||
pthread_set_name_np(pthread_self(), name.c_str());
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
|
||||
pthread_setname_np(pthread_self(), "%s", const_cast<char*>(name.c_str()));
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
pthread_setname_np(name.c_str());
|
||||
|
||||
#elif defined(__HAIKU__)
|
||||
|
||||
rename_thread(find_thread(NULL), name.c_str());
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
// Windows itself doesn't support thread names,
|
||||
// but the MSVC debugger does...
|
||||
THREADNAME_INFO info;
|
||||
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name.c_str();
|
||||
info.dwThreadID = -1;
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try {
|
||||
RaiseException(0x406D1388, 0,
|
||||
sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info);
|
||||
} __except (EXCEPTION_CONTINUE_EXECUTION) {
|
||||
}
|
||||
|
||||
#elif defined(_WIN32) || defined(__GNU__)
|
||||
|
||||
// These platforms are known to not support thread names.
|
||||
// Silently ignore the request.
|
||||
|
||||
#else
|
||||
#warning "Unrecognized platform, thread names will not be available."
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
unsigned int Thread::getNumberOfProcessors()
|
||||
{
|
||||
return std::thread::hardware_concurrency();
|
||||
}
|
||||
|
||||
|
||||
bool Thread::bindToProcessor(unsigned int proc_number)
|
||||
{
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
return false;
|
||||
|
||||
#elif _MSC_VER
|
||||
|
||||
return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number);
|
||||
|
||||
#elif __MINGW32__
|
||||
|
||||
return SetThreadAffinityMask(pthread_gethandle(getThreadHandle()), 1 << proc_number);
|
||||
|
||||
#elif __FreeBSD_version >= 702106 || defined(__linux__) || defined(__DragonFly__)
|
||||
|
||||
cpu_set_t cpuset;
|
||||
|
||||
CPU_ZERO(&cpuset);
|
||||
CPU_SET(proc_number, &cpuset);
|
||||
|
||||
return pthread_setaffinity_np(getThreadHandle(), sizeof(cpuset), &cpuset) == 0;
|
||||
#elif defined(__NetBSD__)
|
||||
|
||||
cpuset_t *cpuset = cpuset_create();
|
||||
if (cpuset == NULL)
|
||||
return false;
|
||||
int r = pthread_setaffinity_np(getThreadHandle(), cpuset_size(cpuset), cpuset);
|
||||
cpuset_destroy(cpuset);
|
||||
return r == 0;
|
||||
#elif defined(__sun) || defined(sun)
|
||||
|
||||
return processor_bind(P_LWPID, P_MYID, proc_number, NULL) == 0
|
||||
|
||||
#elif defined(_AIX)
|
||||
|
||||
return bindprocessor(BINDTHREAD, m_kernel_thread_id, proc_number) == 0;
|
||||
|
||||
#elif defined(__hpux) || defined(hpux)
|
||||
|
||||
pthread_spu_t answer;
|
||||
|
||||
return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
|
||||
&answer, proc_number, getThreadHandle()) == 0;
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
struct thread_affinity_policy tapol;
|
||||
|
||||
thread_port_t threadport = pthread_mach_thread_np(getThreadHandle());
|
||||
tapol.affinity_tag = proc_number + 1;
|
||||
return thread_policy_set(threadport, THREAD_AFFINITY_POLICY,
|
||||
(thread_policy_t)&tapol,
|
||||
THREAD_AFFINITY_POLICY_COUNT) == KERN_SUCCESS;
|
||||
|
||||
#else
|
||||
|
||||
return false;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool Thread::setPriority(int prio)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
|
||||
return SetThreadPriority(getThreadHandle(), prio);
|
||||
|
||||
#elif __MINGW32__
|
||||
|
||||
return SetThreadPriority(pthread_gethandle(getThreadHandle()), prio);
|
||||
|
||||
#else
|
||||
|
||||
struct sched_param sparam;
|
||||
int policy;
|
||||
|
||||
if (pthread_getschedparam(getThreadHandle(), &policy, &sparam) != 0)
|
||||
return false;
|
||||
|
||||
int min = sched_get_priority_min(policy);
|
||||
int max = sched_get_priority_max(policy);
|
||||
|
||||
sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
|
||||
return pthread_setschedparam(getThreadHandle(), policy, &sparam) == 0;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
160
src/threading/thread.h
Normal file
160
src/threading/thread.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
This file is a part of the JThread package, which contains some object-
|
||||
oriented thread wrappers for different thread implementations.
|
||||
|
||||
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/basic_macros.h"
|
||||
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
#ifdef _AIX
|
||||
#include <sys/thread.h> // for tid_t
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
#include <kernel/OS.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On platforms using pthreads, these five priority classes correlate to
|
||||
* even divisions between the minimum and maximum reported thread priority.
|
||||
*/
|
||||
#if !defined(_WIN32)
|
||||
#define THREAD_PRIORITY_LOWEST 0
|
||||
#define THREAD_PRIORITY_BELOW_NORMAL 1
|
||||
#define THREAD_PRIORITY_NORMAL 2
|
||||
#define THREAD_PRIORITY_ABOVE_NORMAL 3
|
||||
#define THREAD_PRIORITY_HIGHEST 4
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
Thread(const std::string &name="");
|
||||
virtual ~Thread();
|
||||
DISABLE_CLASS_COPY(Thread)
|
||||
|
||||
/*
|
||||
* Begins execution of a new thread at the pure virtual method Thread::run().
|
||||
* Execution of the thread is guaranteed to have started after this function
|
||||
* returns.
|
||||
*/
|
||||
bool start();
|
||||
|
||||
/*
|
||||
* Requests that the thread exit gracefully.
|
||||
* Returns immediately; thread execution is guaranteed to be complete after
|
||||
* a subsequent call to Thread::wait.
|
||||
*/
|
||||
bool stop();
|
||||
|
||||
/*
|
||||
* Waits for thread to finish.
|
||||
* Note: This does not stop a thread, you have to do this on your own.
|
||||
* Returns false immediately if the thread is not started or has been waited
|
||||
* on before.
|
||||
*/
|
||||
bool wait();
|
||||
|
||||
/*
|
||||
* Returns true if the calling thread is this Thread object.
|
||||
*/
|
||||
bool isCurrentThread() { return std::this_thread::get_id() == getThreadId(); }
|
||||
|
||||
bool isRunning() { return m_running; }
|
||||
bool stopRequested() { return m_request_stop; }
|
||||
|
||||
std::thread::id getThreadId() { return m_thread_obj->get_id(); }
|
||||
|
||||
/*
|
||||
* Gets the thread return value.
|
||||
* Returns true if the thread has exited and the return value was available,
|
||||
* or false if the thread has yet to finish.
|
||||
*/
|
||||
bool getReturnValue(void **ret);
|
||||
|
||||
/*
|
||||
* Binds (if possible, otherwise sets the affinity of) the thread to the
|
||||
* specific processor specified by proc_number.
|
||||
*/
|
||||
bool bindToProcessor(unsigned int proc_number);
|
||||
|
||||
/*
|
||||
* Sets the thread priority to the specified priority.
|
||||
*
|
||||
* prio can be one of: THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL,
|
||||
* THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST.
|
||||
* On Windows, any of the other priorites as defined by SetThreadPriority
|
||||
* are supported as well.
|
||||
*
|
||||
* Note that it may be necessary to first set the threading policy or
|
||||
* scheduling algorithm to one that supports thread priorities if not
|
||||
* supported by default, otherwise this call will have no effect.
|
||||
*/
|
||||
bool setPriority(int prio);
|
||||
|
||||
/*
|
||||
* Sets the currently executing thread's name to where supported; useful
|
||||
* for debugging.
|
||||
*/
|
||||
static void setName(const std::string &name);
|
||||
|
||||
/*
|
||||
* Returns the number of processors/cores configured and active on this machine.
|
||||
*/
|
||||
static unsigned int getNumberOfProcessors();
|
||||
|
||||
protected:
|
||||
std::string m_name;
|
||||
|
||||
virtual void *run() = 0;
|
||||
|
||||
private:
|
||||
std::thread::native_handle_type getThreadHandle()
|
||||
{ return m_thread_obj->native_handle(); }
|
||||
|
||||
static void threadProc(Thread *thr);
|
||||
|
||||
void *m_retval = nullptr;
|
||||
bool m_joinable = false;
|
||||
std::atomic<bool> m_request_stop;
|
||||
std::atomic<bool> m_running;
|
||||
std::mutex m_mutex;
|
||||
std::mutex m_start_finished_mutex;
|
||||
|
||||
std::thread *m_thread_obj = nullptr;
|
||||
|
||||
|
||||
#ifdef _AIX
|
||||
// For AIX, there does not exist any mapping from pthread_t to tid_t
|
||||
// available to us, so we maintain one ourselves. This is set on thread start.
|
||||
tid_t m_kernel_thread_id;
|
||||
#endif
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user