/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % SSSSS EEEEE M M AAA PPPP H H OOO RRRR EEEEE % % SS E MM MM A A P P H H O O R R E % % SSS EEE M M M AAAAA PPPP HHHHH O O RRRR EEE % % SS E M M A A P H H O O R R E % % SSSSS EEEEE M M A A P H H OOO R R EEEEE % % % % % % MagickCore Semaphore Methods % % % % Software Design % % William Radcliffe % % Cristy % % June 2000 % % % % % % Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % % dedicated to making software imaging solutions freely available. % % % % You may not use this file except in compliance with the License. You may % % obtain a copy of the License at % % % % http://www.imagemagick.org/script/license.php % % % % Unless required by applicable law or agreed to in writing, software % % distributed under the License is distributed on an "AS IS" BASIS, % % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % % See the License for the specific language governing permissions and % % limitations under the License. % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % */ /* Include declarations. */ #include "MagickCore/studio.h" #include "MagickCore/exception.h" #include "MagickCore/exception-private.h" #include "MagickCore/memory_.h" #include "MagickCore/memory-private.h" #include "MagickCore/semaphore.h" #include "MagickCore/semaphore-private.h" #include "MagickCore/string_.h" #include "MagickCore/thread_.h" #include "MagickCore/thread-private.h" /* Struct declaractions. */ struct SemaphoreInfo { MagickMutexType mutex; MagickThreadType id; ssize_t reference_count; size_t signature; }; /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % A c t i v a t e S e m a p h o r e I n f o % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ActivateSemaphoreInfo() activates a semaphore under protection of a mutex % to ensure only one thread allocates the semaphore. % % The format of the ActivateSemaphoreInfo method is: % % void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info) % % A description of each parameter follows: % % o semaphore_info: Specifies a pointer to an SemaphoreInfo structure. % */ MagickExport void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info) { assert(semaphore_info != (SemaphoreInfo **) NULL); if (*semaphore_info == (SemaphoreInfo *) NULL) { InitializeMagickMutex(); LockMagickMutex(); if (*semaphore_info == (SemaphoreInfo *) NULL) *semaphore_info=AcquireSemaphoreInfo(); UnlockMagickMutex(); } } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % A c q u i r e S e m a p h o r e I n f o % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % AcquireSemaphoreInfo() initializes the SemaphoreInfo structure. % % The format of the AcquireSemaphoreInfo method is: % % SemaphoreInfo *AcquireSemaphoreInfo(void) % */ static void *AcquireSemaphoreMemory(const size_t count,const size_t quantum) { #define AlignedExtent(size,alignment) \ (((size)+((alignment)-1)) & ~((alignment)-1)) size_t alignment, extent, size; void *memory; size=count*quantum; if ((count == 0) || (quantum != (size/count))) { errno=ENOMEM; return((void *) NULL); } memory=NULL; alignment=CACHE_LINE_SIZE; extent=AlignedExtent(size,alignment); if ((size == 0) || (alignment < sizeof(void *)) || (extent < size)) return((void *) NULL); #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN) if (posix_memalign(&memory,alignment,extent) != 0) memory=NULL; #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC) memory=_aligned_malloc(extent,alignment); #else { void *p; extent=(size+alignment-1)+sizeof(void *); if (extent > size) { p=malloc(extent); if (p != NULL) { memory=(void *) AlignedExtent((size_t) p+sizeof(void *),alignment); *((void **) memory-1)=p; } } } #endif return(memory); } static void *RelinquishSemaphoreMemory(void *memory) { if (memory == (void *) NULL) return((void *) NULL); #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN) free(memory); #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC) _aligned_free(memory); #else free(*((void **) memory-1)); #endif return(NULL); } 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) ResetMagickMemory(semaphore_info,0,sizeof(SemaphoreInfo)); /* Initialize the semaphore. */ #if defined(MAGICKCORE_OPENMP_SUPPORT) omp_init_lock((omp_lock_t *) &semaphore_info->mutex); #elif defined(MAGICKCORE_THREAD_SUPPORT) { int status; pthread_mutexattr_t mutex_info; status=pthread_mutexattr_init(&mutex_info); if (status != 0) { errno=status; perror("unable to initialize mutex attributes"); _exit(1); } #if defined(MAGICKCORE_DEBUG) #if defined(PTHREAD_MUTEX_ERRORCHECK) status=pthread_mutex_settype(&mutex_info,PTHREAD_MUTEX_ERRORCHECK); if (status != 0) { errno=status; perror("unable to set mutex type"); _exit(1); } #endif #endif status=pthread_mutex_init(&semaphore_info->mutex,&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); } } #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); } } #endif semaphore_info->id=GetMagickThreadId(); semaphore_info->reference_count=0; semaphore_info->signature=MagickCoreSignature; return(semaphore_info); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % L o c k S e m a p h o r e I n f o % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % LockSemaphoreInfo() locks a semaphore. % % The format of the LockSemaphoreInfo method is: % % void LockSemaphoreInfo(SemaphoreInfo *semaphore_info) % % A description of each parameter follows: % % o semaphore_info: Specifies a pointer to an SemaphoreInfo structure. % */ MagickExport void LockSemaphoreInfo(SemaphoreInfo *semaphore_info) { assert(semaphore_info != (SemaphoreInfo *) NULL); assert(semaphore_info->signature == MagickCoreSignature); #if defined(MAGICKCORE_DEBUG) if ((semaphore_info->reference_count > 0) && (IsMagickThreadEqual(semaphore_info->id) != MagickFalse)) { (void) FormatLocaleFile(stderr,"Warning: unexpected recursive lock!\n"); (void) fflush(stderr); } #endif #if defined(MAGICKCORE_OPENMP_SUPPORT) omp_set_lock((omp_lock_t *) &semaphore_info->mutex); #elif defined(MAGICKCORE_THREAD_SUPPORT) { int status; status=pthread_mutex_lock(&semaphore_info->mutex); if (status != 0) { errno=status; perror("unable to lock mutex"); _exit(1); } } #elif defined(MAGICKCORE_WINDOWS_SUPPORT) EnterCriticalSection(&semaphore_info->mutex); #endif #if defined(MAGICKCORE_DEBUG) semaphore_info->id=GetMagickThreadId(); semaphore_info->reference_count++; #endif } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e l i n q u i s h S e m a p h o r e I n f o % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % RelinquishSemaphoreInfo() destroys a semaphore. % % The format of the RelinquishSemaphoreInfo method is: % % void RelinquishSemaphoreInfo(SemaphoreInfo **semaphore_info) % % A description of each parameter follows: % % o semaphore_info: Specifies a pointer to an SemaphoreInfo structure. % */ MagickExport void RelinquishSemaphoreInfo(SemaphoreInfo **semaphore_info) { assert(semaphore_info != (SemaphoreInfo **) NULL); assert((*semaphore_info) != (SemaphoreInfo *) NULL); assert((*semaphore_info)->signature == MagickCoreSignature); InitializeMagickMutex(); LockMagickMutex(); #if defined(MAGICKCORE_OPENMP_SUPPORT) omp_destroy_lock((omp_lock_t *) &(*semaphore_info)->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); } } #elif defined(MAGICKCORE_WINDOWS_SUPPORT) DeleteCriticalSection(&(*semaphore_info)->mutex); #endif (*semaphore_info)->signature=(~MagickCoreSignature); *semaphore_info=(SemaphoreInfo *) RelinquishSemaphoreMemory(*semaphore_info); UnlockMagickMutex(); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % S e m a p h o r e C o m p o n e n t G e n e s i s % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % SemaphoreComponentGenesis() instantiates the semaphore environment. % % The format of the SemaphoreComponentGenesis method is: % % MagickBooleanType SemaphoreComponentGenesis(void) % */ MagickPrivate MagickBooleanType SemaphoreComponentGenesis(void) { InitializeMagickMutex(); return(MagickTrue); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % S e m a p h o r e C o m p o n e n t T e r m i n u s % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % SemaphoreComponentTerminus() destroys the semaphore component. % % The format of the SemaphoreComponentTerminus method is: % % SemaphoreComponentTerminus(void) % */ MagickPrivate void SemaphoreComponentTerminus(void) { DestroyMagickMutex(); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % U n l o c k S e m a p h o r e I n f o % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % UnlockSemaphoreInfo() unlocks a semaphore. % % The format of the UnlockSemaphoreInfo method is: % % void UnlockSemaphoreInfo(SemaphoreInfo *semaphore_info) % % A description of each parameter follows: % % o semaphore_info: Specifies a pointer to an SemaphoreInfo structure. % */ MagickExport void UnlockSemaphoreInfo(SemaphoreInfo *semaphore_info) { assert(semaphore_info != (SemaphoreInfo *) NULL); assert(semaphore_info->signature == MagickCoreSignature); #if defined(MAGICKCORE_DEBUG) assert(IsMagickThreadEqual(semaphore_info->id) != MagickFalse); if (semaphore_info->reference_count == 0) { (void) FormatLocaleFile(stderr, "Warning: semaphore lock already unlocked!\n"); (void) fflush(stderr); return; } semaphore_info->reference_count--; #endif #if defined(MAGICKCORE_OPENMP_SUPPORT) omp_unset_lock((omp_lock_t *) &semaphore_info->mutex); #elif defined(MAGICKCORE_THREAD_SUPPORT) { int status; status=pthread_mutex_unlock(&semaphore_info->mutex); if (status != 0) { errno=status; perror("unable to unlock mutex"); _exit(1); } } #elif defined(MAGICKCORE_WINDOWS_SUPPORT) LeaveCriticalSection(&semaphore_info->mutex); #endif }