Similar tests of the *_trylock behaviour can also be added to the
pthread-mutex tests and to the mtx tests.


2024-08-06  Bruno Haible  <br...@clisp.org>

        mtx tests: Strengthen tests.
        * tests/test-mtx-type.c: New file.
        * modules/mtx-tests (Files): Add it.
        (Makefile.am): Arrange to test test-mtx-type.

2024-08-06  Bruno Haible  <br...@clisp.org>

        pthread-mutex tests: Strengthen tests.
        * tests/test-pthread-mutex-type.c: New file.
        * modules/pthread-mutex-tests (Files): Add it.
        (Makefile.am): Arrange to test test-pthread-mutex-type.
        * doc/posix-functions/pthread_mutex_lock.texi: Mention FreeBSD and
        NetBSD problem.
        * doc/posix-functions/pthread_mutex_trylock.texi: Likewise.

>From f9f125c4f414ec1a85016353319bfa141f120fdb Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Tue, 6 Aug 2024 15:43:16 +0200
Subject: [PATCH 1/2] pthread-mutex tests: Strengthen tests.

* tests/test-pthread-mutex-type.c: New file.
* modules/pthread-mutex-tests (Files): Add it.
(Makefile.am): Arrange to test test-pthread-mutex-type.
* doc/posix-functions/pthread_mutex_lock.texi: Mention FreeBSD and
NetBSD problem.
* doc/posix-functions/pthread_mutex_trylock.texi: Likewise.
---
 ChangeLog                                     |  10 ++
 doc/posix-functions/pthread_mutex_lock.texi   |   5 +
 .../pthread_mutex_trylock.texi                |   5 +
 modules/pthread-mutex-tests                   |   8 +-
 tests/test-pthread-mutex-type.c               | 127 ++++++++++++++++++
 5 files changed, 153 insertions(+), 2 deletions(-)
 create mode 100644 tests/test-pthread-mutex-type.c

diff --git a/ChangeLog b/ChangeLog
index db84b220e2..9e5488a686 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2024-08-06  Bruno Haible  <br...@clisp.org>
+
+	pthread-mutex tests: Strengthen tests.
+	* tests/test-pthread-mutex-type.c: New file.
+	* modules/pthread-mutex-tests (Files): Add it.
+	(Makefile.am): Arrange to test test-pthread-mutex-type.
+	* doc/posix-functions/pthread_mutex_lock.texi: Mention FreeBSD and
+	NetBSD problem.
+	* doc/posix-functions/pthread_mutex_trylock.texi: Likewise.
+
 2024-08-06  Bruno Haible  <br...@clisp.org>
 
 	windows-timedrecmutex: Add tests.
diff --git a/doc/posix-functions/pthread_mutex_lock.texi b/doc/posix-functions/pthread_mutex_lock.texi
index e4ee553206..2d04670a14 100644
--- a/doc/posix-functions/pthread_mutex_lock.texi
+++ b/doc/posix-functions/pthread_mutex_lock.texi
@@ -17,4 +17,9 @@
 
 Portability problems not fixed by Gnulib:
 @itemize
+@item
+This function does not behave as required by POSIX for mutexes of type
+NORMAL and ERRORCHECK, by allowing RECURSIVE locking,
+in programs linked without @code{-lpthread} on some platforms:
+FreeBSD 14.0, NetBSD 10.0.
 @end itemize
diff --git a/doc/posix-functions/pthread_mutex_trylock.texi b/doc/posix-functions/pthread_mutex_trylock.texi
index cefd9b46bc..2cfd516868 100644
--- a/doc/posix-functions/pthread_mutex_trylock.texi
+++ b/doc/posix-functions/pthread_mutex_trylock.texi
@@ -17,4 +17,9 @@
 
 Portability problems not fixed by Gnulib:
 @itemize
+@item
+This function does not behave as required by POSIX for mutexes of type
+NORMAL and ERRORCHECK, by allowing RECURSIVE locking,
+in programs linked without @code{-lpthread} on some platforms:
+FreeBSD 14.0, NetBSD 10.0.
 @end itemize
diff --git a/modules/pthread-mutex-tests b/modules/pthread-mutex-tests
index 068dc24f42..9b242a9852 100644
--- a/modules/pthread-mutex-tests
+++ b/modules/pthread-mutex-tests
@@ -1,5 +1,6 @@
 Files:
 tests/test-pthread-mutex.c
+tests/test-pthread-mutex-type.c
 tests/atomic-int-posix.h
 tests/macros.h
 m4/semaphore.m4
@@ -15,6 +16,9 @@ AC_CHECK_DECLS_ONCE([alarm])
 AC_REQUIRE([gl_SEMAPHORE])
 
 Makefile.am:
-TESTS += test-pthread-mutex
-check_PROGRAMS += test-pthread-mutex
+TESTS += test-pthread-mutex test-pthread-mutex-type
+check_PROGRAMS += test-pthread-mutex test-pthread-mutex-type
 test_pthread_mutex_LDADD = $(LDADD) @LIBPMULTITHREAD@ @SCHED_YIELD_LIB@ @LIB_SEMAPHORE@
