I just noticed that the AIX thrd_join workaround is incomplete: The exit code
of the thread may not only be provided by a 'return' statement in the thread's
main function, but alternatively as an argument to thread_exit(). Thus
thread_exit must be overridden as well.

Done through this patch, with a new unit test.


2023-08-18  Bruno Haible  <br...@clisp.org>

        thrd tests: Add unit test for thrd_exit.
        * tests/test-thrd_exit.c: New file, based on tests/test-thrd_create.c.
        * modules/thrd-tests (Files): Add it.
        (Makefile.am): Compile and run it.

        thrd: On AIX 7.1 and 7.2, override also thrd_exit.
        * lib/threads.in.h (thrd_exit): Consider REPLACE_THRD_EXIT.
        * lib/thrd.c (rpl_thrd_exit): New function.
        * m4/threads_h.m4 (gl_THREADS_H_DEFAULTS): Initialize REPLACE_THRD_EXIT.
        * m4/thrd.m4 (gl_FUNC_THRD_JOIN): Set also REPLACE_THRD_EXIT and adjust
        LIBSTDTHREAD.
        * modules/threads-h (Makefile.am): Substitute REPLACE_THRD_EXIT.
        * doc/posix-functions/thrd_exit.texi: Mention the AIX thrd_join problem
        also here.

>From cdf0821487e02f833fadee1853918e9930901db1 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Fri, 18 Aug 2023 20:52:08 +0200
Subject: [PATCH 1/2] thrd: On AIX 7.1 and 7.2, override also thrd_exit.

* lib/threads.in.h (thrd_exit): Consider REPLACE_THRD_EXIT.
* lib/thrd.c (rpl_thrd_exit): New function.
* m4/threads_h.m4 (gl_THREADS_H_DEFAULTS): Initialize REPLACE_THRD_EXIT.
* m4/thrd.m4 (gl_FUNC_THRD_JOIN): Set also REPLACE_THRD_EXIT and adjust
LIBSTDTHREAD.
* modules/threads-h (Makefile.am): Substitute REPLACE_THRD_EXIT.
* doc/posix-functions/thrd_exit.texi: Mention the AIX thrd_join problem
also here.
---
 ChangeLog                          | 12 ++++++++++++
 doc/posix-functions/thrd_exit.texi |  3 +++
 lib/thrd.c                         | 15 +++++++++++++++
 lib/threads.in.h                   | 12 ++++++++++--
 m4/thrd.m4                         |  6 +++++-
 m4/threads_h.m4                    |  3 ++-
 modules/threads-h                  |  1 +
 7 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index e162045744..8a932dfe44 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2023-08-18  Bruno Haible  <br...@clisp.org>
+
+	thrd: On AIX 7.1 and 7.2, override also thrd_exit.
+	* lib/threads.in.h (thrd_exit): Consider REPLACE_THRD_EXIT.
+	* lib/thrd.c (rpl_thrd_exit): New function.
+	* m4/threads_h.m4 (gl_THREADS_H_DEFAULTS): Initialize REPLACE_THRD_EXIT.
+	* m4/thrd.m4 (gl_FUNC_THRD_JOIN): Set also REPLACE_THRD_EXIT and adjust
+	LIBSTDTHREAD.
+	* modules/threads-h (Makefile.am): Substitute REPLACE_THRD_EXIT.
+	* doc/posix-functions/thrd_exit.texi: Mention the AIX thrd_join problem
+	also here.
+
 2023-08-18  Bruno Haible  <br...@clisp.org>
 
 	aligned_alloc: Fix test failure on AIX 7.3 with ibm-clang.
diff --git a/doc/posix-functions/thrd_exit.texi b/doc/posix-functions/thrd_exit.texi
index e1af16e428..a0e6e0983c 100644
--- a/doc/posix-functions/thrd_exit.texi
+++ b/doc/posix-functions/thrd_exit.texi
@@ -17,6 +17,9 @@
 @item
 This function is missing on many platforms:
 glibc 2.27, macOS 11.1, FreeBSD 9.3, NetBSD 8.0, OpenBSD 6.7, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.3, Cygwin 2.9, mingw, MSVC 14, Android 9.0.
+@item
+The exit code provided to this function is discarded on some platforms:
+AIX 7.2.
 @end itemize
 
 Portability problems not fixed by Gnulib:
diff --git a/lib/thrd.c b/lib/thrd.c
index 5e9a988c2c..9abea10a2c 100644
--- a/lib/thrd.c
+++ b/lib/thrd.c
@@ -203,6 +203,21 @@ rpl_thrd_join (rpl_thrd_t thread, int *exitcodep)
   }
 }
 
