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:
parent
73ef35474f
commit
6129dbfbc2
|
@ -48,6 +48,8 @@ void addAlarm(const std::string&);
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
pid_t gPid = 0;
|
pid_t gPid = 0;
|
||||||
|
PthreadPidMap gPthreadTidMap;
|
||||||
|
RWLock gPthreadTidLock;
|
||||||
|
|
||||||
|
|
||||||
// (pat) If Log messages are printed before the classes in this module are inited
|
// (pat) If Log messages are printed before the classes in this module are inited
|
||||||
|
|
20
Logger.h
20
Logger.h
|
@ -46,6 +46,7 @@
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/unistd.h>
|
#include <sys/unistd.h>
|
||||||
|
#include "Threads.h"
|
||||||
|
|
||||||
// We cannot include Utils.h because it includes Logger.h, so just declare timestr() here.
|
// 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.
|
// 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)
|
#endif // !defined(gettid)
|
||||||
|
|
||||||
extern pid_t gPid;
|
extern pid_t gPid;
|
||||||
|
typedef std::map<pthread_t,pid_t> PthreadPidMap;
|
||||||
|
extern PthreadPidMap gPthreadTidMap;
|
||||||
|
extern RWLock gPthreadTidLock;
|
||||||
|
|
||||||
#define _LOG(level) \
|
#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__ << ": "
|
<< 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.
|
// (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)
|
Log(int wPriority)
|
||||||
:mPriority(wPriority), mDummyInit(false)
|
: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
|
// (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++.
|
// to init the syslog facility. This is a very poor use of C++.
|
||||||
|
|
20
Threads.cpp
20
Threads.cpp
|
@ -225,6 +225,21 @@ void Signal::wait(Mutex& wMutex, long timeout) const
|
||||||
pthread_cond_timedwait(&mSignal,&wMutex.mMutex,&waitTime);
|
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)
|
void Thread::start(void *(*task)(void*), void *arg)
|
||||||
{
|
{
|
||||||
|
@ -235,7 +250,10 @@ void Thread::start(void *(*task)(void*), void *arg)
|
||||||
//assert(!res);
|
//assert(!res);
|
||||||
res = pthread_attr_setstacksize(&mAttrib, mStackSize);
|
res = pthread_attr_setstacksize(&mAttrib, mStackSize);
|
||||||
assert(!res);
|
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);
|
assert(!res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,13 +127,13 @@ class RWLock {
|
||||||
|
|
||||||
~RWLock();
|
~RWLock();
|
||||||
|
|
||||||
void wlock() { pthread_rwlock_wrlock(&mRWLock); }
|
const char * wlock() { pthread_rwlock_wrlock(&mRWLock); return ""; }
|
||||||
void rlock() { pthread_rwlock_rdlock(&mRWLock); }
|
const char * rlock() { pthread_rwlock_rdlock(&mRWLock); return ""; }
|
||||||
|
|
||||||
bool trywlock() { return pthread_rwlock_trywrlock(&mRWLock)==0; }
|
bool trywlock() { return pthread_rwlock_trywrlock(&mRWLock)==0; }
|
||||||
bool tryrlock() { return pthread_rwlock_tryrdlock(&mRWLock)==0; }
|
bool tryrlock() { return pthread_rwlock_tryrdlock(&mRWLock)==0; }
|
||||||
|
|
||||||
void unlock() { pthread_rwlock_unlock(&mRWLock); }
|
const char * unlock() { pthread_rwlock_unlock(&mRWLock); return ""; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue