Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %        SSSSS  EEEEE  M   M   AAA   PPPP   H   H   OOO   RRRR   EEEEE        %
      7 %        SS     E      MM MM  A   A  P   P  H   H  O   O  R   R  E            %
      8 %         SSS   EEE    M M M  AAAAA  PPPP   HHHHH  O   O  RRRR   EEE          %
      9 %           SS  E      M   M  A   A  P      H   H  O   O  R R    E            %
     10 %        SSSSS  EEEEE  M   M  A   A  P      H   H   OOO   R  R   EEEEE        %
     11 %                                                                             %
     12 %                                                                             %
     13 %                        MagickCore Semaphore Methods                         %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                             William Radcliffe                               %
     17 %                                   Cristy                                    %
     18 %                                 June 2000                                   %
     19 %                                                                             %
     20 %                                                                             %
     21 %  Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization      %
     22 %  dedicated to making software imaging solutions freely available.           %
     23 %                                                                             %
     24 %  You may not use this file except in compliance with the License.  You may  %
     25 %  obtain a copy of the License at                                            %
     26 %                                                                             %
     27 %    https://imagemagick.org/script/license.php                               %
     28 %                                                                             %
     29 %  Unless required by applicable law or agreed to in writing, software        %
     30 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     31 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     32 %  See the License for the specific language governing permissions and        %
     33 %  limitations under the License.                                             %
     34 %                                                                             %
     35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     36 %
     37 %
     38 %
     39 */
     40 
     41 /*
     43   Include declarations.
     44 */
     45 #include "MagickCore/studio.h"
     46 #include "MagickCore/exception.h"
     47 #include "MagickCore/exception-private.h"
     48 #include "MagickCore/memory_.h"
     49 #include "MagickCore/memory-private.h"
     50 #include "MagickCore/semaphore.h"
     51 #include "MagickCore/semaphore-private.h"
     52 #include "MagickCore/string_.h"
     53 #include "MagickCore/thread_.h"
     54 #include "MagickCore/thread-private.h"
     55 #include "MagickCore/utility-private.h"
     56 
     57 /*
     59   Struct declaractions.
     60 */
     61 struct SemaphoreInfo
     62 {
     63   MagickMutexType
     64     mutex;
     65 
     66   MagickThreadType
     67     id;
     68 
     69   ssize_t
     70     reference_count;
     71 
     72   size_t
     73     signature;
     74 };
     75 
     76 /*
     78 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     79 %                                                                             %
     80 %                                                                             %
     81 %                                                                             %
     82 %   A c t i v a t e S e m a p h o r e I n f o                                 %
     83 %                                                                             %
     84 %                                                                             %
     85 %                                                                             %
     86 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     87 %
     88 %  ActivateSemaphoreInfo() activates a semaphore under protection of a mutex
     89 %  to ensure only one thread allocates the semaphore.
     90 %
     91 %  The format of the ActivateSemaphoreInfo method is:
     92 %
     93 %      void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info)
     94 %
     95 %  A description of each parameter follows:
     96 %
     97 %    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
     98 %
     99 */
    100 MagickExport void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info)
    101 {
    102   assert(semaphore_info != (SemaphoreInfo **) NULL);
    103   if (*semaphore_info == (SemaphoreInfo *) NULL)
    104     {
    105       InitializeMagickMutex();
    106       LockMagickMutex();
    107       if (*semaphore_info == (SemaphoreInfo *) NULL)
    108         *semaphore_info=AcquireSemaphoreInfo();
    109       UnlockMagickMutex();
    110     }
    111 }
    112 
    113 /*
    115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    116 %                                                                             %
    117 %                                                                             %
    118 %                                                                             %
    119 %   A c q u i r e S e m a p h o r e I n f o                                   %
    120 %                                                                             %
    121 %                                                                             %
    122 %                                                                             %
    123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    124 %
    125 %  AcquireSemaphoreInfo() initializes the SemaphoreInfo structure.
    126 %
    127 %  The format of the AcquireSemaphoreInfo method is:
    128 %
    129 %      SemaphoreInfo *AcquireSemaphoreInfo(void)
    130 %
    131 */
    132 
    133 static void *AcquireSemaphoreMemory(const size_t count,const size_t quantum)
    134 {
    135 #define AlignedExtent(size,alignment) \
    136   (((size)+((alignment)-1)) & ~((alignment)-1))
    137 
    138   size_t
    139     alignment,
    140     extent,
    141     size;
    142 
    143   void
    144     *memory;
    145 
    146   size=count*quantum;
    147   if ((count == 0) || (quantum != (size/count)))
    148     {
    149       errno=ENOMEM;
    150       return((void *) NULL);
    151     }
    152   memory=NULL;
    153   alignment=CACHE_LINE_SIZE;
    154   extent=AlignedExtent(size,CACHE_LINE_SIZE);
    155   if ((size == 0) || (alignment < sizeof(void *)) || (extent < size))
    156     return((void *) NULL);
    157 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
    158   if (posix_memalign(&memory,alignment,extent) != 0)
    159     memory=NULL;
    160 #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
    161    memory=_aligned_malloc(extent,alignment);
    162 #else
    163   {
    164     void
    165       *p;
    166 
    167     extent=(size+alignment-1)+sizeof(void *);
    168     if (extent > size)
    169       {
    170         p=malloc(extent);
    171         if (p != NULL)
    172           {
    173             memory=(void *) AlignedExtent((size_t) p+sizeof(void *),alignment);
    174             *((void **) memory-1)=p;
    175           }
    176       }
    177   }
    178 #endif
    179   return(memory);
    180 }
    181 
    182 static void *RelinquishSemaphoreMemory(void *memory)
    183 {
    184   if (memory == (void *) NULL)
    185     return((void *) NULL);
    186 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
    187   free(memory);
    188 #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
    189   _aligned_free(memory);
    190 #else
    191   free(*((void **) memory-1));
    192 #endif
    193   return(NULL);
    194 }
    195 
    196 MagickExport SemaphoreInfo *AcquireSemaphoreInfo(void)
    197 {
    198   SemaphoreInfo
    199     *semaphore_info;
    200 
    201   /*
    202     Acquire semaphore.
    203   */
    204   semaphore_info=(SemaphoreInfo *) AcquireSemaphoreMemory(1,
    205     sizeof(*semaphore_info));
    206   if (semaphore_info == (SemaphoreInfo *) NULL)
    207     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    208   (void) memset(semaphore_info,0,sizeof(SemaphoreInfo));
    209   /*
    210     Initialize the semaphore.
    211   */
    212 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    213   omp_init_lock((omp_lock_t *) &semaphore_info->mutex);
    214 #elif defined(MAGICKCORE_THREAD_SUPPORT)
    215   {
    216     int
    217       status;
    218 
    219     pthread_mutexattr_t
    220       mutex_info;
    221 
    222     status=pthread_mutexattr_init(&mutex_info);
    223     if (status != 0)
    224       {
    225         errno=status;
    226         perror("unable to initialize mutex attributes");
    227         _exit(1);
    228       }
    229 #if defined(MAGICKCORE_DEBUG)
    230 #if defined(PTHREAD_MUTEX_ERRORCHECK)
    231     status=pthread_mutex_settype(&mutex_info,PTHREAD_MUTEX_ERRORCHECK);
    232     if (status != 0)
    233       {
    234         errno=status;
    235         perror("unable to set mutex type");
    236         _exit(1);
    237       }
    238 #endif
    239 #endif
    240     status=pthread_mutex_init(&semaphore_info->mutex,&mutex_info);
    241     if (status != 0)
    242       {
    243         errno=status;
    244         perror("unable to initialize mutex");
    245         _exit(1);
    246       }
    247     status=pthread_mutexattr_destroy(&mutex_info);
    248     if (status != 0)
    249       {
    250         errno=status;
    251         perror("unable to destroy mutex attributes");
    252         _exit(1);
    253       }
    254   }
    255 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
    256   {
    257     int
    258       status;
    259 
    260     status=InitializeCriticalSectionAndSpinCount(&semaphore_info->mutex,0x0400);
    261     if (status == 0)
    262       {
    263         errno=status;
    264         perror("unable to initialize critical section");
    265         _exit(1);
    266       }
    267   }
    268 #endif
    269   semaphore_info->id=GetMagickThreadId();
    270   semaphore_info->reference_count=0;
    271   semaphore_info->signature=MagickCoreSignature;
    272   return(semaphore_info);
    273 }
    274 
    275 /*
    277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    278 %                                                                             %
    279 %                                                                             %
    280 %                                                                             %
    281 %   L o c k S e m a p h o r e I n f o                                         %
    282 %                                                                             %
    283 %                                                                             %
    284 %                                                                             %
    285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    286 %
    287 %  LockSemaphoreInfo() locks a semaphore.
    288 %
    289 %  The format of the LockSemaphoreInfo method is:
    290 %
    291 %      void LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
    292 %
    293 %  A description of each parameter follows:
    294 %
    295 %    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
    296 %
    297 */
    298 MagickExport void LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
    299 {
    300   assert(semaphore_info != (SemaphoreInfo *) NULL);
    301   assert(semaphore_info->signature == MagickCoreSignature);
    302 #if defined(MAGICKCORE_DEBUG)
    303   if ((semaphore_info->reference_count > 0) &&
    304       (IsMagickThreadEqual(semaphore_info->id) != MagickFalse))
    305     {
    306       (void) FormatLocaleFile(stderr,"Warning: unexpected recursive lock!\n");
    307       (void) fflush(stderr);
    308     }
    309 #endif
    310 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    311   omp_set_lock((omp_lock_t *) &semaphore_info->mutex);
    312 #elif defined(MAGICKCORE_THREAD_SUPPORT)
    313   {
    314     int
    315       status;
    316 
    317     status=pthread_mutex_lock(&semaphore_info->mutex);
    318     if (status != 0)
    319       {
    320         errno=status;
    321         perror("unable to lock mutex");
    322         _exit(1);
    323       }
    324   }
    325 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
    326   EnterCriticalSection(&semaphore_info->mutex);
    327 #endif
    328 #if defined(MAGICKCORE_DEBUG)
    329   semaphore_info->id=GetMagickThreadId();
    330   semaphore_info->reference_count++;
    331 #endif
    332 }
    333 
    334 /*
    336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    337 %                                                                             %
    338 %                                                                             %
    339 %                                                                             %
    340 %   R e l i n q u i s h S e m a p h o r e I n f o                             %
    341 %                                                                             %
    342 %                                                                             %
    343 %                                                                             %
    344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    345 %
    346 %  RelinquishSemaphoreInfo() destroys a semaphore.
    347 %
    348 %  The format of the RelinquishSemaphoreInfo method is:
    349 %
    350 %      void RelinquishSemaphoreInfo(SemaphoreInfo **semaphore_info)
    351 %
    352 %  A description of each parameter follows:
    353 %
    354 %    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
    355 %
    356 */
    357 MagickExport void RelinquishSemaphoreInfo(SemaphoreInfo **semaphore_info)
    358 {
    359   assert(semaphore_info != (SemaphoreInfo **) NULL);
    360   assert((*semaphore_info) != (SemaphoreInfo *) NULL);
    361   assert((*semaphore_info)->signature == MagickCoreSignature);
    362   InitializeMagickMutex();
    363   LockMagickMutex();
    364 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    365   omp_destroy_lock((omp_lock_t *) &(*semaphore_info)->mutex);
    366 #elif defined(MAGICKCORE_THREAD_SUPPORT)
    367   {
    368     int
    369       status;
    370 
    371     status=pthread_mutex_destroy(&(*semaphore_info)->mutex);
    372     if (status != 0)
    373       {
    374         errno=status;
    375         perror("unable to destroy mutex");
    376         _exit(1);
    377       }
    378   }
    379 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
    380   DeleteCriticalSection(&(*semaphore_info)->mutex);
    381 #endif
    382   (*semaphore_info)->signature=(~MagickCoreSignature);
    383   *semaphore_info=(SemaphoreInfo *) RelinquishSemaphoreMemory(*semaphore_info);
    384   UnlockMagickMutex();
    385 }
    386 
    387 /*
    389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    390 %                                                                             %
    391 %                                                                             %
    392 %                                                                             %
    393 %   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                         %
    394 %                                                                             %
    395 %                                                                             %
    396 %                                                                             %
    397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    398 %
    399 %  SemaphoreComponentGenesis() instantiates the semaphore environment.
    400 %
    401 %  The format of the SemaphoreComponentGenesis method is:
    402 %
    403 %      MagickBooleanType SemaphoreComponentGenesis(void)
    404 %
    405 */
    406 MagickPrivate MagickBooleanType SemaphoreComponentGenesis(void)
    407 {
    408   InitializeMagickMutex();
    409   return(MagickTrue);
    410 }
    411 
    412 /*
    414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    415 %                                                                             %
    416 %                                                                             %
    417 %                                                                             %
    418 %   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                       %
    419 %                                                                             %
    420 %                                                                             %
    421 %                                                                             %
    422 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    423 %
    424 %  SemaphoreComponentTerminus() destroys the semaphore component.
    425 %
    426 %  The format of the SemaphoreComponentTerminus method is:
    427 %
    428 %      SemaphoreComponentTerminus(void)
    429 %
    430 */
    431 MagickPrivate void SemaphoreComponentTerminus(void)
    432 {
    433   DestroyMagickMutex();
    434 }
    435 
    436 /*
    438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    439 %                                                                             %
    440 %                                                                             %
    441 %                                                                             %
    442 %   U n l o c k S e m a p h o r e I n f o                                     %
    443 %                                                                             %
    444 %                                                                             %
    445 %                                                                             %
    446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    447 %
    448 %  UnlockSemaphoreInfo() unlocks a semaphore.
    449 %
    450 %  The format of the UnlockSemaphoreInfo method is:
    451 %
    452 %      void UnlockSemaphoreInfo(SemaphoreInfo *semaphore_info)
    453 %
    454 %  A description of each parameter follows:
    455 %
    456 %    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
    457 %
    458 */
    459 MagickExport void UnlockSemaphoreInfo(SemaphoreInfo *semaphore_info)
    460 {
    461   assert(semaphore_info != (SemaphoreInfo *) NULL);
    462   assert(semaphore_info->signature == MagickCoreSignature);
    463 #if defined(MAGICKCORE_DEBUG)
    464   assert(IsMagickThreadEqual(semaphore_info->id) != MagickFalse);
    465   if (semaphore_info->reference_count == 0)
    466     {
    467       (void) FormatLocaleFile(stderr,
    468         "Warning: semaphore lock already unlocked!\n");
    469       (void) fflush(stderr);
    470       return;
    471     }
    472   semaphore_info->reference_count--;
    473 #endif
    474 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    475   omp_unset_lock((omp_lock_t *) &semaphore_info->mutex);
    476 #elif defined(MAGICKCORE_THREAD_SUPPORT)
    477   {
    478     int
    479       status;
    480 
    481     status=pthread_mutex_unlock(&semaphore_info->mutex);
    482     if (status != 0)
    483       {
    484         errno=status;
    485         perror("unable to unlock mutex");
    486         _exit(1);
    487       }
    488   }
    489 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
    490   LeaveCriticalSection(&semaphore_info->mutex);
    491 #endif
    492 }
    493