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