Files
pvData/pvDataApp/misc/thread.cpp

256 lines
5.5 KiB
C++

/* thread.cpp */
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <epicsThread.h>
#include <epicsEvent.h>
#include "lock.h"
#include "event.h"
#include "thread.h"
#include "linkedList.h"
namespace epics { namespace pvData {
static unsigned int epicsPriority[] = {
epicsThreadPriorityLow,
epicsThreadPriorityLow + 15,
epicsThreadPriorityMedium - 15,
epicsThreadPriorityMedium,
epicsThreadPriorityMedium + 15,
epicsThreadPriorityHigh - 15,
epicsThreadPriorityHigh
};
unsigned int const * const ThreadPriorityFunc::getEpicsPriorities()
{
return epicsPriority;
}
static String threadPriorityNames[] = {
String("lowest"),String("lower"),String("low"),
String("middle"),
String("high"),String("higher"),String("highest")
};
class ThreadListElement;
typedef LinkedListNode<ThreadListElement> ThreadListNode;
typedef LinkedList<ThreadListElement> ThreadList;
static volatile int64 totalConstruct = 0;
static volatile int64 totalDestruct = 0;
static Mutex *globalMutex = 0;
static void addThread(Thread *thread);
static void removeThread(Thread *thread);
static ThreadList *list;
class ConstructDestructCallbackThread : public ConstructDestructCallback {
public:
ConstructDestructCallbackThread();
virtual String getConstructName();
virtual int64 getTotalConstruct();
virtual int64 getTotalDestruct();
virtual int64 getTotalReferenceCount();
private:
String name;
};
ConstructDestructCallbackThread::ConstructDestructCallbackThread()
: name("thread")
{
getShowConstructDestruct()->registerCallback(this);
}
String ConstructDestructCallbackThread::getConstructName() {return name;}
int64 ConstructDestructCallbackThread::getTotalConstruct()
{
Lock xx(globalMutex);
return totalConstruct;
}
int64 ConstructDestructCallbackThread::getTotalDestruct()
{
Lock xx(globalMutex);
return totalDestruct;
}
int64 ConstructDestructCallbackThread::getTotalReferenceCount()
{
return 0;
}
static ConstructDestructCallback *pConstructDestructCallback;
static void init()
{
static Mutex mutex = Mutex();
Lock xx(&mutex);
if(globalMutex==0) {
globalMutex = new Mutex();
list = new ThreadList();
pConstructDestructCallback = new ConstructDestructCallbackThread();
}
}
class ThreadListElement {
public:
ThreadListElement(Thread *thread) : thread(thread),node(new ThreadListNode(this)){}
~ThreadListElement(){delete node;}
Thread *thread;
ThreadListNode *node;
};
int ThreadPriorityFunc::getEpicsPriority(ThreadPriority threadPriority) {
return epicsPriority[threadPriority];
}
extern "C" void myFunc ( void * pPvt );
class Runnable : public ThreadReady {
public:
Runnable(Thread *thread,String name,
ThreadPriority priority, RunnableReady *runnable);
virtual ~Runnable();
Thread *start();
void ready();
public: // only used within this source module
Thread *thread;
String name;
ThreadPriority priority;
RunnableReady *runnable;
Event waitStart;
bool isReady;
epicsThreadId id;
};
extern "C" void myFunc ( void * pPvt )
{
Runnable *runnable = (Runnable *)pPvt;
runnable->waitStart.signal();
addThread(runnable->thread);
runnable->runnable->run(runnable);
removeThread(runnable->thread);
}
Runnable::Runnable(Thread *thread,String name,
ThreadPriority priority, RunnableReady *runnable)
: thread(thread),name(name),priority(priority),
runnable(runnable),
waitStart(eventEmpty),
isReady(false),
id(epicsThreadCreate(
name.c_str(),
epicsPriority[priority],
epicsThreadGetStackSize(epicsThreadStackSmall),
myFunc,this))
{
init();
Lock xx(globalMutex);
totalConstruct++;
}
Runnable::~Runnable()
{
Lock xx(globalMutex);
totalDestruct++;
}
Thread * Runnable::start()
{
if(!waitStart.wait(10.0)) {
fprintf(stderr,"thread %s did not call ready\n",thread->getName().c_str());
}
return thread;
}
void Runnable::ready()
{
waitStart.signal();
}
Thread::Thread(String name,ThreadPriority priority,RunnableReady *runnableReady)
: pImpl(new Runnable(this,name,priority,runnableReady))
{
}
Thread::~Thread()
{
delete pImpl;
}
ConstructDestructCallback *Thread::getConstructDestructCallback()
{
init();
return pConstructDestructCallback;
}
void Thread::start()
{
pImpl->start();
}
void Thread::sleep(double seconds)
{
epicsThreadSleep(seconds);;
}
String Thread::getName()
{
return pImpl->name;
}
ThreadPriority Thread::getPriority()
{
return pImpl->priority;
}
void Thread::showThreads(StringBuilder buf)
{
init();
Lock xx(globalMutex);
ThreadListNode *node = list->getHead();
while(node!=0) {
Thread *thread = node->getObject()->thread;
*buf += thread->getName();
*buf += " ";
*buf += threadPriorityNames[thread->getPriority()];
*buf += "\n";
node = list->getNext(node);
}
}
void addThread(Thread *thread)
{
Lock xx(globalMutex);
ThreadListElement *element = new ThreadListElement(thread);
list->addTail(element->node);
}
void removeThread(Thread *thread)
{
Lock xx(globalMutex);
ThreadListNode *node = list->getHead();
while(node!=0) {
if(node->getObject()->thread==thread) {
list->remove(node);
delete node;
return;
}
node = list->getNext(node);
}
fprintf(stderr,"removeThread but thread %s did not in list\n",
thread->getName().c_str());
}
}}