229 lines
7.1 KiB
C++
229 lines
7.1 KiB
C++
/*=============================================================================|
|
|
| PROJECT SNAP7 1.3.0 |
|
|
|==============================================================================|
|
|
| Copyright (C) 2013, 2015 Davide Nardella |
|
|
| All rights reserved. |
|
|
|==============================================================================|
|
|
| SNAP7 is free software: you can redistribute it and/or modify |
|
|
| it under the terms of the Lesser GNU General Public License as published by |
|
|
| the Free Software Foundation, either version 3 of the License, or |
|
|
| (at your option) any later version. |
|
|
| |
|
|
| It means that you can distribute your commercial software linked with |
|
|
| SNAP7 without the requirement to distribute the source code of your |
|
|
| application and without the requirement that your application be itself |
|
|
| distributed under LGPL. |
|
|
| |
|
|
| SNAP7 is distributed in the hope that it will be useful, |
|
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
| Lesser GNU General Public License for more details. |
|
|
| |
|
|
| You should have received a copy of the GNU General Public License and a |
|
|
| copy of Lesser GNU General Public License along with Snap7. |
|
|
| If not, see http://www.gnu.org/licenses/ |
|
|
|==============================================================================|
|
|
| |
|
|
| Posix Threads support (Linux, FreeBSD) |
|
|
| |
|
|
|=============================================================================*/
|
|
#ifndef unix_threads_h
|
|
#define unix_threads_h
|
|
//---------------------------------------------------------------------------
|
|
#include "snap_platform.h"
|
|
#include "snap_sysutils.h"
|
|
#include <semaphore.h>
|
|
#include <pthread.h>
|
|
//---------------------------------------------------------------------------
|
|
|
|
class TSnapCriticalSection
|
|
{
|
|
private:
|
|
pthread_mutex_t mx;
|
|
// int result;
|
|
public:
|
|
|
|
TSnapCriticalSection()
|
|
{
|
|
/*
|
|
|
|
This would be the best code, but very often it causes a segmentation fault in many
|
|
unix systems (the problem seems to be pthread_mutexattr_destroy()).
|
|
So, to avoid problems in future kernel/libc release, we use the "safe" default.
|
|
|
|
pthread_mutexattr_t mxAttr;
|
|
pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE);
|
|
pthread_mutex_init(&mx, &mxAttr);
|
|
pthread_mutexattr_destroy(&mxAttr);
|
|
|
|
*/
|
|
pthread_mutex_init(&mx, 0);
|
|
};
|
|
|
|
~TSnapCriticalSection()
|
|
{
|
|
pthread_mutex_destroy(&mx);
|
|
};
|
|
|
|
void Enter()
|
|
{
|
|
pthread_mutex_lock(&mx);
|
|
};
|
|
|
|
void Leave()
|
|
{
|
|
pthread_mutex_unlock(&mx);
|
|
};
|
|
|
|
bool TryEnter()
|
|
{
|
|
return pthread_mutex_trylock(&mx) == 0;
|
|
};
|
|
};
|
|
typedef TSnapCriticalSection *PSnapCriticalSection;
|
|
|
|
//---------------------------------------------------------------------------
|
|
const longword WAIT_OBJECT_0 = 0x00000000L;
|
|
const longword WAIT_ABANDONED = 0x00000080L;
|
|
const longword WAIT_TIMEOUT = 0x00000102L;
|
|
const longword WAIT_FAILED = 0xFFFFFFFFL;
|
|
|
|
class TSnapEvent
|
|
{
|
|
private:
|
|
pthread_cond_t CVariable;
|
|
pthread_mutex_t Mutex;
|
|
bool AutoReset;
|
|
bool State;
|
|
public:
|
|
|
|
TSnapEvent(bool ManualReset)
|
|
{
|
|
AutoReset = !ManualReset;
|
|
if (pthread_cond_init(&CVariable, 0) == 0)
|
|
pthread_mutex_init(&Mutex, 0);
|
|
State = false;
|
|
}
|
|
|
|
~TSnapEvent()
|
|
{
|
|
pthread_cond_destroy(&CVariable);
|
|
pthread_mutex_destroy(&Mutex);
|
|
};
|
|
|
|
void Set()
|
|
{
|
|
pthread_mutex_lock(&Mutex);
|
|
State = true;
|
|
if (AutoReset)
|
|
pthread_cond_signal(&CVariable);
|
|
else
|
|
pthread_cond_broadcast(&CVariable);
|
|
pthread_mutex_unlock(&Mutex);
|
|
};
|
|
|
|
void Reset()
|
|
{
|
|
pthread_mutex_lock(&Mutex);
|
|
State = false;
|
|
pthread_mutex_unlock(&Mutex);
|
|
}
|
|
|
|
longword WaitForever()
|
|
{
|
|
pthread_mutex_lock(&Mutex);
|
|
while (!State) // <-- to avoid spurious wakeups
|
|
pthread_cond_wait(&CVariable, &Mutex);
|
|
if (AutoReset)
|
|
State = false;
|
|
pthread_mutex_unlock(&Mutex);
|
|
return WAIT_OBJECT_0;
|
|
};
|
|
|
|
longword WaitFor(int64_t Timeout)
|
|
{
|
|
longword Result = WAIT_OBJECT_0;
|
|
if (Timeout == 0)
|
|
Timeout = 1; // 0 is not allowed
|
|
|
|
if (Timeout > 0)
|
|
{
|
|
pthread_mutex_lock(&Mutex);
|
|
if (!State)
|
|
{
|
|
timespec ts;
|
|
timeval tv;
|
|
gettimeofday(&tv, NULL);
|
|
uint64_t nsecs = ((uint64_t) tv.tv_sec) * 1000000000 +
|
|
Timeout * 1000000 +
|
|
((uint64_t) tv.tv_usec) * 1000;
|
|
ts.tv_sec = nsecs / 1000000000;
|
|
ts.tv_nsec = (nsecs - ((uint64_t) ts.tv_sec) * 1000000000);
|
|
do {
|
|
Result = pthread_cond_timedwait(&CVariable, &Mutex, &ts);
|
|
if (Result == ETIMEDOUT)
|
|
Result = WAIT_TIMEOUT;
|
|
} while (Result == 0 && !State);
|
|
}
|
|
else
|
|
if (AutoReset) // take the ownership
|
|
State = false;
|
|
pthread_mutex_unlock(&Mutex);
|
|
return Result;
|
|
}
|
|
else // Timeout<0
|
|
return WaitForever();
|
|
};
|
|
};
|
|
typedef TSnapEvent *PSnapEvent;
|
|
//---------------------------------------------------------------------------
|
|
class TSnapThread
|
|
{
|
|
private:
|
|
pthread_t th;
|
|
bool FCreateSuspended;
|
|
void ThreadCreate();
|
|
|
|
void ThreadJoin()
|
|
{
|
|
pthread_join(th, 0);
|
|
};
|
|
|
|
void ThreadKill()
|
|
{
|
|
pthread_cancel(th);
|
|
};
|
|
|
|
longword ThreadWait(uint64_t Timeout)
|
|
{
|
|
longword Elapsed = SysGetTick();
|
|
while (!Closed && !(DeltaTime(Elapsed) > Timeout))
|
|
SysSleep(100);
|
|
if (Closed)
|
|
return WAIT_OBJECT_0;
|
|
else
|
|
return WAIT_TIMEOUT;
|
|
};
|
|
protected:
|
|
bool Started;
|
|
public:
|
|
bool Terminated;
|
|
bool Closed;
|
|
bool FreeOnTerminate;
|
|
TSnapThread();
|
|
virtual ~TSnapThread();
|
|
|
|
virtual void Execute()
|
|
{
|
|
};
|
|
void Start();
|
|
void Terminate();
|
|
void Kill();
|
|
void Join();
|
|
longword WaitFor(uint64_t Timeout);
|
|
};
|
|
typedef TSnapThread *PSnapThread;
|
|
|
|
//---------------------------------------------------------------------------
|
|
#endif // unix_threads_h
|