Merge branch 'master' of ssh://git.indexdata.com/home/git/pub/yaz
authorDennis Schafroth <dennis@indexdata.com>
Thu, 20 May 2010 14:25:31 +0000 (16:25 +0200)
committerDennis Schafroth <dennis@indexdata.com>
Thu, 20 May 2010 14:25:31 +0000 (16:25 +0200)
17 files changed:
configure.ac
debian/changelog
debian/control
doc/common
doc/installation.xml
include/yaz/Makefile.am
include/yaz/dirent.h
include/yaz/match_glob.h
include/yaz/spipe.h [new file with mode: 0644]
include/yaz/thread_create.h [new file with mode: 0644]
src/Makefile.am
src/condvar.c
src/spipe.c [new file with mode: 0644]
src/thread_create.c [new file with mode: 0644]
test/test_mutex.c
win/makefile
yaz.spec.in

index 59a283c..d158abd 100644 (file)
@@ -1,7 +1,7 @@
 dnl This file is part of the YAZ toolkit.
 dnl Copyright (C) 1995-2010 Index Data
 AC_PREREQ([2.60])
-AC_INIT([yaz],[4.0.8],[yaz-help@indexdata.dk])
+AC_INIT([yaz],[4.0.9],[yaz-help@indexdata.dk])
 AC_CONFIG_SRCDIR([configure.ac])
 AC_CONFIG_AUX_DIR([config])
 AM_INIT_AUTOMAKE([1.9])
index 9f0a2f6..75da0ed 100644 (file)
@@ -1,3 +1,9 @@
+yaz (4.0.9-1indexdata) unstable; urgency=low
+
+  * New yaz_thread functions
+
+ -- Adam Dickmeiss <adam@indexdata.dk>  Wed, 19 May 2010 15:19:25 +0200
+
 yaz (4.0.8-2indexdata) unstable; urgency=low
 
   * Remove *.la files
index 4e5a91d..911d10e 100644 (file)
@@ -37,7 +37,7 @@ Description: documentation for the Z39.50 toolkit
  This package includes HTML documentation for YAZ.
 
 Package: libyaz4-dev
-Depends: libyaz4 (= ${Source-Version}), libxslt1-dev, libicu36-dev|libicu-dev, libgnutls-dev, tcl8.3|tclsh
+Depends: libyaz4 (= ${Source-Version}), libxslt1-dev, libicu36-dev|libicu-dev, tcl8.3|tclsh
 Replaces: yaz-devel
 Conflicts: yaz-devel, libyaz-dev, libyaz2-dev, libyaz3-dev
 Section: libdevel
index cc80f24..ca4e4fa 160000 (submodule)
@@ -1 +1 @@
-Subproject commit cc80f24dcf550d033c2fdf29ea35b4e0961f357d
+Subproject commit ca4e4fa028634b4e07f011eb6375e205ae96c709
index e052ec0..7ef2b4e 100644 (file)
        <term><literal>HAVE_TCL</literal>, <literal>TCL</literal></term>
        <listitem><para>
          If <literal>HAVE_TCL</literal> is set to 1, nmake will
-         use the ASN.1 compiler (Tcl based). You must set
-         <literal>TCL</literal> to the full path of the Tcl
+         use the ASN.1 compiler (<ulink url="&url.tcl;">Tcl</ulink> based).
+         You must set <literal>TCL</literal> to the full path of the Tcl
          interpreter.
         </para>
         <para>
index 72e5896..015c5a7 100644 (file)
@@ -20,7 +20,8 @@ pkginclude_HEADERS= backend.h ccl.h ccl_xml.h cql.h rpn2cql.h comstack.h \
  z-univ.h z-oclcui.h zes-expi.h zes-exps.h zes-order.h zes-pquery.h \
  zes-psched.h zes-admin.h zes-pset.h zes-update.h zes-update0.h \
  zoom.h z-charneg.h charneg.h soap.h srw.h zgdu.h matchstr.h json.h \
- file_glob.h dirent.h thread_id.h gettimeofday.h shptr.h
+ file_glob.h dirent.h thread_id.h gettimeofday.h shptr.h thread_create.h \
+ spipe.h
 
 EXTRA_DIST = yaz-version.h.in
 
