Commit d5c3c14d4 for imagemagick.org

commit d5c3c14d4e8012e7b92ff0da6bb58f057b86f920
Author: Cristy <urban-warrior@imagemagick.org>
Date:   Sun Nov 15 09:10:55 2026 -0500

    support stdatomic which presumably has less overhead than mutexes

diff --git a/MagickCore/semaphore.c b/MagickCore/semaphore.c
index 36cbe7649..324e90c96 100644
--- a/MagickCore/semaphore.c
+++ b/MagickCore/semaphore.c
@@ -53,6 +53,16 @@
 #include "MagickCore/thread_.h"
 #include "MagickCore/thread-private.h"
 #include "MagickCore/utility-private.h"
+#if defined(MAGICKCORE_HAVE_STDATOMIC_H)
+#include <stdatomic.h>
+#endif
+
+/*
+  Define declarations.
+*/
+#if !defined(CACHE_LINE_SIZE)
+#define CACHE_LINE_SIZE  64
+#endif

 /*
   Struct declarations.
@@ -98,13 +108,46 @@ struct SemaphoreInfo
 MagickExport void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info)
 {
   assert(semaphore_info != (SemaphoreInfo **) NULL);
+#if defined(MAGICKCORE_HAVE_STDATOMIC_H)
+  if (atomic_load_explicit((_Atomic(SemaphoreInfo *) *) semaphore_info,memory_order_acquire) == (SemaphoreInfo *) NULL)
+    {
+      LockMagickMutex();
+      if (atomic_load_explicit((_Atomic(SemaphoreInfo *) *) semaphore_info,memory_order_relaxed) == (SemaphoreInfo *) NULL)
+        {
+          SemaphoreInfo
+            *allocated_semaphore;
+
+          allocated_semaphore=AcquireSemaphoreInfo();
+          atomic_store_explicit((_Atomic(SemaphoreInfo *) *) semaphore_info,
+            allocated_semaphore,memory_order_release);
+        }
+      UnlockMagickMutex();
+    }
+#else
   if (*semaphore_info == (SemaphoreInfo *) NULL)
     {
       LockMagickMutex();
       if (*semaphore_info == (SemaphoreInfo *) NULL)
-        *semaphore_info=AcquireSemaphoreInfo();
+        {
+          SemaphoreInfo
+            *allocated_semaphore;
+
+          allocated_semaphore=AcquireSemaphoreInfo();
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+          MemoryBarrier();
+#elif defined(__GNUC__) || defined(__clang__)
+          __atomic_thread_fence(__ATOMIC_RELEASE);
+#endif
+          *semaphore_info=allocated_semaphore;
+        }
       UnlockMagickMutex();
     }
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  MemoryBarrier();
+#elif defined(__GNUC__) || defined(__clang__)
+  __atomic_thread_fence(__ATOMIC_ACQUIRE);
+#endif
+#endif
 }

 /*
@@ -126,11 +169,18 @@ MagickExport void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info)
 %
 */

-static void *AcquireSemaphoreMemory(const size_t count,const size_t quantum)
+static inline size_t AlignSemaphoreExtent(const size_t size,
+  const size_t alignment)
 {
-#define AlignedExtent(size,alignment) \
-  (((size)+((alignment)-1)) & (size_t) ~((alignment)-1))
+  if ((alignment == 0) || ((alignment & (alignment-1)) != 0))
+    return(0);
+  if (size > (SIZE_MAX-(alignment-1)))
+    return(0);
+  return((size+(alignment-1)) & ~(alignment-1));
+}

