Logger: global Log mutex is now available from C code

This way the C++ logging API can still be used while allowing for C
files to use the same mutex.

Change-Id: I473e57479f8ae98a84ad00b76ff338f79f732236
diff --git a/CommonLibs/Logger.cpp b/CommonLibs/Logger.cpp
index 171c635..f68fab5 100644
--- a/CommonLibs/Logger.cpp
+++ b/CommonLibs/Logger.cpp
@@ -35,8 +35,6 @@
 
 using namespace std;
 
-Mutex gLogToLock;
-
 std::ostream& operator<<(std::ostream& os, std::ostringstream& ss)
 {
 	return os << ss.str();
@@ -45,15 +43,13 @@
 Log::~Log()
 {
 	int old_state;
-	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
 	int mlen = mStream.str().size();
 	int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
 	const char *fmt = neednl ? "%s\n" : "%s";
-	ScopedLock lock(gLogToLock);
-	// The COUT() macro prevents messages from stomping each other but adds uninteresting thread numbers,
-	// so just use std::cout.
+
+	log_mutex_lock_canceldisable(&old_state);
 	LOGPSRC(mCategory, mPriority, filename, line, fmt, mStream.str().c_str());
-	pthread_setcancelstate(old_state, NULL);
+	log_mutex_unlock_canceldisable(old_state);
 }
 
 ostringstream& Log::get()
diff --git a/CommonLibs/debug.c b/CommonLibs/debug.c
index 294924d..17ef5bc 100644
--- a/CommonLibs/debug.c
+++ b/CommonLibs/debug.c
@@ -1,3 +1,5 @@
+#include <pthread.h>
+
 #include <osmocom/core/logging.h>
 #include <osmocom/core/utils.h>
 #include "debug.h"
@@ -34,3 +36,49 @@
 	.cat = default_categories,
 	.num_cat = ARRAY_SIZE(default_categories),
 };
+
+pthread_mutex_t log_mutex;
+
+bool log_mutex_init() {
+	int rc;
+	pthread_mutexattr_t attr;
+
+	if ((rc = pthread_mutexattr_init(&attr))) {
+		fprintf(stderr, "pthread_mutexattr_init() failed: %d\n", rc);
+		return false;
+	}
+	if ((rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))) {
+		fprintf(stderr, "pthread_mutexattr_settype() failed: %d\n", rc);
+		return false;
+	}
+	if ((rc = pthread_mutex_init(&log_mutex, &attr))) {
+		fprintf(stderr, "pthread_mutex_init() failed: %d\n", rc);
+		return false;
+	}
+	if ((rc = pthread_mutexattr_destroy(&attr))) {
+		fprintf(stderr, "pthread_mutexattr_destroy() failed: %d\n", rc);
+		return false;
+	}
+	return true;
+	/* FIXME: do we need to call pthread_mutex_destroy() during process exit? */
+}
+
+/* If called inside a C++ destructor, use log_mutex_(un)lock_canceldisable() APIs instead.
+   See osmo-trx commit 86be40b4eb762d5c12e8e3f7388ca9f254e77b36 for more information */
+void log_mutex_lock() {
+	OSMO_ASSERT(!pthread_mutex_lock(&log_mutex));
+}
+
+void log_mutex_unlock() {
+	OSMO_ASSERT(!pthread_mutex_unlock(&log_mutex));
+}
+
+void log_mutex_lock_canceldisable(int *st) {
+	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, st);
+	log_mutex_lock();
+}
+
+void log_mutex_unlock_canceldisable(int st) {
+	log_mutex_unlock();
+	pthread_setcancelstate(st, NULL);
+}
diff --git a/CommonLibs/debug.h b/CommonLibs/debug.h
index a5b9271..760ab32 100644
--- a/CommonLibs/debug.h
+++ b/CommonLibs/debug.h
@@ -1,5 +1,10 @@
 #pragma once
 
+#include <stdbool.h>
+#include <pthread.h>
+
+#include <osmocom/core/logging.h>
+
 extern const struct log_info log_info;
 
 /* Debug Areas of the code */
@@ -9,3 +14,22 @@
 	DDEV,
 	DLMS,
 };
+
+
+bool log_mutex_init();
+void log_mutex_lock();
+void log_mutex_unlock();
+void log_mutex_lock_canceldisable(int *st);
+void log_mutex_unlock_canceldisable(int st);
+
+#define CLOGC(category, level, fmt, args...) do { \
+	log_mutex_lock(); \
+	LOGP(category, level, "[tid=%lu] " fmt, pthread_self(), ##args);  \
+	log_mutex_unlock(); \
+} while(0)
+
+#define CLOGCHAN(chan, category, level, fmt, args...) do { \
+	log_mutex_lock(); \
+	LOGP(category, level, "[tid=%lu][chan=%lu] " fmt, pthread_self(), chan, ##args);  \
+	log_mutex_unlock(); \
+} while(0)