]> granicus.if.org Git - imagemagick/blob - MagickCore/resource.c
Support Stereo composite operator
[imagemagick] / MagickCore / 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-2017 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://www.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 \f
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/cache.h"
44 #include "MagickCore/cache-private.h"
45 #include "MagickCore/configure.h"
46 #include "MagickCore/exception.h"
47 #include "MagickCore/exception-private.h"
48 #include "MagickCore/linked-list.h"
49 #include "MagickCore/log.h"
50 #include "MagickCore/image.h"
51 #include "MagickCore/image-private.h"
52 #include "MagickCore/memory_.h"
53 #include "MagickCore/nt-base-private.h"
54 #include "MagickCore/option.h"
55 #include "MagickCore/policy.h"
56 #include "MagickCore/random_.h"
57 #include "MagickCore/registry.h"
58 #include "MagickCore/resource_.h"
59 #include "MagickCore/resource-private.h"
60 #include "MagickCore/semaphore.h"
61 #include "MagickCore/signature-private.h"
62 #include "MagickCore/string_.h"
63 #include "MagickCore/string-private.h"
64 #include "MagickCore/splay-tree.h"
65 #include "MagickCore/thread-private.h"
66 #include "MagickCore/token.h"
67 #include "MagickCore/utility.h"
68 #include "MagickCore/utility-private.h"
69 \f
70 /*
71   Define declarations.
72 */
73 #define MagickPathTemplate "XXXXXXXXXXXX"
74 \f
75 /*
76   Typedef declarations.
77 */
78 typedef struct _ResourceInfo
79 {
80   MagickOffsetType
81     width,
82     height,
83     area,
84     memory,
85     map,
86     disk,
87     file,
88     thread,
89     throttle,
90     time;
91
92   MagickSizeType
93     width_limit,
94     height_limit,
95     area_limit,
96     memory_limit,
97     map_limit,
98     disk_limit,
99     file_limit,
100     thread_limit,
101     throttle_limit,
102     time_limit;
103 } ResourceInfo;
104 \f
105 /*
106   Global declarations.
107 */
108 static RandomInfo
109   *random_info = (RandomInfo *) NULL;
110
111 static ResourceInfo
112   resource_info =
113   {
114     MagickULLConstant(0),              /* initial width */
115     MagickULLConstant(0),              /* initial height */
116     MagickULLConstant(0),              /* initial area */
117     MagickULLConstant(0),              /* initial memory */
118     MagickULLConstant(0),              /* initial map */
119     MagickULLConstant(0),              /* initial disk */
120     MagickULLConstant(0),              /* initial file */
121     MagickULLConstant(0),              /* initial thread */
122     MagickULLConstant(0),              /* initial throttle */
123     MagickULLConstant(0),              /* initial time */
124     (INT_MAX/(5*sizeof(Quantum))),     /* width limit */
125     (INT_MAX/(5*sizeof(Quantum))),     /* height limit */
126     MagickULLConstant(3072)*1024*1024, /* area limit */
127     MagickULLConstant(1536)*1024*1024, /* memory limit */
128     MagickULLConstant(3072)*1024*1024, /* map limit */
129     MagickResourceInfinity,            /* disk limit */
130     MagickULLConstant(768),            /* file limit */
131     MagickULLConstant(1),              /* thread limit */
132     MagickULLConstant(0),              /* throttle limit */
133     MagickResourceInfinity             /* time limit */
134   };
135
136 static SemaphoreInfo
137   *resource_semaphore = (SemaphoreInfo *) NULL;
138
139 static SplayTreeInfo
140   *temporary_resources = (SplayTreeInfo *) NULL;
141 \f
142 /*
143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
144 %                                                                             %
145 %                                                                             %
146 %                                                                             %
147 %   A c q u i r e M a g i c k R e s o u r c e                                 %
148 %                                                                             %
149 %                                                                             %
150 %                                                                             %
151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
152 %
153 %  AcquireMagickResource() acquires resources of the specified type.
154 %  MagickFalse is returned if the specified resource is exhausted otherwise
155 %  MagickTrue.
156 %
157 %  The format of the AcquireMagickResource() method is:
158 %
159 %      MagickBooleanType AcquireMagickResource(const ResourceType type,
160 %        const MagickSizeType size)
161 %
162 %  A description of each parameter follows:
163 %
164 %    o type: the type of resource.
165 %
166 %    o size: the number of bytes needed from for this resource.
167 %
168 */
169 MagickExport MagickBooleanType AcquireMagickResource(const ResourceType type,
170   const MagickSizeType size)
171 {
172   char
173     resource_current[MagickFormatExtent],
174     resource_limit[MagickFormatExtent],
175     resource_request[MagickFormatExtent];
176
177   MagickBooleanType
178     logging,
179     status;
180
181   MagickSizeType
182     limit;
183
184   status=MagickFalse;
185   logging=IsEventLogging();
186   if (resource_semaphore == (SemaphoreInfo *) NULL)
187     ActivateSemaphoreInfo(&resource_semaphore);
188   LockSemaphoreInfo(resource_semaphore);
189   switch (type)
190   {
191     case AreaResource:
192     {
193       resource_info.area=(MagickOffsetType) size;
194       limit=resource_info.area_limit;
195       if ((limit == MagickResourceInfinity) || (size < limit))
196         status=MagickTrue;
197       if (logging != MagickFalse)
198         {
199           (void) FormatMagickSize(size,MagickFalse,(const char *) NULL,
200             MagickFormatExtent,resource_request);
201           (void) FormatMagickSize(size,MagickFalse,(const char *) NULL,
202             MagickFormatExtent,resource_current);
203           (void) FormatMagickSize(limit,MagickFalse,(const char *) NULL,
204             MagickFormatExtent,resource_limit);
205         }
206       break;
207     }
208     case MemoryResource:
209     {
210       resource_info.memory+=(MagickOffsetType) size;
211       limit=resource_info.memory_limit;
212       if ((limit == MagickResourceInfinity) ||
213           (resource_info.memory < (MagickOffsetType) limit))
214         status=MagickTrue;
215       else
216         resource_info.memory-=(MagickOffsetType) size;
217       if (logging != MagickFalse)
218         {
219           (void) FormatMagickSize(size,MagickTrue,"B",MagickFormatExtent,
220             resource_request);
221           (void) FormatMagickSize((MagickSizeType) resource_info.memory,
222             MagickTrue,"B",MagickFormatExtent,resource_current);
223           (void) FormatMagickSize(limit,MagickTrue,"B",MagickFormatExtent,
224             resource_limit);
225         }
226       break;
227     }
228     case MapResource:
229     {
230       resource_info.map+=(MagickOffsetType) size;
231       limit=resource_info.map_limit;
232       if ((limit == MagickResourceInfinity) ||
233           (resource_info.map < (MagickOffsetType) limit))
234         status=MagickTrue;
235       else
236         resource_info.map-=(MagickOffsetType) size;
237       if (logging != MagickFalse)
238         {
239           (void) FormatMagickSize(size,MagickTrue,"B",MagickFormatExtent,
240             resource_request);
241           (void) FormatMagickSize((MagickSizeType) resource_info.map,
242             MagickTrue,"B",MagickFormatExtent,resource_current);
243           (void) FormatMagickSize(limit,MagickTrue,"B",MagickFormatExtent,
244             resource_limit);
245         }
246       break;
247     }
248     case DiskResource:
249     {
250       resource_info.disk+=(MagickOffsetType) size;
251       limit=resource_info.disk_limit;
252       if ((limit == MagickResourceInfinity) ||
253           (resource_info.disk < (MagickOffsetType) limit))
254         status=MagickTrue;
255       else
256         resource_info.disk-=(MagickOffsetType) size;
257       if (logging != MagickFalse)
258         {
259           (void) FormatMagickSize(size,MagickTrue,"B",MagickFormatExtent,
260             resource_request);
261           (void) FormatMagickSize((MagickSizeType) resource_info.disk,
262             MagickTrue,"B",MagickFormatExtent,resource_current);
263           (void) FormatMagickSize(limit,MagickTrue,"B",MagickFormatExtent,
264             resource_limit);
265         }
266       break;
267     }
268     case FileResource:
269     {
270       resource_info.file+=(MagickOffsetType) size;
271       limit=resource_info.file_limit;
272       if ((limit == MagickResourceInfinity) ||
273           (resource_info.file < (MagickOffsetType) limit))
274         status=MagickTrue;
275       else
276         resource_info.file-=(MagickOffsetType) size;
277       if (logging != MagickFalse)
278         {
279           (void) FormatMagickSize(size,MagickFalse,(const char *) NULL,
280             MagickFormatExtent,resource_request);
281           (void) FormatMagickSize((MagickSizeType) resource_info.file,
282             MagickFalse,(const char *) NULL,MagickFormatExtent,
283             resource_current);
284           (void) FormatMagickSize(limit,MagickTrue,(const char *) NULL,
285             MagickFormatExtent,resource_limit);
286         }
287       break;
288     }
289     case HeightResource:
290     {
291       resource_info.height=(MagickOffsetType) size;
292       limit=resource_info.height_limit;
293       if ((limit == MagickResourceInfinity) || (size < limit))
294         status=MagickTrue;
295       if (logging != MagickFalse)
296         {
297           (void) FormatMagickSize(size,MagickFalse,"P",MagickFormatExtent,
298             resource_request);
299           (void) FormatMagickSize(size,MagickFalse,"P",MagickFormatExtent,
300             resource_current);
301           (void) FormatMagickSize(limit,MagickFalse,"P",MagickFormatExtent,
302             resource_limit);
303         }
304       break;
305     }
306     case ThreadResource:
307     {
308       limit=resource_info.thread_limit;
309       if ((limit == MagickResourceInfinity) ||
310           (resource_info.thread < (MagickOffsetType) limit))
311         status=MagickTrue;
312       if (logging != MagickFalse)
313         {
314           (void) FormatMagickSize(size,MagickFalse,(const char *) NULL,
315             MagickFormatExtent,resource_request);
316           (void) FormatMagickSize((MagickSizeType) resource_info.thread,
317             MagickFalse,(const char *) NULL,MagickFormatExtent,
318             resource_current);
319           (void) FormatMagickSize(limit,MagickFalse,(const char *) NULL,
320             MagickFormatExtent,resource_limit);
321         }
322       break;
323     }
324     case ThrottleResource:
325     {
326       limit=resource_info.throttle_limit;
327       if ((limit == MagickResourceInfinity) ||
328           (resource_info.throttle < (MagickOffsetType) limit))
329         status=MagickTrue;
330       if (logging != MagickFalse)
331         {
332           (void) FormatMagickSize(size,MagickFalse,(const char *) NULL,
333             MagickFormatExtent,resource_request);
334           (void) FormatMagickSize((MagickSizeType) resource_info.throttle,
335             MagickFalse,(const char *) NULL,MagickFormatExtent,
336             resource_current);
337           (void) FormatMagickSize(limit,MagickFalse,(const char *) NULL,
338             MagickFormatExtent,resource_limit);
339         }
340       break;
341     }
342     case TimeResource:
343     {
344       resource_info.time+=(MagickOffsetType) size;
345       limit=resource_info.time_limit;
346       if ((limit == MagickResourceInfinity) ||
347           (resource_info.time < (MagickOffsetType) limit))
348         status=MagickTrue;
349       else
350         resource_info.time-=(MagickOffsetType) size;
351       if (logging != MagickFalse)
352         {
353           (void) FormatMagickSize(size,MagickFalse,(const char *) NULL,
354             MagickFormatExtent,resource_request);
355           (void) FormatMagickSize((MagickSizeType) resource_info.time,
356             MagickFalse,(const char *) NULL,MagickFormatExtent,
357             resource_current);
358           (void) FormatMagickSize(limit,MagickFalse,(const char *) NULL,
359             MagickFormatExtent,resource_limit);
360         }
361       break;
362     }
363     case WidthResource:
364     {
365       resource_info.width=(MagickOffsetType) size;
366       limit=resource_info.width_limit;
367       if ((limit == MagickResourceInfinity) || (size < limit))
368         status=MagickTrue;
369       if (logging != MagickFalse)
370         {
371           (void) FormatMagickSize(size,MagickFalse,"P",MagickFormatExtent,
372             resource_request);
373           (void) FormatMagickSize(size,MagickFalse,"P",MagickFormatExtent,
374             resource_current);
375           (void) FormatMagickSize(limit,MagickFalse,"P",MagickFormatExtent,
376             resource_limit);
377         }
378       break;
379     }
380     default:
381       break;
382   }
383   UnlockSemaphoreInfo(resource_semaphore);
384   if (logging != MagickFalse)
385     {
386       (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
387         CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
388         resource_request,resource_current,resource_limit);
389     }
390   return(status);
391 }
392 \f
393 /*
394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
395 %                                                                             %
396 %                                                                             %
397 %                                                                             %
398 +   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 %
399 %                                                                             %
400 %                                                                             %
401 %                                                                             %
402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403 %
404 %  AsynchronousResourceComponentTerminus() destroys the resource environment.
405 %  It differs from ResourceComponentTerminus() in that it can be called from a
406 %  asynchronous signal handler.
407 %
408 %  The format of the ResourceComponentTerminus() method is:
409 %
410 %      ResourceComponentTerminus(void)
411 %
412 */
413 MagickPrivate void AsynchronousResourceComponentTerminus(void)
414 {
415   const char
416     *path;
417
418   if (temporary_resources == (SplayTreeInfo *) NULL)
419     return;
420   /*
421     Remove any lingering temporary files.
422   */
423   ResetSplayTreeIterator(temporary_resources);
424   path=(const char *) GetNextKeyInSplayTree(temporary_resources);
425   while (path != (const char *) NULL)
426   {
427     (void) ShredFile(path);
428     path=(const char *) GetNextKeyInSplayTree(temporary_resources);
429   }
430 }
431 \f
432 /*
433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
434 %                                                                             %
435 %                                                                             %
436 %                                                                             %
437 %   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                         %
438 %                                                                             %
439 %                                                                             %
440 %                                                                             %
441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
442 %
443 %  AcquireUniqueFileResource() returns a unique file name, and returns a file
444 %  descriptor for the file open for reading and writing.
445 %
446 %  The format of the AcquireUniqueFileResource() method is:
447 %
448 %      int AcquireUniqueFileResource(char *path)
449 %
450 %  A description of each parameter follows:
451 %
452 %   o  path:  Specifies a pointer to an array of characters.  The unique path
453 %      name is returned in this array.
454 %
455 */
456
457 static void *DestroyTemporaryResources(void *temporary_resource)
458 {
459   (void) ShredFile((char *) temporary_resource);
460   temporary_resource=DestroyString((char *) temporary_resource);
461   return((void *) NULL);
462 }
463
464 MagickExport MagickBooleanType GetPathTemplate(char *path)
465 {
466   char
467     *directory,
468     *value;
469
470   ExceptionInfo
471     *exception;
472
473   MagickBooleanType
474     status;
475
476   struct stat
477     attributes;
478
479   (void) FormatLocaleString(path,MagickPathExtent,"magick-%.20g"
480     MagickPathTemplate,(double) getpid());
481   exception=AcquireExceptionInfo();
482   directory=(char *) GetImageRegistry(StringRegistryType,"temporary-path",
483     exception);
484   exception=DestroyExceptionInfo(exception);
485   if (directory == (char *) NULL)
486     directory=GetEnvironmentValue("MAGICK_TEMPORARY_PATH");
487   if (directory == (char *) NULL)
488     directory=GetEnvironmentValue("MAGICK_TMPDIR");
489   if (directory == (char *) NULL)
490     directory=GetEnvironmentValue("TMPDIR");
491 #if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__) || defined(__CYGWIN__)
492   if (directory == (char *) NULL)
493     directory=GetEnvironmentValue("TMP");
494   if (directory == (char *) NULL)
495     directory=GetEnvironmentValue("TEMP");
496 #endif
497 #if defined(__VMS)
498   if (directory == (char *) NULL)
499     directory=GetEnvironmentValue("MTMPDIR");
500 #endif
501 #if defined(P_tmpdir)
502   if (directory == (char *) NULL)
503     directory=ConstantString(P_tmpdir);
504 #endif
505   if (directory == (char *) NULL)
506     return(MagickTrue);
507   value=GetPolicyValue("resource:temporary-path");
508   if (value != (char *) NULL)
509     {
510       (void) CloneString(&directory,value);
511       value=DestroyString(value);
512     }
513   if (strlen(directory) > (MagickPathExtent-25))
514     {
515       directory=DestroyString(directory);
516       return(MagickFalse);
517     }
518   status=GetPathAttributes(directory,&attributes);
519   if ((status == MagickFalse) || !S_ISDIR(attributes.st_mode))
520     {
521       directory=DestroyString(directory);
522       return(MagickFalse);
523     }
524   if (directory[strlen(directory)-1] == *DirectorySeparator)
525     (void) FormatLocaleString(path,MagickPathExtent,
526       "%smagick-%.20g" MagickPathTemplate,directory,(double) getpid());
527   else
528     (void) FormatLocaleString(path,MagickPathExtent,
529       "%s%smagick-%.20g" MagickPathTemplate,directory,DirectorySeparator,
530       (double) getpid());
531   directory=DestroyString(directory);
532 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
533   {
534     register char
535       *p;
536
537     /*
538       Ghostscript does not like backslashes so we need to replace them. The
539       forward slash also works under Windows.
540     */
541     for (p=(path[1] == *DirectorySeparator ? path+2 : path); *p != '\0'; p++)
542       if (*p == *DirectorySeparator)
543         *p='/';
544   }
545 #endif
546   return(MagickTrue);
547 }
548
549 MagickExport int AcquireUniqueFileResource(char *path)
550 {
551 #if !defined(O_NOFOLLOW)
552 #define O_NOFOLLOW 0
553 #endif
554 #if !defined(TMP_MAX)
555 # define TMP_MAX  238328
556 #endif
557
558   int
559     c,
560     file;
561
562   register char
563     *p;
564
565   register ssize_t
566     i;
567
568   static const char
569     portable_filename[65] =
570       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
571
572   StringInfo
573     *key;
574
575   unsigned char
576     *datum;
577
578   assert(path != (char *) NULL);
579   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"...");
580   if (random_info == (RandomInfo *) NULL)
581     {
582       LockSemaphoreInfo(resource_semaphore);
583       if (random_info == (RandomInfo *) NULL)
584         random_info=AcquireRandomInfo();
585       UnlockSemaphoreInfo(resource_semaphore);
586     }
587   file=(-1);
588   for (i=0; i < (ssize_t) TMP_MAX; i++)
589   {
590     register ssize_t
591       j;
592
593     /*
594       Get temporary pathname.
595     */
596     (void) GetPathTemplate(path);
597     key=GetRandomKey(random_info,6);
598     p=path+strlen(path)-strlen(MagickPathTemplate);
599     datum=GetStringInfoDatum(key);
600     for (j=0; j < (ssize_t) GetStringInfoLength(key); j++)
601     {
602       c=(int) (datum[j] & 0x3f);
603       *p++=portable_filename[c];
604     }
605     key=DestroyStringInfo(key);
606 #if defined(MAGICKCORE_HAVE_MKSTEMP)
607     file=mkstemp(path);
608     if (file != -1)
609       {
610 #if defined(MAGICKCORE_HAVE_FCHMOD)
611         (void) fchmod(file,0600);
612 #endif
613 #if defined(__OS2__)
614         setmode(file,O_BINARY);
615 #endif
616         break;
617       }
618 #endif
619     key=GetRandomKey(random_info,strlen(MagickPathTemplate));
620     p=path+strlen(path)-strlen(MagickPathTemplate);
621     datum=GetStringInfoDatum(key);
622     for (j=0; j < (ssize_t) GetStringInfoLength(key); j++)
623     {
624       c=(int) (datum[j] & 0x3f);
625       *p++=portable_filename[c];
626     }
627     key=DestroyStringInfo(key);
628     file=open_utf8(path,O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_NOFOLLOW,
629       S_MODE);
630     if ((file >= 0) || (errno != EEXIST))
631       break;
632   }
633   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
634   if (file == -1)
635     return(file);
636   if (resource_semaphore == (SemaphoreInfo *) NULL)
637     ActivateSemaphoreInfo(&resource_semaphore);
638   LockSemaphoreInfo(resource_semaphore);
639   if (temporary_resources == (SplayTreeInfo *) NULL)
640     temporary_resources=NewSplayTree(CompareSplayTreeString,
641       DestroyTemporaryResources,(void *(*)(void *)) NULL);
642   UnlockSemaphoreInfo(resource_semaphore);
643   (void) AddValueToSplayTree(temporary_resources,ConstantString(path),
644     (const void *) NULL);
645   return(file);
646 }
647 \f
648 /*
649 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
650 %                                                                             %
651 %                                                                             %
652 %                                                                             %
653 %   G e t M a g i c k R e s o u r c e                                         %
654 %                                                                             %
655 %                                                                             %
656 %                                                                             %
657 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
658 %
659 %  GetMagickResource() returns the specified resource.
660 %
661 %  The format of the GetMagickResource() method is:
662 %
663 %      MagickSizeType GetMagickResource(const ResourceType type)
664 %
665 %  A description of each parameter follows:
666 %
667 %    o type: the type of resource.
668 %
669 */
670 MagickExport MagickSizeType GetMagickResource(const ResourceType type)
671 {
672   MagickSizeType
673     resource;
674
675   resource=0;
676   LockSemaphoreInfo(resource_semaphore);
677   switch (type)
678   {
679     case WidthResource:
680     {
681       resource=(MagickSizeType) resource_info.width;
682       break;
683     }
684     case HeightResource:
685     {
686       resource=(MagickSizeType) resource_info.height;
687       break;
688     }
689     case AreaResource:
690     {
691       resource=(MagickSizeType) resource_info.area;
692       break;
693     }
694     case MemoryResource:
695     {
696       resource=(MagickSizeType) resource_info.memory;
697       break;
698     }
699     case MapResource:
700     {
701       resource=(MagickSizeType) resource_info.map;
702       break;
703     }
704     case DiskResource:
705     {
706       resource=(MagickSizeType) resource_info.disk;
707       break;
708     }
709     case FileResource:
710     {
711       resource=(MagickSizeType) resource_info.file;
712       break;
713     }
714     case ThreadResource:
715     {
716       resource=(MagickSizeType) resource_info.thread;
717       break;
718     }
719     case ThrottleResource:
720     {
721       resource=(MagickSizeType) resource_info.throttle;
722       break;
723     }
724     case TimeResource:
725     {
726       resource=(MagickSizeType) resource_info.time;
727       break;
728     }
729     default:
730       break;
731   }
732   UnlockSemaphoreInfo(resource_semaphore);
733   return(resource);
734 }
735 \f
736 /*
737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
738 %                                                                             %
739 %                                                                             %
740 %                                                                             %
741 %   G e t M a g i c k R e s o u r c e L i m i t                               %
742 %                                                                             %
743 %                                                                             %
744 %                                                                             %
745 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
746 %
747 %  GetMagickResourceLimit() returns the specified resource limit.
748 %
749 %  The format of the GetMagickResourceLimit() method is:
750 %
751 %      MagickSizeType GetMagickResourceLimit(const ResourceType type)
752 %
753 %  A description of each parameter follows:
754 %
755 %    o type: the type of resource.
756 %
757 */
758 MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
759 {
760   MagickSizeType
761     resource;
762
763   resource=0;
764   if (resource_semaphore == (SemaphoreInfo *) NULL)
765     ActivateSemaphoreInfo(&resource_semaphore);
766   LockSemaphoreInfo(resource_semaphore);
767   switch (type)
768   {
769     case WidthResource:
770     {
771       resource=resource_info.width_limit;
772       break;
773     }
774     case HeightResource:
775     {
776       resource=resource_info.height_limit;
777       break;
778     }
779     case AreaResource:
780     {
781       resource=resource_info.area_limit;
782       break;
783     }
784     case MemoryResource:
785     {
786       resource=resource_info.memory_limit;
787       break;
788     }
789     case MapResource:
790     {
791       resource=resource_info.map_limit;
792       break;
793     }
794     case DiskResource:
795     {
796       resource=resource_info.disk_limit;
797       break;
798     }
799     case FileResource:
800     {
801       resource=resource_info.file_limit;
802       break;
803     }
804     case ThreadResource:
805     {
806       resource=resource_info.thread_limit;
807       break;
808     }
809     case ThrottleResource:
810     {
811       resource=resource_info.throttle_limit;
812       break;
813     }
814     case TimeResource:
815     {
816       resource=resource_info.time_limit;
817       break;
818     }
819     default:
820       break;
821   }
822   UnlockSemaphoreInfo(resource_semaphore);
823   return(resource);
824 }
825 \f
826 /*
827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
828 %                                                                             %
829 %                                                                             %
830 %                                                                             %
831 %  L i s t M a g i c k R e s o u r c e I n f o                                %
832 %                                                                             %
833 %                                                                             %
834 %                                                                             %
835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
836 %
837 %  ListMagickResourceInfo() lists the resource info to a file.
838 %
839 %  The format of the ListMagickResourceInfo method is:
840 %
841 %      MagickBooleanType ListMagickResourceInfo(FILE *file,
842 %        ExceptionInfo *exception)
843 %
844 %  A description of each parameter follows.
845 %
846 %    o file:  An pointer to a FILE.
847 %
848 %    o exception: return any errors or warnings in this structure.
849 %
850 */
851 MagickExport MagickBooleanType ListMagickResourceInfo(FILE *file,
852   ExceptionInfo *magick_unused(exception))
853 {
854   char
855     area_limit[MagickFormatExtent],
856     disk_limit[MagickFormatExtent],
857     height_limit[MagickFormatExtent],
858     map_limit[MagickFormatExtent],
859     memory_limit[MagickFormatExtent],
860     time_limit[MagickFormatExtent],
861     width_limit[MagickFormatExtent];
862
863   magick_unreferenced(exception);
864
865   if (file == (const FILE *) NULL)
866     file=stdout;
867   if (resource_semaphore == (SemaphoreInfo *) NULL)
868     ActivateSemaphoreInfo(&resource_semaphore);
869   LockSemaphoreInfo(resource_semaphore);
870   (void) FormatMagickSize(resource_info.width_limit,MagickFalse,"P",
871     MagickFormatExtent,width_limit);
872   (void) FormatMagickSize(resource_info.height_limit,MagickFalse,"P",
873     MagickFormatExtent,height_limit);
874   (void) FormatMagickSize(resource_info.area_limit,MagickFalse,"P",
875     MagickFormatExtent,area_limit);
876   (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,"B",
877     MagickFormatExtent,memory_limit);
878   (void) FormatMagickSize(resource_info.map_limit,MagickTrue,"B",
879     MagickFormatExtent,map_limit);
880   (void) CopyMagickString(disk_limit,"unlimited",MagickFormatExtent);
881   if (resource_info.disk_limit != MagickResourceInfinity)
882     (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,"B",
883       MagickFormatExtent,disk_limit);
884   (void) CopyMagickString(time_limit,"unlimited",MagickFormatExtent);
885   if (resource_info.time_limit != MagickResourceInfinity)
886     (void) FormatLocaleString(time_limit,MagickFormatExtent,"%.20g",(double)
887       ((MagickOffsetType) resource_info.time_limit));
888   (void) FormatLocaleFile(file,"Resource limits:\n");
889   (void) FormatLocaleFile(file,"  Width: %s\n",width_limit);
890   (void) FormatLocaleFile(file,"  Height: %s\n",height_limit);
891   (void) FormatLocaleFile(file,"  Area: %s\n",area_limit);
892   (void) FormatLocaleFile(file,"  Memory: %s\n",memory_limit);
893   (void) FormatLocaleFile(file,"  Map: %s\n",map_limit);
894   (void) FormatLocaleFile(file,"  Disk: %s\n",disk_limit);
895   (void) FormatLocaleFile(file,"  File: %.20g\n",(double) ((MagickOffsetType)
896     resource_info.file_limit));
897   (void) FormatLocaleFile(file,"  Thread: %.20g\n",(double) ((MagickOffsetType)
898     resource_info.thread_limit));
899   (void) FormatLocaleFile(file,"  Throttle: %.20g\n",(double)
900     ((MagickOffsetType) resource_info.throttle_limit));
901   (void) FormatLocaleFile(file,"  Time: %s\n",time_limit);
902   (void) fflush(file);
903   UnlockSemaphoreInfo(resource_semaphore);
904   return(MagickTrue);
905 }
906 \f
907 /*
908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
909 %                                                                             %
910 %                                                                             %
911 %                                                                             %
912 %   R e l i n q u i s h M a g i c k R e s o u r c e                           %
913 %                                                                             %
914 %                                                                             %
915 %                                                                             %
916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
917 %
918 %  RelinquishMagickResource() relinquishes resources of the specified type.
919 %
920 %  The format of the RelinquishMagickResource() method is:
921 %
922 %      void RelinquishMagickResource(const ResourceType type,
923 %        const MagickSizeType size)
924 %
925 %  A description of each parameter follows:
926 %
927 %    o type: the type of resource.
928 %
929 %    o size: the size of the resource.
930 %
931 */
932 MagickExport void RelinquishMagickResource(const ResourceType type,
933   const MagickSizeType size)
934 {
935   char
936     resource_current[MagickFormatExtent],
937     resource_limit[MagickFormatExtent],
938     resource_request[MagickFormatExtent];
939
940   MagickBooleanType
941     logging;
942
943   logging=IsEventLogging();
944   if (resource_semaphore == (SemaphoreInfo *) NULL)
945     ActivateSemaphoreInfo(&resource_semaphore);
946   LockSemaphoreInfo(resource_semaphore);
947   switch (type)
948   {
949     case AreaResource:
950     {
951       resource_info.area=(MagickOffsetType) size;
952       if (logging != MagickFalse)
953         {
954           (void) FormatMagickSize(size,MagickFalse,(const char *) NULL,
955             MagickFormatExtent,resource_request);
956           (void) FormatMagickSize((MagickSizeType) resource_info.area,
957             MagickFalse,(const char *) NULL,MagickFormatExtent,
958             resource_current);
959           (void) FormatMagickSize(resource_info.area_limit,MagickFalse,
960             (const char *) NULL,MagickFormatExtent,resource_limit);
961         }
962       break;
963     }
964     case MemoryResource:
965     {
966       resource_info.memory-=size;
967       assert(resource_info.memory >= 0);
968       if (logging != MagickFalse)
969         {
970           (void) FormatMagickSize(size,MagickFalse,"B",MagickFormatExtent,
971             resource_request);
972           (void) FormatMagickSize((MagickSizeType) resource_info.memory,
973             MagickTrue,"B",MagickFormatExtent,resource_current);
974           (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,"B",
975             MagickFormatExtent,resource_limit);
976         }
977       break;
978     }
979     case MapResource:
980     {
981       resource_info.map-=size;
982       assert(resource_info.map >= 0);
983       if (logging != MagickFalse)
984         {
985           (void) FormatMagickSize(size,MagickFalse,"B",MagickFormatExtent,
986             resource_request);
987           (void) FormatMagickSize((MagickSizeType) resource_info.map,
988             MagickTrue,"B",MagickFormatExtent,resource_current);
989           (void) FormatMagickSize(resource_info.map_limit,MagickTrue,"B",
990             MagickFormatExtent,resource_limit);
991         }
992       break;
993     }
994     case DiskResource:
995     {
996       resource_info.disk-=size;
997       assert(resource_info.disk >= 0);
998       if (logging != MagickFalse)
999         {
1000           (void) FormatMagickSize(size,MagickFalse,"B",MagickFormatExtent,
1001             resource_request);
1002           (void) FormatMagickSize((MagickSizeType) resource_info.disk,
1003             MagickTrue,"B",MagickFormatExtent,resource_current);
1004           (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,"B",
1005             MagickFormatExtent,resource_limit);
1006         }
1007       break;
1008     }
1009     case FileResource:
1010     {
1011       resource_info.file-=size;
1012       assert(resource_info.file >= 0);
1013       if (logging != MagickFalse)
1014         {
1015           (void) FormatMagickSize(size,MagickFalse,(const char *) NULL,
1016             MagickFormatExtent,resource_request);
1017           (void) FormatMagickSize((MagickSizeType) resource_info.file,
1018             MagickFalse,(const char *) NULL,MagickFormatExtent,
1019             resource_current);
1020           (void) FormatMagickSize((MagickSizeType) resource_info.file_limit,
1021             MagickFalse,(const char *) NULL,MagickFormatExtent,resource_limit);
1022         }
1023       break;
1024     }
1025     case HeightResource:
1026     {
1027       resource_info.height=(MagickOffsetType) size;
1028       if (logging != MagickFalse)
1029         {
1030           (void) FormatMagickSize(size,MagickFalse,"P",MagickFormatExtent,
1031             resource_request);
1032           (void) FormatMagickSize((MagickSizeType) resource_info.height,
1033             MagickFalse,"P",MagickFormatExtent,resource_current);
1034           (void) FormatMagickSize(resource_info.height_limit,MagickFalse,"P",
1035             MagickFormatExtent,resource_limit);
1036         }
1037       break;
1038     }
1039     case ThreadResource:
1040     {
1041       if (logging != MagickFalse)
1042         {
1043           (void) FormatMagickSize(size,MagickFalse,(const char *) NULL,
1044             MagickFormatExtent,resource_request);
1045           (void) FormatMagickSize((MagickSizeType) resource_info.thread,
1046             MagickFalse,(const char *) NULL,MagickFormatExtent,
1047             resource_current);
1048           (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
1049             MagickFalse,(const char *) NULL,MagickFormatExtent,resource_limit);
1050         }
1051       break;
1052     }
1053     case ThrottleResource:
1054     {
1055       if (logging != MagickFalse)
1056         {
1057           (void) FormatMagickSize(size,MagickFalse,(const char *) NULL,
1058             MagickFormatExtent,resource_request);
1059           (void) FormatMagickSize((MagickSizeType) resource_info.throttle,
1060             MagickFalse,(const char *) NULL,MagickFormatExtent,
1061             resource_current);
1062           (void) FormatMagickSize((MagickSizeType) resource_info.throttle_limit,
1063             MagickFalse,(const char *) NULL,MagickFormatExtent,resource_limit);
1064         }
1065       break;
1066     }
1067     case TimeResource:
1068     {
1069       resource_info.time-=size;
1070       assert(resource_info.time >= 0);
1071       if (logging != MagickFalse)
1072         {
1073           (void) FormatMagickSize(size,MagickFalse,(const char *) NULL,
1074             MagickFormatExtent,resource_request);
1075           (void) FormatMagickSize((MagickSizeType) resource_info.time,
1076             MagickFalse,(const char *) NULL,MagickFormatExtent,
1077             resource_current);
1078           (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
1079             MagickFalse,(const char *) NULL,MagickFormatExtent,resource_limit);
1080         }
1081       break;
1082     }
1083     case WidthResource:
1084     {
1085       resource_info.width=(MagickOffsetType) size;
1086       if (logging != MagickFalse)
1087         {
1088           (void) FormatMagickSize(size,MagickFalse,"P",MagickFormatExtent,
1089             resource_request);
1090           (void) FormatMagickSize((MagickSizeType) resource_info.width,
1091             MagickFalse,"P",MagickFormatExtent,resource_current);
1092           (void) FormatMagickSize(resource_info.width_limit,MagickFalse,"P",
1093             MagickFormatExtent,resource_limit);
1094         }
1095       break;
1096     }
1097     default:
1098       break;
1099   }
1100   UnlockSemaphoreInfo(resource_semaphore);
1101   if (logging != MagickFalse)
1102     {
1103       (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
1104         CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
1105           resource_request,resource_current,resource_limit);
1106     }
1107 }
1108 \f
1109 /*
1110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1111 %                                                                             %
1112 %                                                                             %
1113 %                                                                             %
1114 %    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                  %
1115 %                                                                             %
1116 %                                                                             %
1117 %                                                                             %
1118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119 %
1120 %  RelinquishUniqueFileResource() relinquishes a unique file resource.
1121 %
1122 %  The format of the RelinquishUniqueFileResource() method is:
1123 %
1124 %      MagickBooleanType RelinquishUniqueFileResource(const char *path)
1125 %
1126 %  A description of each parameter follows:
1127 %
1128 %    o name: the name of the temporary resource.
1129 %
1130 */
1131 MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
1132 {
1133   char
1134     cache_path[MagickPathExtent];
1135
1136   MagickBooleanType
1137     status;
1138
1139   assert(path != (const char *) NULL);
1140   status=MagickFalse;
1141   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
1142   if (resource_semaphore == (SemaphoreInfo *) NULL)
1143     ActivateSemaphoreInfo(&resource_semaphore);
1144   LockSemaphoreInfo(resource_semaphore);
1145   if (temporary_resources != (SplayTreeInfo *) NULL)
1146     status=DeleteNodeFromSplayTree(temporary_resources,(const void *) path);
1147   UnlockSemaphoreInfo(resource_semaphore);
1148   (void) CopyMagickString(cache_path,path,MagickPathExtent);
1149   AppendImageFormat("cache",cache_path);
1150   (void) ShredFile(cache_path);
1151   if (status == MagickFalse)
1152     status=ShredFile(path);
1153   return(status);
1154 }
1155 \f
1156 /*
1157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1158 %                                                                             %
1159 %                                                                             %
1160 %                                                                             %
1161 +   R e s o u r c e C o m p o n e n t G e n e s i s                           %
1162 %                                                                             %
1163 %                                                                             %
1164 %                                                                             %
1165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1166 %
1167 %  ResourceComponentGenesis() instantiates the resource component.
1168 %
1169 %  The format of the ResourceComponentGenesis method is:
1170 %
1171 %      MagickBooleanType ResourceComponentGenesis(void)
1172 %
1173 */
1174
1175 static inline MagickSizeType StringToSizeType(const char *string,
1176   const double interval)
1177 {
1178   double
1179     value;
1180
1181   value=SiPrefixToDoubleInterval(string,interval);
1182   if (value >= (double) MagickULLConstant(~0))
1183     return(MagickULLConstant(~0));
1184   return((MagickSizeType) value);
1185 }
1186
1187 MagickPrivate MagickBooleanType ResourceComponentGenesis(void)
1188 {
1189   char
1190     *limit;
1191
1192   MagickSizeType
1193     memory;
1194
1195   ssize_t
1196     files,
1197     pages,
1198     pagesize;
1199
1200   /*
1201     Set Magick resource limits.
1202   */
1203   if (resource_semaphore == (SemaphoreInfo *) NULL)
1204     resource_semaphore=AcquireSemaphoreInfo();
1205   (void) SetMagickResourceLimit(WidthResource,resource_info.width_limit);
1206   limit=GetEnvironmentValue("MAGICK_WIDTH_LIMIT");
1207   if (limit != (char *) NULL)
1208     {
1209       (void) SetMagickResourceLimit(WidthResource,StringToSizeType(limit,
1210         100.0));
1211       limit=DestroyString(limit);
1212     }
1213   (void) SetMagickResourceLimit(HeightResource,resource_info.height_limit);
1214   limit=GetEnvironmentValue("MAGICK_HEIGHT_LIMIT");
1215   if (limit != (char *) NULL)
1216     {
1217       (void) SetMagickResourceLimit(HeightResource,StringToSizeType(limit,
1218         100.0));
1219       limit=DestroyString(limit);
1220     }
1221   pagesize=GetMagickPageSize();
1222   pages=(-1);
1223 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
1224   pages=(ssize_t) sysconf(_SC_PHYS_PAGES);
1225 #endif
1226   memory=(MagickSizeType) pages*pagesize;
1227   if ((pagesize <= 0) || (pages <= 0))
1228     memory=2048UL*1024UL*1024UL;
1229 #if defined(PixelCacheThreshold)
1230   memory=PixelCacheThreshold;
1231 #endif
1232   (void) SetMagickResourceLimit(AreaResource,2*memory);
1233   limit=GetEnvironmentValue("MAGICK_AREA_LIMIT");
1234   if (limit != (char *) NULL)
1235     {
1236       (void) SetMagickResourceLimit(AreaResource,StringToSizeType(limit,100.0));
1237       limit=DestroyString(limit);
1238     }
1239   (void) SetMagickResourceLimit(MemoryResource,memory);
1240   limit=GetEnvironmentValue("MAGICK_MEMORY_LIMIT");
1241   if (limit != (char *) NULL)
1242     {
1243       (void) SetMagickResourceLimit(MemoryResource,
1244         StringToSizeType(limit,100.0));
1245       limit=DestroyString(limit);
1246     }
1247   (void) SetMagickResourceLimit(MapResource,2*memory);
1248   limit=GetEnvironmentValue("MAGICK_MAP_LIMIT");
1249   if (limit != (char *) NULL)
1250     {
1251       (void) SetMagickResourceLimit(MapResource,StringToSizeType(limit,100.0));
1252       limit=DestroyString(limit);
1253     }
1254   (void) SetMagickResourceLimit(DiskResource,MagickResourceInfinity);
1255   limit=GetEnvironmentValue("MAGICK_DISK_LIMIT");
1256   if (limit != (char *) NULL)
1257     {
1258       (void) SetMagickResourceLimit(DiskResource,StringToSizeType(limit,100.0));
1259       limit=DestroyString(limit);
1260     }
1261   files=(-1);
1262 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
1263   files=(ssize_t) sysconf(_SC_OPEN_MAX);
1264 #endif
1265 #if defined(MAGICKCORE_HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
1266   if (files < 0)
1267     {
1268       struct rlimit
1269         resources;
1270
1271       if (getrlimit(RLIMIT_NOFILE,&resources) != -1)
1272         files=(ssize_t) resources.rlim_cur;
1273   }
1274 #endif
1275 #if defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
1276   if (files < 0)
1277     files=(ssize_t) getdtablesize();
1278 #endif
1279   if (files < 0)
1280     files=64;
1281   (void) SetMagickResourceLimit(FileResource,MagickMax((size_t)
1282     (3*files/4),64));
1283   limit=GetEnvironmentValue("MAGICK_FILE_LIMIT");
1284   if (limit != (char *) NULL)
1285     {
1286       (void) SetMagickResourceLimit(FileResource,StringToSizeType(limit,
1287         100.0));
1288       limit=DestroyString(limit);
1289     }
1290   (void) SetMagickResourceLimit(ThreadResource,GetOpenMPMaximumThreads());
1291   limit=GetEnvironmentValue("MAGICK_THREAD_LIMIT");
1292   if (limit != (char *) NULL)
1293     {
1294       (void) SetMagickResourceLimit(ThreadResource,StringToSizeType(limit,
1295         100.0));
1296       limit=DestroyString(limit);
1297     }
1298   (void) SetMagickResourceLimit(ThrottleResource,0);
1299   limit=GetEnvironmentValue("MAGICK_THROTTLE_LIMIT");
1300   if (limit != (char *) NULL)
1301     {
1302       (void) SetMagickResourceLimit(ThrottleResource,StringToSizeType(limit,
1303         100.0));
1304       limit=DestroyString(limit);
1305     }
1306   (void) SetMagickResourceLimit(TimeResource,MagickResourceInfinity);
1307   limit=GetEnvironmentValue("MAGICK_TIME_LIMIT");
1308   if (limit != (char *) NULL)
1309     {
1310       (void) SetMagickResourceLimit(TimeResource,StringToSizeType(limit,100.0));
1311       limit=DestroyString(limit);
1312     }
1313   return(MagickTrue);
1314 }
1315 \f
1316 /*
1317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1318 %                                                                             %
1319 %                                                                             %
1320 %                                                                             %
1321 +   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                         %
1322 %                                                                             %
1323 %                                                                             %
1324 %                                                                             %
1325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1326 %
1327 %  ResourceComponentTerminus() destroys the resource component.
1328 %
1329 %  The format of the ResourceComponentTerminus() method is:
1330 %
1331 %      ResourceComponentTerminus(void)
1332 %
1333 */
1334 MagickPrivate void ResourceComponentTerminus(void)
1335 {
1336   if (resource_semaphore == (SemaphoreInfo *) NULL)
1337     resource_semaphore=AcquireSemaphoreInfo();
1338   LockSemaphoreInfo(resource_semaphore);
1339   if (temporary_resources != (SplayTreeInfo *) NULL)
1340     temporary_resources=DestroySplayTree(temporary_resources);
1341   if (random_info != (RandomInfo *) NULL)
1342     random_info=DestroyRandomInfo(random_info);
1343   UnlockSemaphoreInfo(resource_semaphore);
1344   RelinquishSemaphoreInfo(&resource_semaphore);
1345 }
1346 \f
1347 /*
1348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1349 %                                                                             %
1350 %                                                                             %
1351 %                                                                             %
1352 %   S e t M a g i c k R e s o u r c e L i m i t                               %
1353 %                                                                             %
1354 %                                                                             %
1355 %                                                                             %
1356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1357 %
1358 %  SetMagickResourceLimit() sets the limit for a particular resource.
1359 %
1360 %  The format of the SetMagickResourceLimit() method is:
1361 %
1362 %      MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1363 %        const MagickSizeType limit)
1364 %
1365 %  A description of each parameter follows:
1366 %
1367 %    o type: the type of resource.
1368 %
1369 %    o limit: the maximum limit for the resource.
1370 %
1371 */
1372
1373 MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1374   const MagickSizeType limit)
1375 {
1376   char
1377     *value;
1378
1379   if (resource_semaphore == (SemaphoreInfo *) NULL)
1380     resource_semaphore=AcquireSemaphoreInfo();
1381   LockSemaphoreInfo(resource_semaphore);
1382   value=(char *) NULL;
1383   switch (type)
1384   {
1385     case WidthResource:
1386     {
1387       resource_info.width_limit=limit;
1388       value=GetPolicyValue("resource:width");
1389       if (value != (char *) NULL)
1390         resource_info.width_limit=MagickMin(limit,StringToSizeType(value,
1391           100.0));
1392       break;
1393     }
1394     case HeightResource:
1395     {
1396       resource_info.height_limit=limit;
1397       value=GetPolicyValue("resource:height");
1398       if (value != (char *) NULL)
1399         resource_info.height_limit=MagickMin(limit,StringToSizeType(value,
1400           100.0));
1401       break;
1402     }
1403     case AreaResource:
1404     {
1405       resource_info.area_limit=limit;
1406       value=GetPolicyValue("resource:area");
1407       if (value != (char *) NULL)
1408         resource_info.area_limit=MagickMin(limit,StringToSizeType(value,100.0));
1409       break;
1410     }
1411     case MemoryResource:
1412     {
1413       resource_info.memory_limit=limit;
1414       value=GetPolicyValue("resource:memory");
1415       if (value != (char *) NULL)
1416         resource_info.memory_limit=MagickMin(limit,StringToSizeType(value,
1417           100.0));
1418       break;
1419     }
1420     case MapResource:
1421     {
1422       resource_info.map_limit=limit;
1423       value=GetPolicyValue("resource:map");
1424       if (value != (char *) NULL)
1425         resource_info.map_limit=MagickMin(limit,StringToSizeType(value,100.0));
1426       break;
1427     }
1428     case DiskResource:
1429     {
1430       resource_info.disk_limit=limit;
1431       value=GetPolicyValue("resource:disk");
1432       if (value != (char *) NULL)
1433         resource_info.disk_limit=MagickMin(limit,StringToSizeType(value,100.0));
1434       break;
1435     }
1436     case FileResource:
1437     {
1438       resource_info.file_limit=limit;
1439       value=GetPolicyValue("resource:file");
1440       if (value != (char *) NULL)
1441         resource_info.file_limit=MagickMin(limit,StringToSizeType(value,100.0));
1442       break;
1443     }
1444     case ThreadResource:
1445     {
1446       resource_info.thread_limit=limit;
1447       value=GetPolicyValue("resource:thread");
1448       if (value != (char *) NULL)
1449         resource_info.thread_limit=MagickMin(limit,StringToSizeType(value,
1450           100.0));
1451       if (resource_info.thread_limit > GetOpenMPMaximumThreads())
1452         resource_info.thread_limit=GetOpenMPMaximumThreads();
1453       else
1454         if (resource_info.thread_limit == 0)
1455           resource_info.thread_limit=1;
1456       break;
1457     }
1458     case ThrottleResource:
1459     {
1460       resource_info.throttle_limit=limit;
1461       value=GetPolicyValue("resource:throttle");
1462       if (value != (char *) NULL)
1463         resource_info.throttle_limit=MagickMax(limit,StringToSizeType(value,
1464           100.0));
1465       break;
1466     }
1467     case TimeResource:
1468     {
1469       resource_info.time_limit=limit;
1470       value=GetPolicyValue("resource:time");
1471       if (value != (char *) NULL)
1472         resource_info.time_limit=MagickMin(limit,StringToSizeType(value,100.0));
1473       ResetPixelCacheEpoch();
1474       break;
1475     }
1476     default:
1477       break;
1478   }
1479   if (value != (char *) NULL)
1480     value=DestroyString(value);
1481   UnlockSemaphoreInfo(resource_semaphore);
1482   return(MagickTrue);
1483 }