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-2016 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 %    http://www.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 
     56 /*
     58   Struct declaractions.
     59 */
     60 struct SemaphoreInfo
     61 {
     62   MagickMutexType
     63     mutex;
     64 
     65   MagickThreadType
     66     id;
     67 
     68   ssize_t
     69     reference_count;
     70 
     71   size_t
     72     signature;
     73 };
     74 
     75 /*
     77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     78 %                                                                             %
     79 %                                                                             %
     80 %                                                                             %
     81 %   A c t i v a t e S e m a p h o r e I n f o                                 %
     82 %                                                                             %
     83 %                                                                             %
     84 %                                                                             %
     85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     86 %
     87 %  ActivateSemaphoreInfo() activates a semaphore under protection of a mutex
     88 %  to ensure only one thread allocates the semaphore.
     89 %
     90 %  The format of the ActivateSemaphoreInfo method is:
     91 %
     92 %      void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info)
     93 %
     94 %  A description of each parameter follows:
     95 %
     96 %    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
     97 %
     98 */
     99 MagickExport void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info)
    100 {
    101   assert(semaphore_info != (SemaphoreInfo **) NULL);
    102   if (*semaphore_info == (SemaphoreInfo *) NULL)
    103     {
    104       InitializeMagickMutex();
    105       LockMagickMutex();
    106       if (*semaphore_info == (SemaphoreInfo *) NULL)
    107         *semaphore_info=AcquireSemaphoreInfo();
    108       UnlockMagickMutex();
    109     }
    110 }
    111 
    112 /*
    114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    115 %                                                                             %
    116 %                                                                             %
    117 %                                                                             %
    118 %   A c q u i r e S e m a p h o r e I n f o                                   %
    119 %                                                                             %
    120 %                                                                             %
    121 %                                                                             %
    122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    123 %
    124 %  AcquireSemaphoreInfo() initializes the SemaphoreInfo structure.
    125 %
    126 %  The format of the AcquireSemaphoreInfo method is:
    127 %
    128 %      SemaphoreInfo *AcquireSemaphoreInfo(void)
    129 %
    130 */
    131 
    132 static void *AcquireSemaphoreMemory(const size_t count,const size_t quantum)
    133 {
    134 #define AlignedExtent(size,alignment) \
    135   (((size)+((alignment)-1)) & ~((alignment)-1))
    136 
    137   size_t
    138     alignment,
    139     extent,
    140     size;
    141 
    142   void
    143     *memory;
    144 
    145   size=count*quantum;
    146   if ((count == 0) || (quantum != (size/count)))
    147     {
    148       errno=ENOMEM;
    149       return((void *) NULL);
    150     }
    151   memory=NULL;
    152   alignment=CACHE_LINE_SIZE;
    153   extent=AlignedExtent(size,alignment);
    154   if ((size == 0) || (alignment < sizeof(void *)) || (extent < size))
    155     return((void *) NULL);
    156 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
    157   if (posix_memalign(&memory,alignment,extent) != 0)
    158     memory=NULL;
    159 #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
    160   memory=_aligned_malloc(extent,alignment);
    161 #else
    162   {
    163     void
    164       *p;
    165 
    166     extent=(size+alignment-1)+sizeof(void *);
    167     if (extent > size)
    168       {
    169         p=malloc(extent);
    170         if (p != NULL)
    171           {
    172             memory=(void *) AlignedExtent((size_t) p+sizeof(void *),alignment);
    173             *((void **) memory-1)=p;
    174           }
    175       }
    176   }
    177 #endif
    178   return(memory);
    179 }
    180 
    181 static void *RelinquishSemaphoreMemory(void *memory)
    182 {
    183   if (memory == (void *) NULL)
    184     return((void *) NULL);
    185 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
    186   free(memory);
    187 #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
    188   _aligned_free(memory);
    189 #else
    190   free(*((void **) memory-1));
    191 #endif
    192   return(NULL);
    193 }
    194 
    195 MagickExport SemaphoreInfo *AcquireSemaphoreInfo(void)
    196 {
    197   SemaphoreInfo
    198     *semaphore_info;
    199 
    200   /*
    201     Acquire semaphore.
    202   */
    203   semaphore_info=(SemaphoreInfo *) AcquireSemaphoreMemory(1,
    204     sizeof(*semaphore_info));
    205   if (semaphore_info == (SemaphoreInfo *) NULL)
    206     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    207   (void) ResetMagickMemory(semaphore_info,0,sizeof(SemaphoreInfo));
    208   /*
    209     Initialize the semaphore.
    210   */
    211 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    212   omp_init_lock((omp_lock_t *) &semaphore_info->mutex);
    213 #elif defined(MAGICKCORE_THREAD_SUPPORT)
    214   {
    215     int
    216       status;
    217 
    218     pthread_mutexattr_t
    219       mutex_info;
    220 
    221     status=pthread_mutexattr_init(&mutex_info);
    222     if (status != 0)
    223       {
    224         errno=status;
    225         perror("unable to initialize mutex attributes");
    226         _exit(1);
    227       }
    228 #if defined(MAGICKCORE_DEBUG)
    229 #if defined(PTHREAD_MUTEX_ERRORCHECK)
    230     status=pthread_mutex_settype(&mutex_info,PTHREAD_MUTEX_ERRORCHECK);
    231     if (status != 0)
    232       {
    233         errno=status;
    234         perror("unable to set mutex type");
    235         _exit(1);
    236       }
    237 #endif
    238 #endif
    239     status=pthread_mutex_init(&semaphore_info->mutex,&mutex_info);
    240     if (status != 0)
    241       {
    242         errno=status;
    243         perror("unable to initialize mutex");
    244         _exit(1);
    245       }
    246     status=pthread_mutexattr_destroy(&mutex_info);
    247     if (status != 0)
    248       {
    249         errno=status;
    250         perror("unable to destroy mutex attributes");
    251         _exit(1);
    252       }
    253   }
    254 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
    255   {
    256     int
    257       status;
    258 
    259     status=InitializeCriticalSectionAndSpinCount(&semaphore_info->mutex,0x0400);
    260     if (status == 0)
    261       {
    262         errno=status;
    263         perror("unable to initialize critical section");
    264         _exit(1);
    265       }
    266   }
    267 #endif
    268   semaphore_info->id=GetMagickThreadId();
    269   semaphore_info->reference_count=0;
    270   semaphore_info->signature=MagickCoreSignature;
    271   return(semaphore_info);
    272 }
    273 
    274 /*
    276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    277 %                                                                             %
    278 %                                                                             %
    279 %                                                                             %
    280 %   L o c k S e m a p h o r e I n f o                                         %
    281 %                                                                             %
    282 %                                                                             %
    283 %                                                                             %
    284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    285 %
    286 %  LockSemaphoreInfo() locks a semaphore.
    287 %
    288 %  The format of the LockSemaphoreInfo method is:
    289 %
    290 %      void LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
    291 %
    292 %  A description of each parameter follows:
    293 %
    294 %    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
    295 %
    296 */
    297 MagickExport void LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
    298 {
    299   assert(semaphore_info != (SemaphoreInfo *) NULL);
    300   assert(semaphore_info->signature == MagickCoreSignature);
    301 #if defined(MAGICKCORE_DEBUG)
    302   if ((semaphore_info->reference_count > 0) &&
    303       (IsMagickThreadEqual(semaphore_info->id) != MagickFalse))
    304     {
    305       (void) FormatLocaleFile(stderr,"Warning: unexpected recursive lock!\n");
    306       (void) fflush(stderr);
    307     }
    308 #endif
    309 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    310   omp_set_lock((omp_lock_t *) &semaphore_info->mutex);
    311 #elif defined(MAGICKCORE_THREAD_SUPPORT)
    312   {
    313     int
    314       status;
    315 
    316     status=pthread_mutex_lock(&semaphore_info->mutex);
    317     if (status != 0)
    318       {
    319         errno=status;
    320         perror("unable to lock mutex");
    321         _exit(1);
    322       }
    323   }
    324 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
    325   EnterCriticalSection(&semaphore_info->mutex);
    326 #endif
    327 #if defined(MAGICKCORE_DEBUG)
    328   semaphore_info->id=GetMagickThreadId();
    329   semaphore_info->reference_count++;
    330 #endif
    331 }
    332 
    333 /*
    335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    336 %                                                                             %
    337 %                                                                             %
    338 %                                                                             %
    339 %   R e l i n q u i s h S e m a p h o r e I n f o                             %
    340 %                                                                             %
    341 %                                                                             %
    342 %                                                                             %
    343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    344 %
    345 %  RelinquishSemaphoreInfo() destroys a semaphore.
    346 %
    347 %  The format of the RelinquishSemaphoreInfo method is:
    348 %
    349 %      void RelinquishSemaphoreInfo(SemaphoreInfo **semaphore_info)
    350 %
    351 %  A description of each parameter follows:
    352 %
    353 %    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
    354 %
    355 */
    356 MagickExport void RelinquishSemaphoreInfo(SemaphoreInfo **semaphore_info)
    357 {
    358   assert(semaphore_info != (SemaphoreInfo **) NULL);
    359   assert((*semaphore_info) != (SemaphoreInfo *) NULL);
    360   assert((*semaphore_info)->signature == MagickCoreSignature);
    361   InitializeMagickMutex();
    362   LockMagickMutex();
    363 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    364   omp_destroy_lock((omp_lock_t *) &(*semaphore_info)->mutex);
    365 #elif defined(MAGICKCORE_THREAD_SUPPORT)
    366   {
    367     int
    368       status;
    369 
    370     status=pthread_mutex_destroy(&(*semaphore_info)->mutex);
    371     if (status != 0)
    372       {
    373         errno=status;
    374         perror("unable to destroy mutex");
    375         _exit(1);
    376       }
    377   }
    378 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
    379   DeleteCriticalSection(&(*semaphore_info)->mutex);
    380 #endif
    381   (*semaphore_info)->signature=(~MagickCoreSignature);
    382   *semaphore_info=(SemaphoreInfo *) RelinquishSemaphoreMemory(*semaphore_info);
    383   UnlockMagickMutex();
    384 }
    385 
    386 /*
    388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    389 %                                                                             %
    390 %                                                                             %
    391 %                                                                             %
    392 %   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                         %
    393 %                                                                             %
    394 %                                                                             %
    395 %                                                                             %
    396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    397 %
    398 %  SemaphoreComponentGenesis() instantiates the semaphore environment.
    399 %
    400 %  The format of the SemaphoreComponentGenesis method is:
    401 %
    402 %      MagickBooleanType SemaphoreComponentGenesis(void)
    403 %
    404 */
    405 MagickPrivate MagickBooleanType SemaphoreComponentGenesis(void)
    406 {
    407   InitializeMagickMutex();
    408   return(MagickTrue);
    409 }
    410 
    411 /*
    413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    414 %                                                                             %
    415 %                                                                             %
    416 %                                                                             %
    417 %   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                       %
    418 %                                                                             %
    419 %                                                                             %
    420 %                                                                             %
    421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    422 %
    423 %  SemaphoreComponentTerminus() destroys the semaphore component.
    424 %
    425 %  The format of the SemaphoreComponentTerminus method is:
    426 %
    427 %      SemaphoreComponentTerminus(void)
    428 %
    429 */
    430 MagickPrivate void SemaphoreComponentTerminus(void)
    431 {
    432   DestroyMagickMutex();
    433 }
    434 
    435 /*
    437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    438 %                                                                             %
    439 %                                                                             %
    440 %                                                                             %
    441 %   U n l o c k S e m a p h o r e I n f o                                     %
    442 %                                                                             %
    443 %                                                                             %
    444 %                                                                             %
    445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    446 %
    447 %  UnlockSemaphoreInfo() unlocks a semaphore.
    448 %
    449 %  The format of the UnlockSemaphoreInfo method is:
    450 %
    451 %      void UnlockSemaphoreInfo(SemaphoreInfo *semaphore_info)
    452 %
    453 %  A description of each parameter follows:
    454 %
    455 %    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
    456 %
    457 */
    458 MagickExport void UnlockSemaphoreInfo(SemaphoreInfo *semaphore_info)
    459 {
    460   assert(semaphore_info != (SemaphoreInfo *) NULL);
    461   assert(semaphore_info->signature == MagickCoreSignature);
    462 #if defined(MAGICKCORE_DEBUG)
    463   assert(IsMagickThreadEqual(semaphore_info->id) != MagickFalse);
    464   if (semaphore_info->reference_count == 0)
    465     {
    466       (void) FormatLocaleFile(stderr,
    467         "Warning: semaphore lock already unlocked!\n");
    468       (void) fflush(stderr);
    469       return;
    470     }
    471   semaphore_info->reference_count--;
    472 #endif
    473 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    474   omp_unset_lock((omp_lock_t *) &semaphore_info->mutex);
    475 #elif defined(MAGICKCORE_THREAD_SUPPORT)
    476   {
    477     int
    478       status;
    479 
    480     status=pthread_mutex_unlock(&semaphore_info->mutex);
    481     if (status != 0)
    482       {
    483         errno=status;
    484         perror("unable to unlock mutex");
    485         _exit(1);
    486       }
    487   }
    488 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
    489   LeaveCriticalSection(&semaphore_info->mutex);
    490 #endif
    491 }
    492