+static void *AcquireSemaphoreMemory(const size_t count,const size_t quantum)
+{
   size_t
     alignment,
     extent,
@@ -139,36 +189,48 @@ static void *AcquireSemaphoreMemory(const size_t count,const size_t quantum)
   void
     *memory;

-  size=count*quantum;
-  if ((count == 0) || (quantum != (size/count)))
+  if ((count == 0) || (quantum == 0) || (count > (SIZE_MAX/quantum)))
     {
       errno=ENOMEM;
       return((void *) NULL);
     }
-  memory=NULL;
+  size=count*quantum;
   alignment=CACHE_LINE_SIZE;
-  extent=AlignedExtent(size,CACHE_LINE_SIZE);
-  if ((size == 0) || (alignment < sizeof(void *)) || (extent < size))
-    return((void *) NULL);
+  if (alignment < sizeof(void *))
+    alignment=sizeof(void *);
+  extent=AlignSemaphoreExtent(size,alignment);
+  if (extent == 0)
+    {
+      errno=ENOMEM;
+      return((void *) NULL);
+    }
+  memory=(void *) NULL;
 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
   if (posix_memalign(&memory,alignment,extent) != 0)
-    memory=NULL;
+    memory=(void *) NULL;
 #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
-   memory=_aligned_malloc(extent,alignment);
+  memory=_aligned_malloc(extent,alignment);
 #else
   {
     void
-      *p;
+      *raw_memory;

-    extent=(size+alignment-1)+sizeof(void *);
-    if (extent > size)
+    if (size > (SIZE_MAX-(alignment-1)-sizeof(void *)))
       {
-        p=malloc(extent);
-        if (p != NULL)
-          {
-            memory=(void *) AlignedExtent((size_t) p+sizeof(void *),alignment);
-            *((void **) memory-1)=p;
-          }
+        errno=ENOMEM;
+        return((void *) NULL);
+      }
+    extent=size+(alignment-1)+sizeof(void *);
+    raw_memory=malloc(extent);
+    if (raw_memory != (void *) NULL)
+      {
+        uintptr_t
+          aligned_addr;
+
+        aligned_addr=(uintptr_t) raw_memory+sizeof(void *);
+        aligned_addr=(aligned_addr+(alignment-1)) & ~(uintptr_t) (alignment-1);
+        memory=(void *) aligned_addr;
+        *((void **) memory-1)=raw_memory;
       }
   }
 #endif
@@ -186,27 +248,14 @@ static void *RelinquishSemaphoreMemory(void *memory)
 #else
   free(*((void **) memory-1));
 #endif
-  return(NULL);
+  return((void *) NULL);
 }

