浏览代码

sys: work around a threading-related Visual Studio bug.

When a thread is destroyed during the atexit() callback cleanup, it cannot
be joined and sits there doing nothing if the CRT is Visual Studio 2012 or
2013. Microsoft has stated that they would not be backporting the fix from
Visual Studio 2015. As a workaround we call ExitThread() forcibly after
the thread exits.
undefined
Sam Hocevar 9 年前
父节点
当前提交
816e787201
共有 1 个文件被更改,包括 15 次插入62 次删除
  1. +15
    -62
      src/sys/threadbase.h

+ 15
- 62
src/sys/threadbase.h 查看文件

@@ -26,16 +26,17 @@
# include <condition_variable>
#elif defined HAVE_PTHREAD_H
# include <pthread.h>
#elif defined _XBOX
# include <xtl.h>
# undef near /* Fuck Microsoft */
# undef far /* Fuck Microsoft again */
#elif defined _WIN32
#else
# error No threading support yet :(
#endif

/* XXX: workaround for a bug in Visual Studio 2012 and 2013!
* https://connect.microsoft.com/VisualStudio/feedback/details/747145 */
#if defined(_MSC_VER) && (_MSC_VER < 1900)
# define LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND 1
# include <windows.h>
# undef near /* Fuck Microsoft */
# undef far /* Fuck Microsoft again */
#else
# error No threading support yet :(
#endif

namespace lol
@@ -53,8 +54,6 @@ public:
/* Nothing */
#elif defined HAVE_PTHREAD_H
pthread_mutex_init(&m_mutex, nullptr);
#elif defined _WIN32
InitializeCriticalSection(&m_mutex);
#endif
}

@@ -67,8 +66,6 @@ public:
/* Nothing */
#elif defined HAVE_PTHREAD_H
pthread_mutex_destroy(&m_mutex);
#elif defined _WIN32
DeleteCriticalSection(&m_mutex);
#endif
}

@@ -81,8 +78,6 @@ public:
m_mutex.lock();
#elif defined HAVE_PTHREAD_H
pthread_mutex_lock(&m_mutex);
#elif defined _WIN32
EnterCriticalSection(&m_mutex);
#endif
}

@@ -95,8 +90,6 @@ public:
return m_mutex.try_lock();
#elif defined HAVE_PTHREAD_H
return !pthread_mutex_trylock(&m_mutex);
#elif defined _WIN32
return !!TryEnterCriticalSection(&m_mutex);
#endif
}

@@ -109,8 +102,6 @@ public:
m_mutex.unlock();
#elif defined HAVE_PTHREAD_H
pthread_mutex_unlock(&m_mutex);
#elif defined _WIN32
LeaveCriticalSection(&m_mutex);
#endif
}

@@ -122,8 +113,6 @@ private:
std::mutex m_mutex;
#elif defined HAVE_PTHREAD_H
pthread_mutex_t m_mutex;
#elif defined _WIN32
CRITICAL_SECTION m_mutex;
#endif
};

@@ -144,10 +133,6 @@ public:
pthread_mutex_init(&m_mutex, nullptr);
pthread_cond_init(&m_empty_cond, nullptr);
pthread_cond_init(&m_full_cond, nullptr);
#elif defined _WIN32
m_empty_sem = CreateSemaphore(nullptr, CAPACITY, CAPACITY, nullptr);
m_full_sem = CreateSemaphore(nullptr, 0, CAPACITY, nullptr);
InitializeCriticalSection(&m_mutex);
#endif
}

@@ -161,10 +146,6 @@ public:
pthread_cond_destroy(&m_empty_cond);
pthread_cond_destroy(&m_full_cond);
pthread_mutex_destroy(&m_mutex);
#elif defined _WIN32
CloseHandle(m_empty_sem);
CloseHandle(m_full_sem);
DeleteCriticalSection(&m_mutex);
#endif
}

@@ -184,9 +165,6 @@ public:
while (m_count == CAPACITY)
pthread_cond_wait(&m_full_cond, &m_mutex);
m_pushers--;
#elif defined _WIN32
WaitForSingleObject(m_empty_sem, INFINITE);
EnterCriticalSection(&m_mutex);
#endif

do_push(value); /* Push value */
@@ -202,9 +180,6 @@ public:
if (m_poppers)
pthread_cond_signal(&m_empty_cond);
pthread_mutex_unlock(&m_mutex);
#elif defined _WIN32
LeaveCriticalSection(&m_mutex);
ReleaseSemaphore(m_full_sem, 1, nullptr);
#endif
}

@@ -236,11 +211,6 @@ public:
pthread_mutex_unlock(&m_mutex);
return false;
}
#elif defined _WIN32
DWORD status = WaitForSingleObject(m_empty_sem, 0);
if (status == WAIT_TIMEOUT)
return false;
EnterCriticalSection(&m_mutex);
#endif

do_push(value); /* Push value */
@@ -256,9 +226,6 @@ public:
if (m_poppers)
pthread_cond_signal(&m_empty_cond);
pthread_mutex_unlock(&m_mutex);
#elif defined _WIN32
LeaveCriticalSection(&m_mutex);
ReleaseSemaphore(m_full_sem, 1, nullptr);
#endif

return true;
@@ -282,9 +249,6 @@ public:
while (m_count == 0)
pthread_cond_wait(&m_empty_cond, &m_mutex);
m_poppers--;
#elif defined _WIN32
WaitForSingleObject(m_full_sem, INFINITE);
EnterCriticalSection(&m_mutex);
#endif

T ret = do_pop(); /* Pop value */
@@ -333,11 +297,6 @@ public:
pthread_mutex_unlock(&m_mutex);
return false;
}
#elif defined _WIN32
DWORD status = WaitForSingleObject(m_full_sem, 0);
if (status == WAIT_TIMEOUT)
return false;
EnterCriticalSection(&m_mutex);
#endif

ret = do_pop(); /* Pop value */
@@ -391,9 +350,6 @@ private:
size_t m_poppers, m_pushers;
pthread_mutex_t m_mutex;
pthread_cond_t m_empty_cond, m_full_cond;
#elif defined _WIN32
HANDLE m_empty_sem, m_full_sem;
CRITICAL_SECTION m_mutex;
#endif
};

@@ -417,9 +373,6 @@ public:
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&m_thread, &attr, trampoline, this);
#elif defined _WIN32
m_thread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)trampoline,
this, 0, &m_tid);
#endif
}

@@ -428,13 +381,13 @@ public:
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
/* FIXME: this does not work in Visual Studio 2013! */
//m_thread.join();
# if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND
m_thread.detach();
# else
m_thread.join();
# endif
#elif defined HAVE_PTHREAD_H
pthread_join(m_thread, nullptr);
#elif defined _WIN32
WaitForSingleObject(m_thread, INFINITE);
#endif
}

@@ -445,6 +398,9 @@ private:
static void trampoline(thread_base *that)
{
that->m_function();
# if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND
ExitThread(0);
# endif
}
#else
static void *trampoline(void *data)
@@ -463,9 +419,6 @@ private:
std::thread m_thread;
#elif defined HAVE_PTHREAD_H
pthread_t m_thread;
#elif defined _WIN32
HANDLE m_thread;
DWORD m_tid;
#endif
};



正在加载...
取消
保存