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