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