|
|
/* |
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
|
|
% % |
|
|
% % |
|
|
% % |
|
|
% 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 |
|
|
}
|
|
|
|