implemented iconv descriptor cache
authorVictor Kirhenshtein <victor@netxms.org>
Thu, 18 Sep 2014 18:59:35 +0000 (21:59 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Thu, 18 Sep 2014 18:59:35 +0000 (21:59 +0300)
configure.ac
src/libnetxms/Makefile.am
src/libnetxms/iconv.cpp [new file with mode: 0644]
src/libnetxms/unicode.cpp
tests/include/testtools.h
tests/test-libnetxms/test-libnetxms.cpp

index 0dcafb4..490ddb9 100644 (file)
@@ -380,6 +380,11 @@ AC_ARG_ENABLE(iconv,
        DISABLE_ICONV="yes"
 ])
 
+AC_ARG_ENABLE(iconv-cache,
+[AS_HELP_STRING([--enable-iconv-cache=@<:@yes/no/auto@:>@],
+[cache iconv descriptors [default=auto]])],,
+[enable_iconv_cache=auto])
+
 AC_ARG_ENABLE(readline,
 [AS_HELP_STRING(--disable-readline,do not use libreadline)],
 [
@@ -2121,6 +2126,49 @@ AC_RUN_IFELSE(
   [ AC_MSG_RESULT(no) ]
 )
 
+AC_MSG_CHECKING(whether iconv supports state reset)
+AC_RUN_IFELSE(
+  [AC_LANG_PROGRAM([
+#include <stdio.h>
+#if HAVE_ICONV_H
+#include <iconv.h>
+#endif
+     ], [
+     iconv_t cd = iconv_open("UTF-8","$valid_ucs2_code");
+     if (cd == (iconv_t)(-1)) return 1;
+     return iconv(cd, NULL, NULL, NULL, NULL) != 0;
+     ])
+  ],
+  [ AC_MSG_RESULT(yes)
+    AC_DEFINE(HAVE_ICONV_STATE_RESET, 1, Define to 1 if iconv supports state reset)
+  ],
+  [ AC_MSG_RESULT(no) ],
+  [ AC_MSG_RESULT(no) ]
+)
+
+AC_MSG_CHECKING(whether iconv descriptor cache is needed)
+case $enable_iconv_cache in
+    auto)
+        case $PLATFORM in
+            SunOS|HP-UX|AIX)
+                enable_iconv_cache=yes
+                ;;
+            *)
+                enable_iconv_cache=no
+                ;;
+        esac
+        ;;
+    yes|no)
+        ;;
+    *)
+        AC_MSG_ERROR([Value given to --enable-iconv-cache must be one of yes, no or auto])
+        ;;
+esac
+if test "x$enable_iconv_cache" = "xyes"; then
+    AC_DEFINE(WITH_ICONV_CACHE, 1, Define to 1 to enable iconv descriptor cache)
+fi
+AC_MSG_RESULT($enable_iconv_cache)
+
 # taken from ZSH's configure
 # Check if iconv uses const in prototype declaration
 if test "x$ac_found_iconv" = "xyes"; then
@@ -2143,6 +2191,9 @@ if test "x$ac_found_iconv" = "xyes"; then
     [Define as const if the declaration of iconv() needs const.])
 fi
 
+AC_MSG_CHECKING(if iconv descriptor cache is needed)
+
+
 if test "x$ac_cv_type_wchar_t" = "xyes"; then
        if test $ac_cv_sizeof_wchar_t -eq 2; then
                AC_DEFINE(UNICODE_UCS2, 1, Define to 1 if you have 2-byte wchar_t)
index db846a0..869a852 100644 (file)
@@ -1,6 +1,6 @@
 SOURCES = agent.cpp array.cpp base64.cpp config.cpp crypto.cpp dirw_unix.c \
          gen_uuid.c geolocation.cpp getopt.c dload.cpp hash.cpp ice.c \
-         icmp.cpp inetaddr.cpp log.cpp main.cpp md5.cpp message.cpp \
+         icmp.cpp iconv.cpp inetaddr.cpp log.cpp main.cpp md5.cpp message.cpp \
          msgwq.cpp net.cpp nxcp.cpp parisc_atomic.cpp qsort.c queue.cpp \
          rwlock.cpp scandir.c serial.cpp sha1.cpp solaris9_atomic.c \
          string.cpp stringlist.cpp strmap.cpp strmapbase.cpp strptime.c \
