$NetBSD: patch-9080,v 1.1 2014/11/18 14:38:15 manu Exp $
From db7e7d493f763e0128c879280c9cec01bdea4260 Mon Sep 17 00:00:00 2001
From: Emmanuel Dreyfus <manu@netbsd.org>
Date: Thu, 30 Oct 2014 01:43:32 +0100
Subject: [PATCH] glupy: portability fixes

Fixes portability problems so that NetBSD passes tests/features/glupy.t

- Use python-config to detect python build environment on all systems,
  not just Linux and Darwin.
- Get the site-package directory from python and make sure we install
  glupy.py there, Previously we installed within glusterfs prefix,
  which caused a problem if it was different that python's prefix.
- Set PYTHONPATH for tests so that the detected site-packages is used
  in python's search path. This should be useless, but let us have it
  just in case.
- Pass glupy.so path from glusterfsd to glupy.py through an
  environment variable and use it in CDLL instead of "", as the
  later seems not portable (at least it fails on NetBSD).
- Use gil_init_key pthread_getspecific to avoid deadlocks (that
  code was #ifdef out, perhaps because it was not needed on Linux,
  but it seems to be required for NetBSD.
- Recover the error message from Python and send it to the logs
  to help debugging problems.

Backport of: http://review.gluster.org/8978

BUG: 1138897
Change-Id: I1e23ba5cc18f129ee1032f905cb053953b683a81
Signed-off-by: Emmanuel Dreyfus <manu@netbsd.org>
---
 configure.ac                           | 18 +++++----------
 tests/env.rc.in                        |  5 ++++-
 tests/features/glupy.t                 |  1 +
 xlators/features/glupy/src/Makefile.am |  4 ++--
 xlators/features/glupy/src/glupy.c     | 40 +++++++++++++++++++++++++---------
 xlators/features/glupy/src/glupy.py    |  3 ++-
 6 files changed, 45 insertions(+), 26 deletions(-)

diff --git configure.ac configure.ac
index ddc2cc5..dfcd976 100644
--- configure.ac
+++ configure.ac
@@ -217,6 +217,7 @@ AC_CANONICAL_HOST
 AC_PROG_CC
 AC_DISABLE_STATIC
 AC_PROG_LIBTOOL
+AC_SUBST([shrext_cmds])
 
 AC_CHECK_PROG([RPCGEN], [rpcgen], [yes], [no])
 
@@ -967,18 +968,9 @@ saved_CFLAGS=$CFLAGS
 saved_CPPFLAGS=$CPPFLAGS
 saved_LDFLAGS=$LDFLAGS
 
-case $host_os in
-     linux*)
-       CFLAGS="`${PYTHON}-config --cflags`"
-       CPPFLAGS=$CFLAGS
-       LDFLAGS="-L`${PYTHON}-config --prefix`/lib `${PYTHON}-config --ldflags`"
-       ;;
-     darwin*)
-       CFLAGS="`${PYTHON}-config --cflags`"
-       CPPFLAGS=$CFLAGS
-       LDFLAGS="-L`${PYTHON}-config --prefix`/lib `${PYTHON}-config --ldflags`"
-       ;;
-esac
+CFLAGS="`${PYTHON}-config --cflags`"
+CPPFLAGS=$CFLAGS
+LDFLAGS="-L`${PYTHON}-config --prefix`/lib `${PYTHON}-config --ldflags`"
 
 AC_CHECK_HEADERS([python$PYTHON_VERSION/Python.h],[have_Python_h=yes],[])
 AC_ARG_ENABLE([glupy],
@@ -1029,12 +1021,14 @@ case $host_os in
 esac
 
 if test "x$BUILD_GLUPY" = "xyes"; then
+   BUILD_PYTHON_SITE_PACKAGES=`$PYTHON -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())'`
    BUILD_PYTHON_INC=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_inc()"`
    BUILD_PYTHON_LIB=python$PYTHON_VERSION
    GLUPY_SUBDIR=glupy
    GLUPY_SUBDIR_MAKEFILE=xlators/features/glupy/Makefile
    GLUPY_SUBDIR_SRC_MAKEFILE=xlators/features/glupy/src/Makefile
    echo "building glupy with -isystem $BUILD_PYTHON_INC -l $BUILD_PYTHON_LIB"
+   AC_SUBST(BUILD_PYTHON_SITE_PACKAGES)
    AC_SUBST(BUILD_PYTHON_INC)
    AC_SUBST(BUILD_PYTHON_LIB)
    AC_SUBST(GLUPY_SUBDIR)
diff --git tests/env.rc.in tests/env.rc.in
index 000a80f..1850b7a 100644
--- tests/env.rc.in
+++ tests/env.rc.in
@@ -8,4 +8,7 @@ LD_LIBRARY_PATH=@libdir@:$LD_LIBRARY_PATH
 export LD_LIBRARY_PATH
 
 GLUSTERD_WORKDIR=@GLUSTERD_WORKDIR@
-export GLUSTERD_WORKDIR
\ No newline at end of file
+export GLUSTERD_WORKDIR
+
+PYTHONPATH=@BUILD_PYTHON_SITE_PACKAGES@:$PYTHON_PATH
+export PYTHONPATH
diff --git tests/features/glupy.t tests/features/glupy.t
index a34e48f..8b79a14 100755
--- tests/features/glupy.t
+++ tests/features/glupy.t
@@ -3,6 +3,7 @@
 . $(dirname $0)/../include.rc
 . $(dirname $0)/../volume.rc
 
+echo $PYTHON_PATH >&2
 cleanup;
 
 TEST mkdir -p $B0/glupytest
diff --git xlators/features/glupy/src/Makefile.am xlators/features/glupy/src/Makefile.am
index d9361a5..de8b0de 100644
--- xlators/features/glupy/src/Makefile.am
+++ xlators/features/glupy/src/Makefile.am
@@ -4,7 +4,7 @@ xlator_LTLIBRARIES = glupy.la
 xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features
 glupydir = $(xlatordir)/glupy
 AM_CPPFLAGS = $(PYTHONDEV_CPPFLAGS) $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src -isystem $(BUILD_PYTHON_INC)
-AM_CFLAGS = $(PYTHONDEV_CFLAGS) -Wall -fno-strict-aliasing -DGLUSTER_PYTHON_PATH=\"$(glupydir)\" $(GF_CFLAGS)
+AM_CFLAGS = $(PYTHONDEV_CFLAGS) -Wall -fno-strict-aliasing -DGLUSTER_PYTHON_PATH=\"$(glupydir)\" -DPATH_GLUSTERFS_GLUPY_MODULE=\"${xlatordir}/glupy${shrext_cmds}\" $(GF_CFLAGS)
 
 # Flags to build glupy.so with
 glupy_la_LDFLAGS = $(PYTHONDEV_LDFLAGS) -module -avoid-version -shared -nostartfiles
@@ -15,7 +15,7 @@ glupy_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \
 noinst_HEADERS = glupy.h
 
 # Install glupy.py into the Python site-packages area
-pyglupydir = $(pythondir)/gluster
+pyglupydir = @BUILD_PYTHON_SITE_PACKAGES@/gluster
 pyglupy_PYTHON = glupy.py __init__.py
 
 CLEANFILES =
diff --git xlators/features/glupy/src/glupy.c xlators/features/glupy/src/glupy.c
index 292f5b7..7bb88c0 100644
--- xlators/features/glupy/src/glupy.c
+++ xlators/features/glupy/src/glupy.c
@@ -31,12 +31,10 @@ pthread_key_t gil_init_key;
 PyGILState_STATE
 glupy_enter (void)
 {
-#if 0
         if (!pthread_getspecific(gil_init_key)) {
                 PyEval_ReleaseLock();
                 (void)pthread_setspecific(gil_init_key,(void *)1);
         }
-#endif
 
         return PyGILState_Ensure();
 }
@@ -2333,6 +2331,9 @@ init (xlator_t *this)
         PyObject                *py_args        = NULL;
         PyObject                *syspath        = NULL;
 	PyObject                *path           = NULL;
+	PyObject                *error_type     = NULL;
+	PyObject                *error_msg      = NULL;
+	PyObject                *error_bt       = NULL;
 	static gf_boolean_t      py_inited      = _gf_false;
         void *                   err_cleanup    = &&err_return;
 
@@ -2349,12 +2350,20 @@ init (xlator_t *this)
         err_cleanup = &&err_free_priv;
 
 	if (!py_inited) {
+	        /* 
+                 * This must be done before Py_Initialize(),
+                 * because it will duplicate the environment,
+                 * and fail to see later environment updates.
+                 */
+	        setenv("PATH_GLUSTERFS_GLUPY_MODULE",
+                       PATH_GLUSTERFS_GLUPY_MODULE, 1);
+
                 Py_Initialize();
                 PyEval_InitThreads();
-#if 0
+
                 (void)pthread_key_create(&gil_init_key,NULL);
                 (void)pthread_setspecific(gil_init_key,(void *)1);
-#endif
+
                 /* PyEval_InitThreads takes this "for" us.  No thanks. */
                 PyEval_ReleaseLock();
                 py_inited = _gf_true;
@@ -2370,7 +2379,9 @@ init (xlator_t *this)
         if (!py_mod_name) {
                 gf_log (this->name, GF_LOG_ERROR, "could not create name");
                 if (PyErr_Occurred()) {
-                        PyErr_Print();
+                        PyErr_Fetch (&error_type, &error_msg, &error_bt);
+                        gf_log (this->name, GF_LOG_ERROR, "Python error: %s",
+                                PyString_AsString(error_msg));
                 }
                 goto *err_cleanup;
         }
@@ -2379,9 +2390,12 @@ init (xlator_t *this)
         priv->py_module = PyImport_Import(py_mod_name);
         Py_DECREF(py_mod_name);
         if (!priv->py_module) {
-                gf_log (this->name, GF_LOG_ERROR, "Python import failed");
+                gf_log (this->name, GF_LOG_ERROR, "Python import of %s failed",
+                        module_name);
                 if (PyErr_Occurred()) {
-                        PyErr_Print();
+                        PyErr_Fetch (&error_type, &error_msg, &error_bt);
+                        gf_log (this->name, GF_LOG_ERROR, "Python error: %s",
+                                PyString_AsString(error_msg));
                 }
                 goto *err_cleanup;
         }
@@ -2392,7 +2406,9 @@ init (xlator_t *this)
         if (!py_init_func || !PyCallable_Check(py_init_func)) {
                 gf_log (this->name, GF_LOG_ERROR, "missing init func");
                 if (PyErr_Occurred()) {
-                        PyErr_Print();
+                        PyErr_Fetch (&error_type, &error_msg, &error_bt);
+                        gf_log (this->name, GF_LOG_ERROR, "Python error: %s",
+                                PyString_AsString(error_msg));
                 }
                 goto *err_cleanup;
         }
@@ -2402,7 +2418,9 @@ init (xlator_t *this)
         if (!py_args) {
                 gf_log (this->name, GF_LOG_ERROR, "could not create args");
                 if (PyErr_Occurred()) {
-                        PyErr_Print();
+                        PyErr_Fetch (&error_type, &error_msg, &error_bt);
+                        gf_log (this->name, GF_LOG_ERROR, "Python error: %s",
+                                PyString_AsString(error_msg));
                 }
                 goto *err_cleanup;
         }
@@ -2414,7 +2432,9 @@ init (xlator_t *this)
         if (!priv->py_xlator) {
                 gf_log (this->name, GF_LOG_ERROR, "Python init failed");
                 if (PyErr_Occurred()) {
-                        PyErr_Print();
+                        PyErr_Fetch (&error_type, &error_msg, &error_bt);
+                        gf_log (this->name, GF_LOG_ERROR, "Python error: %s",
+                                PyString_AsString(error_msg));
                 }
                 goto *err_cleanup;
         }
diff --git xlators/features/glupy/src/glupy.py xlators/features/glupy/src/glupy.py
index eda8aeb..b9fc370 100644
--- xlators/features/glupy/src/glupy.py
+++ xlators/features/glupy/src/glupy.py
@@ -9,9 +9,10 @@
 ##
 
 import sys
+import os
 from ctypes import *
 
-dl = CDLL("",RTLD_GLOBAL)
+dl = CDLL(os.getenv("PATH_GLUSTERFS_GLUPY_MODULE", ""),RTLD_GLOBAL)
 
 
 class call_frame_t (Structure):
-- 
1.8.2.3

