summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am52
-rw-r--r--src/dbg_malloc.cpp629
-rw-r--r--src/export.map18
-rw-r--r--src/export_dbg.map29
-rw-r--r--src/span.cpp547
-rw-r--r--src/tracer.cpp874
-rw-r--r--src/util.cpp451
7 files changed, 2600 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..bd72329
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,52 @@
+## Process this file with automake to produce Makefile.in
+##
+##
+AM_CPPFLAGS = @OPENTRACING_C_WRAPPER_CPPFLAGS@
+ AM_CFLAGS = @OPENTRACING_C_WRAPPER_CFLAGS@
+AM_CXXFLAGS = @OPENTRACING_C_WRAPPER_CXXFLAGS@
+ AM_LDFLAGS = @OPENTRACING_C_WRAPPER_LDFLAGS@
+ LIBS = @LIBS@ @OPENTRACING_C_WRAPPER_LIBS@
+
+if WANT_DEBUG
+lib_LTLIBRARIES = libopentracing-c-wrapper_dbg.la
+pkgconfig_DATA = ../opentracing-c-wrapper_dbg.pc
+
+libopentracing_c_wrapper_dbg_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/../include
+libopentracing_c_wrapper_dbg_la_CFLAGS = $(AM_CFLAGS)
+libopentracing_c_wrapper_dbg_la_CXXFLAGS = $(AM_CXXFLAGS)
+libopentracing_c_wrapper_dbg_la_LDFLAGS = $(AM_LDFLAGS) -version-info @LIB_VERSION@ -Wl,--version-script=$(srcdir)/export_dbg.map
+libopentracing_c_wrapper_dbg_la_SOURCES = \
+ dbg_malloc.cpp \
+ span.cpp \
+ tracer.cpp \
+ util.cpp
+
+else
+
+lib_LTLIBRARIES = libopentracing-c-wrapper.la
+pkgconfig_DATA = ../opentracing-c-wrapper.pc
+
+libopentracing_c_wrapper_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/../include
+libopentracing_c_wrapper_la_CFLAGS = $(AM_CFLAGS)
+libopentracing_c_wrapper_la_CXXFLAGS = $(AM_CXXFLAGS)
+libopentracing_c_wrapper_la_LDFLAGS = $(AM_LDFLAGS) -version-info @LIB_VERSION@ -Wl,--version-script=$(srcdir)/export.map
+libopentracing_c_wrapper_la_SOURCES = \
+ span.cpp \
+ tracer.cpp \
+ util.cpp
+endif
+
+pkginclude_HEADERS = \
+ ../include/opentracing-c-wrapper/common.h \
+ ../include/opentracing-c-wrapper/dbg_malloc.h \
+ ../include/opentracing-c-wrapper/define.h \
+ ../include/opentracing-c-wrapper/include.h \
+ ../include/opentracing-c-wrapper/propagation.h \
+ ../include/opentracing-c-wrapper/span.h \
+ ../include/opentracing-c-wrapper/tracer.h \
+ ../include/opentracing-c-wrapper/util.h \
+ ../include/opentracing-c-wrapper/value.h
+
+CLEANFILES = a.out
+##
+## Makefile.am ends here
diff --git a/src/dbg_malloc.cpp b/src/dbg_malloc.cpp
new file mode 100644
index 0000000..18214b1
--- /dev/null
+++ b/src/dbg_malloc.cpp
@@ -0,0 +1,629 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "include.h"
+
+
+static struct otc_dbg_mem *dbg_mem = nullptr;
+
+
+/***
+ * NAME
+ * otc_dbg_set_metadata -
+ *
+ * ARGUMENTS
+ * ptr - the real address of the allocated data
+ * data -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void otc_dbg_set_metadata(void *ptr, struct otc_dbg_mem_data *data)
+{
+ struct otc_dbg_mem_metadata *metadata;
+
+ if (ptr == nullptr)
+ return;
+
+ metadata = OT_CAST_TYPEOF(metadata, ptr);
+ metadata->data = (data == nullptr) ? OT_CAST_TYPEOF(data, metadata) : data;
+ metadata->magic = DBG_MEM_MAGIC;
+}
+
+
+/***
+ * NAME
+ * otc_dbg_mem_add -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * ptr - the real address of the allocated data
+ * size -
+ * data -
+ * op_idx -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void otc_dbg_mem_add(const char *func, int line, void *ptr, size_t size, struct otc_dbg_mem_data *data, int op_idx)
+{
+ (void)snprintf(data->func, sizeof(data->func), "%s:%d", func, line);
+
+ data->ptr = ptr;
+ data->size = size;
+ data->used = 1;
+
+ dbg_mem->size += size;
+ dbg_mem->op_cnt[op_idx]++;
+
+ otc_dbg_set_metadata(ptr, data);
+}
+
+
+/***
+ * NAME
+ * otc_dbg_mem_alloc -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * old_ptr - the address of the data returned to the program
+ * ptr - the real address of the allocated data
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void otc_dbg_mem_alloc(const char *func, int line, void *old_ptr, void *ptr, size_t size)
+{
+ size_t i = 0;
+ int rc;
+
+ if (dbg_mem == nullptr) {
+ return;
+ }
+ else if (ptr == nullptr) {
+ DBG_MEM_ERR("invalid memory address: %p", ptr);
+
+ return;
+ }
+
+ if ((rc = pthread_mutex_lock(&(dbg_mem->mutex))) != 0) {
+ DBG_MEM_ERR("cannot lock mutex: %s", otc_strerror(rc));
+
+ return;
+ }
+
+ if (old_ptr != nullptr) {
+ /* Reallocating memory. */
+ struct otc_dbg_mem_metadata *metadata = OT_CAST_TYPEOF(metadata, ptr);
+
+ if (metadata == nullptr) {
+ DBG_MEM_ERR("no metadata: MEM_REALLOC %s:%d(%p -> %p %zu)", func, line, old_ptr, DBG_MEM_PTR(ptr), size);
+ }
+ else if (metadata->data == nullptr) {
+ DBG_MEM_ERR("invalid metadata: MEM_REALLOC %s:%d(%p -> %p %zu)", func, line, old_ptr, DBG_MEM_PTR(ptr), size);
+ }
+ else if (metadata->data == OT_CAST_TYPEOF(metadata->data, metadata)) {
+ DBG_MEM_ERR("unset metadata: MEM_REALLOC %s:%d(%p -> %p %zu)", func, line, old_ptr, DBG_MEM_PTR(ptr), size);
+ }
+ else if (metadata->magic != DBG_MEM_MAGIC) {
+ DBG_MEM_ERR("invalid magic: MEM_REALLOC %s:%d(%p -> %p %zu) 0x%016" PRIu64, func, line, old_ptr, DBG_MEM_PTR(ptr), size, metadata->magic);
+ }
+ else if (metadata->data->used && (metadata->data->ptr == DBG_MEM_DATA(old_ptr))) {
+ DBG_MEM_INFO(1, "MEM_REALLOC: %s:%d(%p %zu -> %p %zu)", func, line, old_ptr, metadata->data->size, DBG_MEM_PTR(ptr), size);
+
+ dbg_mem->size -= metadata->data->size;
+ otc_dbg_mem_add(func, line, ptr, size, metadata->data, 1);
+ }
+ } else {
+ otc_dbg_set_metadata(ptr, nullptr);
+
+ /*
+ * The first attempt is to find a location that has not been
+ * used at all so far. If such is not found, an attempt is
+ * made to find the first available location.
+ */
+ if (dbg_mem->unused < dbg_mem->count) {
+ i = dbg_mem->unused++;
+ } else {
+ do {
+ if (dbg_mem->reused >= dbg_mem->count)
+ dbg_mem->reused = 0;
+
+ if (!dbg_mem->data[dbg_mem->reused].used) {
+ i = dbg_mem->reused++;
+
+ break;
+ }
+
+ dbg_mem->reused++;
+ } while (++i <= dbg_mem->count);
+ }
+
+ if (i < dbg_mem->count) {
+ DBG_MEM_INFO(1, "MEM_ALLOC: %s:%d(%p %zu %zu)", func, line, DBG_MEM_PTR(ptr), size, i);
+
+ otc_dbg_mem_add(func, line, ptr, size, dbg_mem->data + i, 0);
+ }
+ }
+
+ if ((rc = pthread_mutex_unlock(&(dbg_mem->mutex))) != 0) {
+ DBG_MEM_ERR("cannot unlock mutex: %s", otc_strerror(rc));
+
+ return;
+ }
+
+ if (i >= dbg_mem->count)
+ DBG_MEM_ERR("alloc overflow: %s:%d(%p -> %p %zu)", func, line, old_ptr, DBG_MEM_PTR(ptr), size);
+}
+
+
+/***
+ * NAME
+ * otc_dbg_mem_release -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * ptr - the address of the data returned to the program
+ * op_idx -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void otc_dbg_mem_release(const char *func, int line, void *ptr, int op_idx)
+{
+ struct otc_dbg_mem_metadata *metadata;
+ bool flag_invalid = 0;
+ size_t i;
+ int rc;
+
+ if (dbg_mem == nullptr) {
+ return;
+ }
+ else if (ptr == nullptr) {
+ DBG_MEM_ERR("invalid memory address: %p", ptr);
+
+ return;
+ }
+
+ if ((rc = pthread_mutex_lock(&(dbg_mem->mutex))) != 0) {
+ DBG_MEM_ERR("cannot lock mutex: %s", otc_strerror(rc));
+
+ return;
+ }
+
+ metadata = DBG_MEM_DATA(ptr);
+ if (metadata == nullptr) {
+ DBG_MEM_ERR("no metadata: MEM_%s %s:%d(%p)", (op_idx == 2) ? "FREE" : "RELEASE", func, line, ptr);
+ }
+ else if (metadata->data == nullptr) {
+ DBG_MEM_ERR("invalid metadata: MEM_%s %s:%d(%p)", (op_idx == 2) ? "FREE" : "RELEASE", func, line, ptr);
+ }
+ else if (metadata->data == OT_CAST_TYPEOF(metadata->data, metadata)) {
+ DBG_MEM_ERR("unset metadata: MEM_%s %s:%d(%p)", (op_idx == 2) ? "FREE" : "RELEASE", func, line, ptr);
+ }
+ else if (metadata->magic != DBG_MEM_MAGIC) {
+ DBG_MEM_ERR("invalid magic: MEM_%s %s:%d(%p) 0x%016" PRIu64, (op_idx == 2) ? "FREE" : "RELEASE", func, line, ptr, metadata->magic);
+ }
+ else if (metadata->data->used && (metadata->data->ptr == metadata)) {
+ DBG_MEM_INFO(1, "MEM_%s: %s:%d(%p %zu)", (op_idx == 2) ? "FREE" : "RELEASE", func, line, ptr, metadata->data->size);
+
+ metadata->data->used = 0;
+
+ dbg_mem->size -= metadata->data->size;
+ dbg_mem->op_cnt[op_idx]++;
+ }
+ else {
+ flag_invalid = 1;
+ }
+
+ if ((rc = pthread_mutex_unlock(&(dbg_mem->mutex))) != 0) {
+ DBG_MEM_ERR("cannot unlock mutex: %s", otc_strerror(rc));
+
+ return;
+ }
+
+ if (flag_invalid) {
+ DBG_MEM_ERR("invalid ptr: %s:%d(%p)", func, line, ptr);
+
+ if (metadata != nullptr)
+ for (i = 0; i < dbg_mem->count; i++)
+ if (dbg_mem->data[i].ptr == metadata)
+ DBG_MEM_ERR("possible previous use: %s %hhu", dbg_mem->data[i].func, dbg_mem->data[i].used);
+ }
+}
+
+
+/***
+ * NAME
+ * otc_dbg_malloc -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+void *otc_dbg_malloc(const char *func, int line, size_t size)
+{
+ void *retptr;
+
+ retptr = malloc(DBG_MEM_SIZE(size));
+
+ otc_dbg_mem_alloc(func, line, nullptr, retptr, size);
+
+ return DBG_MEM_RETURN(retptr);
+}
+
+
+/***
+ * NAME
+ * otc_dbg_calloc -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * nelem -
+ * elsize -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+void *otc_dbg_calloc(const char *func, int line, size_t nelem, size_t elsize)
+{
+ void *retptr;
+
+ retptr = malloc(DBG_MEM_SIZE(nelem * elsize));
+ if (retptr != nullptr)
+ (void)memset(retptr, 0, DBG_MEM_SIZE(nelem * elsize));
+
+ otc_dbg_mem_alloc(func, line, nullptr, retptr, nelem * elsize);
+
+ return DBG_MEM_RETURN(retptr);
+}
+
+
+/***
+ * NAME
+ * otc_dbg_realloc -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * ptr -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+void *otc_dbg_realloc(const char *func, int line, void *ptr, size_t size)
+{
+ void *retptr;
+
+ if (ptr == nullptr) {
+ retptr = malloc(DBG_MEM_SIZE(size));
+
+ otc_dbg_mem_alloc(func, line, nullptr, retptr, size);
+ } else {
+ struct otc_dbg_mem_metadata *metadata = DBG_MEM_DATA(ptr);
+
+ /*
+ * If memory is not allocated via these debug functions, it
+ * must not be reallocated via them either.
+ */
+ if ((metadata == nullptr) || (metadata->data == nullptr) || (metadata->magic != DBG_MEM_MAGIC)) {
+ retptr = realloc(ptr, size);
+
+ return retptr;
+ } else {
+ retptr = realloc(DBG_MEM_DATA(ptr), DBG_MEM_SIZE(size));
+
+ otc_dbg_mem_alloc(func, line, ptr, retptr, size);
+ }
+ }
+
+ return DBG_MEM_RETURN(retptr);
+}
+
+
+/***
+ * NAME
+ * otc_dbg_free -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_dbg_free(const char *func, int line, void *ptr)
+{
+ struct otc_dbg_mem_metadata *metadata;
+
+ otc_dbg_mem_release(func, line, ptr, 2);
+
+ metadata = DBG_MEM_DATA(ptr);
+ if ((metadata == nullptr) || (metadata->data == nullptr) || (metadata->magic != DBG_MEM_MAGIC))
+ free(ptr);
+ else
+ free(DBG_MEM_DATA(ptr));
+}
+
+
+/***
+ * NAME
+ * otc_dbg_strdup -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * s -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+char *otc_dbg_strdup(const char *func, int line, const char *s)
+{
+ size_t len = 0;
+ char *retptr = nullptr;
+
+ if (s != nullptr) {
+ len = strlen(s) + 1;
+ retptr = OT_CAST_TYPEOF(retptr, malloc(DBG_MEM_SIZE(len)));
+ if (retptr != nullptr)
+ (void)memcpy(DBG_MEM_PTR(retptr), s, len);
+ }
+
+ otc_dbg_mem_alloc(func, line, nullptr, retptr, len);
+
+ return OT_CAST_TYPEOF(retptr, DBG_MEM_RETURN(retptr));
+}
+
+
+/***
+ * NAME
+ * otc_dbg_strndup -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * s -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+char *otc_dbg_strndup(const char *func, int line, const char *s, size_t size)
+{
+ size_t len = 0;
+ char *retptr = nullptr;
+
+ if (s != nullptr) {
+ len = strlen(s);
+ len = (len < size) ? len : size;
+ retptr = OT_CAST_TYPEOF(retptr, malloc(DBG_MEM_SIZE(len + 1)));
+ if (retptr != nullptr) {
+ (void)memcpy(DBG_MEM_PTR(retptr), s, len);
+ DBG_MEM_PTR(retptr)[len] = '\0';
+ }
+ }
+
+ otc_dbg_mem_alloc(func, line, nullptr, retptr, len + 1);
+
+ return OT_CAST_TYPEOF(retptr, DBG_MEM_RETURN(retptr));
+}
+
+
+/***
+ * NAME
+ * otc_dbg_mem_init -
+ *
+ * ARGUMENTS
+ * mem -
+ * data -
+ * count -
+ * level -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int otc_dbg_mem_init(struct otc_dbg_mem *mem, struct otc_dbg_mem_data *data, size_t count, uint8_t level)
+{
+ pthread_mutexattr_t attr;
+ int rc, retval = -1;
+
+ if ((mem == nullptr) || (data == nullptr) || (count == 0))
+ return retval;
+
+ (void)memset(mem, 0, sizeof(*mem));
+ (void)memset(data, 0, sizeof(*data) * count);
+
+ dbg_mem = mem;
+ dbg_mem->data = data;
+ dbg_mem->count = count;
+ dbg_mem->level = level;
+
+ if ((rc = pthread_mutexattr_init(&attr)) == 0)
+ if ((rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) == 0)
+ if ((rc = pthread_mutex_init(&(dbg_mem->mutex), &attr)) == 0)
+ retval = 0;
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * otc_dbg_mem_disable -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_dbg_mem_disable(void)
+{
+ if (dbg_mem == nullptr)
+ return;
+
+ (void)pthread_mutex_destroy(&(dbg_mem->mutex));
+
+ dbg_mem = nullptr;
+}
+
+
+/***
+ * NAME
+ * otc_dbg_mem_info -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_dbg_mem_info(void)
+{
+#ifdef HAVE_MALLINFO
+ struct mallinfo mi;
+#endif
+ size_t i, n = 0;
+ uint64_t size = 0;
+
+ if (dbg_mem == nullptr)
+ return;
+
+ DBG_MEM_INFO(0, "--- Memory info -------------------------------------");
+ DBG_MEM_INFO(0, " alloc/realloc: %" PRIu64 "/%" PRIu64 ", free/release: %" PRIu64 "/%" PRIu64, dbg_mem->op_cnt[0], dbg_mem->op_cnt[1], dbg_mem->op_cnt[2], dbg_mem->op_cnt[3]);
+ DBG_MEM_INFO(0, " unused: %zu, reused: %zu, count: %zu", dbg_mem->unused, dbg_mem->reused, dbg_mem->count);
+ for (i = 0; i < dbg_mem->count; i++)
+ if (dbg_mem->data[i].used) {
+ DBG_MEM_INFO(0, " %zu %s(%p %zu)", n, dbg_mem->data[i].func, dbg_mem->data[i].ptr, dbg_mem->data[i].size);
+
+ size += dbg_mem->data[i].size;
+ n++;
+ }
+
+ if (n > 0)
+ DBG_MEM_INFO(0, " allocated %zu byte(s) in %zu chunk(s)", size, n);
+
+ if (dbg_mem->size != size)
+ DBG_MEM_INFO(0, " size does not match: %zu != %zu", dbg_mem->size, size);
+
+#ifdef HAVE_MALLINFO
+ mi = mallinfo();
+ DBG_MEM_INFO(0, "--- Memory space usage ------------------------------");
+ DBG_MEM_INFO(0, " Total non-mmapped bytes: %" PRI_MI, mi.arena);
+ DBG_MEM_INFO(0, " # of free chunks: %" PRI_MI, mi.ordblks);
+ DBG_MEM_INFO(0, " # of free fastbin blocks: %" PRI_MI, mi.smblks);
+ DBG_MEM_INFO(0, " Bytes in mapped regions: %" PRI_MI, mi.hblkhd);
+ DBG_MEM_INFO(0, " # of mapped regions: %" PRI_MI, mi.hblks);
+ DBG_MEM_INFO(0, " Max. total allocated space: %" PRI_MI, mi.usmblks);
+ DBG_MEM_INFO(0, " Free bytes held in fastbins: %" PRI_MI, mi.fsmblks);
+ DBG_MEM_INFO(0, " Total allocated space: %" PRI_MI, mi.uordblks);
+ DBG_MEM_INFO(0, " Total free space: %" PRI_MI, mi.fordblks);
+ DBG_MEM_INFO(0, " Topmost releasable block: %" PRI_MI, mi.keepcost);
+#endif
+}
+
+
+/***
+ * NAME
+ * otc_dbg_memdup -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * s -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+void *otc_dbg_memdup(const char *func, int line, const void *s, size_t size)
+{
+ void *retptr = nullptr;
+
+ if (s != nullptr) {
+ retptr = malloc(DBG_MEM_SIZE(size + 1));
+ if (retptr != nullptr) {
+ (void)memcpy(DBG_MEM_PTR(retptr), s, size);
+ DBG_MEM_PTR(retptr)[size] = '\0';
+ }
+ }
+
+ otc_dbg_mem_alloc(func, line, nullptr, retptr, size);
+
+ return DBG_MEM_RETURN(retptr);
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/src/export.map b/src/export.map
new file mode 100644
index 0000000..ab7c3a4
--- /dev/null
+++ b/src/export.map
@@ -0,0 +1,18 @@
+{
+global:
+ otc_tracer_init;
+ otc_tracer_load;
+ otc_tracer_start;
+ otc_tracer_global;
+ otc_tracer_init_global;
+ otc_text_map_new;
+ otc_text_map_add;
+ otc_text_map_destroy;
+ otc_binary_data_new;
+ otc_binary_data_destroy;
+ otc_ext_init;
+ otc_file_read;
+ otc_statistics;
+
+local: *;
+};
diff --git a/src/export_dbg.map b/src/export_dbg.map
new file mode 100644
index 0000000..4a99a3f
--- /dev/null
+++ b/src/export_dbg.map
@@ -0,0 +1,29 @@
+{
+global:
+ otc_tracer_init;
+ otc_tracer_load;
+ otc_tracer_start;
+ otc_tracer_global;
+ otc_tracer_init_global;
+ otc_text_map_new;
+ otc_text_map_add;
+ otc_text_map_destroy;
+ otc_binary_data_new;
+ otc_binary_data_destroy;
+ otc_ext_init;
+ otc_file_read;
+ otc_statistics;
+
+ otc_dbg_calloc;
+ otc_dbg_free;
+ otc_dbg_malloc;
+ otc_dbg_mem_disable;
+ otc_dbg_mem_info;
+ otc_dbg_mem_init;
+ otc_dbg_memdup;
+ otc_dbg_realloc;
+ otc_dbg_strdup;
+ otc_dbg_strndup;
+
+local: *;
+};
diff --git a/src/span.cpp b/src/span.cpp
new file mode 100644
index 0000000..3e9323d
--- /dev/null
+++ b/src/span.cpp
@@ -0,0 +1,547 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "include.h"
+
+
+#ifdef OT_THREADS_NO_LOCKING
+thread_local Handle<opentracing::Span> ot_span_handle;
+thread_local Handle<opentracing::SpanContext> ot_span_context_handle;
+struct HandleData ot_span;
+struct HandleData ot_span_context;
+#else
+struct Handle<opentracing::Span> ot_span;
+struct Handle<opentracing::SpanContext> ot_span_context;
+#endif /* OT_THREADS_NO_LOCKING */
+
+
+/***
+ * NAME
+ * ot_span_finish_with_options -
+ *
+ * ARGUMENTS
+ * span -
+ * options -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_finish_with_options(struct otc_span *span, const struct otc_finish_span_options *options)
+{
+ OT_LOCK_GUARD(span);
+
+ if (!OT_SPAN_IS_VALID(span))
+ return;
+
+ if (options == nullptr) {
+ ot_span_handle.at(span->idx)->Finish();
+ } else {
+ struct opentracing::FinishSpanOptions span_options;
+
+ if (options->finish_time.value.tv_sec > 0) {
+ auto dt = timespec_to_duration(&(options->finish_time.value));
+
+ span_options.finish_steady_timestamp = std::chrono::time_point<std::chrono::steady_clock>(dt);
+ }
+
+ if (options->log_records != nullptr) {
+ for (int i = 0; i < options->num_log_records; i++) {
+ struct opentracing::LogRecord record;
+
+ if (options->log_records[i].timestamp.value.tv_sec > 0) {
+#ifdef __clang__
+ auto dt = timespec_to_duration_us(&(options->log_records[i].timestamp.value));
+#else
+ auto dt = timespec_to_duration(&(options->log_records[i].timestamp.value));
+#endif
+
+ record.timestamp = std::chrono::time_point<std::chrono::system_clock>(dt);
+ }
+
+ for (int j = 0; j < options->log_records[i].num_fields; j++)
+ if (options->log_records[i].fields[j].value.type == otc_value_bool) {
+ record.fields.push_back(std::make_pair(options->log_records[i].fields[j].key, options->log_records[i].fields[j].value.value.bool_value));
+ }
+ else if (options->log_records[i].fields[j].value.type == otc_value_double) {
+ record.fields.push_back(std::make_pair(options->log_records[i].fields[j].key, options->log_records[i].fields[j].value.value.double_value));
+ }
+ else if (options->log_records[i].fields[j].value.type == otc_value_int64) {
+ record.fields.push_back(std::make_pair(options->log_records[i].fields[j].key, options->log_records[i].fields[j].value.value.int64_value));
+ }
+ else if (options->log_records[i].fields[j].value.type == otc_value_uint64) {
+ record.fields.push_back(std::make_pair(options->log_records[i].fields[j].key, options->log_records[i].fields[j].value.value.uint64_value));
+ }
+ else if (options->log_records[i].fields[j].value.type == otc_value_string) {
+ std::string str_value = options->log_records[i].fields[j].value.value.string_value;
+
+ record.fields.push_back(std::make_pair(options->log_records[i].fields[j].key, str_value));
+ }
+ else if (options->log_records[i].fields[j].value.type == otc_value_null) {
+ record.fields.push_back(std::make_pair(options->log_records[i].fields[j].key, nullptr));
+ }
+
+ span_options.log_records.push_back(record);
+ }
+ }
+
+ ot_span_handle.at(span->idx)->FinishWithOptions(span_options);
+ }
+
+ ot_nolock_span_destroy(&span);
+}
+
+
+/***
+ * NAME
+ * ot_span_finish -
+ *
+ * ARGUMENTS
+ * span -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_finish(struct otc_span *span)
+{
+ ot_span_finish_with_options(span, nullptr);
+}
+
+
+/***
+ * NAME
+ * ot_span_get_context -
+ *
+ * ARGUMENTS
+ * span -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static struct otc_span_context *ot_span_get_context(struct otc_span *span)
+{
+ OT_LOCK(span, span_context);
+
+ if (!OT_SPAN_IS_VALID(span))
+ return nullptr;
+
+ return ot_span_context_new(span);
+}
+
+
+/***
+ * NAME
+ * ot_span_set_operation_name -
+ *
+ * ARGUMENTS
+ * span -
+ * operation_name -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_set_operation_name(struct otc_span *span, const char *operation_name)
+{
+ OT_LOCK_GUARD(span);
+
+ if (!OT_SPAN_IS_VALID(span) || (operation_name == nullptr))
+ return;
+
+ ot_span_handle.at(span->idx)->SetOperationName(operation_name);
+}
+
+
+/***
+ * NAME
+ * ot_span_set_tag -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_set_tag(struct otc_span *span, const char *key, const struct otc_value *value)
+{
+ OT_LOCK_GUARD(span);
+
+ if (!OT_SPAN_IS_VALID(span) || (key == nullptr) || (value == nullptr))
+ return;
+
+ if (value->type == otc_value_bool) {
+ ot_span_handle.at(span->idx)->SetTag(key, value->value.bool_value);
+ }
+ else if (value->type == otc_value_double) {
+ ot_span_handle.at(span->idx)->SetTag(key, value->value.double_value);
+ }
+ else if (value->type == otc_value_int64) {
+ ot_span_handle.at(span->idx)->SetTag(key, value->value.int64_value);
+ }
+ else if (value->type == otc_value_uint64) {
+ ot_span_handle.at(span->idx)->SetTag(key, value->value.uint64_value);
+ }
+ else if (value->type == otc_value_string) {
+ std::string str_value = value->value.string_value;
+
+ ot_span_handle.at(span->idx)->SetTag(key, str_value);
+ }
+ else if (value->type == otc_value_null) {
+ ot_span_handle.at(span->idx)->SetTag(key, nullptr);
+ }
+ else {
+ /* Do nothing. */
+ }
+}
+
+
+/***
+ * NAME
+ * ot_span_log_fields -
+ *
+ * ARGUMENTS
+ * span -
+ * fields -
+ * num_fields -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_log_fields(struct otc_span *span, const struct otc_log_field *fields, int num_fields)
+{
+ OT_LOCK_GUARD(span);
+ std::string str_value[OTC_MAXLOGFIELDS];
+
+ if (!OT_SPAN_IS_VALID(span) || (fields == nullptr) || !OT_IN_RANGE(num_fields, 1, OTC_MAXLOGFIELDS))
+ return;
+
+ /* XXX The only data type supported in this function is string. */
+ for (int i = 0; (i < num_fields) && (i < OTC_MAXLOGFIELDS); i++) {
+ if (fields[i].value.type != otc_value_string)
+ str_value[i] = "invalid data type";
+ else if (fields[i].value.value.string_value != nullptr)
+ str_value[i] = fields[i].value.value.string_value;
+ else
+ str_value[i] = "";
+ }
+
+ if (num_fields == 1)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0) });
+ else if (num_fields == 2)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1) });
+ else if (num_fields == 3)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1), OT_LF(2) });
+ else if (num_fields == 4)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1), OT_LF(2), OT_LF(3) });
+ else if (num_fields == 5)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1), OT_LF(2), OT_LF(3), OT_LF(4) });
+ else if (num_fields == 6)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1), OT_LF(2), OT_LF(3), OT_LF(4), OT_LF(5) });
+ else if (num_fields == 7)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1), OT_LF(2), OT_LF(3), OT_LF(4), OT_LF(5), OT_LF(6) });
+ else
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1), OT_LF(2), OT_LF(3), OT_LF(4), OT_LF(5), OT_LF(6), OT_LF(7) });
+}
+
+
+/***
+ * NAME
+ * ot_span_set_baggage_item -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_set_baggage_item(struct otc_span *span, const char *key, const char *value)
+{
+ OT_LOCK_GUARD(span);
+
+ if (!OT_SPAN_IS_VALID(span) || (key == nullptr) || (value == nullptr))
+ return;
+
+ ot_span_handle.at(span->idx)->SetBaggageItem(key, value);
+}
+
+
+/***
+ * NAME
+ * ot_span_baggage_item -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static const char *ot_span_baggage_item(const struct otc_span *span, const char *key)
+{
+ OT_LOCK_GUARD(span);
+ const char *retptr = "";
+
+ if (!OT_SPAN_IS_VALID(span) || (key == nullptr))
+ return retptr;
+
+ auto baggage = ot_span_handle.at(span->idx)->BaggageItem(key);
+ if (!baggage.empty())
+ retptr = OTC_DBG_STRDUP(baggage.c_str());
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_span_tracer -
+ *
+ * ARGUMENTS
+ * span - NOT USED
+ *
+ * DESCRIPTION
+ * - NOT IMPLEMENTED
+ *
+ * RETURN VALUE
+ * -
+ */
+static struct otc_tracer *ot_span_tracer(const struct otc_span *span)
+{
+ struct otc_tracer *retptr = nullptr;
+
+ if (!OT_SPAN_IS_VALID(span))
+ return retptr;
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_nolock_span_destroy -
+ *
+ * ARGUMENTS
+ * span -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void ot_nolock_span_destroy(struct otc_span **span)
+{
+ if ((span == nullptr) || ((*span) == nullptr))
+ return;
+
+ if (OT_SPAN_KEY_IS_VALID(*span)) {
+ ot_span_handle.erase((*span)->idx);
+ ot_span.erase_cnt++;
+ }
+
+ ot_span.destroy_cnt++;
+
+ OT_EXT_FREE_CLEAR(*span);
+}
+
+
+/***
+ * NAME
+ * ot_span_destroy -
+ *
+ * ARGUMENTS
+ * span -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_destroy(struct otc_span **span)
+{
+ OT_LOCK_GUARD(span);
+
+ ot_nolock_span_destroy(span);
+}
+
+
+/***
+ * NAME
+ * ot_span_new -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span *ot_span_new(void)
+{
+ const static struct otc_span span_init = {
+ .idx = 0,
+ .finish = ot_span_finish, /* lock span */
+ .finish_with_options = ot_span_finish_with_options, /* lock span */
+ .span_context = ot_span_get_context, /* lock span and span_context */
+ .set_operation_name = ot_span_set_operation_name, /* lock span */
+ .set_tag = ot_span_set_tag, /* lock span */
+ .log_fields = ot_span_log_fields, /* lock span */
+ .set_baggage_item = ot_span_set_baggage_item, /* lock span */
+ .baggage_item = ot_span_baggage_item, /* lock span */
+ .tracer = ot_span_tracer, /* NOT IMPLEMENTED */
+ .destroy = ot_span_destroy /* lock span */
+ };
+ int64_t idx = ot_span.key++;
+ struct otc_span *retptr;
+
+ if (idx == 0) {
+ ot_span_handle.clear();
+ ot_span_handle.reserve(8192);
+ }
+
+ if ((retptr = OT_CAST_TYPEOF(retptr, OT_EXT_MALLOC(sizeof(*retptr)))) != nullptr) {
+ (void)memcpy(retptr, &span_init, sizeof(*retptr));
+ retptr->idx = idx;
+ } else {
+ ot_span.alloc_fail_cnt++;
+ }
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_nolock_span_context_destroy -
+ *
+ * ARGUMENTS
+ * context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_nolock_span_context_destroy(struct otc_span_context **context)
+{
+ if ((context == nullptr) || (*context == nullptr))
+ return;
+
+ if (OT_CTX_KEY_IS_VALID(*context)) {
+ ot_span_context_handle.erase((*context)->idx);
+ ot_span_context.erase_cnt++;
+ }
+
+ ot_span_context.destroy_cnt++;
+
+ OT_EXT_FREE_CLEAR(*context);
+}
+
+
+/***
+ * NAME
+ * ot_span_context_destroy -
+ *
+ * ARGUMENTS
+ * context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_context_destroy(struct otc_span_context **context)
+{
+ OT_LOCK_GUARD(span_context);
+
+ ot_nolock_span_context_destroy(context);
+}
+
+
+/***
+ * NAME
+ * ot_span_context_new -
+ *
+ * ARGUMENTS
+ * span -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_span_context_new(const struct otc_span *span)
+{
+ int64_t idx = ot_span_context.key++;
+ struct otc_span_context *retptr;
+
+ if (idx == 0) {
+ ot_span_context_handle.clear();
+ ot_span_context_handle.reserve(8192);
+ }
+
+ if ((retptr = OT_CAST_TYPEOF(retptr, OT_EXT_MALLOC(sizeof(*retptr)))) == nullptr) {
+ ot_span_context.alloc_fail_cnt++;
+
+ return retptr;
+ }
+
+ retptr->idx = (span == nullptr) ? idx : -1;
+ retptr->span = span;
+ retptr->destroy = ot_span_context_destroy; /* lock span_context */
+
+ return retptr;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/src/tracer.cpp b/src/tracer.cpp
new file mode 100644
index 0000000..80f56b0
--- /dev/null
+++ b/src/tracer.cpp
@@ -0,0 +1,874 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "include.h"
+
+
+static std::unique_ptr<const opentracing::DynamicTracingLibraryHandle> ot_dynlib = nullptr;
+static std::shared_ptr<opentracing::Tracer> ot_tracer = nullptr;
+
+
+/***
+ * NAME
+ * ot_tracer_load -
+ *
+ * ARGUMENTS
+ * library -
+ * errbuf -
+ * errbufsiz -
+ * handle -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int ot_tracer_load(const char *library, char *errbuf, int errbufsiz, opentracing::DynamicTracingLibraryHandle &handle)
+{
+ std::string errmsg;
+
+ /* Load the tracer library. */
+ auto handle_maybe = opentracing::DynamicallyLoadTracingLibrary(library, errmsg);
+ if (!handle_maybe) {
+ (void)snprintf(errbuf, errbufsiz, "Failed to load tracing library: %s", errmsg.empty() ? handle_maybe.error().message().c_str() : errmsg.c_str());
+
+ return -1;
+ }
+
+ handle = std::move(*handle_maybe);
+
+ return 0;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_start -
+ *
+ * ARGUMENTS
+ * config -
+ * errbuf -
+ * errbufsiz -
+ * tracer -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int ot_tracer_start(const char *config, char *errbuf, int errbufsiz, std::shared_ptr<opentracing::Tracer> &tracer)
+{
+ std::string errmsg;
+
+ auto &tracer_factory = ot_dynlib->tracer_factory();
+
+ /* Create a tracer with the requested configuration. */
+ auto tracer_maybe = tracer_factory.MakeTracer(config, errmsg);
+ if (!tracer_maybe) {
+ (void)snprintf(errbuf, errbufsiz, "Failed to construct tracer: %s", errmsg.empty() ? tracer_maybe.error().message().c_str() : errmsg.c_str());
+
+ return -1;
+ }
+
+ tracer = std::move(*tracer_maybe);
+
+ return 0;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_close -
+ *
+ * ARGUMENTS
+ * tracer -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_tracer_close(struct otc_tracer *tracer)
+{
+ if (tracer == nullptr)
+ return;
+
+ if (ot_dynlib == nullptr)
+ return;
+
+ if (ot_tracer != nullptr)
+ ot_tracer->Close();
+ tracer->destroy(&tracer);
+}
+
+
+/***
+ * NAME
+ * ot_tracer_start_span_with_options -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * operation_name -
+ * options -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static struct otc_span *ot_tracer_start_span_with_options(struct otc_tracer *tracer, const char *operation_name, const struct otc_start_span_options *options)
+{
+ OT_LOCK_GUARD(span);
+ std::unique_ptr<opentracing::Span> span_maybe = nullptr;
+ struct otc_span *retptr = nullptr;
+
+ if (ot_tracer == nullptr)
+ return retptr;
+ else if ((tracer == nullptr) || (operation_name == nullptr))
+ return retptr;
+
+ /* Allocating memory for the span. */
+ if ((retptr = ot_span_new()) == nullptr)
+ return retptr;
+
+ if (options == nullptr) {
+ span_maybe = ot_tracer->StartSpan(operation_name);
+ } else {
+ struct opentracing::StartSpanOptions span_options;
+
+ if (options->start_time_steady.value.tv_sec > 0) {
+ auto dt = timespec_to_duration(&(options->start_time_steady.value));
+
+ span_options.start_steady_timestamp = std::chrono::time_point<std::chrono::steady_clock>(dt);
+ }
+
+ if (options->start_time_system.value.tv_sec > 0) {
+#ifdef __clang__
+ auto dt = timespec_to_duration_us(&(options->start_time_system.value));
+#else
+ auto dt = timespec_to_duration(&(options->start_time_system.value));
+#endif
+
+ span_options.start_system_timestamp = std::chrono::time_point<std::chrono::system_clock>(dt);
+ }
+
+ if (options->references != nullptr) {
+ int lock_cnt = 0;
+
+ for (int i = 0; i < options->num_references; i++) {
+ const opentracing::SpanContext *context = nullptr;
+
+ if (OT_SPAN_IS_VALID(options->references[i].referenced_context->span)) {
+ context = &(ot_span_handle.at(options->references[i].referenced_context->span->idx)->context());
+ }
+ else if (OT_CTX_KEY_IS_VALID(options->references[i].referenced_context)) {
+#ifdef OT_THREADS_NO_LOCKING
+ lock_cnt++;
+#else
+ if (lock_cnt++ == 0)
+ ot_span_context.mutex.lock();
+#endif
+
+ context = ot_span_context_handle.at(options->references[i].referenced_context->idx).get();
+ }
+
+ if (options->references[i].type == otc_span_reference_child_of)
+ span_options.references.push_back(std::make_pair(opentracing::SpanReferenceType::ChildOfRef, context));
+ else if (options->references[i].type == otc_span_reference_follows_from)
+ span_options.references.push_back(std::make_pair(opentracing::SpanReferenceType::FollowsFromRef, context));
+ }
+
+#ifndef OT_THREADS_NO_LOCKING
+ if (lock_cnt > 0)
+ ot_span_context.mutex.unlock();
+#endif
+ }
+
+ if (options->tags != nullptr) {
+ for (int i = 0; i < options->num_tags; i++)
+ if (options->tags[i].value.type == otc_value_bool) {
+ span_options.tags.push_back(std::make_pair(options->tags[i].key, options->tags[i].value.value.bool_value));
+ }
+ else if (options->tags[i].value.type == otc_value_double) {
+ span_options.tags.push_back(std::make_pair(options->tags[i].key, options->tags[i].value.value.double_value));
+ }
+ else if (options->tags[i].value.type == otc_value_int64) {
+ span_options.tags.push_back(std::make_pair(options->tags[i].key, options->tags[i].value.value.int64_value));
+ }
+ else if (options->tags[i].value.type == otc_value_uint64) {
+ span_options.tags.push_back(std::make_pair(options->tags[i].key, options->tags[i].value.value.uint64_value));
+ }
+ else if (options->tags[i].value.type == otc_value_string) {
+ std::string str_value = options->tags[i].value.value.string_value;
+
+ span_options.tags.push_back(std::make_pair(options->tags[i].key, str_value));
+ }
+ else if (options->tags[i].value.type == otc_value_null) {
+ span_options.tags.push_back(std::make_pair(options->tags[i].key, nullptr));
+ }
+ }
+
+ span_maybe = ot_tracer->StartSpanWithOptions(operation_name, span_options);
+ }
+
+ if (span_maybe != nullptr)
+ ot_span_handle.emplace(retptr->idx, std::move(span_maybe));
+ else
+ ot_nolock_span_destroy(&retptr);
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_start_span -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * operation_name -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static struct otc_span *ot_tracer_start_span(struct otc_tracer *tracer, const char *operation_name)
+{
+ return ot_tracer_start_span_with_options(tracer, operation_name, nullptr);
+}
+
+
+/***
+ * NAME
+ * ot_tracer_inject_text_map -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier -
+ * span_context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_inject_text_map(struct otc_tracer *tracer, struct otc_text_map_writer *carrier, const struct otc_span_context *span_context)
+{
+ TextMap text_map;
+ TextMapCarrier text_map_carrier(text_map);
+ opentracing::expected<void> rc;
+
+ if (ot_tracer == nullptr)
+ return otc_propagation_error_code_invalid_tracer;
+ else if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (!OT_CTX_IS_VALID(span_context))
+ return otc_propagation_error_code_span_context_corrupted;
+
+ if (OT_SPAN_IS_VALID(span_context->span)) {
+ OT_LOCK_GUARD(span);
+
+ rc = ot_tracer->Inject(ot_span_handle.at(span_context->span->idx)->context(), text_map_carrier);
+ }
+ else if (OT_CTX_KEY_IS_VALID(span_context)) {
+ OT_LOCK_GUARD(span_context);
+
+ rc = ot_tracer->Inject(*(ot_span_context_handle.at(span_context->idx)), text_map_carrier);
+ }
+
+ if (!rc)
+ return otc_propagation_error_code_unknown;
+ else if (text_map.empty())
+ return otc_propagation_error_code_unknown;
+ else if (otc_text_map_new(&(carrier->text_map), text_map.size()) == nullptr)
+ return otc_propagation_error_code_unknown;
+
+ for (auto const &it : text_map)
+ if (carrier->set != nullptr) {
+ otc_propagation_error_code_t retval = carrier->set(carrier, it.first.c_str(), it.second.c_str());
+ if (retval != otc_propagation_error_code_success)
+ return retval;
+ }
+ else if (otc_text_map_add(&(carrier->text_map), it.first.c_str(), 0, it.second.c_str(), 0, OT_CAST_STAT(otc_text_map_flags_t, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE)) == -1)
+ return otc_propagation_error_code_unknown;
+
+ return otc_propagation_error_code_success;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_inject_http_headers -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier -
+ * span_context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_inject_http_headers(struct otc_tracer *tracer, struct otc_http_headers_writer *carrier, const struct otc_span_context *span_context)
+{
+ TextMap text_map;
+ HTTPHeadersCarrier http_headers_carrier(text_map);
+ opentracing::expected<void> rc;
+
+ if (ot_tracer == nullptr)
+ return otc_propagation_error_code_invalid_tracer;
+ else if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (!OT_CTX_IS_VALID(span_context))
+ return otc_propagation_error_code_span_context_corrupted;
+
+ if (OT_SPAN_IS_VALID(span_context->span)) {
+ OT_LOCK_GUARD(span);
+
+ rc = ot_tracer->Inject(ot_span_handle.at(span_context->span->idx)->context(), http_headers_carrier);
+ }
+ else if (OT_CTX_KEY_IS_VALID(span_context)) {
+ OT_LOCK_GUARD(span_context);
+
+ rc = ot_tracer->Inject(*(ot_span_context_handle.at(span_context->idx)), http_headers_carrier);
+ }
+
+ if (!rc)
+ return otc_propagation_error_code_unknown;
+ else if (text_map.empty())
+ return otc_propagation_error_code_unknown;
+ else if (otc_text_map_new(&(carrier->text_map), text_map.size()) == nullptr)
+ return otc_propagation_error_code_unknown;
+
+ for (auto const &it : text_map)
+ if (carrier->set != nullptr) {
+ otc_propagation_error_code_t retval = carrier->set(carrier, it.first.c_str(), it.second.c_str());
+ if (retval != otc_propagation_error_code_success)
+ return retval;
+ }
+ else if (otc_text_map_add(&(carrier->text_map), it.first.c_str(), 0, it.second.c_str(), 0, OT_CAST_STAT(otc_text_map_flags_t, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE)) == -1)
+ return otc_propagation_error_code_unknown;
+
+ return otc_propagation_error_code_success;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_inject_binary -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier -
+ * span_context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_inject_binary(struct otc_tracer *tracer, struct otc_custom_carrier_writer *carrier, const struct otc_span_context *span_context)
+{
+ std::ostringstream oss(std::ios::binary);
+ opentracing::expected<void> rc;
+
+ if (ot_tracer == nullptr)
+ return otc_propagation_error_code_invalid_tracer;
+ else if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (!OT_CTX_IS_VALID(span_context))
+ return otc_propagation_error_code_span_context_corrupted;
+
+ if (OT_SPAN_IS_VALID(span_context->span)) {
+ OT_LOCK_GUARD(span);
+
+ rc = ot_tracer->Inject(ot_span_handle.at(span_context->span->idx)->context(), oss);
+ }
+ else if (OT_CTX_KEY_IS_VALID(span_context)) {
+ OT_LOCK_GUARD(span_context);
+
+ rc = ot_tracer->Inject(*(ot_span_context_handle.at(span_context->idx)), oss);
+ }
+
+ if (rc)
+ if (otc_binary_data_new(&(carrier->binary_data), oss.str().c_str(), oss.str().size()) != nullptr)
+ return otc_propagation_error_code_success;
+
+ return otc_propagation_error_code_unknown;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_inject_custom -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier - NOT USED
+ * span_context - NOT USED
+ *
+ * DESCRIPTION
+ * - NOT IMPLEMENTED
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_inject_custom(struct otc_tracer *tracer, struct otc_custom_carrier_writer *carrier, const struct otc_span_context *span_context)
+{
+ if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (!OT_CTX_IS_VALID(span_context))
+ return otc_propagation_error_code_span_context_corrupted;
+
+ return otc_propagation_error_code_success;
+}
+
+
+/***
+ * NAME
+ * ot_span_context_add -
+ *
+ * ARGUMENTS
+ * span_context -
+ * span_context_maybe -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_span_context_add(struct otc_span_context **span_context, std::unique_ptr<opentracing::SpanContext> &span_context_maybe)
+{
+ OT_LOCK_GUARD(span_context);
+
+ if ((*span_context = ot_span_context_new(nullptr)) == nullptr) {
+ span_context_maybe.reset(nullptr);
+
+ return otc_propagation_error_code_unknown;
+ }
+
+ ot_span_context_handle.emplace((*span_context)->idx, std::move(span_context_maybe));
+
+ return otc_propagation_error_code_success;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_text_map_add -
+ *
+ * ARGUMENTS
+ * arg -
+ * key -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_text_map_add(void *arg, const char *key, const char *value)
+{
+ TextMap *text_map = OT_CAST_REINTERPRET(TextMap *, arg);
+
+ if ((arg == nullptr) || (key == nullptr) || (value == nullptr))
+ return otc_propagation_error_code_unknown;
+
+ text_map->emplace(key, value);
+
+ return otc_propagation_error_code_success;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_extract_text_map -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier -
+ * span_context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_extract_text_map(struct otc_tracer *tracer, const struct otc_text_map_reader *carrier, struct otc_span_context **span_context)
+{
+ TextMap text_map;
+ TextMapCarrier text_map_carrier(text_map);
+
+ if (ot_tracer == nullptr)
+ return otc_propagation_error_code_invalid_tracer;
+ else if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (span_context == nullptr)
+ return otc_propagation_error_code_invalid_span_context;
+
+ if (carrier->foreach_key != nullptr) {
+ otc_propagation_error_code_t rc = carrier->foreach_key(OT_CAST_CONST(struct otc_text_map_reader *, carrier), ot_tracer_text_map_add, &text_map);
+ if (rc != otc_propagation_error_code_success)
+ return rc;
+ } else {
+ for (size_t i = 0; i < carrier->text_map.count; i++)
+ text_map[carrier->text_map.key[i]] = carrier->text_map.value[i];
+ }
+
+ auto span_context_maybe = ot_tracer->Extract(text_map_carrier);
+ if (!span_context_maybe)
+ return otc_propagation_error_code_span_context_not_found;
+
+ return ot_span_context_add(span_context, *span_context_maybe);
+}
+
+
+/***
+ * NAME
+ * ot_tracer_extract_http_headers -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier -
+ * span_context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_extract_http_headers(struct otc_tracer *tracer, const struct otc_http_headers_reader *carrier, struct otc_span_context **span_context)
+{
+ TextMap text_map;
+ HTTPHeadersCarrier http_headers_carrier(text_map);
+
+ if (ot_tracer == nullptr)
+ return otc_propagation_error_code_invalid_tracer;
+ else if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (span_context == nullptr)
+ return otc_propagation_error_code_invalid_span_context;
+
+ if (carrier->foreach_key != nullptr) {
+ otc_propagation_error_code_t rc = carrier->foreach_key(OT_CAST_CONST(struct otc_http_headers_reader *, carrier), ot_tracer_text_map_add, &text_map);
+ if (rc != otc_propagation_error_code_success)
+ return rc;
+ } else {
+ for (size_t i = 0; i < carrier->text_map.count; i++)
+ text_map[carrier->text_map.key[i]] = carrier->text_map.value[i];
+ }
+
+ auto span_context_maybe = ot_tracer->Extract(http_headers_carrier);
+ if (!span_context_maybe)
+ return otc_propagation_error_code_span_context_not_found;
+
+ return ot_span_context_add(span_context, *span_context_maybe);
+}
+
+
+/***
+ * NAME
+ * ot_tracer_extract_binary -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier -
+ * span_context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_extract_binary(struct otc_tracer *tracer, const struct otc_custom_carrier_reader *carrier, struct otc_span_context **span_context)
+{
+ if (ot_tracer == nullptr)
+ return otc_propagation_error_code_invalid_tracer;
+ else if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (span_context == nullptr)
+ return otc_propagation_error_code_invalid_span_context;
+
+ if ((carrier->binary_data.data == nullptr) || (carrier->binary_data.size == 0))
+ return otc_propagation_error_code_invalid_carrier;
+
+ std::string iss_data(OT_CAST_REINTERPRET(const char *, carrier->binary_data.data), carrier->binary_data.size);
+ std::istringstream iss(iss_data, std::ios::binary);
+
+ auto span_context_maybe = ot_tracer->Extract(iss);
+ if (!span_context_maybe)
+ return otc_propagation_error_code_span_context_not_found;
+
+ return ot_span_context_add(span_context, *span_context_maybe);
+}
+
+
+/***
+ * NAME
+ * ot_tracer_extract_custom -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier - NOT USED
+ * span_context - NOT USED
+ *
+ * DESCRIPTION
+ * - NOT IMPLEMENTED
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_extract_custom(struct otc_tracer *tracer, const struct otc_custom_carrier_reader *carrier, struct otc_span_context **span_context)
+{
+ if ((tracer == nullptr) || (carrier == nullptr) || (span_context == nullptr))
+ return otc_propagation_error_code_unknown;
+
+ return otc_propagation_error_code_success;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_destroy -
+ *
+ * ARGUMENTS
+ * tracer -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_tracer_destroy(struct otc_tracer **tracer)
+{
+ if ((tracer == nullptr) || (*tracer == nullptr))
+ return;
+
+ OT_FREE_CLEAR(*tracer);
+}
+
+
+/***
+ * NAME
+ * ot_tracer_new -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_tracer *ot_tracer_new(void)
+{
+ const static struct otc_tracer tracer_init = {
+ .close = ot_tracer_close, /* lock not required */
+ .start_span = ot_tracer_start_span, /* lock span */
+ .start_span_with_options = ot_tracer_start_span_with_options, /* lock span */
+ .inject_text_map = ot_tracer_inject_text_map, /* lock span and/or span_context */
+ .inject_http_headers = ot_tracer_inject_http_headers, /* lock span and/or span_context */
+ .inject_binary = ot_tracer_inject_binary, /* lock span and/or span_context */
+ .inject_custom = ot_tracer_inject_custom, /* NOT IMPLEMENTED */
+ .extract_text_map = ot_tracer_extract_text_map, /* lock span_context */
+ .extract_http_headers = ot_tracer_extract_http_headers, /* lock span_context */
+ .extract_binary = ot_tracer_extract_binary, /* lock span_context */
+ .extract_custom = ot_tracer_extract_custom, /* NOT IMPLEMENTED */
+ .destroy = ot_tracer_destroy /* lock not required */
+ };
+ struct otc_tracer *retptr;
+
+ if ((retptr = OT_CAST_TYPEOF(retptr, OTC_DBG_CALLOC(1, sizeof(*retptr)))) != nullptr)
+ (void)memcpy(retptr, &tracer_init, sizeof(*retptr));
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_tracer_load -
+ *
+ * ARGUMENTS
+ * library -
+ * errbuf -
+ * errbufsiz -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_tracer *otc_tracer_load(const char *library, char *errbuf, int errbufsiz)
+{
+ std::unique_ptr<opentracing::DynamicTracingLibraryHandle> handle {
+ new opentracing::DynamicTracingLibraryHandle {}
+ };
+ std::shared_ptr<opentracing::Tracer> tracer;
+ struct otc_tracer *retptr = nullptr;
+
+ if ((retptr = ot_tracer_new()) == nullptr) {
+ /* Do nothing. */;
+ }
+ else if (ot_tracer_load(library, errbuf, errbufsiz, *handle) == -1) {
+ retptr->destroy(&retptr);
+ }
+ else {
+ ot_dynlib = std::move(handle);
+ }
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_tracer_start -
+ *
+ * ARGUMENTS
+ * cfgfile -
+ * cfgbuf -
+ * errbuf -
+ * errbufsiz -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int otc_tracer_start(const char *cfgfile, const char *cfgbuf, char *errbuf, int errbufsiz)
+{
+ std::shared_ptr<opentracing::Tracer> tracer;
+ char *config = OT_CAST_CONST(char *, cfgbuf);
+ int retval = -1;
+
+ if (cfgfile != nullptr) {
+ config = otc_file_read(cfgfile, "#", errbuf, errbufsiz);
+ if (config == nullptr)
+ return retval;
+ }
+
+ if (ot_tracer_start(config, errbuf, errbufsiz, tracer) == -1) {
+ /* Do nothing. */;
+ } else {
+ ot_tracer = std::move(tracer);
+
+ (void)opentracing::Tracer::InitGlobal(ot_tracer);
+
+ retval = 0;
+ }
+
+ if (config != cfgbuf)
+ OT_FREE(config);
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * otc_tracer_init -
+ *
+ * ARGUMENTS
+ * library -
+ * cfgfile -
+ * cfgbuf -
+ * errbuf -
+ * errbufsiz -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_tracer *otc_tracer_init(const char *library, const char *cfgfile, const char *cfgbuf, char *errbuf, int errbufsiz)
+{
+ struct otc_tracer *retptr = nullptr;
+
+ if ((retptr = otc_tracer_load(library, errbuf, errbufsiz)) != nullptr)
+ if (otc_tracer_start(cfgfile, cfgbuf, errbuf, errbufsiz) == -1)
+ retptr->destroy(&retptr);
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_tracer_global -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ *
+ * DESCRIPTION
+ * - NOT IMPLEMENTED
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_tracer_global(struct otc_tracer *tracer)
+{
+ if (tracer == nullptr)
+ return;
+}
+
+
+/***
+ * NAME
+ * otc_tracer_init_global -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ *
+ * DESCRIPTION
+ * - NOT IMPLEMENTED
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_tracer_init_global(struct otc_tracer *tracer)
+{
+ if (tracer == nullptr)
+ return;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/src/util.cpp b/src/util.cpp
new file mode 100644
index 0000000..3236e9d
--- /dev/null
+++ b/src/util.cpp
@@ -0,0 +1,451 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "include.h"
+
+
+otc_ext_malloc_t otc_ext_malloc = OT_IFDEF_DBG(otc_dbg_malloc, malloc);
+otc_ext_free_t otc_ext_free = OT_IFDEF_DBG(otc_dbg_free, free);
+
+
+/***
+ * NAME
+ * timespec_to_duration_us -
+ *
+ * ARGUMENTS
+ * ts -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+std::chrono::microseconds timespec_to_duration_us(const struct timespec *ts)
+{
+ auto duration = std::chrono::seconds{ts->tv_sec} + std::chrono::microseconds{ts->tv_nsec / 1000};
+
+ return std::chrono::duration_cast<std::chrono::microseconds>(duration);
+}
+
+
+/***
+ * NAME
+ * timespec_to_duration -
+ *
+ * ARGUMENTS
+ * ts -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+std::chrono::nanoseconds timespec_to_duration(const struct timespec *ts)
+{
+ auto duration = std::chrono::seconds{ts->tv_sec} + std::chrono::nanoseconds{ts->tv_nsec};
+
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
+}
+
+
+/***
+ * NAME
+ * otc_ext_init -
+ *
+ * ARGUMENTS
+ * func_malloc -
+ * func_free -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_ext_init(otc_ext_malloc_t func_malloc, otc_ext_free_t func_free)
+{
+ otc_ext_malloc = (func_malloc != nullptr) ? func_malloc : OT_IFDEF_DBG(otc_dbg_malloc, malloc);
+ otc_ext_free = (func_free != nullptr) ? func_free : OT_IFDEF_DBG(otc_dbg_free, free);
+}
+
+
+/***
+ * NAME
+ * otc_text_map_new -
+ *
+ * ARGUMENTS
+ * text_map -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_text_map *otc_text_map_new(struct otc_text_map *text_map, size_t size)
+{
+ struct otc_text_map *retptr = text_map;
+
+ if (retptr == nullptr)
+ retptr = OT_CAST_TYPEOF(retptr, OTC_DBG_CALLOC(1, sizeof(*retptr)));
+
+ if (retptr != nullptr) {
+ retptr->count = 0;
+ retptr->size = size;
+ retptr->is_dynamic = text_map == nullptr;
+
+ if (size == 0)
+ /* Do nothing. */;
+ else if ((retptr->key = OT_CAST_TYPEOF(retptr->key, OTC_DBG_CALLOC(size, sizeof(*(retptr->key))))) == nullptr)
+ otc_text_map_destroy(&retptr, OT_CAST_STAT(otc_text_map_flags_t, 0));
+ else if ((retptr->value = OT_CAST_TYPEOF(retptr->value, OTC_DBG_CALLOC(size, sizeof(*(retptr->value))))) == nullptr)
+ otc_text_map_destroy(&retptr, OT_CAST_STAT(otc_text_map_flags_t, 0));
+ }
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_text_map_add -
+ *
+ * ARGUMENTS
+ * text_map -
+ * key -
+ * key_len -
+ * value -
+ * value_len -
+ * flags -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int otc_text_map_add(struct otc_text_map *text_map, const char *key, size_t key_len, const char *value, size_t value_len, otc_text_map_flags_t flags)
+{
+ int retval = -1;
+
+ if ((text_map == nullptr) || (key == nullptr) || (value == nullptr))
+ return retval;
+
+ /*
+ * Check if it is necessary to increase the number of key/value pairs.
+ * The number of pairs is increased by half the current number of pairs
+ * (for example: 8 -> 12 -> 18 -> 27 -> 40 -> 60 ...).
+ */
+ if (text_map->count >= text_map->size) {
+ typeof(text_map->key) ptr_key;
+ typeof(text_map->value) ptr_value;
+ size_t size_add = (text_map->size > 1) ? (text_map->size / 2) : 1;
+
+ if ((ptr_key = OT_CAST_TYPEOF(ptr_key, OTC_DBG_REALLOC(text_map->key, OT_TEXT_MAP_SIZE(key, size_add)))) == nullptr)
+ return retval;
+
+ text_map->key = ptr_key;
+ (void)memset(text_map->key + OT_TEXT_MAP_SIZE(key, 0), 0, sizeof(*(text_map->key)) * size_add);
+
+ if ((ptr_value = OT_CAST_TYPEOF(ptr_value, OTC_DBG_REALLOC(text_map->value, OT_TEXT_MAP_SIZE(value, size_add)))) == nullptr)
+ return retval;
+
+ text_map->value = ptr_value;
+ (void)memset(text_map->value + OT_TEXT_MAP_SIZE(value, 0), 0, sizeof(*(text_map->value)) * size_add);
+
+ text_map->size += size_add;
+ }
+
+ text_map->key[text_map->count] = (flags & OTC_TEXT_MAP_DUP_KEY) ? ((key_len > 0) ? OTC_DBG_STRNDUP(key, key_len) : OTC_DBG_STRDUP(key)) : OT_CAST_CONST(char *, key);
+ text_map->value[text_map->count] = (flags & OTC_TEXT_MAP_DUP_VALUE) ? ((value_len > 0) ? OTC_DBG_STRNDUP(value, value_len) : OTC_DBG_STRDUP(value)) : OT_CAST_CONST(char *, value);
+
+ if ((text_map->key[text_map->count] != nullptr) && (text_map->value[text_map->count] != nullptr))
+ retval = text_map->count;
+
+ text_map->count++;
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * otc_text_map_destroy -
+ *
+ * ARGUMENTS
+ * text_map -
+ * flags -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_text_map_destroy(struct otc_text_map **text_map, otc_text_map_flags_t flags)
+{
+ if ((text_map == nullptr) || (*text_map == nullptr))
+ return;
+
+ if ((*text_map)->key != nullptr) {
+ if (flags & OTC_TEXT_MAP_FREE_KEY)
+ for (size_t i = 0; i < (*text_map)->count; i++)
+ OT_FREE((*text_map)->key[i]);
+
+ OT_FREE_CLEAR((*text_map)->key);
+ }
+
+ if ((*text_map)->value != nullptr) {
+ if (flags & OTC_TEXT_MAP_FREE_VALUE)
+ for (size_t i = 0; i < (*text_map)->count; i++)
+ OT_FREE((*text_map)->value[i]);
+
+ OT_FREE_CLEAR((*text_map)->value);
+ }
+
+ if ((*text_map)->is_dynamic) {
+ OT_FREE_CLEAR(*text_map);
+ } else {
+ (*text_map)->count = 0;
+ (*text_map)->size = 0;
+ }
+}
+
+
+/***
+ * NAME
+ * otc_binary_data_new -
+ *
+ * ARGUMENTS
+ * binary_data -
+ * data -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_binary_data *otc_binary_data_new(struct otc_binary_data *binary_data, const void *data, size_t size)
+{
+ struct otc_binary_data *retptr = binary_data;
+
+ if (retptr == nullptr)
+ retptr = OT_CAST_TYPEOF(retptr, OTC_DBG_CALLOC(1, sizeof(*retptr)));
+
+ if (retptr != nullptr) {
+ retptr->size = size;
+ retptr->is_dynamic = binary_data == nullptr;
+
+ if ((data == nullptr) || (size == 0))
+ /* Do nothing. */;
+ else if ((retptr->data = OTC_DBG_MALLOC(size)) != nullptr)
+ (void)memcpy(retptr->data, data, size);
+ else
+ otc_binary_data_destroy(&retptr);
+ }
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_binary_data_destroy -
+ *
+ * ARGUMENTS
+ * binary_data -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_binary_data_destroy(struct otc_binary_data **binary_data)
+{
+ if ((binary_data == nullptr) || (*binary_data == nullptr))
+ return;
+
+ OT_FREE_CLEAR((*binary_data)->data);
+
+ if ((*binary_data)->is_dynamic)
+ OT_FREE_CLEAR(*binary_data);
+ else
+ (*binary_data)->size = 0;
+}
+
+
+/***
+ * NAME
+ * otc_strerror -
+ *
+ * ARGUMENTS
+ * errnum -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+const char *otc_strerror(int errnum)
+{
+ static __THR char retbuf[1024];
+ const char *retptr = retbuf;
+
+ errno = 0;
+ (void)strerror_r(errnum, retbuf, sizeof(retbuf));
+ if (errno != 0)
+ retptr = "Unknown error";
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_file_read -
+ *
+ * ARGUMENTS
+ * filename -
+ * comment -
+ * errbuf -
+ * errbufsiz -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+char *otc_file_read(const char *filename, const char *comment, char *errbuf, int errbufsiz)
+{
+ struct stat statbuf;
+ char *retptr = nullptr;
+ int fd, rc;
+
+ if (filename == nullptr)
+ return retptr;
+
+ if ((fd = open(filename, O_RDONLY)) == -1) {
+ (void)snprintf(errbuf, errbufsiz, "'%s': %s", filename, otc_strerror(errno));
+ }
+ else if ((rc = fstat(fd, &statbuf)) == -1) {
+ (void)snprintf(errbuf, errbufsiz, "'%s': %s", filename, otc_strerror(errno));
+ }
+ else if ((retptr = OT_CAST_TYPEOF(retptr, OTC_DBG_MALLOC(statbuf.st_size + 1))) == nullptr) {
+ (void)snprintf(errbuf, errbufsiz, "cannot allocate memory: %s", otc_strerror(errno));
+ }
+ else {
+ char *buf = retptr;
+ off_t size = statbuf.st_size;
+
+ while (size > 0) {
+ ssize_t n;
+
+ if ((n = read(fd, buf, size)) > 0) {
+ size -= n;
+ buf += n;
+ }
+ else if (n == -1) {
+ if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
+ break;
+ }
+ else if (errno != EINTR)
+ {
+ (void)snprintf(errbuf, errbufsiz, "'%s': %s", filename, otc_strerror(errno));
+ OT_FREE_CLEAR(retptr);
+
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+
+ if (comment != nullptr) {
+ off_t i = 0, c = -1, n = statbuf.st_size;
+
+ for (i = 0; i < n; i++)
+ if (c < 0) {
+ /* Remember the starting position of the comment line. */
+ if ((strchr(comment, retptr[i]) != nullptr) && ((i == 0) || (retptr[i - 1] == '\n')))
+ c = i;
+ }
+ else if ((retptr[i] == '\n') && ((i + 1) < n)) {
+ /* Delete the entire comment line. */
+ (void)memmove(retptr + c, retptr + i + 1, n - i - 1);
+
+ n -= i + 1 - c;
+ i = c - 1;
+ c = -1;
+ }
+
+ /* If a comment remains in the last line, delete it. */
+ if (c >= 0) {
+ n -= i - c;
+ i = c;
+ }
+
+ retptr[i] = '\0';
+ }
+ else if (size != 0)
+ OT_FREE_CLEAR(retptr);
+ }
+
+ (void)close(fd);
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_statistics -
+ *
+ * ARGUMENTS
+ * buffer -
+ * bufsiz -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_statistics(char *buffer, size_t bufsiz)
+{
+ if ((buffer == nullptr) || (bufsiz < 24))
+ return;
+
+ (void)snprintf(buffer, bufsiz, "span: %" PRId64 "/%" PRId64 "+%" PRId64 "(%" PRId64 ")/%" PRId64 ", context: %" PRId64 "/%" PRId64 "+%" PRId64 "(%" PRId64 ")/%" PRId64,
+ ot_span.key, ot_span_handle.size(), ot_span.erase_cnt, ot_span.destroy_cnt, ot_span.alloc_fail_cnt,
+ ot_span_context.key, ot_span_context_handle.size(), ot_span_context.erase_cnt, ot_span_context.destroy_cnt, ot_span_context.alloc_fail_cnt);
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */