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