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