Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package gensio for openSUSE:Factory checked 
in at 2023-12-28 23:03:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/gensio (Old)
 and      /work/SRC/openSUSE:Factory/.gensio.new.28375 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "gensio"

Thu Dec 28 23:03:37 2023 rev:24 rq:1135484 version:2.8.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/gensio/gensio.changes    2023-11-24 
23:36:04.458273302 +0100
+++ /work/SRC/openSUSE:Factory/.gensio.new.28375/gensio.changes 2023-12-28 
23:05:08.526509318 +0100
@@ -1,0 +2,8 @@
+Wed Dec 27 21:47:46 UTC 2023 - Dirk Müller <dmuel...@suse.com>
+
+- update to 2.8.2:
+  * Fix some initialization code I messed up in 2.8.1.
+  * A minor release to fix some Windows issues and clean up some
+    docs.
+
+-------------------------------------------------------------------

Old:
----
  gensio-2.8.0.tar.gz

New:
----
  gensio-2.8.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ gensio.spec ++++++
--- /var/tmp/diff_new_pack.D4YyIP/_old  2023-12-28 23:05:08.946524669 +0100
+++ /var/tmp/diff_new_pack.D4YyIP/_new  2023-12-28 23:05:08.946524669 +0100
@@ -27,7 +27,7 @@
 %bcond_with    openipmi
 %endif
 Name:           gensio
-Version:        2.8.0
+Version:        2.8.2
 Release:        0
 Summary:        Library to abstract stream and packet I/O
 # examples/* is licenced under Apache-2.0

++++++ gensio-2.8.0.tar.gz -> gensio-2.8.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/README.rst new/gensio-2.8.2/README.rst
--- old/gensio-2.8.0/README.rst 2023-11-23 00:01:12.000000000 +0100
+++ new/gensio-2.8.2/README.rst 2023-12-01 00:04:46.000000000 +0100
@@ -551,10 +551,10 @@
 functions like memory allocation, mutexes, the ability to handle file
 descriptors, timers and time, and a few other things.
 
-The library does provide several OS handlers.  The get the default one
-for your system (POSIX or Windows) call gensio_default_os_hnd().  You
-can see that man page for more details.  This will generally be the
-best performing option you have for your system.
+The library does provide several OS handlers.  You can call
+gensio_alloc_os_funcs() to allocate a default one for your system
+(POSIX or Windows).  You can see that man page for more details.  This
+will generally be the best performing option you have for your system.
 
 For POSIX systems, OS handlers for glib and TCL are available,
 allocated with gensio_glib_funcs_alloc() and gensio_tcl_funcs_alloc().
@@ -580,6 +580,63 @@
 
   include/gensio/gensio_os_funcs.h
 
+Threads
+=======
+
+The gensio library fully supports threads and is completely
+thread-safe.  However, it uses signals on POSIX system, and COM on
+Windows systems, so some setup is required.
+
+The "main" thread should call gensio_os_proc_setup() at startup and
+call gensio_os_proc_cleanup() when it is complete.  This sets up
+signals and signal handlers, thread local storage on Windows, and
+other sorts of things.
+
+You can spawn new threads from a thread that is already set up using
+gensio_os_new_thread().  This gives you a basic OS thread and is
+configured properly for gensio.
+
+If you have a thread created by other means that you want to use in
+gensio, as long as the thread create another thread and doesn't do any
+blocking functions (any sort of wait, background processing, functions
+that end in _s like read_s, etc.) you don't have to set them up.  That
+way, some external thread can write data, wake another thread, or do
+things like that.
+
+If an external thread needs to do those things, it should call
+gensio_os_thread_setup().
+
+Signals
+=======
+
+As mentioned in the threads section, the gensio library on Unix uses
+signals for inter-thread wakeups.  I looked hard, and there's really
+no other way to do this cleanly. But Windows has a couple of
+signal-like things, too, and these are available in gensio, also.
+
+If you use gensio_alloc_os_funcs(), you will get an OS funcs using the
+passed in signal for IPC.  You can pass in
+GENSIO_OS_FUNCS_DEFAULT_THREAD_SIGNAL for the signal if you want the
+default, which is SIGUSR1.  The signal you use will be blocked and
+taken over by gensio, you can't use it.
+
+gensio also provides some generic handling for a few signals.  On
+Unix, it will handle SIGHUP through the
+gensio_os_proc_register_reload_handler() function.
+
+On Windows and Unix you can use
+gensio_os_proce_register_term_handler(), which will handle termination
+requests (SIGINT, SIGTERM, SIGQUIT on Unix) and
+gensio_os_proc_register_winsize_handler() (SIGWINCH on Unix).  How
+these come in through Windows is a little messier, but invisible to
+the user.
+
+All the callbacks from from a waiting routine's wait, *not* from the
+signal handler.  That should simplify your life a lot.
+
+You can see the man pages for more details on all of these.
+
+
 Creating a gensio
 =================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/configure.ac 
