Changed logging system to "cache" gettid() values, to avoid system calls at

runtime (ie, when logging).
The implementation is cludgy. This is because we create threads before main,
as a result of global thread objects (as opposed to pointers to thread objects
that get new'ed and started in main).
A view of the system through strace indicates one or two calls to gettid() per
thread (usually 1, occasionally 2). Changing the read lock in Log() to a write
lock deadlocks.
This commit is contained in:
dgotwisner 2014-03-31 12:04:56 +02:00 committed by Michael Iedema
parent 73ef35474f
commit 6129dbfbc2
4 changed files with 42 additions and 6 deletions

View File

@ -48,6 +48,8 @@ void addAlarm(const std::string&);
//@}
pid_t gPid = 0;
PthreadPidMap gPthreadTidMap;
RWLock gPthreadTidLock;
// (pat) If Log messages are printed before the classes in this module are inited

View File

@ -46,6 +46,7 @@
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/unistd.h>
#include "Threads.h"
// We cannot include Utils.h because it includes Logger.h, so just declare timestr() here.
// If timestr decl is changed G++ will whine when Utils.h is included.
@ -56,9 +57,17 @@ namespace Utils { const std::string timestr(); };
#endif // !defined(gettid)
extern pid_t gPid;
typedef std::map<pthread_t,pid_t> PthreadPidMap;
extern PthreadPidMap gPthreadTidMap;
extern RWLock gPthreadTidLock;
#define _LOG(level) \
Log(LOG_##level).get() << "pid(" << gPid << "), tid(" << gettid() << ") " \
Log(LOG_##level).get() << "pid(" << gPid << "), " \
<< "tid(" \
<< gPthreadTidLock.rlock() \
<< gPthreadTidMap[pthread_self()] \
<< gPthreadTidLock.unlock() \
<< ") " \
<< Utils::timestr() << " " __FILE__ ":" << __LINE__ << ":" << __FUNCTION__ << ": "
// (pat) If you '#define LOG_GROUP groupname' before including Logger.h, then you can set Log.Level.groupname as well as Log.Level.filename.
@ -139,7 +148,14 @@ class Log {
Log(int wPriority)
:mPriority(wPriority), mDummyInit(false)
{ }
{
gPthreadTidLock.rlock();
if (gPthreadTidMap[pthread_self()] == 0)
{
gPthreadTidMap[pthread_self()] = gettid();
}
gPthreadTidLock.unlock();
}
// (pat) This constructor is not used to construct a Log record, it is called once per application
// to init the syslog facility. This is a very poor use of C++.

View File

@ -225,6 +225,21 @@ void Signal::wait(Mutex& wMutex, long timeout) const
pthread_cond_timedwait(&mSignal,&wMutex.mMutex,&waitTime);
}
struct wrapArgs
{
void *(*task)(void *);
void *arg;
};
static void *
thread_main(void *arg)
{
struct wrapArgs *p = (struct wrapArgs *)arg;
void *(*task)(void *) = p->task;
void *param = p->arg;
delete p;
return (*task)(param);
}
void Thread::start(void *(*task)(void*), void *arg)
{
@ -235,7 +250,10 @@ void Thread::start(void *(*task)(void*), void *arg)
//assert(!res);
res = pthread_attr_setstacksize(&mAttrib, mStackSize);
assert(!res);
res = pthread_create(&mThread, &mAttrib, task, arg);
struct wrapArgs *p = new wrapArgs;
p->task = task;
p->arg = arg;
res = pthread_create(&mThread, &mAttrib, &thread_main, p);
assert(!res);
}

View File

@ -127,13 +127,13 @@ class RWLock {
~RWLock();
void wlock() { pthread_rwlock_wrlock(&mRWLock); }
void rlock() { pthread_rwlock_rdlock(&mRWLock); }
const char * wlock() { pthread_rwlock_wrlock(&mRWLock); return ""; }
const char * rlock() { pthread_rwlock_rdlock(&mRWLock); return ""; }
bool trywlock() { return pthread_rwlock_trywrlock(&mRWLock)==0; }
bool tryrlock() { return pthread_rwlock_tryrdlock(&mRWLock)==0; }
void unlock() { pthread_rwlock_unlock(&mRWLock); }
const char * unlock() { pthread_rwlock_unlock(&mRWLock); return ""; }
};