index 1f5d68f..b565ec2 100644 (file)
@@ -43,9 +43,9 @@ struct dirent {
 
 typedef struct DIR DIR;
 
-DIR *opendir (const char *path);
-struct dirent *readdir (DIR *dd);
-void closedir (DIR *dd);
+YAZ_EXPORT DIR *opendir (const char *path);
+YAZ_EXPORT struct dirent *readdir (DIR *dd);
+YAZ_EXPORT void closedir (DIR *dd);
 
 YAZ_END_CDECL
 
index 6ff7eaf..a06e02e 100644 (file)
@@ -46,6 +46,7 @@ YAZ_BEGIN_CDECL
           * (any number of any char)
     * (zero or more)
 */
+YAZ_EXPORT
 int yaz_match_glob(const char *glob, const char *text);
 
 YAZ_END_CDECL
diff --git a/include/yaz/spipe.h b/include/yaz/spipe.h
new file mode 100644 (file)
index 0000000..1b48650
--- /dev/null
@@ -0,0 +1,78 @@
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) 1995-2010 Index Data.
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Index Data nor the names of its contributors
+ *       may be used to endorse or promote products derived from this
+ *       software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file spipe.h
+ * \brief socket-pipe header
+ */
+#ifndef YAZ_SPIPE_H
+#define YAZ_SPIPE_H
+
+#include <stddef.h>
+#include <time.h>
+#include <yaz/yconfig.h>
+#include <yaz/wrbuf.h>
+
+YAZ_BEGIN_CDECL
+
+/** \brief YAZ socket pipe opaque pointer */
+typedef struct yaz_spipe *yaz_spipe_t;
+
+/** \brief create socket pipe
+    \param port_to_use port that we temporarily bind to
+    \param err_msg error message reference (0 if not to be set)
+    \returns 0 on failure; != 0 on success
+ */
+YAZ_EXPORT yaz_spipe_t yaz_spipe_create(int port_to_use, WRBUF *err_msg);
+
+/** \brief destroys socket pipe
+    \param p socket pipe pointer
+ */
+YAZ_EXPORT void yaz_spipe_destroy(yaz_spipe_t p);
+
+/** \brief returns reading socket
+    \param p socket pipe pointer
+ */
+YAZ_EXPORT int yaz_spipe_get_read_fd(yaz_spipe_t p);
+
+/** \brief returns writing socket
+    \param p socket pipe pointer
+ */
+YAZ_EXPORT int yaz_spipe_get_write_fd(yaz_spipe_t p);
+
+YAZ_END_CDECL
+
+#endif
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
diff --git a/include/yaz/thread_create.h b/include/yaz/thread_create.h
new file mode 100644 (file)
index 0000000..d93bc03
--- /dev/null
@@ -0,0 +1,73 @@
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) 1995-2010 Index Data.
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Index Data nor the names of its contributors
+ *       may be used to endorse or promote products derived from this
+ *       software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file thread_create.h
+ * \brief Implements thread creation wrappers
+ */
+#ifndef YAZ_THREAD_CREATE_H
+#define YAZ_THREAD_CREATE_H
+
+#include <stddef.h>
+#include <time.h>
+#include <yaz/yconfig.h>
+
+YAZ_BEGIN_CDECL
+
+/** \brief Thread Identifier opaque pointer */
+typedef struct yaz_thread *yaz_thread_t;
+
+/** \brief create thread
+    \param start_routine thread handler
+    \param arg user data to be passed to handler
+    \returns thread_id identifier if successful; NULL on failure
+ */
+YAZ_EXPORT yaz_thread_t yaz_thread_create(void *(*start_routine)(void *p), void *arg);
+
+/** \brief join thread
+    \param tp thread_id reference .. Will be 0 upon completion
+    \param value_ptr ref pointer to routine result (0 if not needed)
+*/
+YAZ_EXPORT void yaz_thread_join(yaz_thread_t *tp, void **value_ptr);
+
+/** \brief detach thread
+    \param tp thread_id reference .. Will be 0 upon completion
+*/
+void yaz_thread_detach(yaz_thread_t *tp);
+
+YAZ_END_CDECL
+
+#endif
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
index 46e2e50..d8dd1e9 100644 (file)
@@ -103,7 +103,7 @@ libyaz_la_SOURCES=version.c options.c log.c \
   iconv_encode_marc8.c iconv_encode_iso_8859_1.c iconv_encode_wchar.c \
   iconv_decode_marc8.c iconv_decode_iso5426.c iconv_decode_danmarc.c sc.c \
   json.c xml_include.c file_glob.c dirent.c mutex-p.h mutex.c condvar.c \
