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