+# If we were to link test-pthread-mutex-type only with @LIBPTHREAD@ instead of
+# @LIBPMULTITHREAD@, this test would fail on FreeBSD and NetBSD.
+test_pthread_mutex_type_LDADD = $(LDADD) @LIBPMULTITHREAD@
diff --git a/tests/test-pthread-mutex-type.c b/tests/test-pthread-mutex-type.c
new file mode 100644
index 0000000000..3406055912
--- /dev/null
+++ b/tests/test-pthread-mutex-type.c
@@ -0,0 +1,127 @@
+/* Test of locking in multithreaded situations.
+   Copyright (C) 2024 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>, 2024.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <pthread.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "macros.h"
+
+/* Returns the effective type of a lock.  */
+static const char *
+get_effective_type (pthread_mutex_t *lock)
+{
+  /* Lock once.  */
+  ASSERT (pthread_mutex_lock (lock) == 0);
+
+  /* Try to lock a second time.  */
+  int err = pthread_mutex_trylock (lock);
+  if (err == 0)
+    return "RECURSIVE";
+  if (err == EBUSY)
+    return "NORMAL";
+
+  /* We can't really check whether the lock is effectively ERRORCHECK, without
+     risking a deadlock.  */
+
+  return "unknown!";
+}
+
+int
+main ()
+{
+  /* Find the effective type of a NORMAL lock.  */
+  const char *type_normal;
+  {
+    pthread_mutex_t lock;
+    pthread_mutexattr_t attr;
+    ASSERT (pthread_mutexattr_init (&attr) == 0);
+    ASSERT (pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL) == 0);
+    ASSERT (pthread_mutex_init (&lock, &attr) == 0);
+    ASSERT (pthread_mutexattr_destroy (&attr) == 0);
+    type_normal = get_effective_type (&lock);
+  }
+
+  /* Find the effective type of an ERRORCHECK lock.  */
+  const char *type_errorcheck;
+  {
+    pthread_mutex_t lock;
+    pthread_mutexattr_t attr;
+    ASSERT (pthread_mutexattr_init (&attr) == 0);
+    ASSERT (pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK) == 0);
+    ASSERT (pthread_mutex_init (&lock, &attr) == 0);
+    ASSERT (pthread_mutexattr_destroy (&attr) == 0);
+    type_errorcheck = get_effective_type (&lock);
+  }
+
+  /* Find the effective type of a RECURSIVE lock.  */
+  const char *type_recursive;
+  {
+    pthread_mutex_t lock;
+    pthread_mutexattr_t attr;
+    ASSERT (pthread_mutexattr_init (&attr) == 0);
+    ASSERT (pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE) == 0);
+    ASSERT (pthread_mutex_init (&lock, &attr) == 0);
+    ASSERT (pthread_mutexattr_destroy (&attr) == 0);
+    type_recursive = get_effective_type (&lock);
+  }
+
+  /* Find the effective type of a DEFAULT lock.  */
+  const char *type_default;
+  {
+    pthread_mutex_t lock;
+    pthread_mutexattr_t attr;
+    ASSERT (pthread_mutexattr_init (&attr) == 0);
+    ASSERT (pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_DEFAULT) == 0);
+    ASSERT (pthread_mutex_init (&lock, &attr) == 0);
+    ASSERT (pthread_mutexattr_destroy (&attr) == 0);
+    type_default = get_effective_type (&lock);
+  }
+
+  /* Find the effective type of a default-initialized lock.  */
+  const char *type_def;
+  {
+    pthread_mutex_t lock;
+    ASSERT (pthread_mutex_init (&lock, NULL) == 0);
+    type_def = get_effective_type (&lock);
+  }
+
+  printf ("PTHREAD_MUTEX_NORMAL     -> type = %s\n", type_normal);
+  printf ("PTHREAD_MUTEX_ERRORCHECK -> type = %s\n", type_errorcheck);
+  printf ("PTHREAD_MUTEX_RECURSIVE  -> type = %s\n", type_recursive);
+  printf ("PTHREAD_MUTEX_DEFAULT    -> type = %s\n", type_default);
+  printf ("Default                  -> type = %s\n", type_def);
+
+  ASSERT (strcmp (type_normal,        "NORMAL") == 0);
+  ASSERT (strcmp (type_errorcheck,    "NORMAL") == 0);
+  ASSERT (strcmp (type_recursive,     "RECURSIVE") == 0);
+
+  ASSERT (strcmp (type_default, type_def) == 0);
+
+  /* This is not required by POSIX, but happens to be the case on all
+     platforms.  */
+  ASSERT (strcmp (type_default,       "NORMAL") == 0);
+  ASSERT (strcmp (type_def,           "NORMAL") == 0);
+
+  return test_exit_status;
+}
-- 
2.34.1