-  thread_id.c gettimeofday.c
+  thread_id.c gettimeofday.c thread_create.c spipe.c
 
 libyaz_la_LDFLAGS=-version-info $(YAZ_VERSION_INFO)
 
index 5bbd92a..19291d4 100644 (file)
@@ -48,11 +48,14 @@ struct yaz_cond {
 
 void yaz_cond_create(YAZ_COND *p)
 {
-    *p = (YAZ_COND) malloc(sizeof(**p));
 #ifdef WIN32
+    *p = (YAZ_COND) malloc(sizeof(**p));
     InitializeConditionVariable(&(*p)->cond);
 #elif YAZ_POSIX_THREADS
+    *p = (YAZ_COND) malloc(sizeof(**p));
     pthread_cond_init(&(*p)->cond, 0);
+#else
+    *p = 0;
 #endif
 }
 
@@ -72,6 +75,7 @@ void yaz_cond_destroy(YAZ_COND *p)
 int yaz_cond_wait(YAZ_COND p, YAZ_MUTEX m, const struct timeval *abstime)
 {
 #ifdef WIN32
+    BOOL v;
     if (abstime)
     {
         struct timeval tval_now;
@@ -81,10 +85,11 @@ int yaz_cond_wait(YAZ_COND p, YAZ_MUTEX m, const struct timeval *abstime)
 
         sec = abstime->tv_sec - tval_now.tv_sec;
         msec = (abstime->tv_usec - tval_now.tv_usec) / 1000;
-        return SleepConditionVariableCS(&p->cond, &m->handle, sec*1000 + msec);
+        v = SleepConditionVariableCS(&p->cond, &m->handle, sec*1000 + msec);
     }
     else
-        return SleepConditionVariableCS(&p->cond, &m->handle, INFINITE);
+        v = SleepConditionVariableCS(&p->cond, &m->handle, INFINITE);
+    return v ? 0 : -1;
 #elif YAZ_POSIX_THREADS
     if (abstime)
     {
diff --git a/src/spipe.c b/src/spipe.c
new file mode 100644 (file)
index 0000000..52c922a
--- /dev/null
@@ -0,0 +1,283 @@
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) 1995-2010 Index Data
+ * See the file LICENSE for details.
+ */
+
+/**
+ * \file spipe.c
+ * \brief Implements socket-pipes
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <yaz/xmalloc.h>
+#include <yaz/nmem.h>
+#include <yaz/log.h>
+#include <yaz/spipe.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#define YAZ_INVALID_SOCKET INVALID_SOCKET
+#else
+#define YAZ_INVALID_SOCKET -1
+#include <fcntl.h>
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+struct yaz_spipe {
+    int m_fd[2];
+    int m_socket;
+};
+
+static void yaz_spipe_close(int *fd)
+{
+#ifdef WIN32
+    if (*fd != YAZ_INVALID_SOCKET)
+        closesocket(*fd);
+#else
+    if (*fd != YAZ_INVALID_SOCKET)
+        close(*fd);
+#endif
+    *fd = YAZ_INVALID_SOCKET;
+}
+
+static int nonblock(int s)
+{
+#ifdef WIN32
+    unsigned long tru = 1;
+    if (ioctlsocket(s, FIONBIO, &tru))
+        return -1;
+#else
+    if (fcntl(s, F_SETFL, O_NONBLOCK))
+        return -1;
+#endif
+    return 0;
+}
+
+yaz_spipe_t yaz_spipe_create(int port_to_use, WRBUF *err_msg)
+{
+    yaz_spipe_t p = xmalloc(sizeof(*p));
+
+#ifdef WIN32
+    {
+        WSADATA wsaData;
+        WORD wVersionRequested = MAKEWORD(2, 0);
+        if (WSAStartup( wVersionRequested, &wsaData))
+        {
+            if (err_msg)
+                wrbuf_printf(*err_msg, "WSAStartup failed");
+            xfree(p);
+            return 0;
+        }
+    }
+#endif
+    p->m_fd[0] = p->m_fd[1] = YAZ_INVALID_SOCKET;
+    p->m_socket = YAZ_INVALID_SOCKET;
+
+    if (port_to_use)
+    {
+        struct sockaddr_in add;
+        struct sockaddr *addr = 0;
+        unsigned int tmpadd;
+        struct sockaddr caddr;
+#ifdef WIN32
+        int caddr_len = sizeof(caddr);
+#else
+        socklen_t caddr_len = sizeof(caddr);
+#endif
+        fd_set write_set;
+
+        // create server socket
+        p->m_socket = socket(AF_INET, SOCK_STREAM, 0);
+        if (p->m_socket == YAZ_INVALID_SOCKET)
+        {
+            if (err_msg)
+                wrbuf_printf(*err_msg, "socket call failed");
+            yaz_spipe_destroy(p);
+            return 0;
+        }
+#ifndef WIN32
+        {
+            unsigned long one = 1;
+            if (setsockopt(p->m_socket, SOL_SOCKET, SO_REUSEADDR, (char*) 
+                           &one, sizeof(one)))
+            {
+                if (err_msg)
+                    wrbuf_printf(*err_msg, "setsockopt call failed");
+                yaz_spipe_destroy(p);
+                return 0;
+            }
+        }
+#endif
+        // bind server socket
+        add.sin_family = AF_INET;
+        add.sin_port = htons(port_to_use);
+        add.sin_addr.s_addr = INADDR_ANY;
+        addr = ( struct sockaddr *) &add;
+        
+        if (bind(p->m_socket, addr, sizeof(struct sockaddr_in)))
+        {
+            if (err_msg)
+                wrbuf_printf(*err_msg, "could not bind to socket");
+            yaz_spipe_destroy(p);
+            return 0;
+        }
+        
+        if (listen(p->m_socket, 3) < 0)
+        {
+            if (err_msg)
+                wrbuf_printf(*err_msg, "could not listen on socket");
+            yaz_spipe_destroy(p);
+            return 0;
+        }
+
+        // client socket
+        tmpadd = (unsigned) inet_addr("127.0.0.1");
+        if (!tmpadd)
+        {
+            if (err_msg)
+                wrbuf_printf(*err_msg, "inet_addr failed");
+            yaz_spipe_destroy(p);
+            return 0;
+        }
+        
+        memcpy(&add.sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
+        p->m_fd[1] = socket(AF_INET, SOCK_STREAM, 0);
+        if (p->m_fd[1] == YAZ_INVALID_SOCKET)
+        {
+            if (err_msg)
+                wrbuf_printf(*err_msg, "socket call failed (2)");
+            yaz_spipe_destroy(p);
+            return 0;
+        }
+        nonblock(p->m_fd[1]);
+
+        if (connect(p->m_fd[1], addr, sizeof(*addr)))
+        {
+            if (
+#ifdef WIN32
+            WSAGetLastError() != WSAEWOULDBLOCK
+#else
+            errno != EINPROGRESS
+#endif
+                )
+            {
+                if (err_msg)
+                    wrbuf_printf(*err_msg, "connect call failed");
+                yaz_spipe_destroy(p);
+                return 0;
+            }
+        }
+
+        /* server accept */
+        p->m_fd[0] = accept(p->m_socket, &caddr, &caddr_len);
+        if (p->m_fd[0] == YAZ_INVALID_SOCKET)
+        {
+            if (err_msg)
+                wrbuf_printf(*err_msg, "accept failed");
+            yaz_spipe_destroy(p);
+            return 0;
+        }
+
+        /* complete connect */
+        FD_ZERO(&write_set);
+        FD_SET(p->m_fd[1], &write_set);
+        if (select(p->m_fd[1]+1, 0, &write_set, 0, 0) != 1)
+        {
+            if (err_msg)
+                wrbuf_printf(*err_msg, "could not complete connect");
+            yaz_spipe_destroy(p);
+            return 0;
+        }
+        yaz_spipe_close(&p->m_socket);
+    }
+    else
+    {
+#ifdef WIN32
+        yaz_spipe_destroy(p);
+        return 0;
+#else
+        if (pipe(p->m_fd))
+        {
+            if (err_msg)
+                wrbuf_printf(*err_msg, "pipe call failed");
+            yaz_spipe_destroy(p);
+            return 0;
+        }
+        assert(p->m_fd[0] != YAZ_INVALID_SOCKET);
+        assert(p->m_fd[1] != YAZ_INVALID_SOCKET);
+#endif
+    }
+
+    return p;
+}
+
+void yaz_spipe_destroy(yaz_spipe_t p)
+{
+    yaz_spipe_close(&p->m_fd[0]);
+    yaz_spipe_close(&p->m_fd[1]);
+    yaz_spipe_close(&p->m_socket);
+    xfree(p);
+#ifdef WIN32
+    WSACleanup();
+#endif
+}
+
+int yaz_spipe_get_read_fd(yaz_spipe_t p)
+{
+    return p->m_fd[0];
+}
+
+int yaz_spipe_get_write_fd(yaz_spipe_t p)
+{
+    return p->m_fd[1];
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
diff --git a/src/thread_create.c b/src/thread_create.c
new file mode 100644 (file)
index 0000000..16be9c5
--- /dev/null
@@ -0,0 +1,129 @@
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) 1995-2010 Index Data
+ * See the file LICENSE for details.
+ */
+
+/**
+ * \file thread_create.c
+ * \brief Implements thread creation wrappers
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stddef.h>
+#include <yaz/xmalloc.h>
+#include <yaz/log.h>
+#include <yaz/thread_create.h>
+
+#if YAZ_POSIX_THREADS
+#include <pthread.h>
+#endif
+#ifdef WIN32
+#include <windows.h>
+#include <process.h>
+#endif
+
+struct yaz_thread {
+#if YAZ_POSIX_THREADS
+    pthread_t id;
+#else
+#ifdef WIN32
+    HANDLE handle;
+    void *(*routine)(void *p);
+#endif
+    void *data;
+#endif
+};
+
+#ifdef WIN32
+unsigned int __stdcall win32_routine(void *p)
+{
+    yaz_thread_t t = (yaz_thread_t) p;
+    void *userdata = t->data;
+    t->data = t->routine(userdata);
+    _endthreadex(0);
+    return 0;
+}
+#endif
+
+yaz_thread_t yaz_thread_create(void *(*start_routine)(void *p), void *arg)
+{
+    yaz_thread_t t = xmalloc(sizeof(*t));
+#if YAZ_POSIX_THREADS
+    int r = pthread_create(&t->id, 0, start_routine, arg);
+    if (r)
+    {
+        xfree(t);
+        t = 0;
+    }
+#else
+#ifdef WIN32
+    /* we create a wrapper on windows and pass yaz_thread struct to that */
+    unsigned threadID;
+    uintptr_t ex_ret;
+    t->data = arg; /* use data for both input and output */
+    t->routine = start_routine;
+    ex_ret = _beginthreadex(NULL, 0, win32_routine, t, 0, &threadID);
+    if (ex_ret == -1L)
+    {
+        xfree(t);
+        t = 0;
+    }
+    t->handle = (HANDLE) ex_ret;
+#else
+    t->data = start_routine(arg);
+#endif
+#endif
+    return t;
+}
+
+void yaz_thread_join(yaz_thread_t *tp, void **value_ptr)
+{
+    if (*tp)
+    {
+#ifdef YAZ_POSIX_THREADS
+        pthread_join((*tp)->id, value_ptr);
+#else
+#ifdef WIN32
+        WaitForSingleObject((*tp)->handle, INFINITE);
+        CloseHandle((*tp)->handle);
+#endif
+        if (value_ptr)
+            *value_ptr = (*tp)->data;
+#endif
+        xfree(*tp);
+        *tp = 0;
+    }
+}
+
+void yaz_thread_detach(yaz_thread_t *tp)
+{
+    if (*tp)
+    {
+#ifdef YAZ_POSIX_THREADS
+        pthread_detach((*tp)->id);
+#else
+#ifdef WIN32
+        CloseHandle((*tp)->handle);
+#endif
+#endif
+        xfree(*tp);
+        *tp = 0;
+    }
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
index 52853b1..a4483fc 100644 (file)
@@ -7,6 +7,7 @@
 #include <stdio.h>
 
 #include <yaz/mutex.h>
+#include <yaz/thread_create.h>
 #if HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
@@ -53,30 +54,61 @@ static void tst_cond(void)
         return;
 
     yaz_cond_create(&c);
-    YAZ_CHECK(c);
-    if (!c)
-        return;
-
-    r = yaz_gettimeofday(&abstime);
-    YAZ_CHECK_EQ(r, 0);
-    
-    abstime.tv_sec += 1; /* wait 1 second */
-    
-    r = yaz_cond_wait(c, p, &abstime);
-    YAZ_CHECK(r != 0);
+    if (c)
+    {
+        r = yaz_gettimeofday(&abstime);
+        YAZ_CHECK_EQ(r, 0);
+        
+        abstime.tv_sec += 1; /* wait 1 second */
+        
+        r = yaz_cond_wait(c, p, &abstime);
+        YAZ_CHECK(r != 0);
 
+    }
     yaz_cond_destroy(&c);
     YAZ_CHECK(c == 0);
     yaz_mutex_destroy(&p);
     YAZ_CHECK(p == 0);
 }
 