new/gensio-2.8.2/configure.ac
--- old/gensio-2.8.0/configure.ac       2023-11-23 00:01:12.000000000 +0100
+++ new/gensio-2.8.2/configure.ac       2023-12-01 00:04:46.000000000 +0100
@@ -1,7 +1,7 @@
-AC_INIT([gensio],[2.8.0],[miny...@acm.org])
+AC_INIT([gensio],[2.8.2],[miny...@acm.org])
 AC_SUBST(gensio_VERSION_MAJOR, 2)
 AC_SUBST(gensio_VERSION_MINOR, 8)
-AC_SUBST(gensio_VERSION_PATCH, 0)
+AC_SUBST(gensio_VERSION_PATCH, 2)
 AC_SUBST(gensio_VERSION_STRING, ${PACKAGE_VERSION})
 AC_CANONICAL_TARGET
 AM_INIT_AUTOMAKE([-Wall])
@@ -37,7 +37,7 @@
 # Per discussions with the Debian maintainer, it's best for
 # maintainers to have all the soname libary versions be the same if
 # they come from a single source.  So here it is.
-GENSIO_LIB_VERSION=6:0:0
+GENSIO_LIB_VERSION=8:0:2
 AC_SUBST(GENSIO_LIB_VERSION)
 
 # Per discussion at:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/gensio.iss new/gensio-2.8.2/gensio.iss
--- old/gensio-2.8.0/gensio.iss 2023-11-23 00:01:12.000000000 +0100
+++ new/gensio-2.8.2/gensio.iss 2023-12-01 00:04:46.000000000 +0100
@@ -2,7 +2,7 @@
 ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
 
 #define MyAppName "Gensio"
-#define MyAppVersion "2.8.0-rc2"
+#define MyAppVersion "2.8.2"
 #define MyAppPublisher "Gensio"
 #define MyAppURL "https://github.com/cminyard/gensio";
 #define InstallDir "c:/msys64/home/cminyard/install/Gensio"
@@ -84,12 +84,18 @@
 Source: "{#mingw64Dir}/bin/libpcre-1.dll"; DestDir: "{app}/bin"
 
 Source: "{#InstallDir}/lib/libgensio.dll.a"; DestDir: "{app}/lib"
+Source: "{#InstallDir}/lib/libgensio.dll.a"; DestDir: "{app}/lib"; DestName: 
"gensio.lib"
 Source: "{#InstallDir}/lib/libgensiocpp.dll.a"; DestDir: "{app}/lib"
+Source: "{#InstallDir}/lib/libgensiocpp.dll.a"; DestDir: "{app}/lib"; 
DestName: "gensiocpp.lib"
 Source: "{#InstallDir}/lib/libgensiomdnscpp.dll.a"; DestDir: "{app}/lib"
+Source: "{#InstallDir}/lib/libgensiomdnscpp.dll.a"; DestDir: "{app}/lib"; 
DestName: "gensiomdnscpp.lib"
 Source: "{#InstallDir}/lib/libgensiooshcpp.dll.a"; DestDir: "{app}/lib"
+Source: "{#InstallDir}/lib/libgensiooshcpp.dll.a"; DestDir: "{app}/lib"; 
DestName: "gensiooshcpp.lib"
 Source: "{#InstallDir}/lib/libgensio_python_swig.dll.a"; DestDir: "{app}/lib"
 Source: "{#InstallDir}/lib/libgensiomdns.dll.a"; DestDir: "{app}/lib"
+Source: "{#InstallDir}/lib/libgensiomdns.dll.a"; DestDir: "{app}/lib"; 
DestName: "gensiomdns.lib"
 Source: "{#InstallDir}/lib/libgensioosh.dll.a"; DestDir: "{app}/lib"
+Source: "{#InstallDir}/lib/libgensioosh.dll.a"; DestDir: "{app}/lib"; 
DestName: "gensioosh.lib"
 
 Source: "{#InstallDir}/python3/_gensio.pyd"; DestDir: "{app}/python3"
 Source: "{#InstallDir}/python3/_pygensio.pyd"; DestDir: "{app}/python3"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/glib/gensio_glib.c 