+_Noreturn void
+rpl_thrd_exit (int exitcode)
+{
+  rpl_thrd_t t = rpl_thrd_current ();
+
+  /* Store the exitcode, for use by thrd_join().  */
+  t->exitcode = exitcode;
+  if (t->detached)
+    {
+      /* Clean up the thread, like thrd_join would do.  */
+      free (t);
+    }
+  pthread_exit (NULL);
+}
+
 # endif
 
 # if BROKEN_THRD_JOIN
diff --git a/lib/threads.in.h b/lib/threads.in.h
index ac87ade571..6d1769cc53 100644
--- a/lib/threads.in.h
+++ b/lib/threads.in.h
@@ -298,11 +298,19 @@ _GL_WARN_ON_USE (thrd_join, "thrd_join is unportable - "
 #endif
 
 #if @GNULIB_THRD@
-# if !@HAVE_THREADS_H@
+# if @REPLACE_THRD_EXIT@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   define thrd_exit rpl_thrd_exit
+#  endif
+_GL_FUNCDECL_RPL (thrd_exit, _Noreturn void, (int));
+_GL_CXXALIAS_RPL (thrd_exit, void, (int));
+# else
+#  if !@HAVE_THREADS_H@
 _GL_FUNCDECL_SYS (thrd_exit, _Noreturn void, (int));
-# endif
+#  endif
 /* Need to cast because of AIX with xlclang++.  */
 _GL_CXXALIAS_SYS_CAST (thrd_exit, void, (int));
+# endif
 _GL_CXXALIASWARN (thrd_exit);
 #elif defined GNULIB_POSIXCHECK
 # undef thrd_exit
diff --git a/m4/thrd.m4 b/m4/thrd.m4
index 452629dbbb..fed111695f 100644
--- a/m4/thrd.m4
+++ b/m4/thrd.m4
@@ -1,4 +1,4 @@
-# thrd.m4 serial 1
+# thrd.m4 serial 2
 dnl Copyright (C) 2019-2023 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -15,9 +15,13 @@ AC_DEFUN([gl_FUNC_THRD_JOIN]
       REPLACE_THRD_CURRENT=1
       REPLACE_THRD_DETACH=1
       REPLACE_THRD_EQUAL=1
+      REPLACE_THRD_EXIT=1
       REPLACE_THRD_JOIN=1
       AC_DEFINE([BROKEN_THRD_START_T], [1],
         [Define if the thrd_start_t type is not as described in ISO C 11.])
+      dnl The thrd_exit replacement relies on pthread_exit, which on AIX is in
+      dnl libpthread.
+      LIBSTDTHREAD="$LIBSTDTHREAD $LIBPTHREAD"
     fi
 
     dnl On Solaris 11.4, thrd_join crashes when the second argument is NULL.
diff --git a/m4/threads_h.m4 b/m4/threads_h.m4
index 851490c123..f74c146173 100644
--- a/m4/threads_h.m4
+++ b/m4/threads_h.m4
@@ -1,4 +1,4 @@
-# threads_h.m4 serial 11
+# threads_h.m4 serial 12
 dnl Copyright (C) 2019-2023 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -175,5 +175,6 @@ AC_DEFUN([gl_THREADS_H_DEFAULTS]
   REPLACE_THRD_CURRENT=0; AC_SUBST([REPLACE_THRD_CURRENT])
   REPLACE_THRD_DETACH=0;  AC_SUBST([REPLACE_THRD_DETACH])
   REPLACE_THRD_EQUAL=0;   AC_SUBST([REPLACE_THRD_EQUAL])
+  REPLACE_THRD_EXIT=0;    AC_SUBST([REPLACE_THRD_EXIT])
   REPLACE_THRD_JOIN=0;    AC_SUBST([REPLACE_THRD_JOIN])
 ])
diff --git a/modules/threads-h b/modules/threads-h
index 1a2b83a354..2056df01f0 100644
--- a/modules/threads-h
+++ b/modules/threads-h
@@ -61,6 +61,7 @@ threads.h: threads.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(_NORETURN_H
 	      -e 's|@''REPLACE_THRD_CURRENT''@|$(REPLACE_THRD_CURRENT)|g' \
 	      -e 's|@''REPLACE_THRD_DETACH''@|$(REPLACE_THRD_DETACH)|g' \
 	      -e 's|@''REPLACE_THRD_EQUAL''@|$(REPLACE_THRD_EQUAL)|g' \
+	      -e 's|@''REPLACE_THRD_EXIT''@|$(REPLACE_THRD_EXIT)|g' \
 	      -e 's|@''REPLACE_THRD_JOIN''@|$(REPLACE_THRD_JOIN)|g' \
 	      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
 	      -e '/definition of _Noreturn/r $(_NORETURN_H)' \
-- 
2.34.1

>From ae27b197e07820e3d38aaad967cbd7fa9c43e006 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Fri, 18 Aug 2023 19:39:03 +0200
Subject: [PATCH 2/2] thrd tests: Add unit test for thrd_exit.

* tests/test-thrd_exit.c: New file, based on tests/test-thrd_create.c.
* modules/thrd-tests (Files): Add it.
(Makefile.am): Compile and run it.
---
 ChangeLog              |  5 +++
 modules/thrd-tests     |  6 ++--
 tests/test-thrd_exit.c | 77 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 86 insertions(+), 2 deletions(-)
 create mode 100644 tests/test-thrd_exit.c

diff --git a/ChangeLog b/ChangeLog
index 8a932dfe44..b2c277f64d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-08-18  Bruno Haible  <br...@clisp.org>
 
+	thrd tests: Add unit test for thrd_exit.
+	* tests/test-thrd_exit.c: New file, based on tests/test-thrd_create.c.
+	* modules/thrd-tests (Files): Add it.
+	(Makefile.am): Compile and run it.
+
 	thrd: On AIX 7.1 and 7.2, override also thrd_exit.
 	* lib/threads.in.h (thrd_exit): Consider REPLACE_THRD_EXIT.
 	* lib/thrd.c (rpl_thrd_exit): New function.
diff --git a/modules/thrd-tests b/modules/thrd-tests
index fdb6600575..c726a8df4b 100644
--- a/modules/thrd-tests
+++ b/modules/thrd-tests
@@ -1,6 +1,7 @@
 Files:
 tests/test-thrd_current.c
 tests/test-thrd_create.c
+tests/test-thrd_exit.c
 tests/macros.h
 
 Depends-on:
@@ -8,7 +9,8 @@ Depends-on:
 configure.ac:
 
 Makefile.am:
-TESTS += test-thrd_current test-thrd_create
-check_PROGRAMS += test-thrd_current test-thrd_create
+TESTS += test-thrd_current test-thrd_create test-thrd_exit
+check_PROGRAMS += test-thrd_current test-thrd_create test-thrd_exit
 test_thrd_current_LDADD = $(LDADD) @LIBSTDTHREAD@
 test_thrd_create_LDADD = $(LDADD) @LIBSTDTHREAD@
+test_thrd_exit_LDADD = $(LDADD) @LIBSTDTHREAD@
diff --git a/tests/test-thrd_exit.c b/tests/test-thrd_exit.c
new file mode 100644
index 0000000000..617dfe9d09
--- /dev/null
+++ b/tests/test-thrd_exit.c
@@ -0,0 +1,77 @@
+/* Test of thrd_exit () function.
+   Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU 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 General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <br...@clisp.org>, 2011.  */
+
+#include <config.h>
+
+#include <threads.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "macros.h"
+
+/* This test is like test-thrd_create.c, except that is uses a thrd_exit()
+   invocation instead of 'return' to provide the thread's result code.  */
+
+static thrd_t main_thread_before;
+static thrd_t main_thread_after;
+static thrd_t worker_thread;
+
+#define MAGIC 1266074729
+static volatile int work_done;
+
+static int
+worker_thread_func (void *arg)
+{
+  work_done = 1;
+  thrd_exit (MAGIC);
+  return 0xBADC0DE;
+}
+
+int
+main ()
+{
+  main_thread_before = thrd_current ();
+
+  if (thrd_create (&worker_thread, worker_thread_func, NULL) == thrd_success)
+    {
+      int ret;
+
+      /* Check that thrd_current () has the same value before than after the
+         first call to thrd_create ().  */
+      main_thread_after = thrd_current ();
+      ASSERT (memcmp (&main_thread_before, &main_thread_after,
+                      sizeof (thrd_t))
+              == 0);
+
+      ASSERT (thrd_join (worker_thread, &ret) == thrd_success);
+
+      /* Check the return value of the thread.  */
+      ASSERT (ret == MAGIC);
+
+      /* Check that worker_thread_func () has finished executing.  */
+      ASSERT (work_done);
+
+      return 0;
+    }
+  else
+    {
+      fputs ("thrd_create failed\n", stderr);
+      return 1;
+    }
+}
-- 
2.34.1

Reply via email to