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-2021 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 /*
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/mutex.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 /*
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 /*
76 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77 %                                                                             %
78 %                                                                             %
79 %                                                                             %
80 %   A c t i v a t e S e m a p h o r e I n f o                                 %
81 %                                                                             %
82 %                                                                             %
83 %                                                                             %
84 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85 %
86 %  ActivateSemaphoreInfo() activates a semaphore under protection of a mutex
87 %  to ensure only one thread allocates the semaphore.
88 %
89 %  The format of the ActivateSemaphoreInfo method is:
90 %
91 %      void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info)
92 %
93 %  A description of each parameter follows:
94 %
95 %    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
96 %
97 */
ActivateSemaphoreInfo(SemaphoreInfo ** semaphore_info)98 MagickExport void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info)
99 {
100   assert(semaphore_info != (SemaphoreInfo **) NULL);
101   if (*semaphore_info == (SemaphoreInfo *) NULL)
102     {
103       LockMagickMutex();
104       if (*semaphore_info == (SemaphoreInfo *) NULL)
105         *semaphore_info=AcquireSemaphoreInfo();
106       UnlockMagickMutex();
107     }
108 }
109 
110 /*
111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
112 %                                                                             %
113 %                                                                             %
114 %                                                                             %
115 %   A c q u i r e S e m a p h o r e I n f o                                   %
116 %                                                                             %
117 %                                                                             %
118 %                                                                             %
119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120 %
121 %  AcquireSemaphoreInfo() initializes the SemaphoreInfo structure.
122 %
123 %  The format of the AcquireSemaphoreInfo method is:
124 %
125 %      SemaphoreInfo *AcquireSemaphoreInfo(void)
126 %
127 */
128 
AcquireSemaphoreMemory(const size_t count,const size_t quantum)129 static void *AcquireSemaphoreMemory(const size_t count,const size_t quantum)
130 {
131 #define AlignedExtent(size,alignment) \
132   (((size)+((alignment)-1)) & ~((alignment)-1))
133 
134   size_t
135     alignment,
136     extent,
137     size;
138 
139   void
140     *memory;
141 
142   size=count*quantum;
143   if ((count == 0) || (quantum != (size/count)))
144     {
145       errno=ENOMEM;
146       return((void *) NULL);
147     }
148   memory=NULL;
149   alignment=CACHE_LINE_SIZE;
150   extent=AlignedExtent(size,CACHE_LINE_SIZE);
151   if ((size == 0) || (alignment < sizeof(void *)) || (extent < size))
152     return((void *) NULL);
153 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
154   if (posix_memalign(&memory,alignment,extent) != 0)
155     memory=NULL;
156 #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
157    memory=_aligned_malloc(extent,alignment);
158 #else
159   {
160     void
161       *p;
162 
163     extent=(size+alignment-1)+sizeof(void *);
164     if (extent > size)
165       {
166         p=malloc(extent);
167         if (p != NULL)
168           {
169             memory=(void *) AlignedExtent((size_t) p+sizeof(void *),alignment);
170             *((void **) memory-1)=p;
171           }
172       }
173   }
174 #endif
175   return(memory);
176 }
177 
RelinquishSemaphoreMemory(void * memory)178 static void *RelinquishSemaphoreMemory(void *memory)
179 {
180   if (memory == (void *) NULL)
181     return((void *) NULL);
182 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
183   free(memory);
184 #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
185   _aligned_free(memory);
186 #else
187   free(*((void **) memory-1));
188 #endif
189   return(NULL);
190 }
191 
AcquireSemaphoreInfo(void)192 MagickExport SemaphoreInfo *AcquireSemaphoreInfo(void)
193 {
194   SemaphoreInfo
195     *semaphore_info;
196 
197   /*
198     Acquire semaphore.
199   */
200   semaphore_info=(SemaphoreInfo *) AcquireSemaphoreMemory(1,
201     sizeof(*semaphore_info));
202   if (semaphore_info == (SemaphoreInfo *) NULL)
203     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
204   (void) memset(semaphore_info,0,sizeof(SemaphoreInfo));
205   /*
206     Initialize the semaphore.
207   */
208 #if defined(MAGICKCORE_OPENMP_SUPPORT)
209   omp_init_lock((omp_lock_t *) &semaphore_info->mutex);
210 #elif defined(MAGICKCORE_THREAD_SUPPORT)
211   {
212     int
213       status;
214 
215     pthread_mutexattr_t
216       mutex_info;
217 
218     status=pthread_mutexattr_init(&mutex_info);
219     if (status != 0)
220       {
221         errno=status;
222         perror("unable to initialize mutex attributes");
223         _exit(1);
224       }
225 #if defined(MAGICKCORE_DEBUG)
226 #if defined(PTHREAD_MUTEX_ERRORCHECK)
227     status=pthread_mutex_settype(&mutex_info,PTHREAD_MUTEX_ERRORCHECK);
228     if (status != 0)
229       {
230         errno=status;
231         perror("unable to set mutex type");
232         _exit(1);
233       }
234 #endif
235 #endif
236     status=pthread_mutex_init(&semaphore_info->mutex,&mutex_info);
237     if (status != 0)
238       {
239         errno=status;
240         perror("unable to initialize mutex");
241         _exit(1);
242       }
243     status=pthread_mutexattr_destroy(&mutex_info);
244     if (status != 0)
245       {
246         errno=status;
247         perror("unable to destroy mutex attributes");
248         _exit(1);
249       }
250   }
251 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
252   {
253     int
254       status;
255 
256     status=InitializeCriticalSectionAndSpinCount(&semaphore_info->mutex,0x0400);
257     if (status == 0)
258       {
259         errno=status;
260         perror("unable to initialize critical section");
261         _exit(1);
262       }
263   }
264 #endif
265   semaphore_info->id=GetMagickThreadId();
266   semaphore_info->reference_count=0;
267   semaphore_info->signature=MagickCoreSignature;
268   return(semaphore_info);
269 }
270 
271 /*
272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273 %                                                                             %
274 %                                                                             %
275 %                                                                             %
276 %   L o c k S e m a p h o r e I n f o                                         %
277 %                                                                             %
278 %                                                                             %
279 %                                                                             %
280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
281 %
282 %  LockSemaphoreInfo() locks a semaphore.
283 %
284 %  The format of the LockSemaphoreInfo method is:
285 %
286 %      void LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
287 %
288 %  A description of each parameter follows:
289 %
290 %    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
291 %
292 */
LockSemaphoreInfo(SemaphoreInfo * semaphore_info)293 MagickExport void LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
294 {
295   assert(semaphore_info != (SemaphoreInfo *) NULL);
296   assert(semaphore_info->signature == MagickCoreSignature);
297 #if defined(MAGICKCORE_DEBUG)
298   if ((semaphore_info->reference_count > 0) &&
299       (IsMagickThreadEqual(semaphore_info->id) != MagickFalse))
300     {
301       (void) FormatLocaleFile(stderr,"Warning: unexpected recursive lock!\n");
302       (void) fflush(stderr);
303     }
304 #endif
305 #if defined(MAGICKCORE_OPENMP_SUPPORT)
306   omp_set_lock((omp_lock_t *) &semaphore_info->mutex);
307 #elif defined(MAGICKCORE_THREAD_SUPPORT)
308   {
309     int
310       status;
311 
312     status=pthread_mutex_lock(&semaphore_info->mutex);
313     if (status != 0)
314       {
315         errno=status;
316         perror("unable to lock mutex");
317         _exit(1);
318       }
319   }
320 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
321   EnterCriticalSection(&semaphore_info->mutex);
322 #endif
323 #if defined(MAGICKCORE_DEBUG)
324   semaphore_info->id=GetMagickThreadId();
325   semaphore_info->reference_count++;
326 #endif
327 }
328 
329 /*
330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331 %                                                                             %
332 %                                                                             %
333 %                                                                             %
334 %   R e l i n q u i s h S e m a p h o r e I n f o                             %
335 %                                                                             %
336 %                                                                             %
337 %                                                                             %
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
339 %
340 %  RelinquishSemaphoreInfo() destroys a semaphore.
341 %
342 %  The format of the RelinquishSemaphoreInfo method is:
343 %
344 %      void RelinquishSemaphoreInfo(SemaphoreInfo **semaphore_info)
345 %
346 %  A description of each parameter follows:
347 %
348 %    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
349 %
350 */
RelinquishSemaphoreInfo(SemaphoreInfo ** semaphore_info)351 MagickExport void RelinquishSemaphoreInfo(SemaphoreInfo **semaphore_info)
352 {
353   assert(semaphore_info != (SemaphoreInfo **) NULL);
354   assert((*semaphore_info) != (SemaphoreInfo *) NULL);
355   assert((*semaphore_info)->signature == MagickCoreSignature);
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 */
SemaphoreComponentGenesis(void)398 MagickPrivate 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 */
SemaphoreComponentTerminus(void)422 MagickPrivate 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 */
UnlockSemaphoreInfo(SemaphoreInfo * semaphore_info)449 MagickExport 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