new/gensio-2.8.2/glib/gensio_glib.c
--- old/gensio-2.8.0/glib/gensio_glib.c 2023-11-23 00:01:12.000000000 +0100
+++ new/gensio-2.8.2/glib/gensio_glib.c 2023-12-01 00:04:46.000000000 +0100
@@ -1938,22 +1938,6 @@
     free(f);
 }
 
-static GMutex once_lock;
-
-static void
-gensio_glib_call_once(struct gensio_os_funcs *f, struct gensio_once *once,
-                     void (*func)(void *cb_data), void *cb_data)
-{
-    if (once->called)
-       return;
-    g_mutex_lock(&once_lock);
-    if (!once->called) {
-       once->called = true;
-       func(cb_data);
-    }
-    g_mutex_unlock(&once_lock);
-}
-
 static void
 gensio_glib_get_monotonic_time(struct gensio_os_funcs *f, gensio_time *time)
 {
@@ -2065,7 +2049,7 @@
     o->service = gensio_glib_service;
     o->get_funcs = gensio_glib_get_funcs;
     o->free_funcs = gensio_glib_free_funcs;
-    o->call_once = gensio_glib_call_once;
+    o->call_once = gensio_call_once;
     o->get_monotonic_time = gensio_glib_get_monotonic_time;
     o->handle_fork = gensio_glib_handle_fork;
     o->add_iod = gensio_glib_add_iod;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/include/gensio/gensio_os_funcs.h 
new/gensio-2.8.2/include/gensio/gensio_os_funcs.h
--- old/gensio-2.8.0/include/gensio/gensio_os_funcs.h   2023-11-23 
00:01:12.000000000 +0100
+++ new/gensio-2.8.2/include/gensio/gensio_os_funcs.h   2023-12-01 
00:04:46.000000000 +0100
@@ -90,7 +90,7 @@
 };
 
 struct gensio_once {
-    bool called;
+    int called;
 };
 
 /* Used by open_listen_sockets() to return the opened sockets. */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/include/gensio/gensio_osops.h 
new/gensio-2.8.2/include/gensio/gensio_osops.h
--- old/gensio-2.8.0/include/gensio/gensio_osops.h      2023-11-23 
00:01:12.000000000 +0100
+++ new/gensio-2.8.2/include/gensio/gensio_osops.h      2023-12-01 
00:04:46.000000000 +0100
@@ -314,6 +314,11 @@
 GENSIOOSH_DLL_PUBLIC
 void gensio_osfunc_exit(int rv);
 
+/* A generic lock-based version of a once call. */
+GENSIOOSH_DLL_PUBLIC
+void gensio_call_once(struct gensio_os_funcs *f, struct gensio_once *once,
+                     void (*func)(void *cb_data), void *cb_data);
+
 #ifdef __cplusplus
 }
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/include/pthread_handler.h 
new/gensio-2.8.2/include/pthread_handler.h
--- old/gensio-2.8.0/include/pthread_handler.h  2023-11-23 00:01:12.000000000 
+0100
+++ new/gensio-2.8.2/include/pthread_handler.h  2023-12-01 00:04:46.000000000 
+0100
@@ -17,6 +17,9 @@
 #define LOCK(l) AcquireSRWLockExclusive(l)
 #define UNLOCK(l) ReleaseSRWLockExclusive(l)
 #define LOCK_INITIALIZER SRWLOCK_INIT
+#define lock_thread_type DWORD
+#define LOCK_GET_THREAD_ID GetCurrentThreadId()
+#define LOCK_THREAD_ID_EQUAL(a,b) ((a) == (b))
 #elif defined(USE_PTHREADS)
 #include <pthread.h>
 #define lock_type pthread_mutex_t
@@ -25,6 +28,9 @@
 #define LOCK(l) pthread_mutex_lock(l)
 #define UNLOCK(l) pthread_mutex_unlock(l)
 #define LOCK_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define lock_thread_type pthread_t
+#define LOCK_GET_THREAD_ID pthread_self()
+#define LOCK_THREAD_ID_EQUAL(a,b) pthread_equal(a,b)
 #else
 #include <assert.h>
 #define lock_type int
@@ -33,4 +39,7 @@
 #define LOCK(l) do { assert(*l == 0); *l = 1; } while(0)
 #define UNLOCK(l) do { assert(*l == 1); *l = 0; } while(0)
 #define LOCK_INITIALIZER 0
