]> granicus.if.org Git - imagemagick/blob - magick/resource.c
39eb8f16af132c5b99182d0ee013aca1575b530f
[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,(long) type),resource_request,
264     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   return((void *) NULL);
336 }
337
338 static MagickBooleanType GetPathTemplate(char *path)
339 {
340   char
341     *directory;
342
343   ExceptionInfo
344     *exception;
345
346   MagickBooleanType
347     status;
348
349   register char
350     *p;
351
352   struct stat
353     attributes;
354
355   (void) CopyMagickString(path,"magick-XXXXXXXX",MaxTextExtent);
356   exception=AcquireExceptionInfo();
357   directory=(char *) GetImageRegistry(StringRegistryType,"temporary-path",
358     exception);
359   exception=DestroyExceptionInfo(exception);
360   if (directory == (char *) NULL)
361     directory=GetEnvironmentValue("MAGICK_TEMPORARY_PATH");
362   if (directory == (char *) NULL)
363     directory=GetEnvironmentValue("MAGICK_TMPDIR");
364   if (directory == (char *) NULL)
365     directory=GetPolicyValue("temporary-path");
366   if (directory == (char *) NULL)
367     directory=GetEnvironmentValue("TMPDIR");
368 #if defined(__WINDOWS__) || defined(__OS2__)
369   if (directory == (char *) NULL)
370     directory=GetEnvironmentValue("TMP");
371   if (directory == (char *) NULL)
372     directory=GetEnvironmentValue("TEMP");
373 #endif
374 #if defined(__VMS)
375   if (directory == (char *) NULL)
376     directory=GetEnvironmentValue("MTMPDIR");
377 #endif
378 #if defined(P_tmpdir)
379   if (directory == (char *) NULL)
380     directory=ConstantString(P_tmpdir);
381 #endif
382   if (directory == (char *) NULL)
383     return(MagickTrue);
384   if (strlen(directory) > (MaxTextExtent-15))
385     {
386       directory=DestroyString(directory);
387       return(MagickTrue);
388     }
389   status=GetPathAttributes(directory,&attributes);
390   if ((status == MagickFalse) || !S_ISDIR(attributes.st_mode))
391     {
392       directory=DestroyString(directory);
393       return(MagickTrue);
394     }
395   if (directory[strlen(directory)-1] == *DirectorySeparator)
396     (void) FormatMagickString(path,MaxTextExtent,"%smagick-XXXXXXXX",directory);
397   else
398     (void) FormatMagickString(path,MaxTextExtent,"%s%smagick-XXXXXXXX",
399       directory,DirectorySeparator);
400   directory=DestroyString(directory);
401   if (*DirectorySeparator != '/')
402     for (p=path; *p != '\0'; p++)
403       if (*p == *DirectorySeparator)
404         *p='/';
405   return(MagickTrue);
406 }
407
408 MagickExport int AcquireUniqueFileResource(char *path)
409 {
410 #if !defined(O_NOFOLLOW)
411 #define O_NOFOLLOW 0
412 #endif
413 #if !defined(TMP_MAX)
414 # define TMP_MAX  238328
415 #endif
416
417   char
418     *resource;
419
420   int
421     c,
422     file;
423
424   register char
425     *p;
426
427   register long
428     i;
429
430   static const char
431     portable_filename[65] =
432       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
433
434   StringInfo
435     *key;
436
437   unsigned char
438     *datum;
439
440   assert(path != (char *) NULL);
441   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
442   if (random_info == (RandomInfo *) NULL)
443     random_info=AcquireRandomInfo();
444   file=(-1);
445   for (i=0; i < TMP_MAX; i++)
446   {
447     /*
448       Get temporary pathname.
449     */
450     (void) GetPathTemplate(path);
451 #if defined(MAGICKCORE_HAVE_MKSTEMP)
452     file=mkstemp(path);
453 #if defined(__OS2__)
454     setmode(file,O_BINARY);
455 #endif
456     if (file != -1)
457       break;
458 #endif
459     key=GetRandomKey(random_info,8);
460     p=path+strlen(path)-8;
461     datum=GetStringInfoDatum(key);
462     for (i=0; i < 8; i++)
463     {
464       c=(int) (datum[i] & 0x3f);
465       *p++=portable_filename[c];
466     }
467     key=DestroyStringInfo(key);
468     file=open(path,O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_NOFOLLOW,S_MODE);
469     if ((file > 0) || (errno != EEXIST))
470       break;
471   }
472   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
473   if (file == -1)
474     return(file);
475   if (resource_semaphore == (SemaphoreInfo *) NULL)
476     AcquireSemaphoreInfo(&resource_semaphore);
477   LockSemaphoreInfo(resource_semaphore);
478   if (temporary_resources == (SplayTreeInfo *) NULL)
479     temporary_resources=NewSplayTree(CompareSplayTreeString,
480       RelinquishMagickMemory,DestroyTemporaryResources);
481   UnlockSemaphoreInfo(resource_semaphore);
482   resource=ConstantString(path);
483   (void) AddValueToSplayTree(temporary_resources,resource,resource);
484   return(file);
485 }
486 \f
487 /*
488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
489 %                                                                             %
490 %                                                                             %
491 %                                                                             %
492 %   G e t M a g i c k R e s o u r c e                                         %
493 %                                                                             %
494 %                                                                             %
495 %                                                                             %
496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
497 %
498 %  GetMagickResource() returns the specified resource.
499 %
500 %  The format of the GetMagickResource() method is:
501 %
502 %      MagickSizeType GetMagickResource(const ResourceType type)
503 %
504 %  A description of each parameter follows:
505 %
506 %    o type: the type of resource.
507 %
508 */
509 MagickExport MagickSizeType GetMagickResource(const ResourceType type)
510 {
511   MagickSizeType
512     resource;
513
514   resource=0;
515   LockSemaphoreInfo(resource_semaphore);
516   switch (type)
517   {
518     case AreaResource:
519     {
520       resource=(MagickSizeType) resource_info.area;
521       break;
522     }
523     case MemoryResource:
524     {
525       resource=(MagickSizeType) resource_info.memory;
526       break;
527     }
528     case MapResource:
529     {
530       resource=(MagickSizeType) resource_info.map;
531       break;
532     }
533     case DiskResource:
534     {
535       resource=(MagickSizeType) resource_info.disk;
536       break;
537     }
538     case FileResource:
539     {
540       resource=(MagickSizeType) resource_info.file;
541       break;
542     }
543     case ThreadResource:
544     {
545       resource=(MagickSizeType) resource_info.thread;
546       break;
547     }
548     case TimeResource:
549     {
550       resource=(MagickSizeType) resource_info.time;
551       break;
552     }
553     default:
554       break;
555   }
556   UnlockSemaphoreInfo(resource_semaphore);
557   return(resource);
558 }
559 \f
560 /*
561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
562 %                                                                             %
563 %                                                                             %
564 %                                                                             %
565 %   G e t M a g i c k R e s o u r c e L i m i t                               %
566 %                                                                             %
567 %                                                                             %
568 %                                                                             %
569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
570 %
571 %  GetMagickResource() returns the specified resource limit.
572 %
573 %  The format of the GetMagickResourceLimit() method is:
574 %
575 %      MagickSizeType GetMagickResourceLimit(const ResourceType type)
576 %
577 %  A description of each parameter follows:
578 %
579 %    o type: the type of resource.
580 %
581 */
582 MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
583 {
584   MagickSizeType
585     resource;
586
587   resource=0;
588   if (resource_semaphore == (SemaphoreInfo *) NULL)
589     AcquireSemaphoreInfo(&resource_semaphore);
590   LockSemaphoreInfo(resource_semaphore);
591   switch (type)
592   {
593     case AreaResource:
594     {
595       resource=resource_info.area_limit;
596       break;
597     }
598     case MemoryResource:
599     {
600       resource=resource_info.memory_limit;
601       break;
602     }
603     case MapResource:
604     {
605       resource=resource_info.map_limit;
606       break;
607     }
608     case DiskResource:
609     {
610       resource=resource_info.disk_limit;
611       break;
612     }
613     case FileResource:
614     {
615       resource=resource_info.file_limit;
616       break;
617     }
618     case ThreadResource:
619     {
620       resource=resource_info.thread_limit;
621       break;
622     }
623     case TimeResource:
624     {
625       resource=resource_info.time_limit;
626       break;
627     }
628     default:
629       break;
630   }
631   UnlockSemaphoreInfo(resource_semaphore);
632   return(resource);
633 }
634 \f
635 /*
636 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
637 %                                                                             %
638 %                                                                             %
639 %                                                                             %
640 %  L i s t M a g i c k R e s o u r c e I n f o                                %
641 %                                                                             %
642 %                                                                             %
643 %                                                                             %
644 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
645 %
646 %  ListMagickResourceInfo() lists the resource info to a file.
647 %
648 %  The format of the ListMagickResourceInfo method is:
649 %
650 %      MagickBooleanType ListMagickResourceInfo(FILE *file,
651 %        ExceptionInfo *exception)
652 %
653 %  A description of each parameter follows.
654 %
655 %    o file:  An pointer to a FILE.
656 %
657 %    o exception: return any errors or warnings in this structure.
658 %
659 */
660 MagickExport MagickBooleanType ListMagickResourceInfo(FILE *file,
661   ExceptionInfo *magick_unused(exception))
662 {
663   char
664     area_limit[MaxTextExtent],
665     disk_limit[MaxTextExtent],
666     map_limit[MaxTextExtent],
667     memory_limit[MaxTextExtent],
668     time_limit[MaxTextExtent];
669
670   if (file == (const FILE *) NULL)
671     file=stdout;
672   if (resource_semaphore == (SemaphoreInfo *) NULL)
673     AcquireSemaphoreInfo(&resource_semaphore);
674   LockSemaphoreInfo(resource_semaphore);
675   (void) FormatMagickSize(resource_info.area_limit,MagickFalse,area_limit);
676   (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,memory_limit);
677   (void) FormatMagickSize(resource_info.map_limit,MagickTrue,map_limit);
678   (void) FormatMagickSize(resource_info.disk_limit,MagickFalse,disk_limit);
679   (void) CopyMagickString(time_limit,"unlimited",MaxTextExtent);
680   if (resource_info.time_limit != MagickResourceInfinity)
681     (void) FormatMagickString(time_limit,MaxTextExtent,"%lu",(unsigned long)
682       resource_info.time_limit);
683   (void) fprintf(file,"File         Area       Memory          Map"
684     "         Disk    Thread         Time\n");
685   (void) fprintf(file,"--------------------------------------------------------"
686     "-----------------------\n");
687   (void) fprintf(file,"%4lu  %10sB  %10sB  %10sB  %10sB    %6lu  %11s\n",
688     (unsigned long) resource_info.file_limit,area_limit,memory_limit,map_limit,
689     disk_limit,(unsigned long) resource_info.thread_limit,time_limit);
690   (void) fflush(file);
691   UnlockSemaphoreInfo(resource_semaphore);
692   return(MagickTrue);
693 }
694 \f
695 /*
696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
697 %                                                                             %
698 %                                                                             %
699 %                                                                             %
700 %   R e l i n q u i s h M a g i c k R e s o u r c e                           %
701 %                                                                             %
702 %                                                                             %
703 %                                                                             %
704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
705 %
706 %  RelinquishMagickResource() relinquishes resources of the specified type.
707 %
708 %  The format of the RelinquishMagickResource() method is:
709 %
710 %      void RelinquishMagickResource(const ResourceType type,
711 %        const MagickSizeType size)
712 %
713 %  A description of each parameter follows:
714 %
715 %    o type: the type of resource.
716 %
717 %    o size: the size of the resource.
718 %
719 */
720 MagickExport void RelinquishMagickResource(const ResourceType type,
721   const MagickSizeType size)
722 {
723   char
724     resource_current[MaxTextExtent],
725     resource_limit[MaxTextExtent],
726     resource_request[MaxTextExtent];
727
728   (void) FormatMagickSize(size,MagickFalse,resource_request);
729   if (resource_semaphore == (SemaphoreInfo *) NULL)
730     AcquireSemaphoreInfo(&resource_semaphore);
731   LockSemaphoreInfo(resource_semaphore);
732   switch (type)
733   {
734     case AreaResource:
735     {
736       resource_info.area=(MagickOffsetType) size;
737       (void) FormatMagickSize((MagickSizeType) resource_info.area,MagickFalse,
738         resource_current);
739       (void) FormatMagickSize(resource_info.area_limit,MagickFalse,
740         resource_limit);
741       break;
742     }
743     case MemoryResource:
744     {
745       resource_info.memory-=size;
746       (void) FormatMagickSize((MagickSizeType) resource_info.memory,
747         MagickTrue,resource_current);
748       (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,
749         resource_limit);
750       break;
751     }
752     case MapResource:
753     {
754       resource_info.map-=size;
755       (void) FormatMagickSize((MagickSizeType) resource_info.map,MagickTrue,
756         resource_current);
757       (void) FormatMagickSize(resource_info.map_limit,MagickTrue,
758         resource_limit);
759       break;
760     }
761     case DiskResource:
762     {
763       resource_info.disk-=size;
764       (void) FormatMagickSize((MagickSizeType) resource_info.disk,MagickFalse,
765         resource_current);
766       (void) FormatMagickSize(resource_info.disk_limit,MagickFalse,
767         resource_limit);
768       break;
769     }
770     case FileResource:
771     {
772       resource_info.file-=size;
773       (void) FormatMagickSize((MagickSizeType) resource_info.file,MagickFalse,
774         resource_current);
775       (void) FormatMagickSize((MagickSizeType) resource_info.file_limit,
776         MagickFalse,resource_limit);
777       break;
778     }
779     case ThreadResource:
780     {
781       resource_info.thread-=size;
782       (void) FormatMagickSize((MagickSizeType) resource_info.thread,MagickFalse,
783         resource_current);
784       (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
785         MagickFalse,resource_limit);
786       break;
787     }
788     case TimeResource:
789     {
790       resource_info.time-=size;
791       (void) FormatMagickSize((MagickSizeType) resource_info.time,MagickFalse,
792         resource_current);
793       (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
794         MagickFalse,resource_limit);
795       break;
796     }
797     default:
798       break;
799   }
800   UnlockSemaphoreInfo(resource_semaphore);
801   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %sB/%sB/%sB",
802     MagickOptionToMnemonic(MagickResourceOptions,(long) type),resource_request,
803     resource_current,resource_limit);
804 }
805 \f
806 /*
807 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
808 %                                                                             %
809 %                                                                             %
810 %                                                                             %
811 %    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                  %
812 %                                                                             %
813 %                                                                             %
814 %                                                                             %
815 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
816 %
817 %  RelinquishUniqueFileResource() relinquishes a unique file resource.
818 %
819 %  The format of the RelinquishUniqueFileResource() method is:
820 %
821 %      MagickBooleanType RelinquishUniqueFileResource(const char *path)
822 %
823 %  A description of each parameter follows:
824 %
825 %    o name: the name of the temporary resource.
826 %
827 */
828 MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
829 {
830   char
831     cache_path[MaxTextExtent];
832
833   assert(path != (const char *) NULL);
834   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
835   if (temporary_resources != (SplayTreeInfo *) NULL)
836     {
837       register char
838         *p;
839
840       ResetSplayTreeIterator(temporary_resources);
841       p=(char *) GetNextKeyInSplayTree(temporary_resources);
842       while (p != (char *) NULL)
843       {
844         if (LocaleCompare(p,path) == 0)
845           break;
846         p=(char *) GetNextKeyInSplayTree(temporary_resources);
847       }
848       if (p != (char *) NULL)
849         (void) DeleteNodeFromSplayTree(temporary_resources,p);
850     }
851   (void) CopyMagickString(cache_path,path,MaxTextExtent);
852   AppendImageFormat("cache",cache_path);
853   (void) remove(cache_path);
854   return(remove(path) == 0 ? MagickTrue : MagickFalse);
855 }
856 \f
857 /*
858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
859 %                                                                             %
860 %                                                                             %
861 %                                                                             %
862 +   R e s o u r c e C o m p o n e n t G e n e s i s                           %
863 %                                                                             %
864 %                                                                             %
865 %                                                                             %
866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867 %
868 %  ResourceComponentGenesis() instantiates the resource component.
869 %
870 %  The format of the ResourceComponentGenesis method is:
871 %
872 %      MagickBooleanType ResourceComponentGenesis(void)
873 %
874 */
875
876 static inline unsigned long MagickMax(const unsigned long x,
877   const unsigned long y)
878 {
879   if (x > y)
880     return(x);
881   return(y);
882 }
883
884 static inline MagickSizeType StringToSizeType(const char *string,
885   const double interval)
886 {
887   double
888     value;
889
890   value=SiPrefixToDouble(string,interval);
891   if (value >= (double) MagickULLConstant(~0))
892     return(MagickULLConstant(~0));
893   return((MagickSizeType) value);
894 }
895
896 MagickExport MagickBooleanType ResourceComponentGenesis(void)
897 {
898   char
899     *limit;
900
901   long
902     files,
903     pages,
904     pagesize;
905
906   MagickSizeType
907     memory;
908
909   /*
910     Set Magick resource limits.
911   */
912   AcquireSemaphoreInfo(&resource_semaphore);
913   pagesize=GetMagickPageSize();
914   pages=(-1);
915 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
916   pages=sysconf(_SC_PHYS_PAGES);
917 #endif
918   memory=(MagickSizeType) pages*pagesize;
919   if ((pagesize <= 0) || (pages <= 0))
920     memory=2048UL*1024UL*1024UL;
921 #if defined(PixelCacheThreshold)
922   memory=PixelCacheThreshold;
923 #endif
924   (void) SetMagickResourceLimit(AreaResource,2UL*memory);
925   (void) SetMagickResourceLimit(MemoryResource,3UL*memory/2UL);
926   (void) SetMagickResourceLimit(MapResource,4UL*memory);
927   limit=GetEnvironmentValue("MAGICK_AREA_LIMIT");
928   if (limit == (char *) NULL)
929     limit=GetPolicyValue("area");
930   if (limit != (char *) NULL)
931     {
932       (void) SetMagickResourceLimit(AreaResource,StringToSizeType(limit,100.0));
933       limit=DestroyString(limit);
934     }
935   limit=GetEnvironmentValue("MAGICK_MEMORY_LIMIT");
936   if (limit == (char *) NULL)
937     limit=GetPolicyValue("memory");
938   if (limit != (char *) NULL)
939     {
940       (void) SetMagickResourceLimit(MemoryResource,
941         StringToSizeType(limit,100.0));
942       limit=DestroyString(limit);
943     }
944   limit=GetEnvironmentValue("MAGICK_MAP_LIMIT");
945   if (limit == (char *) NULL)
946     limit=GetPolicyValue("map");
947   if (limit != (char *) NULL)
948     {
949       (void) SetMagickResourceLimit(MapResource,StringToSizeType(limit,100.0));
950       limit=DestroyString(limit);
951     }
952   limit=GetEnvironmentValue("MAGICK_DISK_LIMIT");
953   if (limit == (char *) NULL)
954     limit=GetPolicyValue("disk");
955   if (limit != (char *) NULL)
956     {
957       (void) SetMagickResourceLimit(DiskResource,StringToSizeType(limit,100.0));
958       limit=DestroyString(limit);
959     }
960   files=(-1);
961 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
962   files=sysconf(_SC_OPEN_MAX);
963 #endif
964 #if defined(MAGICKCORE_HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
965   if (files < 0)
966     {
967       struct rlimit
968         resources;
969
970       if (getrlimit(RLIMIT_NOFILE,&resources) != -1)
971         files=(long) resources.rlim_cur;
972   }
973 #endif
974 #if defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
975   if (files < 0)
976     files=getdtablesize();
977 #endif
978   if (files < 0)
979     files=64;
980   (void) SetMagickResourceLimit(FileResource,MagickMax((unsigned long)
981     (3*files/4),64));
982   limit=GetEnvironmentValue("MAGICK_FILE_LIMIT");
983   if (limit == (char *) NULL)
984     limit=GetPolicyValue("file");
985   if (limit != (char *) NULL)
986     {
987       (void) SetMagickResourceLimit(FileResource,StringToSizeType(limit,100.0));
988       limit=DestroyString(limit);
989     }
990   (void) SetMagickResourceLimit(ThreadResource,GetOpenMPMaximumThreads());
991   limit=GetEnvironmentValue("MAGICK_THREAD_LIMIT");
992   if (limit == (char *) NULL)
993     limit=GetPolicyValue("thread");
994   if (limit != (char *) NULL)
995     {
996       SetOpenMPMaximumThreads(StringToUnsignedLong(limit));
997       (void) SetMagickResourceLimit(ThreadResource,StringToSizeType(limit,
998         100.0));
999       limit=DestroyString(limit);
1000     }
1001   limit=GetEnvironmentValue("MAGICK_TIME_LIMIT");
1002   if (limit == (char *) NULL)
1003     limit=GetPolicyValue("time");
1004   if (limit != (char *) NULL)
1005     {
1006       (void) SetMagickResourceLimit(TimeResource,StringToSizeType(limit,100.0));
1007       limit=DestroyString(limit);
1008     }
1009   return(MagickTrue);
1010 }
1011 \f
1012 /*
1013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1014 %                                                                             %
1015 %                                                                             %
1016 %                                                                             %
1017 +   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                         %
1018 %                                                                             %
1019 %                                                                             %
1020 %                                                                             %
1021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1022 %
1023 %  ResourceComponentTerminus() destroys the resource component.
1024 %
1025 %  The format of the ResourceComponentTerminus() method is:
1026 %
1027 %      ResourceComponentTerminus(void)
1028 %
1029 */
1030 MagickExport void ResourceComponentTerminus(void)
1031 {
1032   if (resource_semaphore == (SemaphoreInfo *) NULL)
1033     AcquireSemaphoreInfo(&resource_semaphore);
1034   LockSemaphoreInfo(resource_semaphore);
1035   if (temporary_resources != (SplayTreeInfo *) NULL)
1036     temporary_resources=DestroySplayTree(temporary_resources);
1037   if (random_info != (RandomInfo *) NULL)
1038     random_info=DestroyRandomInfo(random_info);
1039   UnlockSemaphoreInfo(resource_semaphore);
1040   DestroySemaphoreInfo(&resource_semaphore);
1041 }
1042 \f
1043 /*
1044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1045 %                                                                             %
1046 %                                                                             %
1047 %                                                                             %
1048 %   S e t M a g i c k R e s o u r c e L i m i t                               %
1049 %                                                                             %
1050 %                                                                             %
1051 %                                                                             %
1052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053 %
1054 %  SetMagickResourceLimit() sets the limit for a particular resource.
1055 %
1056 %  The format of the SetMagickResourceLimit() method is:
1057 %
1058 %      MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1059 %        const MagickSizeType limit)
1060 %
1061 %  A description of each parameter follows:
1062 %
1063 %    o type: the type of resource.
1064 %
1065 %    o limit: the maximum limit for the resource.
1066 %
1067 */
1068 MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1069   const MagickSizeType limit)
1070 {
1071   if (resource_semaphore == (SemaphoreInfo *) NULL)
1072     AcquireSemaphoreInfo(&resource_semaphore);
1073   LockSemaphoreInfo(resource_semaphore);
1074   switch (type)
1075   {
1076     case AreaResource:
1077     {
1078       resource_info.area_limit=limit;
1079       break;
1080     }
1081     case MemoryResource:
1082     {
1083       resource_info.memory_limit=limit;
1084       break;
1085     }
1086     case MapResource:
1087     {
1088       resource_info.map_limit=limit;
1089       break;
1090     }
1091     case DiskResource:
1092     {
1093       resource_info.disk_limit=limit;
1094       break;
1095     }
1096     case FileResource:
1097     {
1098       resource_info.file_limit=limit;
1099       break;
1100     }
1101     case ThreadResource:
1102     {
1103       SetOpenMPMaximumThreads((unsigned long) limit);
1104       resource_info.thread_limit=GetOpenMPMaximumThreads();
1105       break;
1106     }
1107     case TimeResource:
1108     {
1109       resource_info.time_limit=limit;
1110       break;
1111     }
1112     default:
1113       break;
1114   }
1115   UnlockSemaphoreInfo(resource_semaphore);
1116   return(MagickTrue);
1117 }