1
0
mirror of https://github.com/danog/libtgvoip.git synced 2024-12-12 17:17:24 +01:00
libtgvoip/threading.h

381 lines
6.7 KiB
C
Raw Normal View History

2017-02-02 17:24:40 +01:00
//
// libtgvoip is free and unencumbered public domain software.
// For more information, see http://unlicense.org or the UNLICENSE file
// you should have received with this source code distribution.
//
#ifndef __THREADING_H
#define __THREADING_H
2018-05-15 20:23:46 +02:00
namespace tgvoip{
class MethodPointerBase{
public:
virtual ~MethodPointerBase(){
}
virtual void Invoke(void* arg)=0;
};
template<typename T> class MethodPointer : public MethodPointerBase{
public:
MethodPointer(void (T::*method)(void*), T* obj){
this->method=method;
this->obj=obj;
}
virtual void Invoke(void* arg){
(obj->*method)(arg);
}
private:
void (T::*method)(void*);
T* obj;
};
}
2017-02-02 17:24:40 +01:00
#if defined(_POSIX_THREADS) || defined(_POSIX_VERSION) || defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
#include <pthread.h>
#include <semaphore.h>
2017-02-02 17:24:40 +01:00
#include <sched.h>
#include <unistd.h>
#ifdef __APPLE__
#include "os/darwin/DarwinSpecific.h"
#endif
2017-02-02 17:24:40 +01:00
2018-05-15 20:23:46 +02:00
namespace tgvoip{
class Mutex{
public:
Mutex(){
pthread_mutex_init(&mtx, NULL);
}
~Mutex(){
pthread_mutex_destroy(&mtx);
}
void Lock(){
pthread_mutex_lock(&mtx);
}
void Unlock(){
pthread_mutex_unlock(&mtx);
}
pthread_mutex_t* NativeHandle(){
return &mtx;
}
2018-05-15 20:23:46 +02:00
private:
Mutex(const Mutex& other);
pthread_mutex_t mtx;
};
class Thread{
public:
Thread(MethodPointerBase* entry, void* arg) : entry(entry), arg(arg){
name=NULL;
}
virtual ~Thread(){
2018-05-15 20:23:46 +02:00
delete entry;
}
void Start(){
if(pthread_create(&thread, NULL, Thread::ActualEntryPoint, this)==0){
valid=true;
}
2018-05-15 20:23:46 +02:00
}
void Join(){
if(valid)
2018-07-19 13:52:38 +02:00
pthread_join(thread, NULL);
2018-05-15 20:23:46 +02:00
}
void SetName(const char* name){
this->name=name;
}
2017-02-02 17:24:40 +01:00
2018-05-15 20:23:46 +02:00
void SetMaxPriority(){
#ifdef __APPLE__
maxPriority=true;
#endif
}
static void Sleep(double seconds){
usleep((useconds_t)(seconds*1000000.0));
}
2018-05-15 20:23:46 +02:00
bool IsCurrent(){
return pthread_equal(thread, pthread_self())!=0;
2018-05-15 20:23:46 +02:00
}
private:
static void* ActualEntryPoint(void* arg){
Thread* self=reinterpret_cast<Thread*>(arg);
if(self->name){
#if !defined(__APPLE__) && !defined(__gnu_hurd__)
2018-05-15 20:23:46 +02:00
pthread_setname_np(self->thread, self->name);
#elif !defined(__gnu_hurd__)
2018-05-15 20:23:46 +02:00
pthread_setname_np(self->name);
if(self->maxPriority){
DarwinSpecific::SetCurrentThreadPriority(DarwinSpecific::THREAD_PRIO_USER_INTERACTIVE);
}
2017-02-02 17:24:40 +01:00
#endif
2018-05-15 20:23:46 +02:00
}
self->entry->Invoke(self->arg);
return NULL;
}
MethodPointerBase* entry;
void* arg;
pthread_t thread;
const char* name;
bool maxPriority=false;
bool valid=false;
2018-05-15 20:23:46 +02:00
};
}
2017-02-02 17:24:40 +01:00
2017-05-03 19:52:05 +02:00
#ifdef __APPLE__
#include <dispatch/dispatch.h>
namespace tgvoip{
class Semaphore{
public:
Semaphore(unsigned int maxCount, unsigned int initValue){
sem = dispatch_semaphore_create(initValue);
}
~Semaphore(){
2017-05-03 23:13:13 +02:00
#if ! __has_feature(objc_arc)
dispatch_release(sem);
#endif
2017-05-03 19:52:05 +02:00
}
void Acquire(){
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}
void Release(){
dispatch_semaphore_signal(sem);
}
void Acquire(int count){
for(int i=0;i<count;i++)
Acquire();
}
void Release(int count){
for(int i=0;i<count;i++)
Release();
}
private:
dispatch_semaphore_t sem;
};
}
#else
namespace tgvoip{
class Semaphore{
public:
Semaphore(unsigned int maxCount, unsigned int initValue){
sem_init(&sem, 0, initValue);
}
~Semaphore(){
sem_destroy(&sem);
}
void Acquire(){
sem_wait(&sem);
}
void Release(){
sem_post(&sem);
}
void Acquire(int count){
for(int i=0;i<count;i++)
Acquire();
}
void Release(int count){
for(int i=0;i<count;i++)
Release();
}
private:
sem_t sem;
};
}
2017-05-03 19:52:05 +02:00
#endif
#elif defined(_WIN32)
#include <Windows.h>
#include <assert.h>
2018-05-15 20:23:46 +02:00
namespace tgvoip{
class Mutex{
public:
Mutex(){
#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
2018-05-15 20:23:46 +02:00
InitializeCriticalSection(&section);
#else
2018-05-15 20:23:46 +02:00
InitializeCriticalSectionEx(&section, 0, 0);
#endif
2018-05-15 20:23:46 +02:00
}
~Mutex(){
DeleteCriticalSection(&section);
}
void Lock(){
EnterCriticalSection(&section);
}
void Unlock(){
LeaveCriticalSection(&section);
}
private:
Mutex(const Mutex& other);
CRITICAL_SECTION section;
};
class Thread{
public:
Thread(MethodPointerBase* entry, void* arg) : entry(entry), arg(arg){
name=NULL;
2018-07-19 13:52:38 +02:00
thread=NULL;
2018-05-15 20:23:46 +02:00
}
~Thread(){
delete entry;
}
void Start(){
thread=CreateThread(NULL, 0, Thread::ActualEntryPoint, this, 0, &id);
2018-05-15 20:23:46 +02:00
}
void Join(){
2018-07-19 13:52:38 +02:00
if(!thread)
return;
#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
2018-05-15 20:23:46 +02:00
WaitForSingleObject(thread, INFINITE);
#else
2018-05-15 20:23:46 +02:00
WaitForSingleObjectEx(thread, INFINITE, false);
#endif
2018-05-15 20:23:46 +02:00
CloseHandle(thread);
}
void SetName(const char* name){
this->name=name;
}
void SetMaxPriority(){
SetThreadPriority(thread, THREAD_PRIORITY_HIGHEST);
}
static void Sleep(double seconds){
::Sleep((DWORD)(seconds*1000));
}
bool IsCurrent(){
return id==GetCurrentThreadId();
}
2018-05-15 20:23:46 +02:00
private:
static const DWORD MS_VC_EXCEPTION=0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_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.
} THREADNAME_INFO;
#pragma pack(pop)
static DWORD WINAPI ActualEntryPoint(void* arg){
Thread* self=reinterpret_cast<Thread*>(arg);
if(self->name){
THREADNAME_INFO info;
info.dwType=0x1000;
info.szName=self->name;
info.dwThreadID=-1;
info.dwFlags=0;
__try{
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
}__except(EXCEPTION_EXECUTE_HANDLER){}
}
self->entry->Invoke(self->arg);
return 0;
}
MethodPointerBase* entry;
void* arg;
HANDLE thread;
DWORD id;
2018-05-15 20:23:46 +02:00
const char* name;
};
class Semaphore{
public:
Semaphore(unsigned int maxCount, unsigned int initValue){
#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
h=CreateSemaphore(NULL, initValue, maxCount, NULL);
#else
h=CreateSemaphoreEx(NULL, initValue, maxCount, NULL, 0, SEMAPHORE_ALL_ACCESS);
assert(h);
#endif
}
~Semaphore(){
CloseHandle(h);
}
void Acquire(){
#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
WaitForSingleObject(h, INFINITE);
#else
WaitForSingleObjectEx(h, INFINITE, false);
#endif
}
void Release(){
ReleaseSemaphore(h, 1, NULL);
}
void Acquire(int count){
for(int i=0;i<count;i++)
Acquire();
}
void Release(int count){
ReleaseSemaphore(h, count, NULL);
}
private:
HANDLE h;
};
}
2017-02-02 17:24:40 +01:00
#else
#error "No threading implementation for your operating system"
#endif
namespace tgvoip{
class MutexGuard{
2017-03-30 16:06:59 +02:00
public:
2018-05-15 20:23:46 +02:00
MutexGuard(Mutex &mutex) : mutex(mutex) {
mutex.Lock();
2017-03-30 16:06:59 +02:00
}
~MutexGuard(){
2018-05-15 20:23:46 +02:00
mutex.Unlock();
2017-03-30 16:06:59 +02:00
}
private:
2018-05-15 20:23:46 +02:00
Mutex &mutex;
2017-03-30 16:06:59 +02:00
};
}
2017-02-02 17:24:40 +01:00
#endif //__THREADING_H