+#define lock_thread_type int
+#define LOCK_GET_THREAD_ID 0
+#define LOCK_THREAD_ID_EQUAL(a,b) ((a) == (b))
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/lib/gensio.c 
new/gensio-2.8.2/lib/gensio.c
--- old/gensio-2.8.0/lib/gensio.c       2023-11-23 00:01:12.000000000 +0100
+++ new/gensio-2.8.2/lib/gensio.c       2023-12-01 00:04:46.000000000 +0100
@@ -2607,6 +2607,7 @@
 static struct gensio_once gensio_default_initialized;
 
 static struct gensio_lock *deflock;
+static struct gensio_os_funcs *deflock_osh;
 
 struct gensio_def_val {
     char *strval;
@@ -2760,12 +2761,14 @@
     struct gensio_os_funcs *o = cb_data;
 
     deflock = o->alloc_lock(o);
-    if (!deflock)
+    if (!deflock) {
        gensio_def_init_rv = GE_NOMEM;
-    else
+    } else {
+       deflock_osh = o->get_funcs(o);
        /* Default reuseaddr to false for UDP. */
        gensio_def_init_rv = l_gensio_set_default(o, "udp", "reuseaddr",
                                                  NULL, 0);
+    }
 }
 
 void
@@ -2796,6 +2799,9 @@
     if (deflock)
        o->free_lock(deflock);
     deflock = NULL;
+    if (deflock_osh)
+       deflock_osh->free_funcs(deflock_osh);
+    deflock_osh = NULL;
 
     if (reg_gensio_acc_lock)
        o->free_lock(reg_gensio_acc_lock);
@@ -2870,12 +2876,12 @@
     unsigned int i;
 
     if (deflock) {
-       o->lock(deflock);
+       deflock_osh->lock(deflock);
        for (i = 0; builtin_defaults[i].name; i++)
            gensio_reset_default(o, &builtin_defaults[i]);
        for (d = defaults; d; d = d->next)
            gensio_reset_default(o, d);
-       o->unlock(deflock);
+       deflock_osh->unlock(deflock);
     }
 }
 
@@ -2952,7 +2958,7 @@
     if (gensio_def_init_rv)
        return gensio_def_init_rv;
 
-    o->lock(deflock);
+    deflock_osh->lock(deflock);
     d = gensio_lookup_default(name, NULL, NULL);
     if (d) {
        err = GE_EXISTS;
@@ -2998,7 +3004,7 @@
     defaults = d;
 
  out_unlock:
-    o->unlock(deflock);
+    deflock_osh->unlock(deflock);
     return err;
 }
 
@@ -3012,7 +3018,7 @@
     char *new_strval = NULL, *end;
     unsigned int i;
 
-    o->lock(deflock);
+    deflock_osh->lock(deflock);
     d = gensio_lookup_default(name, NULL, NULL);
     if (!d) {
        err = GE_NOTFOUND;
@@ -3139,7 +3145,7 @@
  out_unlock:
     if (new_strval)
        o->free(o, new_strval);
-    o->unlock(deflock);
+    deflock_osh->unlock(deflock);
     return err;
 }
 
@@ -3171,7 +3177,7 @@
     if (gensio_def_init_rv)
        return gensio_def_init_rv;
 
-    o->lock(deflock);
+    deflock_osh->lock(deflock);
     d = gensio_lookup_default(name, NULL, NULL);
     if (!d) {
        err = GE_NOTFOUND;
@@ -3239,7 +3245,7 @@
     }
 
  out_unlock:
-    o->unlock(deflock);
+    deflock_osh->unlock(deflock);
 
     return err;
 }
@@ -3257,7 +3263,7 @@
     if (gensio_def_init_rv)
        return gensio_def_init_rv;
 
