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