diff --git a/src/libnetxms/iconv.cpp b/src/libnetxms/iconv.cpp
new file mode 100644 (file)
index 0000000..bdc4635
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ ** NetXMS - Network Management System
+ ** Copyright (C) 2003-2014 Raden Solutions
+ **
+ ** This program is free software; you can redistribute it and/or modify
+ ** it under the terms of the GNU Lesser General Public License as published
+ ** by the Free Software Foundation; either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU Lesser General Public License
+ ** along with this program; if not, write to the Free Software
+ ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ **
+ ** File: iconv.cpp
+ **
+ **/
+
+#include "libnetxms.h"
+
+#if HAVE_ICONV_H
+#include <iconv.h>
+#endif
+
+#if !defined(__DISABLE_ICONV) && WITH_ICONV_CACHE
+
+/**
+ * iconv descriptor
+ */
+struct ICONV_DESCRIPTOR
+{
+   char *from;
+   char *to;
+   iconv_t cd;
+   bool busy;
+};
+
+/**
+ * iconv descriptor cache
+ */
+static ObjectArray<ICONV_DESCRIPTOR> s_cache;
+
+/**
+ * Cache access mutex
+ */
+static MUTEX s_cacheLock = MutexCreate();
+
+/**
+ * Open descriptor
+ */
+iconv_t IconvOpen(const char *to, const char *from)
+{
+   iconv_t cd = (iconv_t)(-1);
+
+   MutexLock(s_cacheLock);
+
+   for(int i = 0; i < s_cache.size(); i++)
+   {
+      ICONV_DESCRIPTOR *d = s_cache.get(i);
+      if (!d->busy && !strcmp(from, d->from) && !strcmp(to, d->to))
+      {
+         d->busy = true;
+         cd = d->cd;
+         break;
+      }
+   }
+
+   if (cd == (iconv_t)(-1))
+   {
+      cd = iconv_open(to, from);
+      if (cd != (iconv_t)(-1))
+      {
+         ICONV_DESCRIPTOR *d = new ICONV_DESCRIPTOR;
+         d->cd = cd;
+         d->busy = true;
+         d->from = strdup(from);
+         d->to = strdup(to);
+         s_cache.add(d);
+      }
+   }
+
+   MutexUnlock(s_cacheLock);
+   return cd;
+}
+
+/**
+ * Close descriptor
+ */
+void IconvClose(iconv_t cd)
+{
+   MutexLock(s_cacheLock);
+   for(int i = 0; i < s_cache.size(); i++)
+   {
+      ICONV_DESCRIPTOR *d = s_cache.get(i);
+      if (d->cd == cd)
+      {
+#if HAVE_ICONV_STATE_RESET
+         iconv(cd, NULL, NULL, NULL, NULL);
+#endif
+         d->busy = false;
+         break;
+      }
+   }
+   MutexUnlock(s_cacheLock);
+}
+
+#endif /* !defined(__DISABLE_ICONV) && WITH_ICONV_CACHE */
index 1c91b0f..08fe73b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  ** NetXMS - Network Management System
- ** Copyright (C) 2003-2014 NetXMS Team
+ ** Copyright (C) 2003-2014 RAden Solutions
  **
  ** This program is free software; you can redistribute it and/or modify
  ** it under the terms of the GNU Lesser General Public License as published
@@ -23,9 +23,8 @@
 #include "libnetxms.h"
 
 /**
- * Static data
+ * Default codepage
  */
-
 static char m_cpDefault[MAX_CODEPAGE_LEN] = ICONV_DEFAULT_CODEPAGE;
 
 #ifndef _WIN32
@@ -37,9 +36,17 @@ static char m_cpDefault[MAX_CODEPAGE_LEN] = ICONV_DEFAULT_CODEPAGE;
 /**
  * UNICODE character set
  */
-
 #ifndef __DISABLE_ICONV
 
