15#include <linux/unistd.h>
20#include <sys/resource.h>
21#include <sys/syscall.h>
27#define ABORT { dsyslog("ABORT!"); cBackTrace::BackTrace(); abort(); }
34#define dbglocking(a...) fprintf(stderr, a)
36#define dbglocking(a...)
39static bool GetAbsTime(
struct timespec *Abstime,
int MillisecondsFromNow)
42 if (gettimeofday(&now, NULL) == 0) {
43 MillisecondsFromNow =
max(MillisecondsFromNow, 3);
44 now.tv_sec += MillisecondsFromNow / 1000;
45 now.tv_usec += (MillisecondsFromNow % 1000) * 1000;
46 if (now.tv_usec >= 1000000) {
48 now.tv_usec -= 1000000;
50 Abstime->tv_sec = now.tv_sec;
51 Abstime->tv_nsec = now.tv_usec * 1000;
62 pthread_mutex_init(&
mutex, NULL);
63 pthread_cond_init(&
cond, NULL);
68 pthread_cond_broadcast(&
cond);
69 pthread_cond_destroy(&
cond);
70 pthread_mutex_destroy(&
mutex);
81 pthread_mutex_lock(&
mutex);
84 struct timespec abstime;
87 if (pthread_cond_timedwait(&
cond, &
mutex, &abstime) == ETIMEDOUT)
97 pthread_mutex_unlock(&
mutex);
103 pthread_mutex_lock(&
mutex);
105 pthread_cond_broadcast(&
cond);
106 pthread_mutex_unlock(&
mutex);
113 pthread_cond_init(&
cond, 0);
118 pthread_cond_broadcast(&
cond);
119 pthread_cond_destroy(&
cond);
125 int locked =
Mutex.locked;
129 Mutex.locked = locked;
138 struct timespec abstime;
140 int locked =
Mutex.locked;
143 if (pthread_cond_timedwait(&
cond, &
Mutex.mutex, &abstime) == ETIMEDOUT)
145 Mutex.locked = locked;
153 pthread_cond_broadcast(&
cond);
162 pthread_rwlockattr_t attr;
163 pthread_rwlockattr_init(&attr);
164 pthread_rwlockattr_setkind_np(&attr, PreferWriter ? PTHREAD_RWLOCK_PREFER_WRITER_NP : PTHREAD_RWLOCK_PREFER_READER_NP);
165 pthread_rwlock_init(&
rwlock, &attr);
170 pthread_rwlock_destroy(&
rwlock);
176 struct timespec abstime;
182 Result = TimeoutMs ? pthread_rwlock_timedwrlock(&
rwlock, &abstime) : pthread_rwlock_wrlock(&
rwlock);
191 Result = TimeoutMs ? pthread_rwlock_timedrdlock(&
rwlock, &abstime) : pthread_rwlock_rdlock(&
rwlock);
204 pthread_rwlock_unlock(&
rwlock);
212 pthread_mutexattr_t attr;
213 pthread_mutexattr_init(&attr);
214 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
215 pthread_mutex_init(&
mutex, &attr);
220 pthread_mutex_destroy(&
mutex);
225 pthread_mutex_lock(&
mutex);
232 pthread_mutex_unlock(&
mutex);
258 if (setpriority(PRIO_PROCESS, 0, Priority) < 0)
264 if (syscall(SYS_ioprio_set, 1, 0, (Priority & 0xff) | (3 << 13)) < 0)
274 va_start(ap, Description);
286 if (prctl(PR_SET_NAME, Thread->
description, 0, 0, 0) < 0)
302#define THREAD_STOP_TIMEOUT 3000
303#define THREAD_STOP_SLEEP 30
317 if (pthread_create(&
childTid, NULL, (
void *(*) (
void *))&
StartThread, (
void *)
this) == 0) {
343 if ((err = pthread_kill(
childTid, 0)) != 0) {
358 if (
active && WaitSeconds > -1) {
359 if (WaitSeconds > 0) {
376 return syscall(__NR_gettid);
441#define BT_BUF_SIZE 100
446 char *Function = NULL;
448 char *Address = NULL;
450 for (
char *q = Module; *q; q++) {
455 else if (*q ==
'+') {
463 else if (*q ==
']') {
469 char *DemangledFunction = NULL;
472 DemangledFunction = abi::__cxa_demangle(Function, NULL, 0, &status);
473 if (DemangledFunction)
474 Function = DemangledFunction;
480 unsigned long long addr = Address ? strtoull(Address, NULL, 0) : 0;
481 unsigned long long offs = Offset ? strtoull(Offset, NULL, 0) : 0;
487 while (e = strstr(e,
".so"))
489 if (p && !strchr(p,
'/')) {
491 if (dladdr(
reinterpret_cast<void*
>(addr), &dlinfo)) {
492 if ((strcmp(Module, dlinfo.dli_fname) == 0) && dlinfo.dli_fbase) {
493 unsigned long long base =
reinterpret_cast<unsigned long long>(dlinfo.dli_fbase);
501 cString cmd =
cString::sprintf(
"addr2line --functions --demangle --inlines --basename --exe=%s 0x%llx", Module, Function ? addr : offs);
503 if (p.
Open(cmd,
"r")) {
506 while (
char *l = rl.
Read(p)) {
508 if (Function && strcmp(l, Function))
517 free(DemangledFunction);
525 if (
char **s = backtrace_symbols(b, n)) {
526 for (
int i =
max(Level, 0) + 1; i < n; i++)
536 for (
int i = 0; i < sl.
Size(); i++) {
538 fprintf(f,
"%s\n", sl[i]);
547 Level =
max(Level, 0) + 1;
550 if (
char **s = backtrace_symbols(b, n)) {
552 Caller = Mangled ? s[Level] : *
Demangle(s[Level]);
562#define SLL_LENGTH 512
563#define SLL_THREADS 20
564#define SLL_MAX_LIST 9
565#define SLL_WRITE_FLAG 0x80000000
566#define SLL_LOCK_FLAG 0x40000000
584 void Check(
const char *Name,
bool Lock,
bool Write =
false);
593 memset(logCaller, 0,
sizeof(logCaller));
601 dsyslog(
"--- begin invalid lock sequence report");
604 for (
int i = 0; i <
SLL_SIZE; i++) {
608 q += sprintf(q,
"%5d", tid);
613 int Changed = LastFlags ^ Flags;
618 if ((Flags & b) != 0)
620 if ((Changed & b) != 0)
621 c = Lock ? Write ?
'W' :
'R' :
'U';
622 q += sprintf(q,
" %c", c);
624 q += sprintf(q,
" %c", Lock ?
'L' :
'U');
636 dsyslog(
"%5d invalid lock sequence: %s", ThreadId, Name);
639 dsyslog(
"--- end invalid lock sequence report");
640 dsyslog(
"--- THERE WILL BE NO FURTHER REPORTS UNTIL VDR IS RESTARTED!");
641 fprintf(stderr,
"invalid lock sequence at %s\n", *
DayDateTime(time(NULL)));
647 int n = *Name -
'0' - 1;
653 int AvailableIndex = -1;
654 for (
int i = 0; i <
threadIds.Size(); i++) {
663 if (AvailableIndex < 0) {
669 Index = AvailableIndex;
675 esyslog(
"ERROR: too many threads holding list locks at the same time - stopped logging locks!");
681 if ((
flags[Index] & ~b) < b)
683 else if ((
flags[Index] & b) == 0)
692 if (
flags[Index] == 0)
700 Dump(Name, ThreadId);
709#define dbglockseq(n, l, w) StateLockLog.Check(n, l, w)
711#define dbglockseq(n, l, w)
735 if (
rwLock.Lock(Write, TimeoutMs)) {
741 StateKey.
write =
true;
755 else if (TimeoutMs) {
760 static bool DoubleWriteLockReported =
false;
761 if (!DoubleWriteLockReported) {
762 dsyslog(
"WARNING: attempt to acquire write lock while already holding a write lock in the same thread - this may crash! (backtrace follows)");
764 DoubleWriteLockReported =
true;
774 esyslog(
"ERROR: cStateLock::Unlock() called with an unused key (tid=%d, lock=%s)",
threadId,
name);
779 esyslog(
"ERROR: cStateLock::Unlock() called without holding a write lock (tid=%d, lock=%s)",
threadId,
name);
790 if (StateKey.
write) {
791 StateKey.
write =
false;
804 esyslog(
"ERROR: cStateLock::SetSyncStateKey() called without holding a write lock (tid=%d, lock=%s)",
threadId,
name);
809 esyslog(
"ERROR: cStateLock::SetSyncStateKey() called with locked key (tid=%d, lock=%s)",
threadId,
name);
814 esyslog(
"ERROR: cStateLock::SetSyncStateKey() called twice (tid=%d, lock=%s)",
threadId,
name);
824 esyslog(
"ERROR: cStateLock::SetExplicitModify() called without holding a write lock (tid=%d, lock=%s)",
threadId,
name);
829 esyslog(
"ERROR: cStateLock::SetExplicitModify() called twice (tid=%d, lock=%s)",
threadId,
name);
839 esyslog(
"ERROR: cStateLock::SetModified() called without holding a write lock (tid=%d, lock=%s)",
threadId,
name);
860 esyslog(
"ERROR: cStateKey::~cStateKey() called without releasing the lock first (tid=%d, lock=%s, key=%p)",
stateLock->threadId,
stateLock->name,
this);
875 esyslog(
"ERROR: cStateKey::Remove() called without holding a lock (key=%p)",
this);
883 esyslog(
"ERROR: cStateKey::StateChanged() called without holding a lock (tid=%d, key=%p)",
cThread::ThreadId(),
this);
958 if ((
pid = fork()) < 0) {
965 const char *mode =
"w";
969 if (strcmp(Mode,
"r") == 0) {
974 if ((
f = fdopen(fd[1 - iopipe], mode)) == NULL) {
976 close(fd[1 - iopipe]);
981 int iofd = STDOUT_FILENO;
982 if (strcmp(Mode,
"w") == 0) {
987 if (dup2(fd[1 - iopipe], iofd) == -1) {
988 close(fd[1 - iopipe]);
992 int MaxPossibleFileDescriptors = getdtablesize();
993 for (
int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++)
995 if (execl(
"/bin/sh",
"sh",
"-c", Command, NULL) == -1) {
996 close(fd[1 - iopipe]);
1017 ret = waitpid(
pid, &status, WNOHANG);
1019 if (errno != EINTR && errno != ECHILD) {
1024 else if (ret ==
pid)
1033 else if (ret == -1 || !WIFEXITED(status))
1047 if ((pid = fork()) < 0) {
1054 if (waitpid(pid, &status, 0) < 0) {
1066 pid_t sid = setsid();
1070 int devnull = open(
"/dev/null", O_RDONLY);
1071 if (devnull < 0 || dup2(devnull, 0) < 0)
1074 int MaxPossibleFileDescriptors = getdtablesize();
1075 for (
int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++)
1077 if (execl(
"/bin/sh",
"sh",
"-c", Command, NULL) == -1)
static void BackTrace(cStringList &StringList, int Level=0, bool Mangled=false)
Produces a backtrace and stores it in the given StringList.
static cString GetCaller(int Level=0, bool Mangled=false)
Returns the caller at the given Level (or the immediate caller, if Level is 0).
static cString Demangle(char *s)
Demangles the function name in the given string and returns the converted version of s.
bool TimedWait(cMutex &Mutex, int TimeoutMs)
bool Wait(int TimeoutMs=0)
Waits at most TimeoutMs milliseconds for a call to Signal(), or forever if TimeoutMs is 0.
void Signal(void)
Signals a caller of Wait() that the condition it is waiting for is met.
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
void Activate(void)
Activates the global I/O throttling mechanism.
void Release(void)
Releases the global I/O throttling mechanism.
static bool Engaged(void)
Returns true if any I/O throttling object is currently active.
cMutexLock(cMutex *Mutex=NULL)
bool Open(const char *Command, const char *Mode)
tThreadId writeLockThreadId
cRwLock(bool PreferWriter=false)
bool Lock(bool Write, int TimeoutMs=0)
cStateKey(bool IgnoreFirst=false)
Sets up a new state key.
void Remove(bool IncState=true)
Removes this key from the lock it was previously used with.
void Reset(void)
Resets the state of this key, so that the next call to a lock's Lock() function with this key will re...
bool StateChanged(void)
Returns true if this key is used for obtaining a write lock, and the lock's state differs from that o...
cVector< tThreadId > threadIds
uint8_t logCounter[SLL_THREADS][SLL_MAX_LIST]
void Check(const char *Name, bool Lock, bool Write=false)
tThreadId logThreadIds[SLL_SIZE]
void Dump(const char *Name, tThreadId ThreadId)
void SetExplicitModify(void)
If you have obtained a write lock on this lock, and you don't want its state to be automatically incr...
cStateLock(const char *Name=NULL)
void Unlock(cStateKey &StateKey, bool IncState=true)
Releases a lock that has been obtained by a previous call to Lock() with the given StateKey.
void SetSyncStateKey(cStateKey &StateKey)
Sets the given StateKey to be synchronized to the state of this lock.
void SetModified(void)
Sets this lock to have its state incremented when the current write lock state key is removed.
bool Lock(cStateKey &StateKey, bool Write=false, int TimeoutMs=0)
Tries to get a lock and returns true if successful.
static cString static cString vsprintf(const char *fmt, va_list &ap)
static cString sprintf(const char *fmt,...) __attribute__((format(printf
cThreadLock(cThread *Thread=NULL)
bool Lock(cThread *Thread)
void SetIOPriority(int Priority)
static void SetMainThreadId(void)
virtual void Action(void)=0
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
void bool Start(void)
Sets the description of this thread, which will be used when logging starting or stopping of the thre...
void SetDescription(const char *Description,...) __attribute__((format(printf
void SetPriority(int Priority)
cThread(const char *Description=NULL, bool LowPriority=false)
Creates a new thread.
static void * StartThread(cThread *Thread)
void Cancel(int WaitSeconds=0)
Cancels the thread by first setting 'running' to false, so that the Action() loop can finish in an or...
static tThreadId mainThreadId
bool Active(void)
Checks whether the thread is still alive.
static tThreadId ThreadId(void)
uint64_t Elapsed(void) const
Returns the number of milliseconds that have elapsed since the last call to Set().
bool TimedOut(void) const
Returns true if the number of milliseconds given in the last call to Set() have passed.
virtual void Append(T Data)
static bool GetAbsTime(struct timespec *Abstime, int MillisecondsFromNow)
#define dbglockseq(n, l, w)
#define THREAD_STOP_SLEEP
int SystemExec(const char *Command, bool Detached)
#define THREAD_STOP_TIMEOUT
static cStateLockLog StateLockLog