+static void *my_handler(void *arg)
+{
+    int *mydata = (int*) arg;
+    (*mydata)++;
+    return mydata;
+}
+
+static void tst_create_thread(void)
+{
+    void *return_data;
+    int mydata = 42;
+    yaz_thread_t t[2];
+
+    t[0] = yaz_thread_create(my_handler, &mydata);
+    YAZ_CHECK(t[0]);
+    t[1] = yaz_thread_create(my_handler, &mydata);
+    YAZ_CHECK(t[1]);
+    
+    return_data = 0;
+    yaz_thread_join(&t[0], &return_data);
+    YAZ_CHECK(!t[0]);
+    YAZ_CHECK(return_data == &mydata);
+
+    return_data = 0;
+    yaz_thread_join(&t[1], &return_data);
+    YAZ_CHECK(!t[1]);
+    YAZ_CHECK(return_data == &mydata);
+    
+    YAZ_CHECK_EQ(mydata, 44);
+}
+
 int main (int argc, char **argv)
 {
     YAZ_CHECK_INIT(argc, argv);
     YAZ_CHECK_LOG();
     tst_mutex();
     tst_cond();
+    tst_create_thread();
     YAZ_CHECK_TERM;
 }
 
index 7ba0dcb..7933622 100644 (file)
@@ -286,7 +286,7 @@ MT=echo
 LINK_LIBS= kernel32.lib ws2_32.lib advapi32.lib \
           $(ICONV_LIB) $(LIBXML2_LIB) $(LIBXSLT_LIB)
 