+// iconv cache functions
+#if WITH_ICONV_CACHE
+iconv_t IconvOpen(const char *to, const char *from);
+void IconvClose(iconv_t cd);
+#else
+#define IconvOpen iconv_open
+#define IconvClose iconv_close
+#endif
+
 // configure first test for libiconv, then for iconv
 // if libiconv was found, HAVE_ICONV will not be set correctly
 #if HAVE_LIBICONV
@@ -211,7 +218,7 @@ inline int WideCharToMultiByteIconv(int iCodePage, DWORD dwFlags, const WCHAR *p
    strcat(cp, "//IGNORE");
 #endif /* HAVE_ICONV_IGNORE */
 
-   cd = iconv_open(iCodePage == CP_UTF8 ? "UTF-8" : cp, UNICODE_CODEPAGE_NAME);
+   cd = IconvOpen(iCodePage == CP_UTF8 ? "UTF-8" : cp, UNICODE_CODEPAGE_NAME);
    if (cd == (iconv_t)(-1))
    {
       return WideCharToMultiByteSimpleCopy(iCodePage, dwFlags, pWideCharStr, cchWideChar, pByteStr, cchByteChar, pDefaultChar, pbUsedDefChar);
@@ -222,7 +229,7 @@ inline int WideCharToMultiByteIconv(int iCodePage, DWORD dwFlags, const WCHAR *p
    outbuf = pByteStr;
    outbytes = cchByteChar;
    nRet = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
-   iconv_close(cd);
+   IconvClose(cd);
    if (nRet == -1)
    {
       if (errno == EILSEQ)
@@ -306,7 +313,7 @@ inline int MultiByteToWideCharIconv(int iCodePage, DWORD dwFlags, const char *pB
    char *outbuf;
    size_t inbytes, outbytes;
 
-   cd = iconv_open(UNICODE_CODEPAGE_NAME, iCodePage == CP_UTF8 ? "UTF-8" : m_cpDefault);
+   cd = IconvOpen(UNICODE_CODEPAGE_NAME, iCodePage == CP_UTF8 ? "UTF-8" : m_cpDefault);
    if (cd == (iconv_t)(-1))
    {
       return MultiByteToWideCharSimpleCopy(iCodePage, dwFlags, pByteStr, cchByteChar, pWideCharStr, cchWideChar);
@@ -317,7 +324,7 @@ inline int MultiByteToWideCharIconv(int iCodePage, DWORD dwFlags, const char *pB
    outbuf = (char *)pWideCharStr;
    outbytes = cchWideChar * sizeof(WCHAR);
    nRet = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
-   iconv_close(cd);
+   IconvClose(cd);
 
    if (nRet == -1)
    {
@@ -503,7 +510,7 @@ size_t LIBNETXMS_EXPORTABLE ucs2_to_ucs4(const UCS2CHAR *src, int srcLen, WCHAR
    char *outbuf;
    size_t count, inbytes, outbytes;
 
-   cd = iconv_open(UCS4_CODEPAGE_NAME, UCS2_CODEPAGE_NAME);
+   cd = IconvOpen(UCS4_CODEPAGE_NAME, UCS2_CODEPAGE_NAME);
    if (cd == (iconv_t) (-1))
    {
       return __internal_ucs2_to_ucs4(src, srcLen, dst, dstLen);
@@ -514,7 +521,7 @@ size_t LIBNETXMS_EXPORTABLE ucs2_to_ucs4(const UCS2CHAR *src, int srcLen, WCHAR
    outbuf = (char *) dst;
    outbytes = (size_t) dstLen * sizeof(WCHAR);
    count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
-   iconv_close(cd);
+   IconvClose(cd);
 
    if (count == (size_t) - 1)
    {
@@ -549,7 +556,7 @@ size_t LIBNETXMS_EXPORTABLE ucs4_to_ucs2(const WCHAR *src, int srcLen, UCS2CHAR
    char *outbuf;
    size_t count, inbytes, outbytes;
 
-   cd = iconv_open(UCS2_CODEPAGE_NAME, UCS4_CODEPAGE_NAME);
+   cd = IconvOpen(UCS2_CODEPAGE_NAME, UCS4_CODEPAGE_NAME);
    if (cd == (iconv_t) (-1))
    {
       return __internal_ucs4_to_ucs2(src, srcLen, dst, dstLen);
@@ -560,7 +567,7 @@ size_t LIBNETXMS_EXPORTABLE ucs4_to_ucs2(const WCHAR *src, int srcLen, UCS2CHAR
    outbuf = (char *) dst;
    outbytes = (size_t) dstLen * sizeof(UCS2CHAR);
    count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
-   iconv_close(cd);
+   IconvClose(cd);
 
    if (count == (size_t) - 1)
    {
@@ -666,7 +673,7 @@ inline size_t ucs2_to_utf8_iconv(const UCS2CHAR *src, int srcLen, char *dst, int
    char *outbuf;
    size_t count, inbytes, outbytes;
 
-   cd = iconv_open("UTF-8", UCS2_CODEPAGE_NAME);
+   cd = IconvOpen("UTF-8", UCS2_CODEPAGE_NAME);
    if (cd == (iconv_t) (-1))
    {
       return ucs2_to_utf8_simple_copy(src, srcLen, dst, dstLen);
@@ -677,7 +684,7 @@ inline size_t ucs2_to_utf8_iconv(const UCS2CHAR *src, int srcLen, char *dst, int
    outbuf = (char *) dst;
    outbytes = (size_t) dstLen;
    count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
-   iconv_close(cd);
+   IconvClose(cd);
 
    if (count == (size_t) - 1)
    {
@@ -746,7 +753,7 @@ inline size_t ucs2_to_mb_iconv(const UCS2CHAR *src, int srcLen, char *dst, int d
    char *outbuf;
    size_t count, inbytes, outbytes;
 
-   cd = iconv_open(m_cpDefault, UCS2_CODEPAGE_NAME);
+   cd = IconvOpen(m_cpDefault, UCS2_CODEPAGE_NAME);
    if (cd == (iconv_t) (-1))
    {
       return ucs2_to_mb_simple_copy(src, srcLen, dst, dstLen);
@@ -757,7 +764,7 @@ inline size_t ucs2_to_mb_iconv(const UCS2CHAR *src, int srcLen, char *dst, int d
    outbuf = (char *) dst;
    outbytes = (size_t) dstLen;
    count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
-   iconv_close(cd);
+   IconvClose(cd);
 
    if (count == (size_t) - 1)
    {
@@ -818,7 +825,7 @@ inline size_t mb_to_ucs2_iconv(const char *src, int srcLen, UCS2CHAR *dst, int d
    char *outbuf;
    size_t count, inbytes, outbytes;
 
-   cd = iconv_open(UCS2_CODEPAGE_NAME, m_cpDefault);
+   cd = IconvOpen(UCS2_CODEPAGE_NAME, m_cpDefault);
    if (cd == (iconv_t) (-1))
    {
       return mb_to_ucs2_simple_copy(src, srcLen, dst, dstLen);
@@ -829,7 +836,7 @@ inline size_t mb_to_ucs2_iconv(const char *src, int srcLen, UCS2CHAR *dst, int d
    outbuf = (char *) dst;
    outbytes = (size_t) dstLen * sizeof(UCS2CHAR);
    count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
-   iconv_close(cd);
+   IconvClose(cd);
 
    if (count == (size_t) - 1)
    {
index 22b2233..edb252e 100644 (file)
@@ -4,7 +4,7 @@
 /**
  * Assert failure
  */
-#define Assert(c) do { if (!(c)) { _tprintf(_T("FAIL\nAssert failed at %s:%d\n"), __FILE__, __LINE__); exit(1); } } while(0)
+#define Assert(c) do { if (!(c)) { _tprintf(_T("FAIL\nAssert failed at %hs:%d\n"), __FILE__, __LINE__); exit(1); } } while(0)
 
 /**
  * Assert that two values are equal
index 10644b9..d9a648a 100644 (file)
@@ -182,7 +182,7 @@ static void TestStringSet()
 /**
  * main()
  */
-int main(int argc, char *argv)
+int main(int argc, char *argv[])
 {
    TestStringConversion();
    TestStringMap();