-    o->lock(deflock);
+    deflock_osh->lock(deflock);
     d = gensio_lookup_default(name, &prev, &isdefault);
     if (!d) {
        err = GE_NOTFOUND;
@@ -3312,7 +3318,7 @@
     o->free(o, d);
 
  out_unlock:
-    o->unlock(deflock);
+    deflock_osh->unlock(deflock);
 
     return err;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/lib/gensio_osops.c 
new/gensio-2.8.2/lib/gensio_osops.c
--- old/gensio-2.8.0/lib/gensio_osops.c 2023-11-23 00:01:12.000000000 +0100
+++ new/gensio-2.8.2/lib/gensio_osops.c 2023-12-01 00:04:46.000000000 +0100
@@ -30,6 +30,7 @@
 #include <gensio/gensio_ax25_addr.h>
 
 #include "errtrig.h"
+#include <pthread_handler.h>
 
 static const char *progname = "gensio";
 
@@ -3525,8 +3526,6 @@
 
 #ifdef ENABLE_INTERNAL_TRACE
 
-#include <pthread_handler.h>
-
 #define MEM_MAGIC 0xddf0983aec9320b0
 #define MEM_BUFFER 32
 struct mem_header {
@@ -3999,3 +3998,74 @@
 {
     return o->other_data;
 }
+
+/*
+ * The once operation is a nasty piece of code.
+ *
+ * This basically implements a recursive lock on the once operation.
+ * There are unfortunate places one a once calls another once and
+ * where these can actually recurse if you don't stop them.
+ *
+ * once_lock protects once_next and once_owner.  once_lock2 is used to
+ * let only one once operation in at a time and to protect
+ * once->called.  You can claim once_lock if holding once_lock2, but
+ * not the other way around.
+ *
+ * The called field in the once is used to tell if we have called it.
+ * It will be 2 if it is in the once function (to detect recursive
+ * calls) and 1 if the once operation has been completed.
+ */
+static lock_type once_lock = LOCK_INITIALIZER;
+static lock_type once_lock2 = LOCK_INITIALIZER;
+static unsigned int once_nest;
+static lock_thread_type once_owner;
+
+void
+gensio_call_once(struct gensio_os_funcs *f, struct gensio_once *once,
+                void (*func)(void *cb_data), void *cb_data)
+{
+    lock_thread_type tid;
+    bool do_unlock = true;
+
+    if (once->called == 1)
+       /* once has been done, just return. */
+       return;
+
+    LOCK(&once_lock);
+    tid = LOCK_GET_THREAD_ID;
+    if (once_nest > 0 && LOCK_THREAD_ID_EQUAL(tid, once_owner)) {
+       /* Called recursively. */
+       once_nest++;
+       UNLOCK(&once_lock);
+       do_unlock = false;
+    } else {
+       /*
+        * First time into the once for this thread, claim the that
+        * only allows one caller.
+        */
+       UNLOCK(&once_lock);
+       LOCK(&once_lock2);
+
+       LOCK(&once_lock);
+       once_owner = tid;
+       once_nest++;
+       UNLOCK(&once_lock);
+    }
+
+    if (!once->called) {
+       /*
+        * Mark that we are in the call.  This way if we recurse into
+        * the same once, we know to not call it again.  Don't set it
+        * to 1 until we are finished processing.
+        */
+       once->called = 2;
+       func(cb_data);
+       once->called = 1;
+    }
+
+    LOCK(&once_lock);
+    once_nest--;
+    UNLOCK(&once_lock);
+    if (do_unlock)
+       UNLOCK(&once_lock2);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/lib/gensio_unix.c 
new/gensio-2.8.2/lib/gensio_unix.c
--- old/gensio-2.8.0/lib/gensio_unix.c  2023-11-23 00:01:12.000000000 +0100
+++ new/gensio-2.8.2/lib/gensio_unix.c  2023-12-01 00:04:46.000000000 +0100
@@ -1020,22 +1020,6 @@
     free(f);
 }
 
-static lock_type once_lock = LOCK_INITIALIZER;
-
-static void
-gensio_unix_call_once(struct gensio_os_funcs *f, struct gensio_once *once,
-                     void (*func)(void *cb_data), void *cb_data)
-{
-    if (once->called)
-       return;
-    LOCK(&once_lock);
-    if (!once->called) {
-       once->called = true;
-       func(cb_data);
-    }
-    UNLOCK(&once_lock);
-}
-
 static void
 gensio_unix_get_monotonic_time(struct gensio_os_funcs *f, gensio_time *time)
 {
@@ -1674,7 +1658,7 @@
     o->get_wake_sig = gensio_unix_get_wake_sig;
     o->get_funcs = gensio_unix_get_funcs;
     o->free_funcs = gensio_unix_free_funcs;
-    o->call_once = gensio_unix_call_once;
+    o->call_once = gensio_call_once;
     o->get_monotonic_time = gensio_unix_get_monotonic_time;
     o->handle_fork = gensio_handle_fork;
     o->add_iod = gensio_unix_add_iod;
@@ -2215,7 +2199,15 @@
     }
     sigdelset(&data->wait_sigs, SIGWINCH);
     data->winch_sig_set = true;
+    /*
+     * For at least MacOS, using kill() to self doesn't seem to work
+     * properly.  pthread_kill() seems to work ok.
+     */
+#ifdef USE_PTHREADS
+    pthread_kill(pthread_self(), SIGWINCH);
+#else
     kill(getpid(), SIGWINCH);
+#endif
 
  out_unlock:
     UNLOCK(&data->handler_lock);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/lib/gensio_win.c 
new/gensio-2.8.2/lib/gensio_win.c
--- old/gensio-2.8.0/lib/gensio_win.c   2023-11-23 00:01:12.000000000 +0100
+++ new/gensio-2.8.2/lib/gensio_win.c   2023-12-01 00:04:46.000000000 +0100
@@ -203,8 +203,6 @@
     struct gensio_list waiting_iods;
     struct gensio_list all_iods;
 
-    CRITICAL_SECTION once_lock;
-
     CRITICAL_SECTION timer_lock;
     struct theap_s timer_heap;
     HANDLE timerth;
@@ -1116,22 +1114,6 @@
     }
 }
 
