// // Lol Engine // // Copyright: (c) 2010-2011 Sam Hocevar // This program is free software; you can redistribute it and/or // modify it under the terms of the Do What The Fuck You Want To // Public License, Version 2, as published by Sam Hocevar. See // http://sam.zoy.org/projects/COPYING.WTFPL for more details. // // // The ThreadBase class // -------------------- // #if !defined __LOL_THREADBASE_H__ #define __LOL_THREADBASE_H__ #if defined __linux__ || defined __native_client__ # include #elif defined _WIN32 # include #else # error No threading support yet :( #endif namespace lol { class MutexBase { public: MutexBase() { #if defined __linux__ || defined __native_client__ pthread_mutex_init(&m_mutex, NULL); #elif defined _WIN32 InitializeCriticalSection(&m_mutex); #endif } ~MutexBase() { #if defined __linux__ || defined __native_client__ pthread_mutex_destroy(&m_mutex); #elif defined _WIN32 DeleteCriticalSection(&m_mutex); #endif } void Lock() { #if defined __linux__ || defined __native_client__ pthread_mutex_lock(&m_mutex); #elif defined _WIN32 EnterCriticalSection(&m_mutex); #endif } void Unlock() { #if defined __linux__ || defined __native_client__ pthread_mutex_unlock(&m_mutex); #elif defined _WIN32 LeaveCriticalSection(&m_mutex); #endif } private: #if defined __linux__ || defined __native_client__ pthread_mutex_t m_mutex; #elif defined _WIN32 CRITICAL_SECTION m_mutex; #endif }; class QueueBase { public: QueueBase() { m_start = m_count = 0; #if defined __linux__ || defined __native_client__ m_poppers = m_pushers = 0; pthread_mutex_init(&m_mutex, NULL); pthread_cond_init(&m_empty_cond, NULL); pthread_cond_init(&m_full_cond, NULL); #elif defined _WIN32 m_empty_sem = CreateSemaphore(NULL, CAPACITY, CAPACITY, NULL); m_full_sem = CreateSemaphore(NULL, 0, CAPACITY, NULL); InitializeCriticalSection(&m_mutex); #endif } ~QueueBase() { #if defined __linux__ || defined __native_client__ 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 } void Push(int value) { #if defined __linux__ || defined __native_client__ pthread_mutex_lock(&m_mutex); /* If queue is full, wait on the "full" cond var. */ m_pushers++; 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 /* Push value */ m_values[(m_start + m_count) % CAPACITY] = value; m_count++; #if defined __linux__ || defined __native_client__ /* If there were poppers waiting, signal the "empty" cond var. */ 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, NULL); #endif } int Pop() { #if defined __linux__ || defined __native_client__ pthread_mutex_lock(&m_mutex); /* Wait until there is something in the queue. Be careful, we * could get woken up but another thread may have eaten the * message in the meantime. */ m_poppers++; 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 /* Pop value */ int ret = m_values[m_start]; m_start = (m_start + 1) % CAPACITY; m_count--; #if defined __linux__ || defined __native_client__ /* If there were pushers waiting, signal the "full" cond var. */ if (m_pushers) pthread_cond_signal(&m_full_cond); pthread_mutex_unlock(&m_mutex); #else LeaveCriticalSection(&m_mutex); ReleaseSemaphore(m_empty_sem, 1, NULL); #endif return ret; } private: static size_t const CAPACITY = 100; int m_values[CAPACITY]; size_t m_start, m_count; #if defined __linux__ || defined __native_client__ 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 }; class ThreadBase { public: ThreadBase(void *(*fn)(void *), void *data) { #if defined __linux__ || defined __native_client__ /* Set the joinable attribute for systems who don't play nice */ pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_create(&m_thread, &attr, fn, data); #elif defined _WIN32 m_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)fn, data, 0, &m_tid); #endif } virtual ~ThreadBase() { #if defined __linux__ || defined __native_client__ pthread_join(m_thread, NULL); #elif defined _WIN32 WaitForSingleObject(m_thread, INFINITE); #endif } private: #if defined __linux__ || defined __native_client__ pthread_t m_thread; #elif defined _WIN32 HANDLE m_thread; DWORD m_tid; #endif }; } /* namespace lol */ #endif // __LOL_THREADBASE_H__