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