]> granicus.if.org Git - imagemagick/blob - MagickCore/resource.c
Thread limit should be at least 1.
[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-2015 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 (resource_semaphore == (SemaphoreInfo *) NULL)
895     ActivateSemaphoreInfo(&resource_semaphore);
896   LockSemaphoreInfo(resource_semaphore);
897   if (temporary_resources != (SplayTreeInfo *) NULL)
898     (void) DeleteNodeFromSplayTree(temporary_resources, (const void *) path);
899   UnlockSemaphoreInfo(resource_semaphore);
900   (void) CopyMagickString(cache_path,path,MaxTextExtent);
901   AppendImageFormat("cache",cache_path);
902   (void) ShredFile(cache_path);
903   return(ShredFile(path));
904 }
905 \f
906 /*
907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
908 %                                                                             %
909 %                                                                             %
910 %                                                                             %
911 +   R e s o u r c e C o m p o n e n t G e n e s i s                           %
912 %                                                                             %
913 %                                                                             %
914 %                                                                             %
915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
916 %
917 %  ResourceComponentGenesis() instantiates the resource component.
918 %
919 %  The format of the ResourceComponentGenesis method is:
920 %
921 %      MagickBooleanType ResourceComponentGenesis(void)
922 %
923 */
924
925 static inline size_t MagickMax(const size_t x,const size_t y)
926 {
927   if (x > y)
928     return(x);
929   return(y);
930 }
931
932 static inline MagickSizeType StringToSizeType(const char *string,
933   const double interval)
934 {
935   double
936     value;
937
938   value=SiPrefixToDoubleInterval(string,interval);
939   if (value >= (double) MagickULLConstant(~0))
940     return(MagickULLConstant(~0));
941   return((MagickSizeType) value);
942 }
943
944 MagickPrivate MagickBooleanType ResourceComponentGenesis(void)
945 {
946   char
947     *limit;
948
949   MagickSizeType
950     memory;
951
952   ssize_t
953     files,
954     pages,
955     pagesize;
956
957   /*
958     Set Magick resource limits.
959   */
960   if (resource_semaphore == (SemaphoreInfo *) NULL)
961     resource_semaphore=AcquireSemaphoreInfo();
962   pagesize=GetMagickPageSize();
963   pages=(-1);
964 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
965   pages=(ssize_t) sysconf(_SC_PHYS_PAGES);
966 #endif
967   memory=(MagickSizeType) pages*pagesize;
968   if ((pagesize <= 0) || (pages <= 0))
969     memory=2048UL*1024UL*1024UL;
970 #if defined(PixelCacheThreshold)
971   memory=PixelCacheThreshold;
972 #endif
973   (void) SetMagickResourceLimit(AreaResource,2*memory);
974   limit=GetEnvironmentValue("MAGICK_AREA_LIMIT");
975   if (limit != (char *) NULL)
976     {
977       (void) SetMagickResourceLimit(AreaResource,StringToSizeType(limit,100.0));
978       limit=DestroyString(limit);
979     }
980   (void) SetMagickResourceLimit(MemoryResource,memory);
981   limit=GetEnvironmentValue("MAGICK_MEMORY_LIMIT");
982   if (limit != (char *) NULL)
983     {
984       (void) SetMagickResourceLimit(MemoryResource,
985         StringToSizeType(limit,100.0));
986       limit=DestroyString(limit);
987     }
988   (void) SetMagickResourceLimit(MapResource,2*memory);
989   limit=GetEnvironmentValue("MAGICK_MAP_LIMIT");
990   if (limit != (char *) NULL)
991     {
992       (void) SetMagickResourceLimit(MapResource,StringToSizeType(limit,100.0));
993       limit=DestroyString(limit);
994     }
995   (void) SetMagickResourceLimit(DiskResource,MagickResourceInfinity);
996   limit=GetEnvironmentValue("MAGICK_DISK_LIMIT");
997   if (limit != (char *) NULL)
998     {
999       (void) SetMagickResourceLimit(DiskResource,StringToSizeType(limit,100.0));
1000       limit=DestroyString(limit);
1001     }
1002   files=(-1);
1003 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
1004   files=(ssize_t) sysconf(_SC_OPEN_MAX);
1005 #endif
1006 #if defined(MAGICKCORE_HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
1007   if (files < 0)
1008     {
1009       struct rlimit
1010         resources;
1011
1012       if (getrlimit(RLIMIT_NOFILE,&resources) != -1)
1013         files=(ssize_t) resources.rlim_cur;
1014   }
1015 #endif
1016 #if defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
1017   if (files < 0)
1018     files=(ssize_t) getdtablesize();
1019 #endif
1020   if (files < 0)
1021     files=64;
1022   (void) SetMagickResourceLimit(FileResource,MagickMax((size_t)
1023     (3*files/4),64));
1024   limit=GetEnvironmentValue("MAGICK_FILE_LIMIT");
1025   if (limit != (char *) NULL)
1026     {
1027       (void) SetMagickResourceLimit(FileResource,StringToSizeType(limit,
1028         100.0));
1029       limit=DestroyString(limit);
1030     }
1031   (void) SetMagickResourceLimit(ThreadResource,GetOpenMPMaximumThreads());
1032   limit=GetEnvironmentValue("MAGICK_THREAD_LIMIT");
1033   if (limit != (char *) NULL)
1034     {
1035       (void) SetMagickResourceLimit(ThreadResource,StringToSizeType(limit,
1036         100.0));
1037       limit=DestroyString(limit);
1038     }
1039   (void) SetMagickResourceLimit(ThrottleResource,0);
1040   limit=GetEnvironmentValue("MAGICK_THROTTLE_LIMIT");
1041   if (limit != (char *) NULL)
1042     {
1043       (void) SetMagickResourceLimit(ThrottleResource,StringToSizeType(limit,
1044         100.0));
1045       limit=DestroyString(limit);
1046     }
1047   (void) SetMagickResourceLimit(TimeResource,MagickResourceInfinity);
1048   limit=GetEnvironmentValue("MAGICK_TIME_LIMIT");
1049   if (limit != (char *) NULL)
1050     {
1051       (void) SetMagickResourceLimit(TimeResource,StringToSizeType(limit,100.0));
1052       limit=DestroyString(limit);
1053     }
1054   return(MagickTrue);
1055 }
1056 \f
1057 /*
1058 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1059 %                                                                             %
1060 %                                                                             %
1061 %                                                                             %
1062 +   R e s o u r c e C o m p o n e n t T e r m i n u s                         %
1063 %                                                                             %
1064 %                                                                             %
1065 %                                                                             %
1066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1067 %
1068 %  ResourceComponentTerminus() destroys the resource component.
1069 %
1070 %  The format of the ResourceComponentTerminus() method is:
1071 %
1072 %      ResourceComponentTerminus(void)
1073 %
1074 */
1075 MagickPrivate void ResourceComponentTerminus(void)
1076 {
1077   if (resource_semaphore == (SemaphoreInfo *) NULL)
1078     resource_semaphore=AcquireSemaphoreInfo();
1079   LockSemaphoreInfo(resource_semaphore);
1080   if (temporary_resources != (SplayTreeInfo *) NULL)
1081     temporary_resources=DestroySplayTree(temporary_resources);
1082   if (random_info != (RandomInfo *) NULL)
1083     random_info=DestroyRandomInfo(random_info);
1084   UnlockSemaphoreInfo(resource_semaphore);
1085   RelinquishSemaphoreInfo(&resource_semaphore);
1086 }
1087 \f
1088 /*
1089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1090 %                                                                             %
1091 %                                                                             %
1092 %                                                                             %
1093 %   S e t M a g i c k R e s o u r c e L i m i t                               %
1094 %                                                                             %
1095 %                                                                             %
1096 %                                                                             %
1097 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1098 %
1099 %  SetMagickResourceLimit() sets the limit for a particular resource.
1100 %
1101 %  The format of the SetMagickResourceLimit() method is:
1102 %
1103 %      MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1104 %        const MagickSizeType limit)
1105 %
1106 %  A description of each parameter follows:
1107 %
1108 %    o type: the type of resource.
1109 %
1110 %    o limit: the maximum limit for the resource.
1111 %
1112 */
1113
1114 static inline MagickSizeType MagickMin(const MagickSizeType x,
1115   const MagickSizeType y)
1116 {
1117   if (x < y)
1118     return(x);
1119   return(y);
1120 }
1121
1122 MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1123   const MagickSizeType limit)
1124 {
1125   char
1126     *value;
1127
1128   if (resource_semaphore == (SemaphoreInfo *) NULL)
1129     resource_semaphore=AcquireSemaphoreInfo();
1130   LockSemaphoreInfo(resource_semaphore);
1131   value=(char *) NULL;
1132   switch (type)
1133   {
1134     case AreaResource:
1135     {
1136       resource_info.area_limit=limit;
1137       value=GetPolicyValue("area");
1138       if (value != (char *) NULL)
1139         resource_info.area_limit=MagickMin(limit,StringToSizeType(value,100.0));
1140       break;
1141     }
1142     case MemoryResource:
1143     {
1144       resource_info.memory_limit=limit;
1145       value=GetPolicyValue("memory");
1146       if (value != (char *) NULL)
1147         resource_info.memory_limit=MagickMin(limit,StringToSizeType(value,
1148           100.0));
1149       break;
1150     }
1151     case MapResource:
1152     {
1153       resource_info.map_limit=limit;
1154       value=GetPolicyValue("map");
1155       if (value != (char *) NULL)
1156         resource_info.map_limit=MagickMin(limit,StringToSizeType(value,100.0));
1157       break;
1158     }
1159     case DiskResource:
1160     {
1161       resource_info.disk_limit=limit;
1162       value=GetPolicyValue("disk");
1163       if (value != (char *) NULL)
1164         resource_info.disk_limit=MagickMin(limit,StringToSizeType(value,100.0));
1165       break;
1166     }
1167     case FileResource:
1168     {
1169       resource_info.file_limit=limit;
1170       value=GetPolicyValue("file");
1171       if (value != (char *) NULL)
1172         resource_info.file_limit=MagickMin(limit,StringToSizeType(value,100.0));
1173       break;
1174     }
1175     case ThreadResource:
1176     {
1177       resource_info.thread_limit=limit;
1178       value=GetPolicyValue("thread");
1179       if (value != (char *) NULL)
1180         resource_info.thread_limit=MagickMin(limit,StringToSizeType(value,
1181           100.0));
1182       if (resource_info.thread_limit > GetOpenMPMaximumThreads())
1183         resource_info.thread_limit=GetOpenMPMaximumThreads();
1184       else if (resource_info.thread_limit == 0)
1185         resource_info.thread_limit=1;
1186       break;
1187     }
1188     case ThrottleResource:
1189     {
1190       resource_info.throttle_limit=limit;
1191       value=GetPolicyValue("throttle");
1192       if (value != (char *) NULL)
1193         resource_info.throttle_limit=MagickMin(limit,StringToSizeType(value,
1194           100.0));
1195       if (resource_info.throttle_limit > GetOpenMPMaximumThreads())
1196         resource_info.throttle_limit=GetOpenMPMaximumThreads();
1197       break;
1198     }
1199     case TimeResource:
1200     {
1201       resource_info.time_limit=limit;
1202       value=GetPolicyValue("time");
1203       if (value != (char *) NULL)
1204         resource_info.time_limit=MagickMin(limit,StringToSizeType(value,100.0));
1205       break;
1206     }
1207     default:
1208       break;
1209   }
1210   if (value != (char *) NULL)
1211     value=DestroyString(value);
1212   UnlockSemaphoreInfo(resource_semaphore);
1213   return(MagickTrue);
1214 }