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