]> 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-2011 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/sizeof(PixelPacket),
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       resource_info.thread+=size;
237       limit=resource_info.thread_limit;
238       status=(resource_info.thread_limit == MagickResourceInfinity) ||
239         ((MagickSizeType) resource_info.thread < limit) ?
240         MagickTrue : MagickFalse;
241       (void) FormatMagickSize((MagickSizeType) resource_info.thread,MagickFalse,
242         resource_current);
243       (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
244         MagickFalse,resource_limit);
245       break;
246     }
247     case TimeResource:
248     {
249       resource_info.time+=size;
250       limit=resource_info.time_limit;
251       status=(resource_info.time_limit == MagickResourceInfinity) ||
252         ((MagickSizeType) resource_info.time < limit) ?
253         MagickTrue : MagickFalse;
254       (void) FormatMagickSize((MagickSizeType) resource_info.time,MagickFalse,
255         resource_current);
256       (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
257         MagickFalse,resource_limit);
258       break;
259     }
260     default:
261       break;
262   }
263   UnlockSemaphoreInfo(resource_semaphore);
264   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
265     CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
266     resource_request,resource_current,resource_limit);
267   return(status);
268 }
269 \f
270 /*
271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
272 %                                                                             %
273 %                                                                             %
274 %                                                                             %
275 +   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 %
276 %                                                                             %
277 %                                                                             %
278 %                                                                             %
279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280 %
281 %  AsynchronousResourceComponentTerminus() destroys the resource environment.
282 %  It differs from ResourceComponentTerminus() in that it can be called from a
283 %  asynchronous signal handler.
284 %
285 %  The format of the ResourceComponentTerminus() method is:
286 %
287 %      ResourceComponentTerminus(void)
288 %
289 */
290 MagickPrivate void AsynchronousResourceComponentTerminus(void)
291 {
292   const char
293     *path;
294
295   if (temporary_resources == (SplayTreeInfo *) NULL)
296     return;
297   /*
298     Remove any lingering temporary files.
299   */
300   ResetSplayTreeIterator(temporary_resources);
301   path=(const char *) GetNextKeyInSplayTree(temporary_resources);
302   while (path != (const char *) NULL)
303   {
304     (void) remove(path);
305     path=(const char *) GetNextKeyInSplayTree(temporary_resources);
306   }
307 }
308 \f
309 /*
310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
311 %                                                                             %
312 %                                                                             %
313 %                                                                             %
314 %   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                         %
315 %                                                                             %
316 %                                                                             %
317 %                                                                             %
318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319 %
320 %  AcquireUniqueFileResource() returns a unique file name, and returns a file
321 %  descriptor for the file open for reading and writing.
322 %
323 %  The format of the AcquireUniqueFileResource() method is:
324 %
325 %      int AcquireUniqueFileResource(char *path)
326 %
327 %  A description of each parameter follows:
328 %
329 %   o  path:  Specifies a pointer to an array of characters.  The unique path
330 %      name is returned in this array.
331 %
332 */
333
334 static void *DestroyTemporaryResources(void *temporary_resource)
335 {
336   (void) remove((char *) temporary_resource);
337   temporary_resource=DestroyString((char *) temporary_resource);
338   return((void *) NULL);
339 }
340
341 static MagickBooleanType GetPathTemplate(char *path)
342 {
343   char
344     *directory;
345
346   ExceptionInfo
347     *exception;
348
349   MagickBooleanType
350     status;
351
352   register char
353     *p;
354
355   struct stat
356     attributes;
357
358   (void) CopyMagickString(path,"magick-XXXXXXXX",MaxTextExtent);
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-15))
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-XXXXXXXX",directory);
400   else
401     (void) FormatLocaleString(path,MaxTextExtent,"%s%smagick-XXXXXXXX",
402       directory,DirectorySeparator);
403   directory=DestroyString(directory);
404   if (*DirectorySeparator != '/')
405     for (p=path; *p != '\0'; p++)
406       if (*p == *DirectorySeparator)
407         *p='/';
408   return(MagickTrue);
409 }
410
411 MagickExport int AcquireUniqueFileResource(char *path)
412 {
413 #if !defined(O_NOFOLLOW)
414 #define O_NOFOLLOW 0
415 #endif
416 #if !defined(TMP_MAX)
417 # define TMP_MAX  238328
418 #endif
419
420   int
421     c,
422     file;
423
424   register char
425     *p;
426
427   register ssize_t
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 < (ssize_t) TMP_MAX; i++)
446   {
447     /*
448       Get temporary pathname.
449     */
450     (void) GetPathTemplate(path);
451     key=GetRandomKey(random_info,2);
452     p=path+strlen(path)-8;
453     datum=GetStringInfoDatum(key);
454     for (i=0; i < (ssize_t) GetStringInfoLength(key); i++)
455     {
456       c=(int) (datum[i] & 0x3f);
457       *p++=portable_filename[c];
458     }
459     key=DestroyStringInfo(key);
460 #if defined(MAGICKCORE_HAVE_MKSTEMP)
461     file=mkstemp(path);
462 #if defined(__OS2__)
463     setmode(file,O_BINARY);
464 #endif
465     if (file != -1)
466       break;
467 #endif
468     key=GetRandomKey(random_info,6);
469     p=path+strlen(path)-6;
470     datum=GetStringInfoDatum(key);
471     for (i=0; i < (ssize_t) GetStringInfoLength(key); i++)
472     {
473       c=(int) (datum[i] & 0x3f);
474       *p++=portable_filename[c];
475     }
476     key=DestroyStringInfo(key);
477     file=open(path,O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_NOFOLLOW,S_MODE);
478     if ((file >= 0) || (errno != EEXIST))
479       break;
480   }
481   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
482   if (file == -1)
483     return(file);
484   if (resource_semaphore == (SemaphoreInfo *) NULL)
485     AcquireSemaphoreInfo(&resource_semaphore);
486   LockSemaphoreInfo(resource_semaphore);
487   if (temporary_resources == (SplayTreeInfo *) NULL)
488     temporary_resources=NewSplayTree(CompareSplayTreeString,
489       DestroyTemporaryResources,(void *(*)(void *)) NULL);
490   UnlockSemaphoreInfo(resource_semaphore);
491   (void) AddValueToSplayTree(temporary_resources,ConstantString(path),
492     (const void *) NULL);
493   return(file);
494 }
495 \f
496 /*
497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
498 %                                                                             %
499 %                                                                             %
500 %                                                                             %
501 %   G e t M a g i c k R e s o u r c e                                         %
502 %                                                                             %
503 %                                                                             %
504 %                                                                             %
505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
506 %
507 %  GetMagickResource() returns the specified resource.
508 %
509 %  The format of the GetMagickResource() method is:
510 %
511 %      MagickSizeType GetMagickResource(const ResourceType type)
512 %
513 %  A description of each parameter follows:
514 %
515 %    o type: the type of resource.
516 %
517 */
518 MagickExport MagickSizeType GetMagickResource(const ResourceType type)
519 {
520   MagickSizeType
521     resource;
522
523   resource=0;
524   LockSemaphoreInfo(resource_semaphore);
525   switch (type)
526   {
527     case AreaResource:
528     {
529       resource=(MagickSizeType) resource_info.area;
530       break;
531     }
532     case MemoryResource:
533     {
534       resource=(MagickSizeType) resource_info.memory;
535       break;
536     }
537     case MapResource:
538     {
539       resource=(MagickSizeType) resource_info.map;
540       break;
541     }
542     case DiskResource:
543     {
544       resource=(MagickSizeType) resource_info.disk;
545       break;
546     }
547     case FileResource:
548     {
549       resource=(MagickSizeType) resource_info.file;
550       break;
551     }
552     case ThreadResource:
553     {
554       resource=(MagickSizeType) resource_info.thread;
555       break;
556     }
557     case TimeResource:
558     {
559       resource=(MagickSizeType) resource_info.time;
560       break;
561     }
562     default:
563       break;
564   }
565   UnlockSemaphoreInfo(resource_semaphore);
566   return(resource);
567 }
568 \f
569 /*
570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
571 %                                                                             %
572 %                                                                             %
573 %                                                                             %
574 %   G e t M a g i c k R e s o u r c e L i m i t                               %
575 %                                                                             %
576 %                                                                             %
577 %                                                                             %
578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
579 %
580 %  GetMagickResourceLimit() returns the specified resource limit.
581 %
582 %  The format of the GetMagickResourceLimit() method is:
583 %
584 %      MagickSizeType GetMagickResourceLimit(const ResourceType type)
585 %
586 %  A description of each parameter follows:
587 %
588 %    o type: the type of resource.
589 %
590 */
591 MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
592 {
593   MagickSizeType
594     resource;
595
596   resource=0;
597   if (resource_semaphore == (SemaphoreInfo *) NULL)
598     AcquireSemaphoreInfo(&resource_semaphore);
599   LockSemaphoreInfo(resource_semaphore);
600   switch (type)
601   {
602     case AreaResource:
603     {
604       resource=resource_info.area_limit;
605       break;
606     }
607     case MemoryResource:
608     {
609       resource=resource_info.memory_limit;
610       break;
611     }
612     case MapResource:
613     {
614       resource=resource_info.map_limit;
615       break;
616     }
617     case DiskResource:
618     {
619       resource=resource_info.disk_limit;
620       break;
621     }
622     case FileResource:
623     {
624       resource=resource_info.file_limit;
625       break;
626     }
627     case ThreadResource:
628     {
629       resource=resource_info.thread_limit;
630       break;
631     }
632     case TimeResource:
633     {
634       resource=resource_info.time_limit;
635       break;
636     }
637     default:
638       break;
639   }
640   UnlockSemaphoreInfo(resource_semaphore);
641   return(resource);
642 }
643 \f
644 /*
645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
646 %                                                                             %
647 %                                                                             %
648 %                                                                             %
649 %  L i s t M a g i c k R e s o u r c e I n f o                                %
650 %                                                                             %
651 %                                                                             %
652 %                                                                             %
653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
654 %
655 %  ListMagickResourceInfo() lists the resource info to a file.
656 %
657 %  The format of the ListMagickResourceInfo method is:
658 %
659 %      MagickBooleanType ListMagickResourceInfo(FILE *file,
660 %        ExceptionInfo *exception)
661 %
662 %  A description of each parameter follows.
663 %
664 %    o file:  An pointer to a FILE.
665 %
666 %    o exception: return any errors or warnings in this structure.
667 %
668 */
669 MagickExport MagickBooleanType ListMagickResourceInfo(FILE *file,
670   ExceptionInfo *magick_unused(exception))
671 {
672   char
673     area_limit[MaxTextExtent],
674     disk_limit[MaxTextExtent],
675     map_limit[MaxTextExtent],
676     memory_limit[MaxTextExtent],
677     time_limit[MaxTextExtent];
678
679   if (file == (const FILE *) NULL)
680     file=stdout;
681   if (resource_semaphore == (SemaphoreInfo *) NULL)
682     AcquireSemaphoreInfo(&resource_semaphore);
683   LockSemaphoreInfo(resource_semaphore);
684   (void) FormatMagickSize(resource_info.area_limit,MagickFalse,area_limit);
685   (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,memory_limit);
686   (void) FormatMagickSize(resource_info.map_limit,MagickTrue,map_limit);
687   (void) CopyMagickString(disk_limit,"unlimited",MaxTextExtent);
688   if (resource_info.disk_limit != MagickResourceInfinity)
689     (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,disk_limit);
690   (void) CopyMagickString(time_limit,"unlimited",MaxTextExtent);
691   if (resource_info.time_limit != MagickResourceInfinity)
692     (void) FormatLocaleString(time_limit,MaxTextExtent,"%.20g",(double)
693       ((MagickOffsetType) resource_info.time_limit));
694   (void) FormatLocaleFile(file,"File         Area       Memory          Map"
695     "         Disk    Thread         Time\n");
696   (void) FormatLocaleFile(file,
697     "--------------------------------------------------------"
698     "-----------------------\n");
699   (void) FormatLocaleFile(file,"%4g   %10s   %10s   %10s   %10s    %6g  %11s\n",
700     (double) ((MagickOffsetType) resource_info.file_limit),area_limit,
701     memory_limit,map_limit,disk_limit,(double) ((MagickOffsetType)
702     resource_info.thread_limit),time_limit);
703   (void) fflush(file);
704   UnlockSemaphoreInfo(resource_semaphore);
705   return(MagickTrue);
706 }
707 \f
708 /*
709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
710 %                                                                             %
711 %                                                                             %
712 %                                                                             %
713 %   R e l i n q u i s h M a g i c k R e s o u r c e                           %
714 %                                                                             %
715 %                                                                             %
716 %                                                                             %
717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
718 %
719 %  RelinquishMagickResource() relinquishes resources of the specified type.
720 %
721 %  The format of the RelinquishMagickResource() method is:
722 %
723 %      void RelinquishMagickResource(const ResourceType type,
724 %        const MagickSizeType size)
725 %
726 %  A description of each parameter follows:
727 %
728 %    o type: the type of resource.
729 %
730 %    o size: the size of the resource.
731 %
732 */
733 MagickExport void RelinquishMagickResource(const ResourceType type,
734   const MagickSizeType size)
735 {
736   char
737     resource_current[MaxTextExtent],
738     resource_limit[MaxTextExtent],
739     resource_request[MaxTextExtent];
740
741   (void) FormatMagickSize(size,MagickFalse,resource_request);
742   if (resource_semaphore == (SemaphoreInfo *) NULL)
743     AcquireSemaphoreInfo(&resource_semaphore);
744   LockSemaphoreInfo(resource_semaphore);
745   switch (type)
746   {
747     case AreaResource:
748     {
749       resource_info.area=(MagickOffsetType) size;
750       (void) FormatMagickSize((MagickSizeType) resource_info.area,MagickFalse,
751         resource_current);
752       (void) FormatMagickSize(resource_info.area_limit,MagickFalse,
753         resource_limit);
754       break;
755     }
756     case MemoryResource:
757     {
758       resource_info.memory-=size;
759       (void) FormatMagickSize((MagickSizeType) resource_info.memory,
760         MagickTrue,resource_current);
761       (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,
762         resource_limit);
763       break;
764     }
765     case MapResource:
766     {
767       resource_info.map-=size;
768       (void) FormatMagickSize((MagickSizeType) resource_info.map,MagickTrue,
769         resource_current);
770       (void) FormatMagickSize(resource_info.map_limit,MagickTrue,
771         resource_limit);
772       break;
773     }
774     case DiskResource:
775     {
776       resource_info.disk-=size;
777       (void) FormatMagickSize((MagickSizeType) resource_info.disk,MagickTrue,
778         resource_current);
779       (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,
780         resource_limit);
781       break;
782     }
783     case FileResource:
784     {
785       resource_info.file-=size;
786       (void) FormatMagickSize((MagickSizeType) resource_info.file,MagickFalse,
787         resource_current);
788       (void) FormatMagickSize((MagickSizeType) resource_info.file_limit,
789         MagickFalse,resource_limit);
790       break;
791     }
792     case ThreadResource:
793     {
794       resource_info.thread-=size;
795       (void) FormatMagickSize((MagickSizeType) resource_info.thread,MagickFalse,
796         resource_current);
797       (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
798         MagickFalse,resource_limit);
799       break;
800     }
801     case TimeResource:
802     {
803       resource_info.time-=size;
804       (void) FormatMagickSize((MagickSizeType) resource_info.time,MagickFalse,
805         resource_current);
806       (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
807         MagickFalse,resource_limit);
808       break;
809     }
810     default:
811       break;
812   }
813   UnlockSemaphoreInfo(resource_semaphore);
814   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
815     CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
816       resource_request,resource_current,resource_limit);
817 }
818 \f
819 /*
820 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
821 %                                                                             %
822 %                                                                             %
823 %                                                                             %
824 %    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                  %
825 %                                                                             %
826 %                                                                             %
827 %                                                                             %
828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
829 %
830 %  RelinquishUniqueFileResource() relinquishes a unique file resource.
831 %
832 %  The format of the RelinquishUniqueFileResource() method is:
833 %
834 %      MagickBooleanType RelinquishUniqueFileResource(const char *path)
835 %
836 %  A description of each parameter follows:
837 %
838 %    o name: the name of the temporary resource.
839 %
840 */
841 MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
842 {
843   char
844     cache_path[MaxTextExtent];
845
846   assert(path != (const char *) NULL);
847   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
848   if (temporary_resources != (SplayTreeInfo *) NULL)
849     {
850       register char
851         *p;
852
853       ResetSplayTreeIterator(temporary_resources);
854       p=(char *) GetNextKeyInSplayTree(temporary_resources);
855       while (p != (char *) NULL)
856       {
857         if (LocaleCompare(p,path) == 0)
858           break;
859         p=(char *) GetNextKeyInSplayTree(temporary_resources);
860       }
861       if (p != (char *) NULL)
862         (void) DeleteNodeFromSplayTree(temporary_resources,p);
863     }
864   (void) CopyMagickString(cache_path,path,MaxTextExtent);
865   AppendImageFormat("cache",cache_path);
866   (void) remove(cache_path);
867   return(remove(path) == 0 ? MagickTrue : MagickFalse);
868 }
869 \f
870 /*
871 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
872 %                                                                             %
873 %                                                                             %
874 %                                                                             %
875 +   R e s o u r c e C o m p o n e n t G e n e s i s                           %
876 %                                                                             %
877 %                                                                             %
878 %                                                                             %
879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
880 %
881 %  ResourceComponentGenesis() instantiates the resource component.
882 %
883 %  The format of the ResourceComponentGenesis method is:
884 %
885 %      MagickBooleanType ResourceComponentGenesis(void)
886 %
887 */
888
889 static inline size_t MagickMax(const size_t x,const size_t y)
890 {
891   if (x > y)
892     return(x);
893   return(y);
894 }
895
896 static inline MagickSizeType StringToSizeType(const char *string,
897   const double interval)
898 {
899   double
900     value;
901
902   value=SiPrefixToDouble(string,interval);
903   if (value >= (double) MagickULLConstant(~0))
904     return(MagickULLConstant(~0));
905   return((MagickSizeType) value);
906 }
907
908 MagickPrivate MagickBooleanType ResourceComponentGenesis(void)
909 {
910   char
911     *limit;
912
913   MagickSizeType
914     memory;
915
916   ssize_t
917     files,
918     pages,
919     pagesize;
920
921   /*
922     Set Magick resource limits.
923   */
924   AcquireSemaphoreInfo(&resource_semaphore);
925   pagesize=GetMagickPageSize();
926   pages=(-1);
927 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
928   pages=(ssize_t) sysconf(_SC_PHYS_PAGES);
929 #endif
930   memory=(MagickSizeType) pages*pagesize;
931   if ((pagesize <= 0) || (pages <= 0))
932     memory=2048UL*1024UL*1024UL;
933 #if defined(PixelCacheThreshold)
934   memory=PixelCacheThreshold;
935 #endif
936   (void) SetMagickResourceLimit(AreaResource,2*memory/sizeof(PixelPacket));
937   (void) SetMagickResourceLimit(MemoryResource,memory);
938   (void) SetMagickResourceLimit(MapResource,2*memory);
939   limit=GetEnvironmentValue("MAGICK_AREA_LIMIT");
940   if (limit == (char *) NULL)
941     limit=GetPolicyValue("area");
942   if (limit != (char *) NULL)
943     {
944       (void) SetMagickResourceLimit(AreaResource,StringToSizeType(limit,100.0));
945       limit=DestroyString(limit);
946     }
947   limit=GetEnvironmentValue("MAGICK_MEMORY_LIMIT");
948   if (limit == (char *) NULL)
949     limit=GetPolicyValue("memory");
950   if (limit != (char *) NULL)
951     {
952       (void) SetMagickResourceLimit(MemoryResource,
953         StringToSizeType(limit,100.0));
954       limit=DestroyString(limit);
955     }
956   limit=GetEnvironmentValue("MAGICK_MAP_LIMIT");
957   if (limit == (char *) NULL)
958     limit=GetPolicyValue("map");
959   if (limit != (char *) NULL)
960     {
961       (void) SetMagickResourceLimit(MapResource,StringToSizeType(limit,100.0));
962       limit=DestroyString(limit);
963     }
964   limit=GetEnvironmentValue("MAGICK_DISK_LIMIT");
965   if (limit == (char *) NULL)
966     limit=GetPolicyValue("disk");
967   if (limit != (char *) NULL)
968     {
969       (void) SetMagickResourceLimit(DiskResource,StringToSizeType(limit,100.0));
970       limit=DestroyString(limit);
971     }
972   files=(-1);
973 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
974   files=(ssize_t) sysconf(_SC_OPEN_MAX);
975 #endif
976 #if defined(MAGICKCORE_HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
977   if (files < 0)
978     {
979       struct rlimit
980         resources;
981
982       if (getrlimit(RLIMIT_NOFILE,&resources) != -1)
983         files=(ssize_t) resources.rlim_cur;
984   }
985 #endif
986 #if defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
987   if (files < 0)
988     files=(ssize_t) getdtablesize();
989 #endif
990   if (files < 0)
991     files=64;
992   (void) SetMagickResourceLimit(FileResource,MagickMax((size_t)
993     (3*files/4),64));
994   limit=GetEnvironmentValue("MAGICK_FILE_LIMIT");
995   if (limit == (char *) NULL)
996     limit=GetPolicyValue("file");
997   if (limit != (char *) NULL)
998     {
999       (void) SetMagickResourceLimit(FileResource,StringToSizeType(limit,100.0));
1000       limit=DestroyString(limit);
1001     }
1002   (void) SetMagickResourceLimit(ThreadResource,GetOpenMPMaximumThreads());
1003   limit=GetEnvironmentValue("MAGICK_THREAD_LIMIT");
1004   if (limit == (char *) NULL)
1005     limit=GetPolicyValue("thread");
1006   if (limit != (char *) NULL)
1007     {
1008       (void) SetMagickResourceLimit(ThreadResource,StringToSizeType(limit,
1009         100.0));
1010       limit=DestroyString(limit);
1011     }
1012   limit=GetEnvironmentValue("MAGICK_TIME_LIMIT");
1013   if (limit == (char *) NULL)
1014     limit=GetPolicyValue("time");
1015   if (limit != (char *) NULL)
1016     {
1017       (void) SetMagickResourceLimit(TimeResource,StringToSizeType(limit,100.0));
1018       limit=DestroyString(limit);
1019     }
1020   return(MagickTrue);
1021 }
1022 \f
1023 /*
1024 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1025 %                                                                             %
1026 %                                                                             %
1027 %                                                                             %
1028 +   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                         %
1029 %                                                                             %
1030 %                                                                             %
1031 %                                                                             %
1032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1033 %
1034 %  ResourceComponentTerminus() destroys the resource component.
1035 %
1036 %  The format of the ResourceComponentTerminus() method is:
1037 %
1038 %      ResourceComponentTerminus(void)
1039 %
1040 */
1041 MagickPrivate void ResourceComponentTerminus(void)
1042 {
1043   if (resource_semaphore == (SemaphoreInfo *) NULL)
1044     AcquireSemaphoreInfo(&resource_semaphore);
1045   LockSemaphoreInfo(resource_semaphore);
1046   if (temporary_resources != (SplayTreeInfo *) NULL)
1047     temporary_resources=DestroySplayTree(temporary_resources);
1048   if (random_info != (RandomInfo *) NULL)
1049     random_info=DestroyRandomInfo(random_info);
1050   UnlockSemaphoreInfo(resource_semaphore);
1051   DestroySemaphoreInfo(&resource_semaphore);
1052 }
1053 \f
1054 /*
1055 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1056 %                                                                             %
1057 %                                                                             %
1058 %                                                                             %
1059 %   S e t M a g i c k R e s o u r c e L i m i t                               %
1060 %                                                                             %
1061 %                                                                             %
1062 %                                                                             %
1063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1064 %
1065 %  SetMagickResourceLimit() sets the limit for a particular resource.
1066 %
1067 %  The format of the SetMagickResourceLimit() method is:
1068 %
1069 %      MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1070 %        const MagickSizeType limit)
1071 %
1072 %  A description of each parameter follows:
1073 %
1074 %    o type: the type of resource.
1075 %
1076 %    o limit: the maximum limit for the resource.
1077 %
1078 */
1079
1080 static inline MagickSizeType MagickMin(const MagickSizeType x,
1081   const MagickSizeType y)
1082 {
1083   if (x < y)
1084     return(x);
1085   return(y);
1086 }
1087
1088 MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1089   const MagickSizeType limit)
1090 {
1091   char
1092     *value;
1093
1094   if (resource_semaphore == (SemaphoreInfo *) NULL)
1095     AcquireSemaphoreInfo(&resource_semaphore);
1096   LockSemaphoreInfo(resource_semaphore);
1097   value=(char *) NULL;
1098   switch (type)
1099   {
1100     case AreaResource:
1101     {
1102       resource_info.area_limit=limit;
1103       value=GetPolicyValue("area");
1104       if (value != (char *) NULL)
1105         resource_info.area_limit=MagickMin(limit,StringToSizeType(value,100.0));
1106       break;
1107     }
1108     case MemoryResource:
1109     {
1110       resource_info.memory_limit=limit;
1111       value=GetPolicyValue("memory");
1112       if (value != (char *) NULL)
1113         resource_info.memory_limit=MagickMin(limit,StringToSizeType(value,
1114           100.0));
1115       break;
1116     }
1117     case MapResource:
1118     {
1119       resource_info.map_limit=limit;
1120       value=GetPolicyValue("map");
1121       if (value != (char *) NULL)
1122         resource_info.map_limit=MagickMin(limit,StringToSizeType(value,100.0));
1123       break;
1124     }
1125     case DiskResource:
1126     {
1127       resource_info.disk_limit=limit;
1128       value=GetPolicyValue("disk");
1129       if (value != (char *) NULL)
1130         resource_info.disk_limit=MagickMin(limit,StringToSizeType(value,100.0));
1131       break;
1132     }
1133     case FileResource:
1134     {
1135       resource_info.file_limit=limit;
1136       value=GetPolicyValue("file");
1137       if (value != (char *) NULL)
1138         resource_info.file_limit=MagickMin(limit,StringToSizeType(value,100.0));
1139       break;
1140     }
1141     case ThreadResource:
1142     {
1143       resource_info.thread_limit=limit;
1144       value=GetPolicyValue("thread");
1145       if (value != (char *) NULL)
1146         resource_info.thread_limit=MagickMin(limit,StringToSizeType(value,
1147           100.0));
1148       SetOpenMPMaximumThreads((int) resource_info.thread_limit);
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 }