context: Add support for [per-thread] global talloc contexts

Rather than having applications maintain their own talloc cotexts,
let's offer some root talloc contexts in libosmocore.  Let's also
make them per thread right from the beginning.  This will help
some multi-threaded applications to use talloc in a thread-safe
way.

Change-Id: Iae39cd57274bf6753ecaf186f229e582b42662e3
diff --git a/src/Makefile.am b/src/Makefile.am
index f937810..245eb6d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,7 +13,7 @@
 lib_LTLIBRARIES = libosmocore.la
 
 libosmocore_la_LIBADD = $(BACKTRACE_LIB) $(TALLOC_LIBS) $(LIBRARY_RT)
-libosmocore_la_SOURCES = timer.c timer_gettimeofday.c timer_clockgettime.c \
+libosmocore_la_SOURCES = context.c timer.c timer_gettimeofday.c timer_clockgettime.c \
 			 select.c signal.c msgb.c bits.c \
 			 bitvec.c bitcomp.c counter.c fsm.c \
 			 write_queue.c utils.c socket.c \
diff --git a/src/context.c b/src/context.c
new file mode 100644
index 0000000..bad012b
--- /dev/null
+++ b/src/context.c
@@ -0,0 +1,52 @@
+/*! \file context.c
+ * talloc context handling.
+ *
+ * (C) 2019 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserverd.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301, USA.
+ */
+#include <string.h>
+#include <errno.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/utils.h>
+
+__thread struct osmo_talloc_contexts *osmo_ctx;
+
+int osmo_ctx_init(const char *id)
+{
+	osmo_ctx = talloc_named(NULL, sizeof(*osmo_ctx), "global-%s", id);
+	if (!osmo_ctx)
+		return -ENOMEM;
+	memset(osmo_ctx, 0, sizeof(*osmo_ctx));
+	osmo_ctx->global = osmo_ctx;
+	osmo_ctx->select = talloc_named_const(osmo_ctx->global, 0, "select");
+	if (!osmo_ctx->select) {
+		talloc_free(osmo_ctx);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+/* initialize osmo_ctx on main tread */
+static __attribute__((constructor)) void on_dso_load_ctx(void)
+{
+	OSMO_ASSERT(osmo_ctx_init("main") == 0);
+}
+
+/*! @} */
diff --git a/src/select.c b/src/select.c
index 7ce135f..394a59d 100644
--- a/src/select.c
+++ b/src/select.c
@@ -36,6 +36,8 @@
 #include <osmocom/core/linuxlist.h>
 #include <osmocom/core/timer.h>
 #include <osmocom/core/logging.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/utils.h>
 
 #include "../config.h"
 
@@ -233,11 +235,7 @@
 	return work;
 }
 
-/*! select main loop integration
- *  \param[in] polling should we pollonly (1) or block on select (0)
- *  \returns 0 if no fd handled; 1 if fd handled; negative in case of error
- */
-int osmo_select_main(int polling)
+static int _osmo_select_main(int polling)
 {
 	fd_set readset, writeset, exceptset;
 	int rc;
@@ -259,10 +257,42 @@
 	/* fire timers */
 	osmo_timers_update();
 
+	OSMO_ASSERT(osmo_ctx->select);
+
 	/* call registered callback functions */
 	return osmo_fd_disp_fds(&readset, &writeset, &exceptset);
 }
 
+/*! select main loop integration
+ *  \param[in] polling should we pollonly (1) or block on select (0)
+ *  \returns 0 if no fd handled; 1 if fd handled; negative in case of error
+ */
+int osmo_select_main(int polling)
+{
+	int rc = _osmo_select_main(polling);
+#ifndef EMBEDDED
+	if (talloc_total_size(osmo_ctx->select) != 0) {
+		osmo_panic("You cannot use the 'select' volatile "
+			   "context if you don't use osmo_select_main_ctx()!\n");
+	}
+#endif
+	return rc;
+}
+
+#ifndef EMBEDDED
+/*! select main loop integration with temporary select-dispatch talloc context
+ *  \param[in] polling should we pollonly (1) or block on select (0)
+ *  \returns 0 if no fd handled; 1 if fd handled; negative in case of error
+ */
+int osmo_select_main_ctx(int polling)
+{
+	int rc = _osmo_select_main(polling);
+	/* free all the children of the volatile 'select' scope context */
+	talloc_free_children(osmo_ctx->select);
+	return rc;
+}
+#endif
+
 /*! find an osmo_fd based on the integer fd
  *  \param[in] fd file descriptor to use as search key
  *  \returns \ref osmo_fd for \ref fd; NULL in case it doesn't exist */