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