-static void win_call_once(struct gensio_os_funcs *o, struct gensio_once *once,
-                         void (*func)(void *cb_data), void *cb_data)
-{
-    struct gensio_data *d = o->user_data;
-    if (once->called)
-       return;
-    EnterCriticalSection(&d->once_lock);
-    if (!once->called) {
-       once->called = true;
-       LeaveCriticalSection(&d->once_lock);
-       func(cb_data);
-    } else {
-       LeaveCriticalSection(&d->once_lock);
-    }
-}
-
 static void win_get_monotonic_time(struct gensio_os_funcs *o,
                                   gensio_time *time)
 {
@@ -3763,10 +3745,8 @@
     gensio_stdsock_cleanup(o);
     DeleteCriticalSection(&d->glock);
     DeleteCriticalSection(&d->timer_lock);
-    DeleteCriticalSection(&d->once_lock);
     free(d);
     free(o);
-    WSACleanup();
 }
 
 static int
@@ -3809,7 +3789,6 @@
     d->refcount = 1;
     InitializeCriticalSection(&d->glock);
     InitializeCriticalSection(&d->timer_lock);
-    InitializeCriticalSection(&d->once_lock);
     gensio_list_init(&d->waiting_iods);
     gensio_list_init(&d->all_iods);
     theap_init(&d->timer_heap);
@@ -3859,7 +3838,7 @@
     o->service = win_service;
     o->free_funcs = win_free_funcs;
     o->get_funcs = win_get_funcs;
-    o->call_once = win_call_once;
+    o->call_once = gensio_call_once;
     o->get_monotonic_time = win_get_monotonic_time;
     o->handle_fork = win_handle_fork;
     o->wait_intr_sigmask = win_wait_intr_sigmask;
@@ -3946,24 +3925,53 @@
 static struct gensio_os_proc_data proc_data;
 bool proc_setup;
 
-int
-gensio_os_thread_setup(struct gensio_os_funcs *o)
+/*
+ * Code so CoInitialize() gets called for each thread and cleaned up
+ * when the thread is complete.
+ */
+static SRWLOCK threadinfo_idx_lock = SRWLOCK_INIT;
+static DWORD threadinfo_idx;
+static bool threadinfo_setup;
+
+static void __attribute__((stdcall))
+threadinfo_cb(PVOID lpFlsData)
 {
-    return 0;
+    if (!lpFlsData)
+       return;
+    CoUninitialize();
+}
+
+static int
+gensio_os_thread_cleanup(void)
+{
+    FlsSetValue(threadinfo_idx, NULL);
+    CoUninitialize();
 }
 
 int
