]> git.lizzy.rs Git - minetest.git/blobdiff - src/threading/thread.cpp
Util: Use quotation marks for safe path handling
[minetest.git] / src / threading / thread.cpp
index ecf8563f135605b9ee4405bc829e75a1c73a2940..ef025ac1d0ea72e29808f5df61b4672149c35aab 100644 (file)
@@ -28,36 +28,13 @@ DEALINGS IN THE SOFTWARE.
 #include "log.h"
 #include "porting.h"
 
-#define UNUSED(expr) do { (void)(expr); } while (0)
-
-#if USE_CPP11_THREADS
-       #include <chrono>
-       #include <system_error>
-#elif USE_WIN_THREADS
-       #ifndef _WIN32_WCE
-               #include <process.h>
-       #endif
-#elif USE_POSIX_THREADS
-       #include <time.h>
-       #include <assert.h>
-       #include <stdlib.h>
-       #include <unistd.h>
-       #include <sys/time.h>
-
-       #if defined(__FreeBSD__) || defined(__APPLE__)
-               #include <sys/types.h>
-               #include <sys/sysctl.h>
-       #elif defined(_GNU_SOURCE)
-               #include <sys/sysinfo.h>
-       #endif
-#endif
-
-
 // for setName
-#if defined(linux) || defined(__linux)
+#if defined(__linux__)
        #include <sys/prctl.h>
-#elif defined(__FreeBSD__) || defined(__OpenBSD__)
+#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
@@ -70,8 +47,6 @@ DEALINGS IN THE SOFTWARE.
 // for bindToProcessor
 #if __FreeBSD_version >= 702106
        typedef cpuset_t cpu_set_t;
-#elif defined(__linux) || defined(linux)
-       #include <sched.h>
 #elif defined(__sun) || defined(sun)
        #include <sys/types.h>
        #include <sys/processor.h>
@@ -87,8 +62,6 @@ DEALINGS IN THE SOFTWARE.
 
 Thread::Thread(const std::string &name) :
        m_name(name),
-       m_retval(NULL),
-       m_joinable(false),
        m_request_stop(false),
        m_running(false)
 {
@@ -100,7 +73,33 @@ Thread::Thread(const std::string &name) :
 
 Thread::~Thread()
 {
-       kill();
+       // 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();
+
 }
 
 
@@ -113,7 +112,8 @@ bool Thread::start()
 
        m_request_stop = false;
 
-#if USE_CPP11_THREADS
+       // 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);
@@ -121,23 +121,12 @@ bool Thread::start()
                return false;
        }
 
-#elif USE_WIN_THREADS
-
-       m_thread_handle = CreateThread(NULL, 0, threadProc, this, 0, &m_thread_id);
-       if (!m_thread_handle)
-               return false;
-
-#elif USE_POSIX_THREADS
-
-       int status = pthread_create(&m_thread_handle, NULL, threadProc, this);
-       if (status)
-               return false;
-
-#endif
-
        while (!m_running)
                sleep_ms(1);
 
+       // Allow spawned thread to continue
+       m_start_finished_mutex.unlock();
+
        m_joinable = true;
 
        return true;
@@ -158,30 +147,11 @@ bool Thread::wait()
        if (!m_joinable)
                return false;
 
-#if USE_CPP11_THREADS
 
        m_thread_obj->join();
 
        delete m_thread_obj;
-       m_thread_obj = NULL;
-
-#elif USE_WIN_THREADS
-
-       int ret = WaitForSingleObject(m_thread_handle, INFINITE);
-       assert(ret == WAIT_OBJECT_0);
-       UNUSED(ret);
-
-       CloseHandle(m_thread_handle);
-       m_thread_handle = NULL;
-       m_thread_id = -1;
-
-#elif USE_POSIX_THREADS
-
-       int ret = pthread_join(m_thread_handle, NULL);
-       assert(ret == 0);
-       UNUSED(ret);
-
-#endif
+       m_thread_obj = nullptr;
 
        assert(m_running == false);
        m_joinable = false;
@@ -189,36 +159,6 @@ bool Thread::wait()
 }
 
 
-bool Thread::kill()
-{
-       if (!m_running) {
-               wait();
-               return false;
-       }
-
-       m_running = false;
-
-#ifdef _WIN32
-       TerminateThread(m_thread_handle, 0);
-       CloseHandle(m_thread_handle);
-#else
-       // We need to pthread_kill instead on Android since NDKv5's pthread
-       // implementation is incomplete.
-# ifdef __ANDROID__
-       pthread_kill(m_thread_handle, SIGKILL);
-# else
-       pthread_cancel(m_thread_handle);
-# endif
-       wait();
-#endif
-
-       m_retval       = NULL;
-       m_joinable     = false;
-       m_request_stop = false;
-
-       return true;
-}
-
 
 bool Thread::getReturnValue(void **ret)
 {
@@ -230,18 +170,10 @@ bool Thread::getReturnValue(void **ret)
 }
 
 
