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)
########
#