>From fe3c170040eed9ad3dad2030e919c6fd402bb106 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Tue, 6 Aug 2024 15:45:02 +0200
Subject: [PATCH 2/2] mtx tests: Strengthen tests.

* tests/test-mtx-type.c: New file.
* modules/mtx-tests (Files): Add it.
(Makefile.am): Arrange to test test-mtx-type.
---
 ChangeLog             |  7 ++++
 modules/mtx-tests     |  6 ++-
 tests/test-mtx-type.c | 93 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 104 insertions(+), 2 deletions(-)
 create mode 100644 tests/test-mtx-type.c

diff --git a/ChangeLog b/ChangeLog
index 9e5488a686..d9658c938b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2024-08-06  Bruno Haible  <br...@clisp.org>
+
+	mtx tests: Strengthen tests.
+	* tests/test-mtx-type.c: New file.
+	* modules/mtx-tests (Files): Add it.
+	(Makefile.am): Arrange to test test-mtx-type.
+
 2024-08-06  Bruno Haible  <br...@clisp.org>
 
 	pthread-mutex tests: Strengthen tests.
diff --git a/modules/mtx-tests b/modules/mtx-tests
index b29fb0b6ce..58101a1bd1 100644
--- a/modules/mtx-tests
+++ b/modules/mtx-tests
@@ -1,5 +1,6 @@
 Files:
 tests/test-mtx.c
+tests/test-mtx-type.c
 tests/atomic-int-isoc.h
 tests/macros.h
 m4/semaphore.m4
@@ -15,6 +16,7 @@ AC_CHECK_DECLS_ONCE([alarm])
 AC_REQUIRE([gl_SEMAPHORE])
 
 Makefile.am:
-TESTS += test-mtx
-check_PROGRAMS += test-mtx
+TESTS += test-mtx test-mtx-type
+check_PROGRAMS += test-mtx test-mtx-type
 test_mtx_LDADD = $(LDADD) @LIBSTDTHREAD@ @LIBTHREAD@ @LIB_SEMAPHORE@
+test_mtx_type_LDADD = $(LDADD) @LIBSTDTHREAD@
diff --git a/tests/test-mtx-type.c b/tests/test-mtx-type.c
new file mode 100644
index 0000000000..9b4f089236
--- /dev/null
+++ b/tests/test-mtx-type.c
@@ -0,0 +1,93 @@
+/* Test of locking in multithreaded situations.
+   Copyright (C) 2024 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>, 2024.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <threads.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "macros.h"
+
+/* Returns the effective type of a lock.  */
+static const char *
+get_effective_type (mtx_t *lock)
+{
+  /* Lock once.  */
+  ASSERT (mtx_lock (lock) == thrd_success);
+
+  /* Try to lock a second time.  */
+  int err = mtx_trylock (lock);
+  if (err == thrd_success)
+    return "RECURSIVE";
+  if (err == thrd_busy)
+    return "NORMAL";
+
+  return "unknown!";
+}
+
+int
+main ()
+{
+  /* Find the effective type of a PLAIN lock.  */
+  const char *type_plain;
+  {
+    mtx_t lock;
+    ASSERT (mtx_init (&lock, mtx_plain) == thrd_success);
+    type_plain = get_effective_type (&lock);
+  }
+
+  /* Find the effective type of a TIMED lock.  */
+  const char *type_timed;
+  {
+    mtx_t lock;
+    ASSERT (mtx_init (&lock, mtx_timed) == thrd_success);
+    type_timed = get_effective_type (&lock);
+  }
+
+  /* Find the effective type of a PLAIN RECURSIVE lock.  */
+  const char *type_plain_rec;
+  {
+    mtx_t lock;
+    ASSERT (mtx_init (&lock, mtx_plain | mtx_recursive) == thrd_success);
+    type_plain_rec = get_effective_type (&lock);
+  }
+
+  /* Find the effective type of a TIMED RECURSIVE lock.  */
+  const char *type_timed_rec;
+  {
+    mtx_t lock;
+    ASSERT (mtx_init (&lock, mtx_timed | mtx_recursive) == thrd_success);
+    type_timed_rec = get_effective_type (&lock);
+  }
+
+  printf ("PLAIN           -> type = %s\n", type_plain);
+  printf ("TIMED           -> type = %s\n", type_timed);
+  printf ("PLAIN RECURSIVE -> type = %s\n", type_plain_rec);
+  printf ("TIMED RECURSIVE -> type = %s\n", type_timed_rec);
+
+  ASSERT (strcmp (type_plain,     "NORMAL") == 0);
+  ASSERT (strcmp (type_timed,     "NORMAL") == 0);
+  ASSERT (strcmp (type_plain_rec, "RECURSIVE") == 0);
+  ASSERT (strcmp (type_timed_rec, "RECURSIVE") == 0);
+
+  return test_exit_status;
+}
-- 
2.34.1

Reply via email to