*/
#include <iostream>
#include <string>
+#include <assert.h>
#include <dlfcn.h>
#include <errno.h>
#include "tensor_filter_cpp.hh"
std::unordered_map<std::string, tensor_filter_cpp*> tensor_filter_cpp::filters;
+std::vector<void *> tensor_filter_cpp::handles;
+G_LOCK_DEFINE_STATIC (lock_handles);
static gchar filter_subplugin_cpp[] = "cpp";
+bool tensor_filter_cpp::dlclose_all_called = false;
static GstTensorFilterFramework NNS_support_cpp = {
.name = filter_subplugin_cpp,
#define loadClass(name, ptr) \
class tensor_filter_cpp *name = (tensor_filter_cpp *) *(ptr); \
- g_assert (*(ptr)); \
- g_assert (name->isValid());
+ assert (false == dlclose_all_called); \
+ assert (*(ptr)); \
+ assert (name->isValid());
/**
* @brief Class constructor
return -EINVAL; /** Model file / name not found */
}
- /** At this stage, the constructor of the .so file should have registered
- * itself with tensor_filter_cpp_register() */
- dlclose (handle);
-
if (filters.find(prop->model_files[0]) == filters.end()) {
/** It's still not found. it's not there. */
+ dlclose (handle);
g_printerr_once (__FILE__, __LINE__, "C++ custom filter %s is not found in %s.\n",
prop->model_files[0], prop->model_files[1]);
return -EINVAL;
}
+
+ /** We do not know until when this handle might be required: user may
+ * invoke functions from it at anytime while the pipeline is not
+ * closed */
+ G_LOCK (lock_handles);
+ handles.push_back (handle);
+ G_UNLOCK (lock_handles);
+
}
*private_data = cpp = filters[prop->model_files[0]];
void init_filter_cpp (void) __attribute__ ((constructor));
void fini_filter_cpp (void) __attribute__ ((destructor));
+/**
+ * @brief Call dlclose for all handle
+ */
+void tensor_filter_cpp::dlclose_all ()
+{
+ assert (false == dlclose_all_called);
+/**
+ * Ubuntu 16.04 / GLIBC 2.23 Workaround
+ * If we do dlclose at exit() function, it may incur
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1264556#c42
+ * , which is a GLIBC bug at 2.23.
+ * The corresponding error message is:
+ * Inconsistency detected by ld.so: dl-close.c: 811:
+ * _dl_close: Assertion `map->l_init_called' failed!
+ */
+#if defined(__GLIBC__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 23)
+ /* Do not call dlclose */
+#else
+ G_LOCK (lock_handles);
+ for (void *handle : handles) {
+ dlclose (handle);
+ }
+ G_UNLOCK (lock_handles);
+#endif
+ dlclose_all_called = true;
+}
+
/** @brief Initialize this object for tensor_filter subplugin runtime register */
void
init_filter_cpp (void)
fini_filter_cpp (void)
{
nnstreamer_filter_exit (NNS_support_cpp.name);
+ tensor_filter_cpp::dlclose_all ();
}
G_END_DECLS
* - - so's init() { myfilter fx("myfilter");
* fx.register(); }
*
+ * User should aware that the model name of a filter should be
+ * unique across all the .so files used in a pipeline. Otherwise,
+ * "Already registered (-EINVAL)" may occur.
+ *
*/
#ifndef __NNS_TENSOR_FITLER_CPP_H__
#define __NNS_TENSOR_FITLER_CPP_H__
+#ifdef __cplusplus
+
#include <atomic>
+#include <vector>
#include <stdint.h>
#include <unordered_map>
#include <nnstreamer_plugin_api_filter.h>
-#ifdef __cplusplus
-
/**
* @brief This allows to have a c++ class inserted as a filter in a neural network pipeline of nnstreamer
* @note This is experimental.
std::atomic_uint ref_count;
static std::unordered_map<std::string, tensor_filter_cpp*> filters;
+ static std::vector<void *> handles;
+ static bool dlclose_all_called;
protected:
const GstTensorFilterProperties *prop;
(constructed) by tensor_filter at run-time.
If you don't want to touch initial ref_count, keep it 0.
*/
+ /** @brief Register this instance (same effect with __register) */
int _register(unsigned int ref_count = 0) {
return __register(this, ref_count);
}
/**< Unregister the run-time registered c++ filter.
Do not call this to filters loaded as a .so (independent)
filter. */
+ /** @brief Unregister this instance (same effect with __unregister */
int _unregister() {
return __unregister(this->name);
}
static int invoke (const GstTensorFilterProperties *prop, void **private_data, const GstTensorMemory *input, GstTensorMemory *output);
static int open (const GstTensorFilterProperties *prop, void **private_data);
static void close (const GstTensorFilterProperties *prop, void **private_data);
+ static void dlclose_all (void);
};
#endif /* __cplusplus */