-gensio_os_proc_setup(struct gensio_os_funcs *o,
-                    struct gensio_os_proc_data **data)
+gensio_os_thread_setup(struct gensio_os_funcs *o)
 {
-    int rv = GE_INUSE;
+    int rv = 0;
     HRESULT res;
+    void *threadval;
 
-    AcquireSRWLockExclusive(&def_win_os_funcs_lock);
-    if (proc_setup)
-       goto out;
+    if (!threadinfo_setup) {
+       AcquireSRWLockExclusive(&threadinfo_idx_lock);
+       if (!threadinfo_setup) {
+           threadinfo_idx = FlsAlloc(threadinfo_cb);
+           if (threadinfo_idx == FLS_OUT_OF_INDEXES) {
+               ReleaseSRWLockExclusive(&threadinfo_idx_lock);
+               return GE_INUSE;
+           }
+           threadinfo_setup = true;
+       }
+       ReleaseSRWLockExclusive(&threadinfo_idx_lock);
+    }
+
+    threadval = FlsGetValue(threadinfo_idx);
+    if (threadval)
+       return 0; /* Already initialized. */
 
-    rv = 0;
     res = CoInitializeEx(NULL, COINIT_MULTITHREADED);
     switch (res) {
     case S_OK: case S_FALSE:   break;
@@ -3972,12 +3980,34 @@
     case E_OUTOFMEMORY:                rv = GE_NOMEM; break;
     case E_UNEXPECTED: default: rv = GE_OSERR; break;
     }
+
+    if (!rv) {
+       if (!FlsSetValue(threadinfo_idx, (void *)(intptr_t) 1)) {
+           gensio_os_thread_cleanup();
+           rv = GE_OSERR;
+       }
+    }
+
+    return rv;
+}
+
+int
+gensio_os_proc_setup(struct gensio_os_funcs *o,
+                    struct gensio_os_proc_data **data)
+{
+    int rv = GE_INUSE;
+
+    AcquireSRWLockExclusive(&def_win_os_funcs_lock);
+    if (proc_setup)
+       goto out;
+
+    rv = gensio_os_thread_setup(o);
     if (rv)
        goto out;
 
     proc_data.global_waiter = CreateSemaphoreA(NULL, 0, 1000000, NULL);
     if (!proc_data.global_waiter) {
-       CoUninitialize();
+       gensio_os_thread_cleanup();
        rv = GE_NOMEM;
        goto out;
     }
@@ -3985,7 +4015,7 @@
     rv = o->control(o, GENSIO_CONTROL_SET_PROC_DATA, &proc_data, NULL);
     if (rv) {
        CloseHandle(proc_data.global_waiter);
-       CoUninitialize();
+       gensio_os_thread_cleanup();
        proc_data.global_waiter = NULL;
        goto out;
     }
@@ -4104,7 +4134,6 @@
        data->global_waiter = NULL;
     }
     LOCK_DESTROY(&proc_data.lock);
-    CoUninitialize();
  out:
     ReleaseSRWLockExclusive(&def_win_os_funcs_lock);
 }
@@ -4210,6 +4239,7 @@
 {
     struct gensio_thread *tid = info;
 
+    gensio_os_thread_setup(tid->o); /* Shouldn't be able to fail. */
     tid->start_func(tid->data);
     return 0;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/lib/sergensio.c 
new/gensio-2.8.2/lib/sergensio.c
--- old/gensio-2.8.0/lib/sergensio.c    2023-11-23 00:01:12.000000000 +0100
+++ new/gensio-2.8.2/lib/sergensio.c    2023-12-01 00:04:46.000000000 +0100
@@ -842,8 +842,6 @@
     struct gensio_lock *lock;
 
     struct gensio_accepter *assoc_acc;
-
-    bool autofree;
 };
 
 struct gensio_accepter *
@@ -919,7 +917,6 @@
                                child_sio, &sio);
     if (rv)
        return rv;
-    sio->autofree = true;
     return 0;
 }
 
