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