-#if USE_CPP11_THREADS || USE_POSIX_THREADS
-void *Thread::threadProc(void *param)
-#elif defined(_WIN32_WCE)
-DWORD Thread::threadProc(LPVOID param)
-#elif defined(_WIN32)
-DWORD WINAPI Thread::threadProc(LPVOID param)
-#endif
+void Thread::threadProc(Thread *thr)
 {
-       Thread *thr = (Thread *)param;
-
 #ifdef _AIX
-       m_kernel_thread_id = thread_self();
+       thr->m_kernel_thread_id = thread_self();
 #endif
 
        thr->setName(thr->m_name);
@@ -249,37 +181,46 @@ DWORD WINAPI Thread::threadProc(LPVOID param)
        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();
-
-       // 0 is returned here to avoid an unnecessary ifdef clause
-       return 0;
 }
 
 
 void Thread::setName(const std::string &name)
 {
-#if defined(linux) || defined(__linux)
+#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__)
+#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
 
        pthread_set_name_np(pthread_self(), name.c_str());
 
 #elif defined(__NetBSD__)
 
-       pthread_setname_np(pthread_self(), name.c_str());
+       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,
@@ -310,46 +251,7 @@ void Thread::setName(const std::string &name)
 
 unsigned int Thread::getNumberOfProcessors()
 {
-#if __cplusplus >= 201103L
-
        return std::thread::hardware_concurrency();
-
-#elif defined(_SC_NPROCESSORS_ONLN)
-
-       return sysconf(_SC_NPROCESSORS_ONLN);
-
-#elif defined(__FreeBSD__) || defined(__NetBSD__) || \
-       defined(__DragonFly__) || defined(__APPLE__)
-
-       unsigned int num_cpus = 1;
-       size_t len = sizeof(num_cpus);
-
-       int mib[2];
-       mib[0] = CTL_HW;
-       mib[1] = HW_NCPU;
-
-       sysctl(mib, 2, &num_cpus, &len, NULL, 0);
-       return num_cpus;
-
-#elif defined(_GNU_SOURCE)
-
-       return get_nprocs();
-
-#elif defined(_WIN32)
-
-       SYSTEM_INFO sysinfo;
-       GetSystemInfo(&sysinfo);
-       return sysinfo.dwNumberOfProcessors;
-
-#elif defined(PTW32_VERSION) || defined(__hpux)
-
-       return pthread_num_processors_np();
-
-#else
-
-       return 1;
-
-#endif
 }
 
 
@@ -359,19 +261,30 @@ bool Thread::bindToProcessor(unsigned int proc_number)
 
        return false;
 
-#elif defined(_WIN32)
+#elif _MSC_VER
+
+       return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number);
+
+#elif __MINGW32__
 
-       return SetThreadAffinityMask(m_thread_handle, 1 << proc_number);
+       return SetThreadAffinityMask(pthread_gethandle(getThreadHandle()), 1 << proc_number);
 
-#elif __FreeBSD_version >= 702106 || defined(__linux) || defined(linux)
+#elif __FreeBSD_version >= 702106 || defined(__linux__) || defined(__DragonFly__)
 
        cpu_set_t cpuset;
 
        CPU_ZERO(&cpuset);
        CPU_SET(proc_number, &cpuset);
 
-       return pthread_setaffinity_np(m_thread_handle, sizeof(cpuset), &cpuset) == 0;
+       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
@@ -385,13 +298,13 @@ bool Thread::bindToProcessor(unsigned int proc_number)
        pthread_spu_t answer;
 
        return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
-                       &answer, proc_number, m_thread_handle) == 0;
+                       &answer, proc_number, getThreadHandle()) == 0;
 
 #elif defined(__APPLE__)
 
        struct thread_affinity_policy tapol;
 
-       thread_port_t threadport = pthread_mach_thread_np(m_thread_handle);
+       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,
@@ -407,23 +320,27 @@ bool Thread::bindToProcessor(unsigned int proc_number)
 
 bool Thread::setPriority(int prio)
 {
-#if defined(_WIN32)
+#ifdef _MSC_VER
+
+       return SetThreadPriority(getThreadHandle(), prio);
+
+#elif __MINGW32__
 
-       return SetThreadPriority(m_thread_handle, prio);
+       return SetThreadPriority(pthread_gethandle(getThreadHandle()), prio);
 
 #else
 
        struct sched_param sparam;
        int policy;
 
-       if (pthread_getschedparam(m_thread_handle, &policy, &sparam) != 0)
+       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(m_thread_handle, policy, &sparam) == 0;
+       return pthread_setschedparam(getThreadHandle(), policy, &sparam) == 0;
 
 #endif
 }