-COMMON_LNK_OPTIONS= /nologo /subsystem:windows /machine:i386 /incremental:no
+COMMON_LNK_OPTIONS= /nologo /subsystem:windows /incremental:no
 
 DEBUG_LNK_OPTIONS= /debug 
 
@@ -504,6 +504,8 @@ MISC_OBJS= \
    $(OBJDIR)\iconv_decode_iso5426.obj \
    $(OBJDIR)\iconv_decode_danmarc.obj \
    $(OBJDIR)\mutex.obj \
+   $(OBJDIR)\thread_create.obj \
+   $(OBJDIR)\spipe.obj \
    $(OBJDIR)\gettimeofday.obj \
    $(OBJDIR)\json.obj \
    $(OBJDIR)\sc.obj \
index 40a7783..0749222 100644 (file)
@@ -36,7 +36,7 @@ Retrieval.
 %package -n libyaz4-devel
 Summary: Z39.50 Library - development package
 Group: Development/Libraries
-Requires: libyaz4 = %{version} libxml2-devel libxslt-devel libicu-devel gnutls-devel %{TCPWRAPPER}
+Requires: libyaz4 = %{version} libxml2-devel libxslt-devel libicu-devel
 Conflicts: libyaz-devel
 
 %description -n libyaz4-devel
@@ -73,6 +73,7 @@ make CFLAGS="$RPM_OPT_FLAGS"
 rm -fr ${RPM_BUILD_ROOT}
 make prefix=${RPM_BUILD_ROOT}/%{_prefix} mandir=${RPM_BUILD_ROOT}/%{_mandir} \
        libdir=${RPM_BUILD_ROOT}/%{_libdir} install
+rm ${RPM_BUILD_ROOT}/%{_libdir}/*.la
 
 %clean
 rm -fr ${RPM_BUILD_ROOT}