Coverage Report

Created: 2026-06-30 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/MagickCore/semaphore.c
Line
Count
Source
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 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/license/                                         %
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 declarations.
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
*/
98
MagickExport void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info)
99
613
{
100
613
  assert(semaphore_info != (SemaphoreInfo **) NULL);
101
613
  if (*semaphore_info == (SemaphoreInfo *) NULL)
102
613
    {
103
613
      LockMagickMutex();
104
613
      if (*semaphore_info == (SemaphoreInfo *) NULL)
105
613
        *semaphore_info=AcquireSemaphoreInfo();
106
613
      UnlockMagickMutex();
107
613
    }
108
613
}
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
129
static void *AcquireSemaphoreMemory(const size_t count,const size_t quantum)
130
210M
{
131
210M
#define AlignedExtent(size,alignment) \
132
210M
  (((size)+((alignment)-1)) & (size_t) ~((alignment)-1))
133
134
210M
  size_t
135
210M
    alignment,
136
210M
    extent,
137
210M
    size;
138
139
210M
  void
140
210M
    *memory;
141
142
210M
  size=count*quantum;
143
210M
  if ((count == 0) || (quantum != (size/count)))
144
0
    {
145
0
      errno=ENOMEM;
146
0
      return((void *) NULL);
147
0
    }
148
210M
  memory=NULL;
149
210M
  alignment=CACHE_LINE_SIZE;
150
210M
  extent=AlignedExtent(size,CACHE_LINE_SIZE);
151
210M
  if ((size == 0) || (alignment < sizeof(void *)) || (extent < size))
152
0
    return((void *) NULL);
153
210M
#if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
154
210M
  if (posix_memalign(&memory,alignment,extent) != 0)
155
0
    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
210M
  return(memory);
176
210M
}
177
178
static void *RelinquishSemaphoreMemory(void *memory)
179
210M
{
180
210M
  if (memory == (void *) NULL)
181
0
    return((void *) NULL);
182
210M
#if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
183
210M
  free(memory);
184
#elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
185
  _aligned_free(memory);
186
#else
187
  free(*((void **) memory-1));
188
#endif
189
210M
  return(NULL);
190
210M
}
191
192
MagickExport SemaphoreInfo *AcquireSemaphoreInfo(void)
193
210M
{
194
210M
  SemaphoreInfo
195
210M
    *semaphore_info;
196
197
  /*
198
    Acquire semaphore.
199
  */
200
210M
  semaphore_info=(SemaphoreInfo *) AcquireSemaphoreMemory(1,
201
210M
    sizeof(*semaphore_info));
202
210M
  if (semaphore_info == (SemaphoreInfo *) NULL)
203
210M
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
204
210M
  (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
210M
    int
213
210M
      status;
214
215
210M
    pthread_mutexattr_t
216
210M
      mutex_info;
217
218
210M
    status=pthread_mutexattr_init(&mutex_info);
219
210M
    if (status != 0)
220
0
      {
221
0
        errno=status;
222
0
        perror("unable to initialize mutex attributes");
223
0
        _exit(1);
224
0
      }
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
210M
    status=pthread_mutex_init(&semaphore_info->mutex,&mutex_info);
237
210M
    if (status != 0)
238
0
      {
239
0
        errno=status;
240
0
        perror("unable to initialize mutex");
241
0
        _exit(1);
242
0
      }
243
210M
    status=pthread_mutexattr_destroy(&mutex_info);
244
210M
    if (status != 0)
245
0
      {
246
0
        errno=status;
247
0
        perror("unable to destroy mutex attributes");
248
0
        _exit(1);
249
0
      }
250
210M
  }
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
210M
  semaphore_info->id=GetMagickThreadId();
266
210M
  semaphore_info->reference_count=0;
267
210M
  semaphore_info->signature=MagickCoreSignature;
268
210M
  return(semaphore_info);
269
210M
}
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
*/
293
MagickExport void LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
294
947M
{
295
947M
  assert(semaphore_info != (SemaphoreInfo *) NULL);
296
947M
  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
947M
  {
309
947M
    int
310
947M
      status;
311
312
947M
    status=pthread_mutex_lock(&semaphore_info->mutex);
313
947M
    if (status != 0)
314
0
      {
315
0
        errno=status;
316
0
        perror("unable to lock mutex");
317
0
        _exit(1);
318
0
      }
319
947M
  }
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
947M
}
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
*/
351
MagickExport void RelinquishSemaphoreInfo(SemaphoreInfo **semaphore_info)
352
210M
{
353
210M
  assert(semaphore_info != (SemaphoreInfo **) NULL);
354
210M
  assert((*semaphore_info) != (SemaphoreInfo *) NULL);
355
210M
  assert((*semaphore_info)->signature == MagickCoreSignature);
356
210M
  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
210M
    int
362
210M
      status;
363
364
210M
    status=pthread_mutex_destroy(&(*semaphore_info)->mutex);
365
210M
    if (status != 0)
366
0
      {
367
0
        errno=status;
368
0
        perror("unable to destroy mutex");
369
0
        _exit(1);
370
0
      }
371
210M
  }
372
#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
373
  DeleteCriticalSection(&(*semaphore_info)->mutex);
374
#endif
375
210M
  (*semaphore_info)->signature=(~MagickCoreSignature);
376
210M
  *semaphore_info=(SemaphoreInfo *) RelinquishSemaphoreMemory(*semaphore_info);
377
210M
  UnlockMagickMutex();
378
210M
}
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
*/
398
MagickPrivate MagickBooleanType SemaphoreComponentGenesis(void)
399
295
{
400
295
  InitializeMagickMutex();
401
295
  return(MagickTrue);
402
295
}
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
*/
422
MagickPrivate void SemaphoreComponentTerminus(void)
423
0
{
424
0
  DestroyMagickMutex();
425
0
}
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
*/
449
MagickExport void UnlockSemaphoreInfo(SemaphoreInfo *semaphore_info)
450
947M
{
451
947M
  assert(semaphore_info != (SemaphoreInfo *) NULL);
452
947M
  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
947M
  {
468
947M
    int
469
947M
      status;
470
471
947M
    status=pthread_mutex_unlock(&semaphore_info->mutex);
472
947M
    if (status != 0)
473
0
      {
474
0
        errno=status;
475
0
        perror("unable to unlock mutex");
476
0
        _exit(1);
477
0
      }
478
947M
  }
479
#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
480
  LeaveCriticalSection(&semaphore_info->mutex);
481
#endif
482
947M
}