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