MagickCore  6.9.13-17
Convert, Edit, Or Compose Bitmap Images
resource.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % RRRR EEEEE SSSSS OOO U U RRRR CCCC EEEEE %
7 % R R E SS O O U U R R C E %
8 % RRRR EEE SSS O O U U RRRR C EEE %
9 % R R E SS O O U U R R C E %
10 % R R EEEEE SSSSS OOO UUU R R CCCC EEEEE %
11 % %
12 % %
13 % Get/Set MagickCore Resources %
14 % %
15 % Software Design %
16 % Cristy %
17 % September 2002 %
18 % %
19 % %
20 % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 ␌
39 /*
40  Include declarations.
41 */
42 #include "magick/studio.h"
43 #include "magick/cache.h"
44 #include "magick/cache-private.h"
45 #include "magick/configure.h"
46 #include "magick/exception.h"
47 #include "magick/exception-private.h"
48 #include "magick/hashmap.h"
49 #include "magick/log.h"
50 #include "magick/image.h"
51 #include "magick/image-private.h"
52 #include "magick/memory_.h"
53 #include "magick/nt-base-private.h"
54 #include "magick/option.h"
55 #include "magick/policy.h"
56 #include "magick/random_.h"
57 #include "magick/registry.h"
58 #include "magick/resource_.h"
59 #include "magick/semaphore.h"
60 #include "magick/signature-private.h"
61 #include "magick/string_.h"
62 #include "magick/string-private.h"
63 #include "magick/splay-tree.h"
64 #include "magick/thread-private.h"
65 #include "magick/timer-private.h"
66 #include "magick/token.h"
67 #include "magick/timer-private.h"
68 #include "magick/utility.h"
69 #include "magick/utility-private.h"
70 ␌
71 /*
72  Define declarations.
73 */
74 #define MagickPathTemplate "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" /* min 6 X's */
75 #define NumberOfResourceTypes \
76  (sizeof(resource_semaphore)/sizeof(*resource_semaphore))
77 ␌
78 /*
79  Typedef declarations.
80 */
81 typedef struct _ResourceInfo
82 {
83  MagickOffsetType
84  width,
85  height,
86  list_length,
87  area,
88  memory,
89  map,
90  disk,
91  file,
92  thread,
93  throttle,
94  time;
95 
96  MagickSizeType
97  width_limit,
98  height_limit,
99  list_length_limit,
100  area_limit,
101  memory_limit,
102  map_limit,
103  disk_limit,
104  file_limit,
105  thread_limit,
106  throttle_limit,
107  time_limit;
108 } ResourceInfo;
109 ␌
110 /*
111  Global declarations.
112 */
113 static RandomInfo
114  *random_info = (RandomInfo *) NULL;
115 
116 static ResourceInfo
117  resource_info =
118  {
119  MagickULLConstant(0), /* initial width */
120  MagickULLConstant(0), /* initial height */
121  MagickULLConstant(0), /* initial list length */
122  MagickULLConstant(0), /* initial area */
123  MagickULLConstant(0), /* initial memory */
124  MagickULLConstant(0), /* initial map */
125  MagickULLConstant(0), /* initial disk */
126  MagickULLConstant(0), /* initial file */
127  MagickULLConstant(0), /* initial thread */
128  MagickULLConstant(0), /* initial throttle */
129  MagickULLConstant(0), /* initial time */
130  (MagickSizeType) (MAGICK_SSIZE_MAX/sizeof(PixelPacket)/5), /* width limit */
131  (MagickSizeType) (MAGICK_SSIZE_MAX/sizeof(PixelPacket)/5), /* height limit */
132  MagickResourceInfinity, /* list length limit */
133  MagickULLConstant(3072)*1024*1024, /* area limit */
134  MagickULLConstant(1536)*1024*1024, /* memory limit */
135  MagickULLConstant(3072)*1024*1024, /* map limit */
136  MagickResourceInfinity, /* disk limit */
137  MagickULLConstant(768), /* file limit */
138  MagickULLConstant(1), /* thread limit */
139  MagickULLConstant(0), /* throttle limit */
140  MagickULLConstant(0), /* time limit */
141  };
142 
143 static SemaphoreInfo
144  *resource_semaphore[] = {
145  (SemaphoreInfo *) NULL,
146  (SemaphoreInfo *) NULL,
147  (SemaphoreInfo *) NULL,
148  (SemaphoreInfo *) NULL,
149  (SemaphoreInfo *) NULL,
150  (SemaphoreInfo *) NULL,
151  (SemaphoreInfo *) NULL,
152  (SemaphoreInfo *) NULL,
153  (SemaphoreInfo *) NULL,
154  (SemaphoreInfo *) NULL,
155  (SemaphoreInfo *) NULL,
156  (SemaphoreInfo *) NULL
157  };
158 
159 static SplayTreeInfo
160  *temporary_resources = (SplayTreeInfo *) NULL;
161 ␌
162 /*
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164 % %
165 % %
166 % %
167 % A c q u i r e M a g i c k R e s o u r c e %
168 % %
169 % %
170 % %
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 %
173 % AcquireMagickResource() acquires resources of the specified type.
174 % MagickFalse is returned if the specified resource is exhausted otherwise
175 % MagickTrue.
176 %
177 % The format of the AcquireMagickResource() method is:
178 %
179 % MagickBooleanType AcquireMagickResource(const ResourceType type,
180 % const MagickSizeType size)
181 %
182 % A description of each parameter follows:
183 %
184 % o type: the type of resource.
185 %
186 % o size: the number of bytes needed from for this resource.
187 %
188 */
189 MagickExport MagickBooleanType AcquireMagickResource(const ResourceType type,
190  const MagickSizeType size)
191 {
192  char
193  resource_current[MaxTextExtent] = "",
194  resource_limit[MaxTextExtent] = "",
195  resource_request[MaxTextExtent] = "";
196 
197  MagickBooleanType
198  logging,
199  status;
200 
201  MagickOffsetType
202  request;
203 
204  MagickSizeType
205  limit;
206 
207  request=(MagickOffsetType) size;
208  if (request < 0)
209  return(MagickFalse);
210  status=MagickFalse;
211  logging=(GetLogEventMask() & ResourceEvent) != 0 ? MagickTrue : MagickFalse;
212  switch (type)
213  {
214  case DiskResource:
215  case FileResource:
216  case MapResource:
217  case MemoryResource:
218  case TimeResource:
219  {
220  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
221  ActivateSemaphoreInfo(&resource_semaphore[type]);
222  LockSemaphoreInfo(resource_semaphore[type]);
223  break;
224  }
225  default: ;
226  }
227  switch (type)
228  {
229  case AreaResource:
230  {
231  resource_info.area=(MagickOffsetType) size;
232  limit=resource_info.area_limit;
233  if ((limit == MagickResourceInfinity) || (size < limit))
234  status=MagickTrue;
235  if (logging != MagickFalse)
236  {
237  (void) FormatMagickSize(size,MagickFalse,resource_request);
238  (void) FormatMagickSize(size,MagickFalse,resource_current);
239  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
240  }
241  break;
242  }
243  case DiskResource:
244  {
245  limit=resource_info.disk_limit;
246  if (((MagickSizeType) resource_info.disk+request) >
247  (MagickSizeType) resource_info.disk)
248  {
249  resource_info.disk+=request;
250  if ((limit == MagickResourceInfinity) ||
251  (resource_info.disk < (MagickOffsetType) limit))
252  status=MagickTrue;
253  else
254  resource_info.disk-=request;
255  }
256  if (logging != MagickFalse)
257  {
258  (void) FormatMagickSize(size,MagickTrue,resource_request);
259  (void) FormatMagickSize((MagickSizeType) resource_info.disk,
260  MagickTrue,resource_current);
261  (void) FormatMagickSize(limit,MagickTrue,resource_limit);
262  }
263  break;
264  }
265  case FileResource:
266  {
267  limit=resource_info.file_limit;
268  if (((MagickSizeType) resource_info.file+request) >
269  (MagickSizeType) resource_info.file)
270  {
271  resource_info.file+=request;
272  if ((limit == MagickResourceInfinity) ||
273  (resource_info.file < (MagickOffsetType) limit))
274  status=MagickTrue;
275  }
276  if (logging != MagickFalse)
277  {
278  (void) FormatMagickSize(size,MagickFalse,resource_request);
279  (void) FormatMagickSize((MagickSizeType) resource_info.file,
280  MagickFalse,resource_current);
281  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
282  }
283  break;
284  }
285  case HeightResource:
286  {
287  resource_info.height=(MagickOffsetType) size;
288  limit=resource_info.height_limit;
289  if ((limit == MagickResourceInfinity) || (size < limit))
290  status=MagickTrue;
291  if (logging != MagickFalse)
292  {
293  (void) FormatMagickSize(size,MagickFalse,resource_request);
294  (void) FormatMagickSize(size,MagickFalse,resource_current);
295  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
296  }
297  break;
298  }
299  case ListLengthResource:
300  {
301  resource_info.list_length=(MagickOffsetType) size;
302  limit=resource_info.list_length_limit;
303  if ((limit == MagickResourceInfinity) || (size < limit))
304  status=MagickTrue;
305  if (logging != MagickFalse)
306  {
307  (void) FormatMagickSize(size,MagickFalse,resource_request);
308  (void) FormatMagickSize(size,MagickFalse,resource_current);
309  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
310  }
311  break;
312  }
313  case MapResource:
314  {
315  limit=resource_info.map_limit;
316  if (((MagickSizeType) resource_info.map+request) >
317  (MagickSizeType) resource_info.map)
318  {
319  resource_info.map+=request;
320  if ((limit == MagickResourceInfinity) ||
321  (resource_info.map < (MagickOffsetType) limit))
322  status=MagickTrue;
323  else
324  resource_info.map-=request;
325  }
326  if (logging != MagickFalse)
327  {
328  (void) FormatMagickSize(size,MagickTrue,resource_request);
329  (void) FormatMagickSize((MagickSizeType) resource_info.map,
330  MagickTrue,resource_current);
331  (void) FormatMagickSize(limit,MagickTrue,resource_limit);
332  }
333  break;
334  }
335  case MemoryResource:
336  {
337  limit=resource_info.memory_limit;
338  if (((MagickSizeType) resource_info.memory+request) >
339  (MagickSizeType) resource_info.memory)
340  {
341  resource_info.memory+=request;
342  if ((limit == MagickResourceInfinity) ||
343  (resource_info.memory < (MagickOffsetType) limit))
344  status=MagickTrue;
345  else
346  resource_info.memory-=request;
347  }
348  if (logging != MagickFalse)
349  {
350  (void) FormatMagickSize(size,MagickTrue,resource_request);
351  (void) FormatMagickSize((MagickSizeType) resource_info.memory,
352  MagickTrue,resource_current);
353  (void) FormatMagickSize(limit,MagickTrue,resource_limit);
354  }
355  break;
356  }
357  case ThreadResource:
358  {
359  limit=resource_info.thread_limit;
360  if ((limit == MagickResourceInfinity) ||
361  (resource_info.thread < (MagickOffsetType) limit))
362  status=MagickTrue;
363  if (logging != MagickFalse)
364  {
365  (void) FormatMagickSize(size,MagickFalse,resource_request);
366  (void) FormatMagickSize((MagickSizeType) resource_info.thread,
367  MagickFalse,resource_current);
368  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
369  }
370  break;
371  }
372  case ThrottleResource:
373  {
374  limit=resource_info.throttle_limit;
375  if ((limit == MagickResourceInfinity) ||
376  (resource_info.throttle < (MagickOffsetType) limit))
377  status=MagickTrue;
378  if (logging != MagickFalse)
379  {
380  (void) FormatMagickSize(size,MagickFalse,resource_request);
381  (void) FormatMagickSize((MagickSizeType) resource_info.throttle,
382  MagickFalse,resource_current);
383  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
384  }
385  break;
386  }
387  case TimeResource:
388  {
389  limit=resource_info.time_limit;
390  if (((MagickSizeType) resource_info.time+request) > (MagickSizeType) resource_info.time)
391  {
392  resource_info.time+=request;
393  if ((limit == 0) || ((MagickSizeType) resource_info.time < limit))
394  status=MagickTrue;
395  else
396  resource_info.time-=request;
397  }
398  if (logging != MagickFalse)
399  {
400  (void) FormatMagickSize(size,MagickFalse,resource_request);
401  (void) FormatMagickSize((MagickSizeType) resource_info.time,
402  MagickFalse,resource_current);
403  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
404  }
405  break;
406  }
407  case WidthResource:
408  {
409  resource_info.width=(MagickOffsetType) size;
410  limit=resource_info.width_limit;
411  if ((limit == MagickResourceInfinity) || (size < limit))
412  status=MagickTrue;
413  if (logging != MagickFalse)
414  {
415  (void) FormatMagickSize(size,MagickFalse,resource_request);
416  (void) FormatMagickSize(size,MagickFalse,resource_current);
417  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
418  }
419  break;
420  }
421  default:
422  break;
423  }
424  switch (type)
425  {
426  case DiskResource:
427  case FileResource:
428  case MapResource:
429  case MemoryResource:
430  case TimeResource:
431  {
432  UnlockSemaphoreInfo(resource_semaphore[type]);
433  break;
434  }
435  default: ;
436  }
437  if (logging != MagickFalse)
438  {
439  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
440  CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
441  resource_request,resource_current,resource_limit);
442  }
443  return(status);
444 }
445 ␌
446 /*
447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448 % %
449 % %
450 % %
451 + A s y n c h r o n o u s R e s o u r c e C o m p o n e n t T e r m i n u s %
452 % %
453 % %
454 % %
455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
456 %
457 % AsynchronousResourceComponentTerminus() destroys the resource environment.
458 % It differs from ResourceComponentTerminus() in that it can be called from a
459 % asynchronous signal handler.
460 %
461 % The format of the ResourceComponentTerminus() method is:
462 %
463 % ResourceComponentTerminus(void)
464 %
465 */
466 MagickExport void AsynchronousResourceComponentTerminus(void)
467 {
468  const char
469  *path;
470 
471  if (temporary_resources == (SplayTreeInfo *) NULL)
472  return;
473  /*
474  Remove any lingering temporary files.
475  */
476  ResetSplayTreeIterator(temporary_resources);
477  path=(const char *) GetNextKeyInSplayTree(temporary_resources);
478  while (path != (const char *) NULL)
479  {
480  (void) ShredFile(path);
481  (void) remove_utf8(path);
482  path=(const char *) GetNextKeyInSplayTree(temporary_resources);
483  }
484 }
485 ␌
486 /*
487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
488 % %
489 % %
490 % %
491 % A c q u i r e U n i q u e F i l e R e s o u r c e %
492 % %
493 % %
494 % %
495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
496 %
497 % AcquireUniqueFileResource() returns a unique file name, and returns a file
498 % descriptor for the file open for reading and writing.
499 %
500 % The format of the AcquireUniqueFileResource() method is:
501 %
502 % int AcquireUniqueFileResource(char *path)
503 %
504 % A description of each parameter follows:
505 %
506 % o path: Specifies a pointer to an array of characters. The unique path
507 % name is returned in this array.
508 %
509 */
510 
511 static void *DestroyTemporaryResources(void *temporary_resource)
512 {
513  (void) ShredFile((char *) temporary_resource);
514  (void) remove_utf8((char *) temporary_resource);
515  temporary_resource=DestroyString((char *) temporary_resource);
516  return((void *) NULL);
517 }
518 
519 MagickExport MagickBooleanType GetPathTemplate(char *path)
520 {
521  char
522  *directory,
523  *value;
524 
526  *exception;
527 
528  MagickBooleanType
529  status;
530 
531  struct stat
532  attributes;
533 
534  (void) FormatLocaleString(path,MaxTextExtent,"magick-" MagickPathTemplate);
535  exception=AcquireExceptionInfo();
536  directory=(char *) GetImageRegistry(StringRegistryType,"temporary-path",
537  exception);
538  exception=DestroyExceptionInfo(exception);
539  if (directory == (char *) NULL)
540  directory=GetEnvironmentValue("MAGICK_TEMPORARY_PATH");
541  if (directory == (char *) NULL)
542  directory=GetEnvironmentValue("MAGICK_TMPDIR");
543  if (directory == (char *) NULL)
544  directory=GetEnvironmentValue("TMPDIR");
545 #if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__) || defined(__CYGWIN__)
546  if (directory == (char *) NULL)
547  directory=GetEnvironmentValue("TMP");
548  if (directory == (char *) NULL)
549  directory=GetEnvironmentValue("TEMP");
550 #endif
551 #if defined(__VMS)
552  if (directory == (char *) NULL)
553  directory=GetEnvironmentValue("MTMPDIR");
554 #endif
555 #if defined(P_tmpdir)
556  if (directory == (char *) NULL)
557  directory=ConstantString(P_tmpdir);
558 #endif
559  if (directory == (char *) NULL)
560  return(MagickTrue);
561  value=GetPolicyValue("resource:temporary-path");
562  if (value != (char *) NULL)
563  {
564  (void) CloneString(&directory,value);
565  value=DestroyString(value);
566  }
567  if (strlen(directory) > (MaxTextExtent-25))
568  {
569  directory=DestroyString(directory);
570  return(MagickFalse);
571  }
572  status=GetPathAttributes(directory,&attributes);
573  if ((status == MagickFalse) || !S_ISDIR(attributes.st_mode))
574  {
575  directory=DestroyString(directory);
576  return(MagickFalse);
577  }
578  if (directory[strlen(directory)-1] == *DirectorySeparator)
579  (void) FormatLocaleString(path,MaxTextExtent,"%smagick-" MagickPathTemplate,
580  directory);
581  else
582  (void) FormatLocaleString(path,MaxTextExtent,"%s%smagick-"
583  MagickPathTemplate,directory,DirectorySeparator);
584  directory=DestroyString(directory);
585 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
586  {
587  char
588  *p;
589 
590  /*
591  Ghostscript does not like backslashes so we need to replace them. The
592  forward slash also works under Windows.
593  */
594  for (p=(path[1] == *DirectorySeparator ? path+2 : path); *p != '\0'; p++)
595  if (*p == *DirectorySeparator)
596  *p='/';
597  }
598 #endif
599  return(MagickTrue);
600 }
601 
602 MagickExport int AcquireUniqueFileResource(char *path)
603 {
604 #if !defined(O_NOFOLLOW)
605 #define O_NOFOLLOW 0
606 #endif
607 #if !defined(TMP_MAX)
608 # define TMP_MAX 238328
609 #endif
610 
611  int
612  c,
613  file;
614 
615  char
616  *p;
617 
618  ssize_t
619  i;
620 
621  static const char
622  portable_filename[65] =
623  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
624 
625  StringInfo
626  *key;
627 
628  unsigned char
629  *datum;
630 
631  assert(path != (char *) NULL);
632  if ((GetLogEventMask() & ResourceEvent) != 0)
633  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"...");
634  if (random_info == (RandomInfo *) NULL)
635  {
636  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
637  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
638  LockSemaphoreInfo(resource_semaphore[FileResource]);
639  if (random_info == (RandomInfo *) NULL)
640  random_info=AcquireRandomInfo();
641  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
642  }
643  file=(-1);
644  for (i=0; i < (ssize_t) TMP_MAX; i++)
645  {
646  ssize_t
647  j;
648 
649  /*
650  Get temporary pathname.
651  */
652  (void) GetPathTemplate(path);
653  key=GetRandomKey(random_info,strlen(MagickPathTemplate)-6);
654  p=path+strlen(path)-strlen(MagickPathTemplate);
655  datum=GetStringInfoDatum(key);
656  for (j=0; j < (ssize_t) GetStringInfoLength(key); j++)
657  {
658  c=(int) (datum[j] & 0x3f);
659  *p++=portable_filename[c];
660  }
661  key=DestroyStringInfo(key);
662 #if defined(MAGICKCORE_HAVE_MKSTEMP)
663  file=mkstemp(path);
664  if (file != -1)
665  {
666 #if defined(MAGICKCORE_HAVE_FCHMOD)
667  (void) fchmod(file,0600);
668 #endif
669 #if defined(__OS2__)
670  setmode(file,O_BINARY);
671 #endif
672  break;
673  }
674 #endif
675  key=GetRandomKey(random_info,strlen(MagickPathTemplate));
676  p=path+strlen(path)-strlen(MagickPathTemplate);
677  datum=GetStringInfoDatum(key);
678  for (j=0; j < (ssize_t) GetStringInfoLength(key); j++)
679  {
680  c=(int) (datum[j] & 0x3f);
681  *p++=portable_filename[c];
682  }
683  key=DestroyStringInfo(key);
684  file=open_utf8(path,O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_NOFOLLOW,
685  S_MODE);
686  if ((file >= 0) || (errno != EEXIST))
687  break;
688  }
689  if ((GetLogEventMask() & ResourceEvent) != 0)
690  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"Acquire %s",path);
691  if (file == -1)
692  return(file);
693  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
694  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
695  LockSemaphoreInfo(resource_semaphore[FileResource]);
696  if (temporary_resources == (SplayTreeInfo *) NULL)
697  temporary_resources=NewSplayTree(CompareSplayTreeString,
698  DestroyTemporaryResources,(void *(*)(void *)) NULL);
699  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
700  (void) AddValueToSplayTree(temporary_resources,ConstantString(path),
701  (const void *) NULL);
702  return(file);
703 }
704 ␌
705 /*
706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
707 % %
708 % %
709 % %
710 % G e t M a g i c k R e s o u r c e %
711 % %
712 % %
713 % %
714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
715 %
716 % GetMagickResource() returns the specified resource.
717 %
718 % The format of the GetMagickResource() method is:
719 %
720 % MagickSizeType GetMagickResource(const ResourceType type)
721 %
722 % A description of each parameter follows:
723 %
724 % o type: the type of resource.
725 %
726 */
727 MagickExport MagickSizeType GetMagickResource(const ResourceType type)
728 {
729  MagickSizeType
730  resource;
731 
732  resource=0;
733  switch (type)
734  {
735  case DiskResource:
736  case FileResource:
737  case MapResource:
738  case MemoryResource:
739  case TimeResource:
740  {
741  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
742  ActivateSemaphoreInfo(&resource_semaphore[type]);
743  LockSemaphoreInfo(resource_semaphore[type]);
744  break;
745  }
746  default: ;
747  }
748  switch (type)
749  {
750  case AreaResource:
751  {
752  resource=(MagickSizeType) resource_info.area;
753  break;
754  }
755  case DiskResource:
756  {
757  resource=(MagickSizeType) resource_info.disk;
758  break;
759  }
760  case FileResource:
761  {
762  resource=(MagickSizeType) resource_info.file;
763  break;
764  }
765  case HeightResource:
766  {
767  resource=(MagickSizeType) resource_info.height;
768  break;
769  }
770  case ListLengthResource:
771  {
772  resource=(MagickSizeType) resource_info.list_length;
773  break;
774  }
775  case MapResource:
776  {
777  resource=(MagickSizeType) resource_info.map;
778  break;
779  }
780  case MemoryResource:
781  {
782  resource=(MagickSizeType) resource_info.memory;
783  break;
784  }
785  case ThreadResource:
786  {
787  resource=(MagickSizeType) resource_info.thread;
788  break;
789  }
790  case ThrottleResource:
791  {
792  resource=(MagickSizeType) resource_info.throttle;
793  break;
794  }
795  case TimeResource:
796  {
797  resource=(MagickSizeType) resource_info.time;
798  break;
799  }
800  case WidthResource:
801  {
802  resource=(MagickSizeType) resource_info.width;
803  break;
804  }
805  default:
806  break;
807  }
808  switch (type)
809  {
810  case DiskResource:
811  case FileResource:
812  case MapResource:
813  case MemoryResource:
814  case TimeResource:
815  {
816  UnlockSemaphoreInfo(resource_semaphore[type]);
817  break;
818  }
819  default: ;
820  }
821  return(resource);
822 }
823 ␌
824 /*
825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
826 % %
827 % %
828 % %
829 % G e t M a g i c k R e s o u r c e L i m i t %
830 % %
831 % %
832 % %
833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
834 %
835 % GetMagickResourceLimit() returns the specified resource limit.
836 %
837 % The format of the GetMagickResourceLimit() method is:
838 %
839 % MagickSizeType GetMagickResourceLimit(const ResourceType type)
840 %
841 % A description of each parameter follows:
842 %
843 % o type: the type of resource.
844 %
845 */
846 MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
847 {
848  MagickSizeType
849  resource;
850 
851  resource=0;
852  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
853  ActivateSemaphoreInfo(&resource_semaphore[type]);
854  LockSemaphoreInfo(resource_semaphore[type]);
855  switch (type)
856  {
857  case AreaResource:
858  {
859  resource=resource_info.area_limit;
860  break;
861  }
862  case DiskResource:
863  {
864  resource=resource_info.disk_limit;
865  break;
866  }
867  case FileResource:
868  {
869  resource=resource_info.file_limit;
870  break;
871  }
872  case HeightResource:
873  {
874  resource=resource_info.height_limit;
875  break;
876  }
877  case ListLengthResource:
878  {
879  resource=resource_info.list_length_limit;
880  break;
881  }
882  case MemoryResource:
883  {
884  resource=resource_info.memory_limit;
885  break;
886  }
887  case MapResource:
888  {
889  resource=resource_info.map_limit;
890  break;
891  }
892  case ThreadResource:
893  {
894  resource=resource_info.thread_limit;
895  break;
896  }
897  case ThrottleResource:
898  {
899  resource=resource_info.throttle_limit;
900  break;
901  }
902  case TimeResource:
903  {
904  resource=resource_info.time_limit;
905  break;
906  }
907  case WidthResource:
908  {
909  resource=resource_info.width_limit;
910  break;
911  }
912  default:
913  break;
914  }
915  UnlockSemaphoreInfo(resource_semaphore[type]);
916  return(resource);
917 }
918 ␌
919 /*
920 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
921 % %
922 % %
923 % %
924 % L i s t M a g i c k R e s o u r c e I n f o %
925 % %
926 % %
927 % %
928 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929 %
930 % ListMagickResourceInfo() lists the resource info to a file.
931 %
932 % The format of the ListMagickResourceInfo method is:
933 %
934 % MagickBooleanType ListMagickResourceInfo(FILE *file,
935 % ExceptionInfo *exception)
936 %
937 % A description of each parameter follows.
938 %
939 % o file: An pointer to a FILE.
940 %
941 % o exception: return any errors or warnings in this structure.
942 %
943 */
944 
945 static ssize_t FormatPixelSize(const MagickSizeType size,
946  const MagickBooleanType bi,char *format)
947 {
948  const char
949  **units;
950 
951  double
952  bytes,
953  length;
954 
955  ssize_t
956  count,
957  i,
958  j;
959 
960  static const char
961  *bi_units[] =
962  {
963  "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi", "Ri", "Qi", (char *) NULL
964  },
965  *traditional_units[] =
966  {
967  "", "K", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q", (char *) NULL
968  };
969 
970  bytes=1000.0;
971  units=traditional_units;
972  if (bi != MagickFalse)
973  {
974  bytes=1024.0;
975  units=bi_units;
976  }
977 #if defined(_MSC_VER) && (_MSC_VER == 1200)
978  length=(double) ((MagickOffsetType) size);
979 #else
980  length=(double) size;
981 #endif
982  for (i=0; (length >= bytes) && (units[i+1] != (const char *) NULL); i++)
983  length/=bytes;
984  count=0;
985  for (j=2; j < 12; j++)
986  {
987  count=FormatLocaleString(format,MaxTextExtent,"%.*g%sP",(int) (i+j),length,
988  units[i]);
989  if (strchr(format,'+') == (char *) NULL)
990  break;
991  }
992  return(count);
993 }
994 
995 static void FormatTimeToLive(const MagickSizeType ttl,char *timeString)
996 {
997  MagickSizeType
998  days,
999  hours,
1000  minutes,
1001  months,
1002  seconds,
1003  weeks,
1004  years;
1005 
1006  years=ttl/31536000;
1007  seconds=ttl % 31536000;
1008  if (seconds == 0)
1009  {
1010  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld years",years);
1011  return;
1012  }
1013  months=ttl/2628000;
1014  seconds=ttl % 2628000;
1015  if (seconds == 0)
1016  {
1017  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld months",
1018  months);
1019  return;
1020  }
1021  weeks=ttl/604800;
1022  seconds=ttl % 604800;
1023  if (seconds == 0)
1024  {
1025  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld weeks",weeks);
1026  return;
1027  }
1028  days=ttl/86400;
1029  seconds=ttl % 86400;
1030  if (seconds == 0)
1031  {
1032  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld days",days);
1033  return;
1034  }
1035  hours=ttl/3600;
1036  seconds=ttl % 3600;
1037  if (seconds == 0)
1038  {
1039  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld hours",hours);
1040  return;
1041  }
1042  minutes=ttl/60;
1043  seconds=ttl % 60;
1044  if (seconds == 0)
1045  {
1046  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld minutes",
1047  minutes);
1048  return;
1049  }
1050  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld seconds",ttl);
1051 }
1052 
1053 MagickExport MagickBooleanType ListMagickResourceInfo(FILE *file,
1054  ExceptionInfo *magick_unused(exception))
1055 {
1056  char
1057  area_limit[MaxTextExtent],
1058  disk_limit[MaxTextExtent],
1059  height_limit[MaxTextExtent],
1060  list_length_limit[MaxTextExtent],
1061  map_limit[MaxTextExtent],
1062  memory_limit[MaxTextExtent],
1063  time_limit[MaxTextExtent],
1064  width_limit[MaxTextExtent];
1065 
1066  magick_unreferenced(exception);
1067 
1068  if (file == (const FILE *) NULL)
1069  file=stdout;
1070  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
1071  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
1072  LockSemaphoreInfo(resource_semaphore[FileResource]);
1073  (void) FormatPixelSize(resource_info.width_limit,MagickFalse,width_limit);
1074  (void) FormatPixelSize(resource_info.height_limit,MagickFalse,height_limit);
1075  (void) FormatPixelSize(resource_info.area_limit,MagickFalse,area_limit);
1076  (void) CopyMagickString(list_length_limit,"unlimited",MaxTextExtent);
1077  if (resource_info.list_length_limit != MagickResourceInfinity)
1078  (void) FormatMagickSize(resource_info.list_length_limit,MagickTrue,
1079  list_length_limit);
1080  (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,memory_limit);
1081  (void) FormatMagickSize(resource_info.map_limit,MagickTrue,map_limit);
1082  (void) CopyMagickString(disk_limit,"unlimited",MaxTextExtent);
1083  if (resource_info.disk_limit != MagickResourceInfinity)
1084  (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,disk_limit);
1085  (void) CopyMagickString(time_limit,"unlimited",MaxTextExtent);
1086  if (resource_info.time_limit != 0)
1087  FormatTimeToLive(resource_info.time_limit,time_limit);
1088  (void) FormatLocaleFile(file,"Resource limits:\n");
1089  (void) FormatLocaleFile(file," Width: %s\n",width_limit);
1090  (void) FormatLocaleFile(file," Height: %s\n",height_limit);
1091  (void) FormatLocaleFile(file," List length: %s\n",list_length_limit);
1092  (void) FormatLocaleFile(file," Area: %s\n",area_limit);
1093  (void) FormatLocaleFile(file," Memory: %s\n",memory_limit);
1094  (void) FormatLocaleFile(file," Map: %s\n",map_limit);
1095  (void) FormatLocaleFile(file," Disk: %s\n",disk_limit);
1096  (void) FormatLocaleFile(file," File: %.20g\n",(double) ((MagickOffsetType)
1097  resource_info.file_limit));
1098  (void) FormatLocaleFile(file," Thread: %.20g\n",(double) ((MagickOffsetType)
1099  resource_info.thread_limit));
1100  (void) FormatLocaleFile(file," Throttle: %.20g\n",(double)
1101  ((MagickOffsetType) resource_info.throttle_limit));
1102  (void) FormatLocaleFile(file," Time: %s\n",time_limit);
1103  (void) fflush(file);
1104  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1105  return(MagickTrue);
1106 }
1107 ␌
1108 /*
1109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1110 % %
1111 % %
1112 % %
1113 % R e l i n q u i s h M a g i c k R e s o u r c e %
1114 % %
1115 % %
1116 % %
1117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1118 %
1119 % RelinquishMagickResource() relinquishes resources of the specified type.
1120 %
1121 % The format of the RelinquishMagickResource() method is:
1122 %
1123 % void RelinquishMagickResource(const ResourceType type,
1124 % const MagickSizeType size)
1125 %
1126 % A description of each parameter follows:
1127 %
1128 % o type: the type of resource.
1129 %
1130 % o size: the size of the resource.
1131 %
1132 */
1133 MagickExport void RelinquishMagickResource(const ResourceType type,
1134  const MagickSizeType size)
1135 {
1136  char
1137  resource_current[MaxTextExtent],
1138  resource_limit[MaxTextExtent],
1139  resource_request[MaxTextExtent];
1140 
1141  MagickBooleanType
1142  logging;
1143 
1144  logging=(GetLogEventMask() & ResourceEvent) != 0 ? MagickTrue : MagickFalse;
1145  if (logging != MagickFalse)
1146  (void) FormatMagickSize(size,MagickFalse,resource_request);
1147  switch (type)
1148  {
1149  case DiskResource:
1150  case FileResource:
1151  case MapResource:
1152  case MemoryResource:
1153  case TimeResource:
1154  {
1155  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
1156  ActivateSemaphoreInfo(&resource_semaphore[type]);
1157  LockSemaphoreInfo(resource_semaphore[type]);
1158  break;
1159  }
1160  default: ;
1161  }
1162  switch (type)
1163  {
1164  case AreaResource:
1165  {
1166  resource_info.area=(MagickOffsetType) size;
1167  if (logging != MagickFalse)
1168  {
1169  (void) FormatMagickSize((MagickSizeType) resource_info.area,
1170  MagickFalse,resource_current);
1171  (void) FormatMagickSize(resource_info.area_limit,MagickFalse,
1172  resource_limit);
1173  }
1174  break;
1175  }
1176  case DiskResource:
1177  {
1178  resource_info.disk-=size;
1179  assert(resource_info.disk >= 0);
1180  if (logging != MagickFalse)
1181  {
1182  (void) FormatMagickSize((MagickSizeType) resource_info.disk,
1183  MagickTrue,resource_current);
1184  (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,
1185  resource_limit);
1186  }
1187  break;
1188  }
1189  case FileResource:
1190  {
1191  resource_info.file-=size;
1192  assert(resource_info.file >= 0);
1193  if (logging != MagickFalse)
1194  {
1195  (void) FormatMagickSize((MagickSizeType) resource_info.file,
1196  MagickFalse,resource_current);
1197  (void) FormatMagickSize((MagickSizeType) resource_info.file_limit,
1198  MagickFalse,resource_limit);
1199  }
1200  break;
1201  }
1202  case HeightResource:
1203  {
1204  resource_info.height=(MagickOffsetType) size;
1205  if (logging != MagickFalse)
1206  {
1207  (void) FormatMagickSize((MagickSizeType) resource_info.height,
1208  MagickFalse,resource_current);
1209  (void) FormatMagickSize(resource_info.height_limit,MagickFalse,
1210  resource_limit);
1211  }
1212  break;
1213  }
1214  case ListLengthResource:
1215  {
1216  resource_info.list_length=(MagickOffsetType) size;
1217  if (logging != MagickFalse)
1218  {
1219  (void) FormatMagickSize((MagickSizeType) resource_info.list_length,
1220  MagickFalse,resource_current);
1221  (void) FormatMagickSize(resource_info.list_length_limit,MagickFalse,
1222  resource_limit);
1223  }
1224  break;
1225  }
1226  case MapResource:
1227  {
1228  resource_info.map-=size;
1229  assert(resource_info.map >= 0);
1230  if (logging != MagickFalse)
1231  {
1232  (void) FormatMagickSize((MagickSizeType) resource_info.map,
1233  MagickTrue,resource_current);
1234  (void) FormatMagickSize(resource_info.map_limit,MagickTrue,
1235  resource_limit);
1236  }
1237  break;
1238  }
1239  case MemoryResource:
1240  {
1241  resource_info.memory-=size;
1242  assert(resource_info.memory >= 0);
1243  if (logging != MagickFalse)
1244  {
1245  (void) FormatMagickSize((MagickSizeType) resource_info.memory,
1246  MagickTrue,resource_current);
1247  (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,
1248  resource_limit);
1249  }
1250  break;
1251  }
1252  case ThreadResource:
1253  {
1254  if (logging != MagickFalse)
1255  {
1256  (void) FormatMagickSize((MagickSizeType) resource_info.thread,
1257  MagickFalse,resource_current);
1258  (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
1259  MagickFalse,resource_limit);
1260  }
1261  break;
1262  }
1263  case ThrottleResource:
1264  {
1265  if (logging != MagickFalse)
1266  {
1267  (void) FormatMagickSize((MagickSizeType) resource_info.throttle,
1268  MagickFalse,resource_current);
1269  (void) FormatMagickSize((MagickSizeType) resource_info.throttle_limit,
1270  MagickFalse,resource_limit);
1271  }
1272  break;
1273  }
1274  case TimeResource:
1275  {
1276  resource_info.time-=size;
1277  assert(resource_info.time >= 0);
1278  if (logging != MagickFalse)
1279  {
1280  (void) FormatMagickSize((MagickSizeType) resource_info.time,
1281  MagickFalse,resource_current);
1282  (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
1283  MagickFalse,resource_limit);
1284  }
1285  break;
1286  }
1287  case WidthResource:
1288  {
1289  resource_info.width=(MagickOffsetType) size;
1290  if (logging != MagickFalse)
1291  {
1292  (void) FormatMagickSize((MagickSizeType) resource_info.width,
1293  MagickFalse,resource_current);
1294  (void) FormatMagickSize(resource_info.width_limit,MagickFalse,
1295  resource_limit);
1296  }
1297  break;
1298  }
1299  default:
1300  break;
1301  }
1302  switch (type)
1303  {
1304  case DiskResource:
1305  case FileResource:
1306  case MapResource:
1307  case MemoryResource:
1308  case TimeResource:
1309  {
1310  UnlockSemaphoreInfo(resource_semaphore[type]);
1311  break;
1312  }
1313  default: ;
1314  }
1315  if (logging != MagickFalse)
1316  {
1317  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
1318  CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
1319  resource_request,resource_current,resource_limit);
1320  }
1321 }
1322 ␌
1323 /*
1324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1325 % %
1326 % %
1327 % %
1328 % R e l i n q u i s h U n i q u e F i l e R e s o u r c e %
1329 % %
1330 % %
1331 % %
1332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333 %
1334 % RelinquishUniqueFileResource() relinquishes a unique file resource.
1335 %
1336 % The format of the RelinquishUniqueFileResource() method is:
1337 %
1338 % MagickBooleanType RelinquishUniqueFileResource(const char *path)
1339 %
1340 % A description of each parameter follows:
1341 %
1342 % o name: the name of the temporary resource.
1343 %
1344 */
1345 MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
1346 {
1347  char
1348  cache_path[MaxTextExtent];
1349 
1350  MagickStatusType
1351  status;
1352 
1353  assert(path != (const char *) NULL);
1354  status=MagickFalse;
1355  if ((GetLogEventMask() & ResourceEvent) != 0)
1356  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"Relinquish %s",path);
1357  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
1358  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
1359  LockSemaphoreInfo(resource_semaphore[FileResource]);
1360  if (temporary_resources != (SplayTreeInfo *) NULL)
1361  status=DeleteNodeFromSplayTree(temporary_resources, (const void *) path);
1362  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1363  (void) CopyMagickString(cache_path,path,MaxTextExtent);
1364  AppendImageFormat("cache",cache_path);
1365  if (access_utf8(cache_path,F_OK) == 0)
1366  {
1367  status=ShredFile(cache_path);
1368  status|=remove_utf8(cache_path);
1369  }
1370  if (status == MagickFalse)
1371  {
1372  status=ShredFile(path);
1373  status|=remove_utf8(path);
1374  }
1375  return(status == 0 ? MagickFalse : MagickTrue);
1376 }
1377 ␌
1378 /*
1379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1380 % %
1381 % %
1382 % %
1383 + R e s o u r c e C o m p o n e n t G e n e s i s %
1384 % %
1385 % %
1386 % %
1387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1388 %
1389 % ResourceComponentGenesis() instantiates the resource component.
1390 %
1391 % The format of the ResourceComponentGenesis method is:
1392 %
1393 % MagickBooleanType ResourceComponentGenesis(void)
1394 %
1395 */
1396 MagickExport MagickBooleanType ResourceComponentGenesis(void)
1397 {
1398  char
1399  *limit;
1400 
1401  MagickSizeType
1402  memory;
1403 
1404  ssize_t
1405  files,
1406  i,
1407  number_threads,
1408  pages,
1409  pagesize;
1410 
1411  /*
1412  Set Magick resource limits.
1413  */
1414  for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1415  if (resource_semaphore[i] == (SemaphoreInfo *) NULL)
1416  ActivateSemaphoreInfo(&resource_semaphore[i]);
1417  (void) SetMagickResourceLimit(WidthResource,resource_info.width_limit);
1418  limit=GetEnvironmentValue("MAGICK_WIDTH_LIMIT");
1419  if (limit != (char *) NULL)
1420  {
1421  (void) SetMagickResourceLimit(WidthResource,StringToSizeType(limit,
1422  100.0));
1423  limit=DestroyString(limit);
1424  }
1425  (void) SetMagickResourceLimit(HeightResource,resource_info.height_limit);
1426  limit=GetEnvironmentValue("MAGICK_HEIGHT_LIMIT");
1427  if (limit != (char *) NULL)
1428  {
1429  (void) SetMagickResourceLimit(HeightResource,StringToSizeType(limit,
1430  100.0));
1431  limit=DestroyString(limit);
1432  }
1433  pagesize=GetMagickPageSize();
1434  pages=(-1);
1435 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
1436  pages=(ssize_t) sysconf(_SC_PHYS_PAGES);
1437 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1438  pages=pages/2;
1439 #endif
1440 #endif
1441  memory=(MagickSizeType) pages*pagesize;
1442  if ((pagesize <= 0) || (pages <= 0))
1443  memory=2048UL*1024UL*1024UL;
1444 #if defined(MAGICKCORE_PixelCacheThreshold)
1445  memory=StringToMagickSizeType(MAGICKCORE_PixelCacheThreshold,100.0);
1446 #endif
1447  (void) SetMagickResourceLimit(AreaResource,4*memory);
1448  limit=GetEnvironmentValue("MAGICK_AREA_LIMIT");
1449  if (limit != (char *) NULL)
1450  {
1451  (void) SetMagickResourceLimit(AreaResource,StringToSizeType(limit,100.0));
1452  limit=DestroyString(limit);
1453  }
1454  (void) SetMagickResourceLimit(MemoryResource,memory);
1455  limit=GetEnvironmentValue("MAGICK_MEMORY_LIMIT");
1456  if (limit != (char *) NULL)
1457  {
1458  (void) SetMagickResourceLimit(MemoryResource,
1459  StringToSizeType(limit,100.0));
1460  limit=DestroyString(limit);
1461  }
1462  (void) SetMagickResourceLimit(MapResource,2*memory);
1463  limit=GetEnvironmentValue("MAGICK_MAP_LIMIT");
1464  if (limit != (char *) NULL)
1465  {
1466  (void) SetMagickResourceLimit(MapResource,StringToSizeType(limit,100.0));
1467  limit=DestroyString(limit);
1468  }
1469  (void) SetMagickResourceLimit(DiskResource,MagickResourceInfinity);
1470  limit=GetEnvironmentValue("MAGICK_DISK_LIMIT");
1471  if (limit != (char *) NULL)
1472  {
1473  (void) SetMagickResourceLimit(DiskResource,StringToSizeType(limit,100.0));
1474  limit=DestroyString(limit);
1475  }
1476  files=(-1);
1477 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
1478  files=(ssize_t) sysconf(_SC_OPEN_MAX);
1479 #endif
1480 #if defined(MAGICKCORE_HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
1481  if (files < 0)
1482  {
1483  struct rlimit
1484  resources;
1485 
1486  if (getrlimit(RLIMIT_NOFILE,&resources) != -1)
1487  files=(ssize_t) resources.rlim_cur;
1488  }
1489 #endif
1490 #if defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
1491  if (files < 0)
1492  files=(ssize_t) getdtablesize();
1493 #endif
1494  if (files < 0)
1495  files=64;
1496  (void) SetMagickResourceLimit(FileResource,MagickMax((size_t)
1497  (3*files/4),64));
1498  limit=GetEnvironmentValue("MAGICK_FILE_LIMIT");
1499  if (limit != (char *) NULL)
1500  {
1501  (void) SetMagickResourceLimit(FileResource,StringToSizeType(limit,100.0));
1502  limit=DestroyString(limit);
1503  }
1504  number_threads=(ssize_t) GetOpenMPMaximumThreads();
1505  if (number_threads > 1)
1506  number_threads--; /* reserve core for OS */
1507  (void) SetMagickResourceLimit(ThreadResource,(size_t) number_threads);
1508  limit=GetEnvironmentValue("MAGICK_THREAD_LIMIT");
1509  if (limit != (char *) NULL)
1510  {
1511  (void) SetMagickResourceLimit(ThreadResource,StringToSizeType(limit,
1512  100.0));
1513  limit=DestroyString(limit);
1514  }
1515  (void) SetMagickResourceLimit(ThrottleResource,0);
1516  limit=GetEnvironmentValue("MAGICK_THROTTLE_LIMIT");
1517  if (limit != (char *) NULL)
1518  {
1519  (void) SetMagickResourceLimit(ThrottleResource,StringToSizeType(limit,
1520  100.0));
1521  limit=DestroyString(limit);
1522  }
1523  (void) SetMagickResourceLimit(TimeResource,0);
1524  limit=GetEnvironmentValue("MAGICK_TIME_LIMIT");
1525  if (limit != (char *) NULL)
1526  {
1527  (void) SetMagickResourceLimit(TimeResource,(MagickSizeType)
1528  ParseMagickTimeToLive(limit));
1529  limit=DestroyString(limit);
1530  }
1531  (void) SetMagickResourceLimit(ListLengthResource,MagickResourceInfinity);
1532  limit=GetEnvironmentValue("MAGICK_LIST_LENGTH_LIMIT");
1533  if (limit != (char *) NULL)
1534  {
1535  (void) SetMagickResourceLimit(ListLengthResource,
1536  StringToSizeType(limit,100.0));
1537  limit=DestroyString(limit);
1538  }
1539  return(MagickTrue);
1540 }
1541 ␌
1542 /*
1543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1544 % %
1545 % %
1546 % %
1547 + R e s o u r c e C o m p o n e n t T e r m i n u s %
1548 % %
1549 % %
1550 % %
1551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1552 %
1553 % ResourceComponentTerminus() destroys the resource component.
1554 %
1555 % The format of the ResourceComponentTerminus() method is:
1556 %
1557 % ResourceComponentTerminus(void)
1558 %
1559 */
1560 MagickExport void ResourceComponentTerminus(void)
1561 {
1562  ssize_t
1563  i;
1564 
1565  for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1566  if (resource_semaphore[i] == (SemaphoreInfo *) NULL)
1567  ActivateSemaphoreInfo(&resource_semaphore[i]);
1568  LockSemaphoreInfo(resource_semaphore[FileResource]);
1569  if (temporary_resources != (SplayTreeInfo *) NULL)
1570  temporary_resources=DestroySplayTree(temporary_resources);
1571  if (random_info != (RandomInfo *) NULL)
1572  random_info=DestroyRandomInfo(random_info);
1573  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1574  for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1575  DestroySemaphoreInfo(&resource_semaphore[i]);
1576 }
1577 ␌
1578 /*
1579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1580 % %
1581 % %
1582 % %
1583 % S e t M a g i c k R e s o u r c e L i m i t %
1584 % %
1585 % %
1586 % %
1587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588 %
1589 % SetMagickResourceLimit() sets the limit for a particular resource.
1590 %
1591 % The format of the SetMagickResourceLimit() method is:
1592 %
1593 % MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1594 % const MagickSizeType limit)
1595 %
1596 % A description of each parameter follows:
1597 %
1598 % o type: the type of resource.
1599 %
1600 % o limit: the maximum limit for the resource.
1601 %
1602 */
1603 
1604 MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1605  const MagickSizeType limit)
1606 {
1607  char
1608  *value;
1609 
1610  MagickBooleanType
1611  status;
1612 
1613  status=MagickTrue;
1614  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
1615  ActivateSemaphoreInfo(&resource_semaphore[type]);
1616  LockSemaphoreInfo(resource_semaphore[type]);
1617  value=(char *) NULL;
1618  switch (type)
1619  {
1620  case AreaResource:
1621  {
1622  value=GetPolicyValue("resource:area");
1623  if (value == (char *) NULL)
1624  resource_info.area_limit=limit;
1625  else
1626  resource_info.area_limit=MagickMin(limit,StringToSizeType(value,100.0));
1627  break;
1628  }
1629  case DiskResource:
1630  {
1631  value=GetPolicyValue("resource:disk");
1632  if (value == (char *) NULL)
1633  resource_info.disk_limit=limit;
1634  else
1635  resource_info.disk_limit=MagickMin(limit,StringToSizeType(value,100.0));
1636  break;
1637  }
1638  case FileResource:
1639  {
1640  value=GetPolicyValue("resource:file");
1641  if (value == (char *) NULL)
1642  resource_info.file_limit=limit;
1643  else
1644  resource_info.file_limit=MagickMin(limit,StringToSizeType(value,100.0));
1645  break;
1646  }
1647  case HeightResource:
1648  {
1649  value=GetPolicyValue("resource:height");
1650  if (value == (char *) NULL)
1651  resource_info.height_limit=limit;
1652  else
1653  resource_info.height_limit=MagickMin(limit,StringToSizeType(value,
1654  100.0));
1655  resource_info.height_limit=MagickMin(resource_info.height_limit,
1656  (MagickSizeType) MAGICK_SSIZE_MAX);
1657  break;
1658  }
1659  case ListLengthResource:
1660  {
1661  value=GetPolicyValue("resource:list-length");
1662  if (value == (char *) NULL)
1663  resource_info.list_length_limit=limit;
1664  else
1665  resource_info.list_length_limit=MagickMin(limit,
1666  StringToSizeType(value,100.0));
1667  break;
1668  }
1669  case MapResource:
1670  {
1671  value=GetPolicyValue("resource:map");
1672  if (value == (char *) NULL)
1673  resource_info.map_limit=limit;
1674  else
1675  resource_info.map_limit=MagickMin(limit,StringToSizeType(value,100.0));
1676  break;
1677  }
1678  case MemoryResource:
1679  {
1680  value=GetPolicyValue("resource:memory");
1681  if (value == (char *) NULL)
1682  resource_info.memory_limit=limit;
1683  else
1684  resource_info.memory_limit=MagickMin(limit,StringToSizeType(value,
1685  100.0));
1686  break;
1687  }
1688  case ThreadResource:
1689  {
1690  value=GetPolicyValue("resource:thread");
1691  if (value == (char *) NULL)
1692  resource_info.thread_limit=limit;
1693  else
1694  resource_info.thread_limit=MagickMin(limit,StringToSizeType(value,
1695  100.0));
1696  if (resource_info.thread_limit > GetOpenMPMaximumThreads())
1697  resource_info.thread_limit=GetOpenMPMaximumThreads();
1698  else
1699  if (resource_info.thread_limit == 0)
1700  resource_info.thread_limit=1;
1701  break;
1702  }
1703  case ThrottleResource:
1704  {
1705  value=GetPolicyValue("resource:throttle");
1706  if (value == (char *) NULL)
1707  resource_info.throttle_limit=limit;
1708  else
1709  resource_info.throttle_limit=MagickMax(limit,StringToSizeType(value,
1710  100.0));
1711  break;
1712  }
1713  case TimeResource:
1714  {
1715  value=GetPolicyValue("resource:time");
1716  if (value == (char *) NULL)
1717  resource_info.time_limit=limit;
1718  else
1719  resource_info.time_limit=MagickMin(limit,(MagickSizeType)
1720  ParseMagickTimeToLive(value));
1721  break;
1722  }
1723  case WidthResource:
1724  {
1725  value=GetPolicyValue("resource:width");
1726  if (value == (char *) NULL)
1727  resource_info.width_limit=limit;
1728  else
1729  resource_info.width_limit=MagickMin(limit,StringToSizeType(value,
1730  100.0));
1731  resource_info.width_limit=MagickMin(resource_info.width_limit,
1732  (MagickSizeType) MAGICK_SSIZE_MAX);
1733  break;
1734  }
1735  default:
1736  {
1737  status=MagickFalse;
1738  break;
1739  }
1740  }
1741  if (value != (char *) NULL)
1742  value=DestroyString(value);
1743  UnlockSemaphoreInfo(resource_semaphore[type]);
1744  return(status);
1745 }