#ifndef X265_THREADING_H
#define X265_THREADING_H
#include "common.h"
#include "x265.h"
#ifdef _WIN32
#include <windows.h>
#include "winxp.h"
#else
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#include <fcntl.h>
#endif
#if MACOS
#include <sys/param.h>
#include <sys/sysctl.h>
#endif
#if NO_ATOMICS
#include <sys/time.h>
#include <unistd.h>
namespace X265_NS {
int no_atomic_or(int* ptr, int mask);
int no_atomic_and(int* ptr, int mask);
int no_atomic_inc(int* ptr);
int no_atomic_dec(int* ptr);
int no_atomic_add(int* ptr, int val);
}
#define CLZ(id, x) id = (unsigned long)__builtin_clz(x) ^ 31
#define CTZ(id, x) id = (unsigned long)__builtin_ctz(x)
#define ATOMIC_OR(ptr, mask) no_atomic_or((int*)ptr, mask)
#define ATOMIC_AND(ptr, mask) no_atomic_and((int*)ptr, mask)
#define ATOMIC_INC(ptr) no_atomic_inc((int*)ptr)
#define ATOMIC_DEC(ptr) no_atomic_dec((int*)ptr)
#define ATOMIC_ADD(ptr, val) no_atomic_add((int*)ptr, val)
#define GIVE_UP_TIME() usleep(0)
#elif __GNUC__
#include <sys/time.h>
#include <unistd.h>
#define CLZ(id, x) id = (unsigned long)__builtin_clz(x) ^ 31
#define CTZ(id, x) id = (unsigned long)__builtin_ctz(x)
#define ATOMIC_OR(ptr, mask) __sync_fetch_and_or(ptr, mask)
#define ATOMIC_AND(ptr, mask) __sync_fetch_and_and(ptr, mask)
#define ATOMIC_INC(ptr) __sync_add_and_fetch((volatile int32_t*)ptr, 1)
#define ATOMIC_DEC(ptr) __sync_add_and_fetch((volatile int32_t*)ptr, -1)
#define ATOMIC_ADD(ptr, val) __sync_fetch_and_add((volatile int32_t*)ptr, val)
#define GIVE_UP_TIME() usleep(0)
#elif defined(_MSC_VER)
#include <intrin.h>
#define CLZ(id, x) _BitScanReverse(&id, x)
#define CTZ(id, x) _BitScanForward(&id, x)
#define ATOMIC_INC(ptr) InterlockedIncrement((volatile LONG*)ptr)
#define ATOMIC_DEC(ptr) InterlockedDecrement((volatile LONG*)ptr)
#define ATOMIC_ADD(ptr, val) InterlockedExchangeAdd((volatile LONG*)ptr, val)
#define ATOMIC_OR(ptr, mask) _InterlockedOr((volatile LONG*)ptr, (LONG)mask)
#define ATOMIC_AND(ptr, mask) _InterlockedAnd((volatile LONG*)ptr, (LONG)mask)
#define GIVE_UP_TIME() Sleep(0)
#endif
namespace X265_NS {
#ifdef _WIN32
typedef HANDLE ThreadHandle;
class Lock
{
public:
Lock()
{
InitializeCriticalSection(&this->handle);
}
~Lock()
{
DeleteCriticalSection(&this->handle);
}
void acquire()
{
EnterCriticalSection(&this->handle);
}
void release()
{
LeaveCriticalSection(&this->handle);
}
protected:
CRITICAL_SECTION handle;
};
class Event
{
public:
Event()
{
this->handle = CreateEvent(NULL, FALSE, FALSE, NULL);
}
~Event()
{
CloseHandle(this->handle);
}
void wait()
{
WaitForSingleObject(this->handle, INFINITE);
}
bool timedWait(uint32_t milliseconds)
{
return WaitForSingleObject(this->handle, milliseconds) == WAIT_TIMEOUT;
}
void trigger()
{
SetEvent(this->handle);
}
protected:
HANDLE handle;
};
class ThreadSafeInteger
{
public:
ThreadSafeInteger()
{
m_val = 0;
InitializeCriticalSection(&m_cs);
InitializeConditionVariable(&m_cv);
}
~ThreadSafeInteger()
{
DeleteCriticalSection(&m_cs);
XP_CONDITION_VAR_FREE(&m_cv);
}
int waitForChange(int prev)
{
EnterCriticalSection(&m_cs);
if (m_val == prev)
SleepConditionVariableCS(&m_cv, &m_cs, INFINITE);
LeaveCriticalSection(&m_cs);
return m_val;
}
int get()
{
EnterCriticalSection(&m_cs);
int ret = m_val;
LeaveCriticalSection(&m_cs);
return ret;
}
int getIncr(int n = 1)
{
EnterCriticalSection(&m_cs);
int ret = m_val;
m_val += n;
LeaveCriticalSection(&m_cs);
return ret;
}
void set(int newval)
{
EnterCriticalSection(&m_cs);
m_val = newval;
WakeAllConditionVariable(&m_cv);
LeaveCriticalSection(&m_cs);
}
void poke(void)
{
EnterCriticalSection(&m_cs);
WakeAllConditionVariable(&m_cv);
LeaveCriticalSection(&m_cs);
}
void incr()
{
EnterCriticalSection(&m_cs);
m_val++;
WakeAllConditionVariable(&m_cv);
LeaveCriticalSection(&m_cs);
}
protected:
CRITICAL_SECTION m_cs;
CONDITION_VARIABLE m_cv;
int m_val;
};
#else
typedef pthread_t ThreadHandle;
class Lock
{
public:
Lock()
{
pthread_mutex_init(&this->handle, NULL);
}
~Lock()
{
pthread_mutex_destroy(&this->handle);
}
void acquire()
{
pthread_mutex_lock(&this->handle);
}
void release()
{
pthread_mutex_unlock(&this->handle);
}
protected:
pthread_mutex_t handle;
};
class Event
{
public:
Event()
{
m_counter = 0;
if (pthread_mutex_init(&m_mutex, NULL) ||
pthread_cond_init(&m_cond, NULL))
{
x265_log(NULL, X265_LOG_ERROR, "fatal: unable to initialize conditional variable\n");
}
}
~Event()
{
pthread_cond_destroy(&m_cond);
pthread_mutex_destroy(&m_mutex);
}
void wait()
{
pthread_mutex_lock(&m_mutex);
while (!m_counter)
pthread_cond_wait(&m_cond, &m_mutex);
m_counter--;
pthread_mutex_unlock(&m_mutex);
}
bool timedWait(uint32_t waitms)
{
bool bTimedOut = false;
pthread_mutex_lock(&m_mutex);
if (!m_counter)
{
struct timeval tv;
struct timespec ts;
gettimeofday(&tv, NULL);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000;
ts.tv_nsec += 1000 * 1000 * (waitms % 1000);
ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
ts.tv_nsec %= (1000 * 1000 * 1000);
ts.tv_sec += waitms / 1000;
bTimedOut = pthread_cond_timedwait(&m_cond, &m_mutex, &ts) == ETIMEDOUT;
}
if (m_counter > 0)
{
m_counter--;
bTimedOut = false;
}
pthread_mutex_unlock(&m_mutex);
return bTimedOut;
}
void trigger()
{
pthread_mutex_lock(&m_mutex);
if (m_counter < UINT_MAX)
m_counter++;
pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex);
}
protected:
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
uint32_t m_counter;
};
class ThreadSafeInteger
{
public:
ThreadSafeInteger()
{
m_val = 0;
if (pthread_mutex_init(&m_mutex, NULL) ||
pthread_cond_init(&m_cond, NULL))
{
x265_log(NULL, X265_LOG_ERROR, "fatal: unable to initialize conditional variable\n");
}
}
~ThreadSafeInteger()
{
pthread_cond_destroy(&m_cond);
pthread_mutex_destroy(&m_mutex);
}
int waitForChange(int prev)
{
pthread_mutex_lock(&m_mutex);
if (m_val == prev)
pthread_cond_wait(&m_cond, &m_mutex);
pthread_mutex_unlock(&m_mutex);
return m_val;
}
int get()
{
pthread_mutex_lock(&m_mutex);
int ret = m_val;
pthread_mutex_unlock(&m_mutex);
return ret;
}
int getIncr(int n = 1)
{
pthread_mutex_lock(&m_mutex);
int ret = m_val;
m_val += n;
pthread_mutex_unlock(&m_mutex);
return ret;
}
void set(int newval)
{
pthread_mutex_lock(&m_mutex);
m_val = newval;
pthread_cond_broadcast(&m_cond);
pthread_mutex_unlock(&m_mutex);
}
void poke(void)
{
pthread_mutex_lock(&m_mutex);
pthread_cond_broadcast(&m_cond);
pthread_mutex_unlock(&m_mutex);
}
void incr()
{
pthread_mutex_lock(&m_mutex);
m_val++;
pthread_cond_broadcast(&m_cond);
pthread_mutex_unlock(&m_mutex);
}
protected:
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
int m_val;
};
#endif
class ScopedLock
{
public:
ScopedLock(Lock &instance) : inst(instance)
{
this->inst.acquire();
}
~ScopedLock()
{
this->inst.release();
}
protected:
ScopedLock &operator =(const ScopedLock &);
Lock &inst;
};
struct ScopedElapsedTime
{
ScopedElapsedTime(int64_t& accum) : accumlatedTime(accum) { startTime = x265_mdate(); }
~ScopedElapsedTime() { accumlatedTime += x265_mdate() - startTime; }
protected:
int64_t startTime;
int64_t& accumlatedTime;
ScopedElapsedTime &operator =(const ScopedElapsedTime &);
};
class Thread
{
private:
ThreadHandle thread;
public:
Thread();
virtual ~Thread();
virtual void threadMain() = 0;
bool start();
void stop();
};
}
#endif