@@ -928,8 +925,7 @@
 {
     struct sergensio_accepter *sio = classdata;
 
-    if (sio->autofree)
-       sergensio_acc_data_free(sio);
+    sergensio_acc_data_free(sio);
 }
 
 static struct gensio_acc_classops sergensio_acc_classops = {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/lib/sergensio_telnet.c 
new/gensio-2.8.2/lib/sergensio_telnet.c
--- old/gensio-2.8.0/lib/sergensio_telnet.c     2023-11-23 00:01:12.000000000 
+0100
+++ new/gensio-2.8.2/lib/sergensio_telnet.c     2023-12-01 00:04:46.000000000 
+0100
@@ -1399,8 +1399,7 @@
 {
     struct stela_data *stela = acc_data;
 
-    if (stela->sacc)
-       sergensio_acc_data_free(stela->sacc);
+    /* stela->sacc will be freed in the class callback. */
     stela->o->free(stela->o, stela);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/man/gensio_err.3 
new/gensio-2.8.2/man/gensio_err.3
--- old/gensio-2.8.0/man/gensio_err.3   2023-11-23 00:01:12.000000000 +0100
+++ new/gensio-2.8.2/man/gensio_err.3   2023-12-01 00:04:46.000000000 +0100
@@ -75,10 +75,24 @@
 GE_ADDRINUSE             Address already in use
 .br
 GE_INTERRUPTED           Operation was interrupted by a signal
-.PP
+.br
 GE_SHUTDOWN              Operation on shutdown file descriptor
-.PP
+.br
 GE_LOCALCLOSED           Local side closed connection
+.br
+GE_PERM                  Permission denied
+.br
+GE_APPERR                Application error
+.br
+GE_UNKNOWN_NAME_ERROR    Unknown name server lookup failure
+.br
+GE_NAME_ERROR            Unable to find a valid name on the name server
+.br
+GE_NAME_SERVER_FAILURE   Serious name server failure
+.br
+GE_NAME_INVALID          Invalid name server information
+.br
+GE_NAME_NET_NOT_UP       Network address for the given name is not available
 .PP
 .B gensio_err_to_str
 converts an integer error value to the given string.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/man/gensio_os_funcs.3 
new/gensio-2.8.2/man/gensio_os_funcs.3
--- old/gensio-2.8.0/man/gensio_os_funcs.3      2023-11-23 00:01:12.000000000 
+0100
+++ new/gensio-2.8.2/man/gensio_os_funcs.3      2023-12-01 00:04:46.000000000 
+0100
@@ -9,7 +9,9 @@
 .PP
 .B int gensio_default_os_hnd(int wake_sig, struct gensio_os_funcs **o)
 .PP
-.B int gensio_alloc_os_funcs(int wake_sig, struct gensio_os_funcs **o)
+.B int gensio_alloc_os_funcs(int wake_sig, struct gensio_os_funcs **o,
+.br
+                unsigned int flags, ...)
 .PP
 .B int gensio_unix_funcs_alloc(struct selector_s *sel, int wake_sig,
 .br
@@ -241,7 +243,7 @@
 reason for more than one of these.
 
 The
-.I wait_sig
+.I wake_sig
 parameter usage on Windows is unused.  For Unix systems, this signal
 is used to signal other processes that may be waiting that they need
 to wake up.  This is used to wake up a process waiting on a waiter,
@@ -264,6 +266,9 @@
 funcs, you must make sure those other threads have this signal
 blocked.
 
+You can pass in GENSIO_OS_FUNCS_DEFAULT_THREAD_SIGNAL to take the
+default signal handler, which is SIGUSR1.
+
 On unix,
 .B gensio_os_proc_setup
 function handles all the above mentioned signal setup for you
@@ -286,7 +291,14 @@
 is much like gensio_os_proc_setup, but it only sets up the signal
 handlers and blocking signals for the wakeup signal, it doesn't do any
 of the other setup.  It allows you to bring a thread in to gensio that
-wasn't created by gensio.  It should be used very carefully.
+wasn't created by gensio.  It also does some necessary setup on
+Windows for the thread.  If you have no signal handling needs, you can
+generally use this instead of
+.B gensio_os_proc_setup().
+If you have signal handling needs, one thread should call
+.B gensio_os_proc_setup()
+and all other threads should call this function if they were not
+created by gensio.
 
 .B gensio_unix_funcs_alloc
 and
@@ -364,7 +376,8 @@
 that you must pass into the wait function.  This is just basic generic
 threads, you can use your OS functions if you need more control over
 the threads.  If you use threads, make sure to see the notes above
-about setting up for them properly.
+about setting up for them properly.  This must be called from a thread
+that is already set up.
 
 The
 .I gensio_os_wait_thread
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gensio-2.8.0/tcl/gensio_tcl.c 
new/gensio-2.8.2/tcl/gensio_tcl.c
--- old/gensio-2.8.0/tcl/gensio_tcl.c   2023-11-23 00:01:12.000000000 +0100
+++ new/gensio-2.8.2/tcl/gensio_tcl.c   2023-12-01 00:04:46.000000000 +0100
@@ -1433,22 +1433,6 @@
     free(f);
 }
 
-static Tcl_Mutex once_lock;
-
-static void
-gensio_tcl_call_once(struct gensio_os_funcs *f, struct gensio_once *once,
-                     void (*func)(void *cb_data), void *cb_data)
-{
-    if (once->called)
-       return;
-    Tcl_MutexLock(&once_lock);
-    if (!once->called) {
-       once->called = true;
-       func(cb_data);
-    }
-    Tcl_MutexUnlock(&once_lock);
-}
-
 static void
 gensio_tcl_get_monotonic_time(struct gensio_os_funcs *f, gensio_time *time)
 {
@@ -1569,7 +1553,7 @@
     o->service = gensio_tcl_service;
     o->get_funcs = gensio_tcl_get_funcs;
     o->free_funcs = gensio_tcl_free_funcs;
-    o->call_once = gensio_tcl_call_once;
+    o->call_once = gensio_call_once;
     o->get_monotonic_time = gensio_tcl_get_monotonic_time;
     o->handle_fork = gensio_tcl_handle_fork;
     o->add_iod = gensio_tcl_add_iod;

Reply via email to