-MagickExport SemaphoreInfo *AcquireSemaphoreInfo(void)
+static MagickBooleanType InitializeSemaphoreMutex(SemaphoreInfo *semaphore_info)
 {
-  SemaphoreInfo
-    *semaphore_info;
-
-  /*
-    Acquire semaphore.
-  */
-  semaphore_info=(SemaphoreInfo *) AcquireSemaphoreMemory(1,
-    sizeof(*semaphore_info));
-  if (semaphore_info == (SemaphoreInfo *) NULL)
-    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
-  (void) memset(semaphore_info,0,sizeof(SemaphoreInfo));
-  /*
-    Initialize the semaphore.
-  */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   omp_init_lock((omp_lock_t *) &semaphore_info->mutex);
+  return(MagickTrue);
 #elif defined(MAGICKCORE_THREAD_SUPPORT)
   {
     int
@@ -219,49 +268,61 @@ MagickExport SemaphoreInfo *AcquireSemaphoreInfo(void)
     if (status != 0)
       {
         errno=status;
-        perror("unable to initialize mutex attributes");
-        _exit(1);
+        return(MagickFalse);
       }
-#if defined(MAGICKCORE_DEBUG)
-#if defined(PTHREAD_MUTEX_ERRORCHECK)
-    status=pthread_mutex_settype(&mutex_info,PTHREAD_MUTEX_ERRORCHECK);
+#if defined(MAGICKCORE_DEBUG) && defined(PTHREAD_MUTEX_ERRORCHECK)
+    status=pthread_mutexattr_settype(&mutex_info,PTHREAD_MUTEX_ERRORCHECK);
     if (status != 0)
       {
         errno=status;
-        perror("unable to set mutex type");
-        _exit(1);
+        (void) pthread_mutexattr_destroy(&mutex_info);
+        return(MagickFalse);
       }
-#endif
 #endif
     status=pthread_mutex_init(&semaphore_info->mutex,&mutex_info);
+    (void) pthread_mutexattr_destroy(&mutex_info);
     if (status != 0)
       {
         errno=status;
-        perror("unable to initialize mutex");
-        _exit(1);
-      }
-    status=pthread_mutexattr_destroy(&mutex_info);
-    if (status != 0)
-      {
-        errno=status;
-        perror("unable to destroy mutex attributes");
-        _exit(1);
+        return(MagickFalse);
       }
   }
+  return(MagickTrue);
 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
-  {
-    int
-      status;
-
-    status=InitializeCriticalSectionAndSpinCount(&semaphore_info->mutex,0x0400);
-    if (status == 0)
-      {
-        errno=status;
-        perror("unable to initialize critical section");
-        _exit(1);
-      }
-  }
+  if (InitializeCriticalSectionAndSpinCount(&semaphore_info->mutex,0x0400) == 0)
+    {
+      errno=ENOMEM;
+      return(MagickFalse);
+    }
+  return(MagickTrue);
+#else
+  magick_unreferenced(semaphore_info);
+  return(MagickTrue);
 #endif
+}
+
+MagickExport SemaphoreInfo *AcquireSemaphoreInfo(void)
+{
+  SemaphoreInfo
+    *semaphore_info;
+
+  /*
+    Acquire semaphore.
+  */
+  semaphore_info=(SemaphoreInfo *) AcquireSemaphoreMemory(1,
+    sizeof(*semaphore_info));
+  if (semaphore_info == (SemaphoreInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) memset(semaphore_info,0,sizeof(*semaphore_info));
+  /*
+    Initialize the semaphore.
+  */
+  if (InitializeSemaphoreMutex(semaphore_info) == MagickFalse)
+    {
+      semaphore_info=(SemaphoreInfo *) RelinquishSemaphoreMemory(
+        semaphore_info);
+      ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+    }
   semaphore_info->id=GetMagickThreadId();
   semaphore_info->reference_count=0;
   semaphore_info->signature=MagickCoreSignature;
@@ -350,30 +411,43 @@ MagickExport void LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
 */
 MagickExport void RelinquishSemaphoreInfo(SemaphoreInfo **semaphore_info)
 {
+  SemaphoreInfo
+    *target_semaphore;
+
   assert(semaphore_info != (SemaphoreInfo **) NULL);
-  assert((*semaphore_info) != (SemaphoreInfo *) NULL);
-  assert((*semaphore_info)->signature == MagickCoreSignature);
   LockMagickMutex();
+#if defined(MAGICKCORE_HAVE_STDATOMIC_H)
+  target_semaphore=atomic_exchange_explicit(
+    (_Atomic(SemaphoreInfo *) *) semaphore_info,(SemaphoreInfo *) NULL,
+    memory_order_acq_rel);
+#else
+  target_semaphore=(*semaphore_info);
+  *semaphore_info=(SemaphoreInfo *) NULL;
+#endif
+  if (target_semaphore != (SemaphoreInfo *) NULL)
+    {
+      assert(target_semaphore->signature == MagickCoreSignature);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  omp_destroy_lock((omp_lock_t *) &(*semaphore_info)->mutex);
+      omp_destroy_lock((omp_lock_t *) &target_semaphore->mutex);
 #elif defined(MAGICKCORE_THREAD_SUPPORT)
-  {
-    int
-      status;
-
-    status=pthread_mutex_destroy(&(*semaphore_info)->mutex);
-    if (status != 0)
       {
-        errno=status;
-        perror("unable to destroy mutex");
-        _exit(1);
+        int
+          status;
+
+        status=pthread_mutex_destroy(&target_semaphore->mutex);
+        if (status != 0)
+          {
+            errno=status;
+            perror("unable to destroy mutex");
+            _exit(1);
+          }
       }
-  }
 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
-  DeleteCriticalSection(&(*semaphore_info)->mutex);
+      DeleteCriticalSection(&target_semaphore->mutex);
 #endif
-  (*semaphore_info)->signature=(~MagickCoreSignature);
-  *semaphore_info=(SemaphoreInfo *) RelinquishSemaphoreMemory(*semaphore_info);
+      target_semaphore->signature=(~MagickCoreSignature);
+      (void) RelinquishSemaphoreMemory(target_semaphore);
+    }
   UnlockMagickMutex();
 }

diff --git a/config/config.h.in b/config/config.h.in
index 36143834c..f3380a21d 100644
--- a/config/config.h.in
+++ b/config/config.h.in
@@ -485,6 +485,9 @@
 /* Define to 1 if you have the <stdarg.h> header file. */
 #undef HAVE_STDARG_H

+/* Define to 1 if you have the <stdatomic.h> header file. */
+#undef HAVE_STDATOMIC_H
+
 /* Define to 1 if stdbool.h conforms to C99. */
 #undef HAVE_STDBOOL_H

diff --git a/configure b/configure
index 1981d9d04..7b62cf0f8 100755
--- a/configure
+++ b/configure
@@ -5306,7 +5306,7 @@ MAGICK_PATCHLEVEL_VERSION=36

 MAGICK_VERSION=7.1.2-36

-MAGICK_GIT_REVISION=8d240f762:20261108
+MAGICK_GIT_REVISION=64330ffff:20261115


 # Substitute library versioning
@@ -5340,7 +5340,7 @@ PACKAGE_LIB_VERSION=0x712

 PACKAGE_LIB_VERSION_NUMBER=7,1,2,36

-PACKAGE_RELEASE_DATE=2026-11-08
+PACKAGE_RELEASE_DATE=2026-11-15


 # Ensure that make can run correctly
@@ -25965,6 +25965,12 @@ if test "x$ac_cv_header_stdarg_h" = xyes
 then :
   printf '%s\n' "#define HAVE_STDARG_H 1" >>confdefs.h

+fi
+ac_fn_c_check_header_compile "$LINENO" "stdatomic.h" "ac_cv_header_stdatomic_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdatomic_h" = xyes
+then :
+  printf '%s\n' "#define HAVE_STDATOMIC_H 1" >>confdefs.h
+
 fi
 ac_fn_c_check_header_compile "$LINENO" "stddef.h" "ac_cv_header_stddef_h" "$ac_includes_default"
 if test "x$ac_cv_header_stddef_h" = xyes
diff --git a/configure.ac b/configure.ac
index 5bafe3c08..34ed004bc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -984,7 +984,7 @@ AC_HEADER_ASSERT
 AC_HEADER_DIRENT

 # Check additional headers
-AC_CHECK_HEADERS(arm/limits.h arpa/inet.h complex.h errno.h fcntl.h float.h inttypes.h limits.h linux/unistd.h locale.h machine/param.h mach-o/dyld.h malloc.h netdb.h netinet/in.h OS.h process.h sun_prefetch.h stdarg.h stddef.h stdint.h strings.h sys/ipc.h sys/loadavg.h sys/mman.h sys/resource.h sys/sendfile.h sys/socket.h sys/syslimits.h sys/time.h sys/times.h sys/uio.h unistd.h sys/wait.h utime.h wchar.h xlocale.h)
+AC_CHECK_HEADERS(arm/limits.h arpa/inet.h complex.h errno.h fcntl.h float.h inttypes.h limits.h linux/unistd.h locale.h machine/param.h mach-o/dyld.h malloc.h netdb.h netinet/in.h OS.h process.h sun_prefetch.h stdarg.h stdatomic.h stddef.h stdint.h strings.h sys/ipc.h sys/loadavg.h sys/mman.h sys/resource.h sys/sendfile.h sys/socket.h sys/syslimits.h sys/time.h sys/times.h sys/uio.h unistd.h sys/wait.h utime.h wchar.h xlocale.h)

 ########
 #