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