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