summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Ross <tross@apache.org>2013-06-07 21:50:01 +0000
committerTed Ross <tross@apache.org>2013-06-07 21:50:01 +0000
commita34b08be238e74e30bcf7a6ba285846bdd847d61 (patch)
tree48b66949384fe7d55a7a26088d54de388af632e2
parent51c92f5b0d6ee67f65041b7b81e655f7e6ae30b6 (diff)
downloadqpid-python-a34b08be238e74e30bcf7a6ba285846bdd847d61.tar.gz
QPID-4913 - Work-in-progres for configuration file reader.
Note that this commit adds the use of embedded Python code. Installation support is needed to ensure that the embedded python components are installed in the libexec area. Also, the configuration file path is currently hard-coded. This will be fixed shortly. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@1490848 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--extras/dispatch/CMakeLists.txt16
-rw-r--r--extras/dispatch/include/qpid/dispatch/config.h29
-rw-r--r--extras/dispatch/include/qpid/dispatch/dispatch.h8
-rw-r--r--extras/dispatch/router/src/main.c2
-rw-r--r--extras/dispatch/src/config.c203
-rw-r--r--extras/dispatch/src/config_private.h29
-rw-r--r--extras/dispatch/src/dispatch.c39
-rw-r--r--extras/dispatch/src/py/config/__init__.py20
-rw-r--r--extras/dispatch/src/py/config/configparse.py146
-rw-r--r--extras/dispatch/src/python_embedded.c64
-rw-r--r--extras/dispatch/src/python_embedded.h29
-rw-r--r--extras/dispatch/src/router_node.c2
-rw-r--r--extras/dispatch/src/server.c3
13 files changed, 577 insertions, 13 deletions
diff --git a/extras/dispatch/CMakeLists.txt b/extras/dispatch/CMakeLists.txt
index f96f62817b..d01e6c1321 100644
--- a/extras/dispatch/CMakeLists.txt
+++ b/extras/dispatch/CMakeLists.txt
@@ -17,15 +17,22 @@
## under the License.
##
+project(qpid-dispatch C)
+
cmake_minimum_required(VERSION 2.6)
include(CheckLibraryExists)
include(CheckSymbolExists)
-
-project(qpid-dispatch C)
+include(CheckFunctionExists)
+include(CheckIncludeFiles)
+include(FindPythonLibs)
enable_testing()
include (CTest)
+if (NOT PYTHONLIBS_FOUND)
+ message(FATAL_ERROR "Python Development Libraries are needed.")
+endif (NOT PYTHONLIBS_FOUND)
+
set (SO_VERSION_MAJOR 0)
set (SO_VERSION_MINOR 1)
set (SO_VERSION "${SO_VERSION_MAJOR}.${SO_VERSION_MINOR}")
@@ -49,6 +56,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
${proton_include}
+ ${PYTHON_INCLUDE_DIRS}
)
##
@@ -70,6 +78,7 @@ set(server_SOURCES
src/alloc.c
src/auth.c
src/buffer.c
+ src/config.c
src/container.c
src/dispatch.c
src/hash.c
@@ -78,6 +87,7 @@ set(server_SOURCES
src/log.c
src/message.c
src/posix/threading.c
+ src/python_embedded.c
src/router_node.c
src/server.c
src/timer.c
@@ -85,7 +95,7 @@ set(server_SOURCES
)
add_library(qpid-dispatch SHARED ${server_SOURCES})
-target_link_libraries(qpid-dispatch ${proton_lib} ${pthread_lib} ${rt_lib})
+target_link_libraries(qpid-dispatch ${proton_lib} ${pthread_lib} ${rt_lib} ${PYTHON_LIBRARIES})
set_target_properties(qpid-dispatch PROPERTIES
VERSION "${SO_VERSION}"
SOVERSION "${SO_VERSION_MAJOR}"
diff --git a/extras/dispatch/include/qpid/dispatch/config.h b/extras/dispatch/include/qpid/dispatch/config.h
new file mode 100644
index 0000000000..81f7bc5d98
--- /dev/null
+++ b/extras/dispatch/include/qpid/dispatch/config.h
@@ -0,0 +1,29 @@
+#ifndef __dispatch_config_h__
+#define __dispatch_config_h__ 1
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+
+typedef struct dx_config_t dx_config_t;
+
+int dx_config_item_count(const dx_config_t *config, const char *section);
+const char *dx_config_item_value_string(const dx_config_t *config, const char *section, int index, const char* key);
+uint32_t dx_config_item_value_int(const dx_config_t *config, const char *section, int index, const char* key);
+
+#endif
diff --git a/extras/dispatch/include/qpid/dispatch/dispatch.h b/extras/dispatch/include/qpid/dispatch/dispatch.h
index d6c2832f6f..e785cb6385 100644
--- a/extras/dispatch/include/qpid/dispatch/dispatch.h
+++ b/extras/dispatch/include/qpid/dispatch/dispatch.h
@@ -29,15 +29,9 @@ typedef struct dx_dispatch_t dx_dispatch_t;
/**
* \brief Initialize the Dispatch library and prepare it for operation.
*
- * @param thread_count The number of worker threads (1 or more) that the server shall create
- * @param container_name The name of the container. If NULL, a UUID will be generated.
- * @param router_area The name of the router's area. If NULL, a default value will be supplied.
- * @param router_id The identifying name of the router. If NULL, it will be set the same as the
- * container_name.
* @return A handle to be used in API calls for this instance.
*/
-dx_dispatch_t *dx_dispatch(int thread_count, const char *container_name,
- const char *router_area, const char *router_id);
+dx_dispatch_t *dx_dispatch();
/**
diff --git a/extras/dispatch/router/src/main.c b/extras/dispatch/router/src/main.c
index 5fb194980b..d97895208f 100644
--- a/extras/dispatch/router/src/main.c
+++ b/extras/dispatch/router/src/main.c
@@ -106,7 +106,7 @@ int main(int argc, char **argv)
{
dx_log_set_mask(LOG_INFO | LOG_TRACE | LOG_ERROR);
- dispatch = dx_dispatch(4, "Qpid.Dispatch", "area", "Router.A");
+ dispatch = dx_dispatch();
dx_server_set_signal_handler(dispatch, server_signal_handler, 0);
dx_server_set_start_handler(dispatch, thread_start_handler, 0);
diff --git a/extras/dispatch/src/config.c b/extras/dispatch/src/config.c
new file mode 100644
index 0000000000..bc99d7f91c
--- /dev/null
+++ b/extras/dispatch/src/config.c
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "python_embedded.h"
+#include "config_private.h"
+#include <qpid/dispatch/alloc.h>
+#include <qpid/dispatch/log.h>
+
+#define PYTHON_MODULE "config"
+
+static const char *log_module = "CONFIG";
+
+struct dx_config_t {
+ PyObject *pModule;
+ PyObject *pClass;
+ PyObject *pObject;
+};
+
+ALLOC_DECLARE(dx_config_t);
+ALLOC_DEFINE(dx_config_t);
+
+void dx_config_initialize()
+{
+ dx_python_start();
+}
+
+
+void dx_config_finalize()
+{
+ dx_python_stop();
+}
+
+
+dx_config_t *dx_config(char *filename)
+{
+ dx_config_t *config = new_dx_config_t();
+
+ //
+ // Load the Python configuration module and get a reference to the config class.
+ //
+ PyObject *pName = PyString_FromString(PYTHON_MODULE);
+ config->pModule = PyImport_Import(pName);
+ Py_DECREF(pName);
+
+ if (!config->pModule) {
+ PyErr_Print();
+ free_dx_config_t(config);
+ dx_log(log_module, LOG_ERROR, "Unable to load configuration module: %s", PYTHON_MODULE);
+ return 0;
+ }
+
+ config->pClass = PyObject_GetAttrString(config->pModule, "DXConfig");
+ if (!config->pClass || !PyClass_Check(config->pClass)) {
+ PyErr_Print();
+ Py_DECREF(config->pModule);
+ free_dx_config_t(config);
+ dx_log(log_module, LOG_ERROR, "Problem with configuration module: Missing DXConfig class");
+ return 0;
+ }
+
+ //
+ // Instantiate the DXConfig class, passing in the configuration file name.
+ //
+ PyObject *pArgs = PyTuple_New(1);
+ PyObject *fname = PyString_FromString(filename);
+ PyTuple_SetItem(pArgs, 0, fname);
+ config->pObject = PyInstance_New(config->pClass, pArgs, 0);
+ Py_DECREF(pArgs);
+
+ if (config->pObject == 0) {
+ PyErr_Print();
+ Py_DECREF(config->pModule);
+ free_dx_config_t(config);
+ dx_log(log_module, LOG_ERROR, "Configuration file '%s' could not be read", filename);
+ return 0;
+ }
+
+ return config;
+}
+
+
+void dx_config_free(dx_config_t *config)
+{
+ if (config) {
+ Py_DECREF(config->pClass);
+ Py_DECREF(config->pModule);
+ free_dx_config_t(config);
+ }
+}
+
+
+int dx_config_item_count(const dx_config_t *config, const char *section)
+{
+ PyObject *pSection;
+ PyObject *pMethod;
+ PyObject *pArgs;
+ PyObject *pResult;
+ int result = 0;
+
+ pMethod = PyObject_GetAttrString(config->pObject, "item_count");
+ if (!pMethod || !PyCallable_Check(pMethod)) {
+ dx_log(log_module, LOG_ERROR, "Problem with configuration module: No callable 'item_count'");
+ if (pMethod)
+ Py_DECREF(pMethod);
+ return 0;
+ }
+
+ pSection = PyString_FromString(section);
+ pArgs = PyTuple_New(1);
+ PyTuple_SetItem(pArgs, 0, pSection);
+ pResult = PyObject_CallObject(pMethod, pArgs);
+ Py_DECREF(pArgs);
+ if (pResult && PyInt_Check(pResult))
+ result = (int) PyInt_AsLong(pResult);
+ if (pResult)
+ Py_DECREF(pResult);
+ Py_DECREF(pMethod);
+
+ return result;
+}
+
+
+static PyObject *item_value(const dx_config_t *config, const char *section, int index, const char* key, const char* method)
+{
+ PyObject *pSection;
+ PyObject *pIndex;
+ PyObject *pKey;
+ PyObject *pMethod;
+ PyObject *pArgs;
+ PyObject *pResult;
+
+ pMethod = PyObject_GetAttrString(config->pObject, method);
+ if (!pMethod || !PyCallable_Check(pMethod)) {
+ dx_log(log_module, LOG_ERROR, "Problem with configuration module: No callable '%s'", method);
+ if (pMethod)
+ Py_DECREF(pMethod);
+ return 0;
+ }
+
+ pSection = PyString_FromString(section);
+ pIndex = PyInt_FromLong((long) index);
+ pKey = PyString_FromString(key);
+ pArgs = PyTuple_New(3);
+ PyTuple_SetItem(pArgs, 0, pSection);
+ PyTuple_SetItem(pArgs, 1, pIndex);
+ PyTuple_SetItem(pArgs, 2, pKey);
+ pResult = PyObject_CallObject(pMethod, pArgs);
+ Py_DECREF(pArgs);
+ Py_DECREF(pMethod);
+
+ return pResult;
+}
+
+
+const char *dx_config_item_value_string(const dx_config_t *config, const char *section, int index, const char* key)
+{
+ PyObject *pResult = item_value(config, section, index, key, "value_string");
+ char *value = 0;
+
+ if (pResult && PyString_Check(pResult)) {
+ Py_ssize_t size = PyString_Size(pResult);
+ value = (char*) malloc(size + 1);
+ strncpy(value, PyString_AsString(pResult), size + 1);
+ }
+
+ if (pResult)
+ Py_DECREF(pResult);
+
+ return value;
+}
+
+
+uint32_t dx_config_item_value_int(const dx_config_t *config, const char *section, int index, const char* key)
+{
+ PyObject *pResult = item_value(config, section, index, key, "value_int");
+ uint32_t value = 0;
+
+ if (pResult && PyLong_Check(pResult))
+ value = (uint32_t) PyLong_AsLong(pResult);
+
+ if (pResult)
+ Py_DECREF(pResult);
+
+ return value;
+}
+
+
diff --git a/extras/dispatch/src/config_private.h b/extras/dispatch/src/config_private.h
new file mode 100644
index 0000000000..bb114ebde0
--- /dev/null
+++ b/extras/dispatch/src/config_private.h
@@ -0,0 +1,29 @@
+#ifndef __config_private_h__
+#define __config_private_h__ 1
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 <qpid/dispatch/config.h>
+
+void dx_config_initialize();
+void dx_config_finalize();
+dx_config_t *dx_config(char *filename);
+void dx_config_free(dx_config_t *config);
+
+#endif
diff --git a/extras/dispatch/src/dispatch.c b/extras/dispatch/src/dispatch.c
index 0176d3189e..3c8fa9ba83 100644
--- a/extras/dispatch/src/dispatch.c
+++ b/extras/dispatch/src/dispatch.c
@@ -17,10 +17,12 @@
* under the License.
*/
+#include "python_embedded.h"
#include <qpid/dispatch.h>
#include "dispatch_private.h"
#include "alloc_private.h"
#include "log_private.h"
+#include "config_private.h"
/**
* Private Function Prototypes
@@ -38,14 +40,43 @@ dx_agent_t *dx_agent(dx_dispatch_t *dx);
void dx_agent_free(dx_agent_t *agent);
-dx_dispatch_t *dx_dispatch(int thread_count, const char *container_name,
- const char *router_area, const char *router_id)
+static const char *CONF_CONTAINER = "container";
+static const char *CONF_ROUTER = "router";
+
+
+dx_dispatch_t *dx_dispatch()
{
dx_dispatch_t *dx = NEW(dx_dispatch_t);
+ int thread_count = 0;
+ const char *container_name = 0;
+ const char *router_area = 0;
+ const char *router_id = 0;
+
+ dx_python_initialize();
dx_log_initialize();
dx_alloc_initialize();
+ dx_config_initialize();
+ dx_config_t *config = dx_config("../etc/qpid-dispatch.conf");
+
+ if (config) {
+ int count = dx_config_item_count(config, CONF_CONTAINER);
+ if (count == 1) {
+ thread_count = dx_config_item_value_int(config, CONF_CONTAINER, 0, "worker-threads");
+ container_name = dx_config_item_value_string(config, CONF_CONTAINER, 0, "container-name");
+ }
+
+ count = dx_config_item_count(config, CONF_ROUTER);
+ if (count == 1) {
+ router_area = dx_config_item_value_string(config, CONF_ROUTER, 0, "area");
+ router_id = dx_config_item_value_string(config, CONF_ROUTER, 0, "router-id");
+ }
+ }
+
+ if (thread_count == 0)
+ thread_count = 1;
+
if (!container_name)
container_name = "00000000-0000-0000-0000-000000000000"; // TODO - gen a real uuid
@@ -64,16 +95,20 @@ dx_dispatch_t *dx_dispatch(int thread_count, const char *container_name,
dx_container_setup_agent(dx);
dx_router_setup_agent(dx);
+ dx_config_free(config);
+
return dx;
}
void dx_dispatch_free(dx_dispatch_t *dx)
{
+ dx_config_finalize();
dx_agent_free(dx->agent);
dx_router_free(dx->router);
dx_container_free(dx->container);
dx_server_free(dx->server);
dx_log_finalize();
+ dx_python_finalize();
}
diff --git a/extras/dispatch/src/py/config/__init__.py b/extras/dispatch/src/py/config/__init__.py
new file mode 100644
index 0000000000..349026251a
--- /dev/null
+++ b/extras/dispatch/src/py/config/__init__.py
@@ -0,0 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+from config.configparse import DXConfig
diff --git a/extras/dispatch/src/py/config/configparse.py b/extras/dispatch/src/py/config/configparse.py
new file mode 100644
index 0000000000..051c3d3187
--- /dev/null
+++ b/extras/dispatch/src/py/config/configparse.py
@@ -0,0 +1,146 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements. See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership. The ASF licenses this file
+## to you 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
+##
+
+import json
+
+class DXConfig:
+ """
+ Configuration File Parser for Qpid Dispatch
+
+ Configuration files are made up of "sections" having the following form:
+
+ section-name {
+ key0: value0
+ key1: value1
+ ...
+ keyN: valueN
+ }
+
+ Sections may be repeated (i.e. there may be multiple instances with the same section name).
+ The keys must be unique within a section. Values can be of string or integer types. No
+ quoting is necessary anywhere in the configuration file. Values may contain whitespace.
+
+ Comment lines starting with the '#' character will be ignored.
+
+ This parser converts the configuration file into a json string where the file is represented
+ as a list of maps. Each map has one item, the key being the section name and the value being
+ a nested map of keys and values from the file. This json string is parsed into a data
+ structure that may then be queried.
+
+ """
+
+ def __init__(self, path):
+ self.path = path
+ self.config = None
+
+ cfile = open(self.path)
+ text = cfile.read()
+ cfile.close()
+
+ self.json_text = "[" + self._toJson(text) + "]"
+ self.config = json.loads(self.json_text);
+
+
+ def __repr__(self):
+ return "%r" % self.config
+
+
+ def _toJson(self, text):
+ lines = text.split('\n')
+ stripped = ""
+ for line in lines:
+ sline = line.strip()
+
+ #
+ # Ignore empty lines
+ #
+ if len(sline) == 0:
+ continue
+
+ #
+ # Ignore comment lines
+ #
+ if sline.find('#') == 0:
+ continue
+
+ #
+ # Convert section opens, closes, and colon-separated key:value lines into json
+ #
+ if sline[-1:] == '{':
+ sline = '{"' + sline[:-1].strip() + '" : {'
+ elif sline == '}':
+ sline = '}},'
+ else:
+ colon = sline.find(':')
+ if colon > 1:
+ sline = '"' + sline[:colon] + '":"' + sline[colon+1:].strip() + '",'
+ stripped += sline
+
+ #
+ # Remove the trailing commas in map entries
+ #
+ stripped = stripped.replace(",}", "}")
+
+ #
+ # Return the entire document minus the trailing comma
+ #
+ return stripped[:-1]
+
+
+ def _getSection(self, section):
+ result = []
+ for item in self.config:
+ if item.__class__ == dict and section in item:
+ result.append(item[section])
+ return result
+
+
+ def item_count(self, section):
+ """
+ Return the number of items in a section (i.e. the number if instances of a section-name).
+ """
+ sec = self._getSection(section)
+ return len(sec)
+
+ def _value(self, section, idx, key):
+ sec = self._getSection(section)
+ if idx >= len(sec):
+ return None
+ item = sec[idx]
+ if item.__class__ == dict and key in item:
+ return item[key]
+ return None
+
+ def value_string(self, section, idx, key):
+ """
+ Return the string value for the key in the idx'th item in the section.
+ """
+ value = self._value(section, idx, key)
+ if value:
+ return str(value)
+ return None
+
+ def value_int(self, section, idx, key):
+ """
+ Return the integer value for the key in the idx'th item in the section.
+ """
+ value = self._value(section, idx, key)
+ return long(value)
+
+
diff --git a/extras/dispatch/src/python_embedded.c b/extras/dispatch/src/python_embedded.c
new file mode 100644
index 0000000000..17c97ae10e
--- /dev/null
+++ b/extras/dispatch/src/python_embedded.c
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "python_embedded.h"
+#include <qpid/dispatch/threading.h>
+#include <qpid/dispatch/log.h>
+
+static uint32_t ref_count = 0;
+static sys_mutex_t *lock = 0;
+static char *log_module = "PYTHON";
+
+void dx_python_initialize()
+{
+ lock = sys_mutex();
+}
+
+
+void dx_python_finalize()
+{
+ assert(ref_count == 0);
+ sys_mutex_free(lock);
+}
+
+
+void dx_python_start()
+{
+ sys_mutex_lock(lock);
+ if (ref_count == 0) {
+ Py_Initialize();
+ dx_log(log_module, LOG_TRACE, "Embedded Python Interpreter Initialized");
+ }
+ ref_count++;
+ sys_mutex_unlock(lock);
+}
+
+
+void dx_python_stop()
+{
+ sys_mutex_lock(lock);
+ ref_count--;
+ if (ref_count == 0) {
+ Py_Finalize();
+ dx_log(log_module, LOG_TRACE, "Embedded Python Interpreter Shut Down");
+ }
+ sys_mutex_unlock(lock);
+}
+
+
diff --git a/extras/dispatch/src/python_embedded.h b/extras/dispatch/src/python_embedded.h
new file mode 100644
index 0000000000..455925eecf
--- /dev/null
+++ b/extras/dispatch/src/python_embedded.h
@@ -0,0 +1,29 @@
+#ifndef __python_embedded_h__
+#define __python_embedded_h__ 1
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 <Python.h>
+
+void dx_python_initialize();
+void dx_python_finalize();
+void dx_python_start();
+void dx_python_stop();
+
+#endif
diff --git a/extras/dispatch/src/router_node.c b/extras/dispatch/src/router_node.c
index e361e9ce8e..bfa89eddf4 100644
--- a/extras/dispatch/src/router_node.c
+++ b/extras/dispatch/src/router_node.c
@@ -509,6 +509,8 @@ dx_router_t *dx_router(dx_dispatch_t *dx, const char *area, const char *id)
//
dx_field_iterator_set_address(area, id);
+ dx_log(module, LOG_INFO, "Router started, area=%s id=%s", area, id);
+
return router;
}
diff --git a/extras/dispatch/src/server.c b/extras/dispatch/src/server.c
index fccee7fac0..41df72e1b5 100644
--- a/extras/dispatch/src/server.c
+++ b/extras/dispatch/src/server.c
@@ -605,6 +605,8 @@ dx_server_t *dx_server(int thread_count, const char *container_name)
dx_server->pause_now_serving = 0;
dx_server->pending_signal = 0;
+ dx_log(module, LOG_INFO, "Container Name: %s", dx_server->container_name);
+
return dx_server;
}
@@ -727,6 +729,7 @@ void dx_server_signal(dx_dispatch_t *dx, int signum)
dx_server->pending_signal = signum;
sys_cond_signal_all(dx_server->cond);
+ pn_driver_wakeup(dx_server->driver);
}