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