MagickCore 6.9.13-53
Convert, Edit, Or Compose Bitmap Images
Loading...
Searching...
No Matches
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 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% https://imagemagick.org/license/ %
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
39/*
40 Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/cache.h"
44#include "magick/cache-private.h"
45#include "magick/configure.h"
46#include "magick/exception.h"
47#include "magick/exception-private.h"
48#include "magick/hashmap.h"
49#include "magick/log.h"
50#include "magick/image.h"
51#include "magick/image-private.h"
52#include "magick/memory_.h"
53#include "magick/nt-base-private.h"
54#include "magick/option.h"
55#include "magick/policy.h"
56#include "magick/random_.h"
57#include "magick/registry.h"
58#include "magick/resource_.h"
59#include "magick/resource-private.h"
60#include "magick/semaphore.h"
61#include "magick/signature-private.h"
62#include "magick/string_.h"
63#include "magick/string-private.h"
64#include "magick/splay-tree.h"
65#include "magick/thread-private.h"
66#include "magick/timer-private.h"
67#include "magick/token.h"
68#include "magick/timer-private.h"
69#include "magick/utility.h"
70#include "magick/utility-private.h"
71
72/*
73 Define declarations.
74*/
75#define NumberOfResourceTypes \
76 (sizeof(resource_semaphore)/sizeof(*resource_semaphore))
77
78/*
79 Typedef declarations.
80*/
81typedef struct _ResourceInfo
82{
83 MagickOffsetType
84 width,
85 height,
86 list_length,
87 area,
88 memory,
89 map,
90 disk,
91 file,
92 thread,
93 throttle,
94 time;
95
96 MagickSizeType
97 width_limit,
98 height_limit,
99 list_length_limit,
100 area_limit,
101 memory_limit,
102 map_limit,
103 disk_limit,
104 file_limit,
105 thread_limit,
106 throttle_limit,
107 time_limit;
108} ResourceInfo;
109
110/*
111 Global declarations.
112*/
113static RandomInfo
114 *random_info = (RandomInfo *) NULL;
115
116static ResourceInfo
117 resource_info =
118 {
119 MagickULLConstant(0), /* initial width */
120 MagickULLConstant(0), /* initial height */
121 MagickULLConstant(0), /* initial list length */
122 MagickULLConstant(0), /* initial area */
123 MagickULLConstant(0), /* initial memory */
124 MagickULLConstant(0), /* initial map */
125 MagickULLConstant(0), /* initial disk */
126 MagickULLConstant(0), /* initial file */
127 MagickULLConstant(0), /* initial thread */
128 MagickULLConstant(0), /* initial throttle */
129 MagickULLConstant(0), /* initial time */
130 (MagickSizeType) (MAGICK_SSIZE_MAX/sizeof(PixelPacket)/5), /* width limit */
131 (MagickSizeType) (MAGICK_SSIZE_MAX/sizeof(PixelPacket)/5), /* height limit */
132 MagickResourceInfinity, /* list length limit */
133 MagickULLConstant(3072)*1024*1024, /* area limit */
134 MagickULLConstant(1536)*1024*1024, /* memory limit */
135 MagickULLConstant(3072)*1024*1024, /* map limit */
136 MagickResourceInfinity, /* disk limit */
137 MagickULLConstant(768), /* file limit */
138 MagickULLConstant(1), /* thread limit */
139 MagickULLConstant(0), /* throttle limit */
140 MagickResourceInfinity, /* time limit */
141 };
142
143static SemaphoreInfo
144 *resource_semaphore[] = {
145 (SemaphoreInfo *) NULL,
146 (SemaphoreInfo *) NULL,
147 (SemaphoreInfo *) NULL,
148 (SemaphoreInfo *) NULL,
149 (SemaphoreInfo *) NULL,
150 (SemaphoreInfo *) NULL,
151 (SemaphoreInfo *) NULL,
152 (SemaphoreInfo *) NULL,
153 (SemaphoreInfo *) NULL,
154 (SemaphoreInfo *) NULL,
155 (SemaphoreInfo *) NULL,
156 (SemaphoreInfo *) NULL
157 };
158
159static SplayTreeInfo
160 *temporary_resources = (SplayTreeInfo *) NULL;
161
162/*
163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164% %
165% %
166% %
167% A c q u i r e M a g i c k R e s o u r c e %
168% %
169% %
170% %
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172%
173% AcquireMagickResource() acquires resources of the specified type.
174% MagickFalse is returned if the specified resource is exhausted otherwise
175% MagickTrue.
176%
177% The format of the AcquireMagickResource() method is:
178%
179% MagickBooleanType AcquireMagickResource(const ResourceType type,
180% const MagickSizeType size)
181%
182% A description of each parameter follows:
183%
184% o type: the type of resource.
185%
186% o size: the number of bytes needed from for this resource.
187%
188*/
189MagickExport MagickBooleanType AcquireMagickResource(const ResourceType type,
190 const MagickSizeType size)
191{
192 char
193 resource_current[MaxTextExtent] = "",
194 resource_limit[MaxTextExtent] = "",
195 resource_request[MaxTextExtent] = "";
196
197 MagickBooleanType
198 logging,
199 status;
200
201 MagickOffsetType
202 request;
203
204 MagickSizeType
205 limit;
206
207 request=(MagickOffsetType) size;
208 if (request < 0)
209 return(MagickFalse);
210 status=MagickFalse;
211 logging=(GetLogEventMask() & ResourceEvent) != 0 ? MagickTrue : MagickFalse;
212 switch (type)
213 {
214 case DiskResource:
215 case FileResource:
216 case MapResource:
217 case MemoryResource:
218 case TimeResource:
219 {
220 if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
221 ActivateSemaphoreInfo(&resource_semaphore[type]);
222 LockSemaphoreInfo(resource_semaphore[type]);
223 break;
224 }
225 default: ;
226 }
227 switch (type)
228 {
229 case AreaResource:
230 {
231 resource_info.area=(MagickOffsetType) size;
232 limit=resource_info.area_limit;
233 if ((limit == MagickResourceInfinity) || (size < limit))
234 status=MagickTrue;
235 if (logging != MagickFalse)
236 {
237 (void) FormatMagickSize(size,MagickFalse,resource_request);
238 (void) FormatMagickSize(size,MagickFalse,resource_current);
239 (void) FormatMagickSize(limit,MagickFalse,resource_limit);
240 }
241 break;
242 }
243 case DiskResource:
244 {
245 limit=resource_info.disk_limit;
246 if (resource_info.disk <= (MagickOffsetMax-request))
247 {
248 resource_info.disk+=request;
249 if ((limit == MagickResourceInfinity) ||
250 (resource_info.disk < (MagickOffsetType) limit))
251 status=MagickTrue;
252 else
253 resource_info.disk-=request;
254 }
255 if (logging != MagickFalse)
256 {
257 (void) FormatMagickSize(size,MagickTrue,resource_request);
258 (void) FormatMagickSize((MagickSizeType) resource_info.disk,
259 MagickTrue,resource_current);
260 (void) FormatMagickSize(limit,MagickTrue,resource_limit);
261 }
262 break;
263 }
264 case FileResource:
265 {
266 limit=resource_info.file_limit;
267 if (resource_info.file <= (MagickOffsetMax-request))
268 {
269 resource_info.file+=request;
270 if ((limit == MagickResourceInfinity) ||
271 (resource_info.file < (MagickOffsetType) limit))
272 status=MagickTrue;
273 }
274 if (logging != MagickFalse)
275 {
276 (void) FormatMagickSize(size,MagickFalse,resource_request);
277 (void) FormatMagickSize((MagickSizeType) resource_info.file,
278 MagickFalse,resource_current);
279 (void) FormatMagickSize(limit,MagickFalse,resource_limit);
280 }
281 break;
282 }
283 case HeightResource:
284 {
285 resource_info.height=(MagickOffsetType) size;
286 limit=resource_info.height_limit;
287 if ((limit == MagickResourceInfinity) || (size < limit))
288 status=MagickTrue;
289 if (logging != MagickFalse)
290 {
291 (void) FormatMagickSize(size,MagickFalse,resource_request);
292 (void) FormatMagickSize(size,MagickFalse,resource_current);
293 (void) FormatMagickSize(limit,MagickFalse,resource_limit);
294 }
295 break;
296 }
297 case ListLengthResource:
298 {
299 resource_info.list_length=(MagickOffsetType) size;
300 limit=resource_info.list_length_limit;
301 if ((limit == MagickResourceInfinity) || (size < limit))
302 status=MagickTrue;
303 if (logging != MagickFalse)
304 {
305 (void) FormatMagickSize(size,MagickFalse,resource_request);
306 (void) FormatMagickSize(size,MagickFalse,resource_current);
307 (void) FormatMagickSize(limit,MagickFalse,resource_limit);
308 }
309 break;
310 }
311 case MapResource:
312 {
313 limit=resource_info.map_limit;
314 if (resource_info.map <= (MagickOffsetMax-request))
315 {
316 resource_info.map+=request;
317 if ((limit == MagickResourceInfinity) ||
318 (resource_info.map < (MagickOffsetType) limit))
319 status=MagickTrue;
320 else
321 resource_info.map-=request;
322 }
323 if (logging != MagickFalse)
324 {
325 (void) FormatMagickSize(size,MagickTrue,resource_request);
326 (void) FormatMagickSize((MagickSizeType) resource_info.map,
327 MagickTrue,resource_current);
328 (void) FormatMagickSize(limit,MagickTrue,resource_limit);
329 }
330 break;
331 }
332 case MemoryResource:
333 {
334 limit=resource_info.memory_limit;
335 if (resource_info.memory <= (MagickOffsetMax-request))
336 {
337 resource_info.memory+=request;
338 if ((limit == MagickResourceInfinity) ||
339 (resource_info.memory < (MagickOffsetType) limit))
340 status=MagickTrue;
341 else
342 resource_info.memory-=request;
343 }
344 if (logging != MagickFalse)
345 {
346 (void) FormatMagickSize(size,MagickTrue,resource_request);
347 (void) FormatMagickSize((MagickSizeType) resource_info.memory,
348 MagickTrue,resource_current);
349 (void) FormatMagickSize(limit,MagickTrue,resource_limit);
350 }
351 break;
352 }
353 case ThreadResource:
354 {
355 limit=resource_info.thread_limit;
356 if ((limit == MagickResourceInfinity) ||
357 (resource_info.thread < (MagickOffsetType) limit))
358 status=MagickTrue;
359 if (logging != MagickFalse)
360 {
361 (void) FormatMagickSize(size,MagickFalse,resource_request);
362 (void) FormatMagickSize((MagickSizeType) resource_info.thread,
363 MagickFalse,resource_current);
364 (void) FormatMagickSize(limit,MagickFalse,resource_limit);
365 }
366 break;
367 }
368 case ThrottleResource:
369 {
370 limit=resource_info.throttle_limit;
371 if ((limit == MagickResourceInfinity) ||
372 (resource_info.throttle < (MagickOffsetType) limit))
373 status=MagickTrue;
374 if (logging != MagickFalse)
375 {
376 (void) FormatMagickSize(size,MagickFalse,resource_request);
377 (void) FormatMagickSize((MagickSizeType) resource_info.throttle,
378 MagickFalse,resource_current);
379 (void) FormatMagickSize(limit,MagickFalse,resource_limit);
380 }
381 break;
382 }
383 case TimeResource:
384 {
385 limit=resource_info.time_limit;
386 if (resource_info.time <= (MagickOffsetMax-request))
387 {
388 resource_info.time+=request;
389 if ((limit == MagickResourceInfinity) ||
390 (resource_info.time < (MagickOffsetType) limit))
391 status=MagickTrue;
392 else
393 resource_info.time-=request;
394 }
395 if (logging != MagickFalse)
396 {
397 (void) FormatMagickSize(size,MagickFalse,resource_request);
398 (void) FormatMagickSize((MagickSizeType) resource_info.time,
399 MagickFalse,resource_current);
400 (void) FormatMagickSize(limit,MagickFalse,resource_limit);
401 }
402 break;
403 }
404 case WidthResource:
405 {
406 resource_info.width=(MagickOffsetType) size;
407 limit=resource_info.width_limit;
408 if ((limit == MagickResourceInfinity) || (size < limit))
409 status=MagickTrue;
410 if (logging != MagickFalse)
411 {
412 (void) FormatMagickSize(size,MagickFalse,resource_request);
413 (void) FormatMagickSize(size,MagickFalse,resource_current);
414 (void) FormatMagickSize(limit,MagickFalse,resource_limit);
415 }
416 break;
417 }
418 default:
419 break;
420 }
421 switch (type)
422 {
423 case DiskResource:
424 case FileResource:
425 case MapResource:
426 case MemoryResource:
427 case TimeResource:
428 {
429 UnlockSemaphoreInfo(resource_semaphore[type]);
430 break;
431 }
432 default: ;
433 }
434 if (logging != MagickFalse)
435 {
436 (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
437 CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
438 resource_request,resource_current,resource_limit);
439 }
440 return(status);
441}
442
443/*
444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
445% %
446% %
447% %
448+ 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 %
449% %
450% %
451% %
452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
453%
454% AsynchronousResourceComponentTerminus() destroys the resource environment.
455% It differs from ResourceComponentTerminus() in that it can be called from a
456% asynchronous signal handler.
457%
458% The format of the ResourceComponentTerminus() method is:
459%
460% ResourceComponentTerminus(void)
461%
462*/
463MagickExport void AsynchronousResourceComponentTerminus(void)
464{
465 const char
466 *path;
467
468 if (temporary_resources == (SplayTreeInfo *) NULL)
469 return;
470 /*
471 Remove any lingering temporary files.
472 */
473 ResetSplayTreeIterator(temporary_resources);
474 path=(const char *) GetNextKeyInSplayTree(temporary_resources);
475 while (path != (const char *) NULL)
476 {
477 (void) ShredFile(path);
478 (void) remove_utf8(path);
479 path=(const char *) GetNextKeyInSplayTree(temporary_resources);
480 }
481}
482
483/*
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485% %
486% %
487% %
488% 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 %
489% %
490% %
491% %
492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493%
494% AcquireUniqueFileResource() returns a unique file name, and returns a file
495% descriptor for the file open for reading and writing.
496%
497% The format of the AcquireUniqueFileResource() method is:
498%
499% int AcquireUniqueFileResource(char *path)
500%
501% A description of each parameter follows:
502%
503% o path: Specifies a pointer to an array of characters. The unique path
504% name is returned in this array.
505%
506*/
507
508static void *DestroyTemporaryResources(void *temporary_resource)
509{
510 (void) ShredFile((char *) temporary_resource);
511 (void) remove_utf8((char *) temporary_resource);
512 temporary_resource=DestroyString((char *) temporary_resource);
513 return((void *) NULL);
514}
515
516MagickExport int AcquireUniqueFileResource(char *path)
517{
518#if !defined(O_NOFOLLOW)
519#define O_NOFOLLOW 0
520#endif
521#if !defined(TMP_MAX)
522# define TMP_MAX 238328
523#endif
524
525 int
526 c,
527 file;
528
529 char
530 *p;
531
532 MagickBooleanType
533 status;
534
535 ssize_t
536 i;
537
538 static const char
539 portable_filename[65] =
540 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
541
542 StringInfo
543 *key;
544
545 struct stat
546 *attributes;
547
548 unsigned char
549 *datum;
550
551 assert(path != (char *) NULL);
552 if ((GetLogEventMask() & ResourceEvent) != 0)
553 (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"...");
554 if (random_info == (RandomInfo *) NULL)
555 {
556 if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
557 ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
558 LockSemaphoreInfo(resource_semaphore[FileResource]);
559 if (random_info == (RandomInfo *) NULL)
560 random_info=AcquireRandomInfo();
561 UnlockSemaphoreInfo(resource_semaphore[FileResource]);
562 }
563 file=(-1);
564 for (i=0; i < (ssize_t) TMP_MAX; i++)
565 {
566 ssize_t
567 j;
568
569 /*
570 Get temporary pathname.
571 */
572 (void) GetPathTemplate(path);
573 key=GetRandomKey(random_info,strlen(MagickPathTemplate)-6);
574 p=path+strlen(path)-strlen(MagickPathTemplate);
575 datum=GetStringInfoDatum(key);
576 for (j=0; j < (ssize_t) GetStringInfoLength(key); j++)
577 {
578 c=(int) (datum[j] & 0x3f);
579 *p++=portable_filename[c];
580 }
581 key=DestroyStringInfo(key);
582#if defined(MAGICKCORE_HAVE_MKSTEMP)
583 file=mkstemp(path);
584 if (file != -1)
585 {
586#if defined(MAGICKCORE_HAVE_FCHMOD)
587 (void) fchmod(file,0600);
588#endif
589#if defined(__OS2__)
590 setmode(file,O_BINARY);
591#endif
592 break;
593 }
594#endif
595 key=GetRandomKey(random_info,strlen(MagickPathTemplate));
596 p=path+strlen(path)-strlen(MagickPathTemplate);
597 datum=GetStringInfoDatum(key);
598 for (j=0; j < (ssize_t) GetStringInfoLength(key); j++)
599 {
600 c=(int) (datum[j] & 0x3f);
601 *p++=portable_filename[c];
602 }
603 key=DestroyStringInfo(key);
604 file=open_utf8(path,O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_NOFOLLOW,
605 S_MODE);
606 if ((file >= 0) || (errno != EEXIST))
607 break;
608 }
609 if ((GetLogEventMask() & ResourceEvent) != 0)
610 (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"Acquire %s",path);
611 if (file == -1)
612 return(file);
613 if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
614 ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
615 LockSemaphoreInfo(resource_semaphore[FileResource]);
616 if (temporary_resources == (SplayTreeInfo *) NULL)
617 temporary_resources=NewSplayTree(CompareSplayTreeString,
618 DestroyTemporaryResources,RelinquishMagickMemory);
619 UnlockSemaphoreInfo(resource_semaphore[FileResource]);
620 attributes=(struct stat *) AcquireCriticalMemory(sizeof(struct stat));
621 status=GetPathAttributes(path,attributes);
622 if (status == MagickFalse)
623 attributes=(struct stat *) RelinquishMagickMemory(attributes);
624 else
625 status=AddValueToSplayTree(temporary_resources,ConstantString(path),
626 attributes);
627 if (status == MagickFalse)
628 file=close_utf8(file)-1;
629 return(file);
630}
631
632/*
633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
634% %
635% %
636% %
637% G e t M a g i c k R e s o u r c e %
638% %
639% %
640% %
641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
642%
643% GetMagickResource() returns the specified resource.
644%
645% The format of the GetMagickResource() method is:
646%
647% MagickSizeType GetMagickResource(const ResourceType type)
648%
649% A description of each parameter follows:
650%
651% o type: the type of resource.
652%
653*/
654MagickExport MagickSizeType GetMagickResource(const ResourceType type)
655{
656 MagickSizeType
657 resource;
658
659 resource=0;
660 switch (type)
661 {
662 case DiskResource:
663 case FileResource:
664 case MapResource:
665 case MemoryResource:
666 case TimeResource:
667 {
668 if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
669 ActivateSemaphoreInfo(&resource_semaphore[type]);
670 LockSemaphoreInfo(resource_semaphore[type]);
671 break;
672 }
673 default: ;
674 }
675 switch (type)
676 {
677 case AreaResource:
678 {
679 resource=(MagickSizeType) resource_info.area;
680 break;
681 }
682 case DiskResource:
683 {
684 resource=(MagickSizeType) resource_info.disk;
685 break;
686 }
687 case FileResource:
688 {
689 resource=(MagickSizeType) resource_info.file;
690 break;
691 }
692 case HeightResource:
693 {
694 resource=(MagickSizeType) resource_info.height;
695 break;
696 }
697 case ListLengthResource:
698 {
699 resource=(MagickSizeType) resource_info.list_length;
700 break;
701 }
702 case MapResource:
703 {
704 resource=(MagickSizeType) resource_info.map;
705 break;
706 }
707 case MemoryResource:
708 {
709 resource=(MagickSizeType) resource_info.memory;
710 break;
711 }
712 case ThreadResource:
713 {
714 resource=(MagickSizeType) resource_info.thread;
715 break;
716 }
717 case ThrottleResource:
718 {
719 resource=(MagickSizeType) resource_info.throttle;
720 break;
721 }
722 case TimeResource:
723 {
724 resource=(MagickSizeType) resource_info.time;
725 break;
726 }
727 case WidthResource:
728 {
729 resource=(MagickSizeType) resource_info.width;
730 break;
731 }
732 default:
733 break;
734 }
735 switch (type)
736 {
737 case DiskResource:
738 case FileResource:
739 case MapResource:
740 case MemoryResource:
741 case TimeResource:
742 {
743 UnlockSemaphoreInfo(resource_semaphore[type]);
744 break;
745 }
746 default: ;
747 }
748 return(resource);
749}
750
751/*
752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
753% %
754% %
755% %
756% I s F i l e R e s o u r c e I d e n t i t y V a l i d %
757% %
758% %
759% %
760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
761%
762% IsFileResourceIdentityValid() returns MagickTrue if the file resource
763% identity is valid.
764%
765% The format of the IsFileResourceIdentityValid() method is:
766%
767% MagickBooleanType IsFileResourceIdentityValid(const char *path)
768%
769% A description of each parameter follows:
770%
771% o path: the file resource path.
772%
773*/
774MagickExport MagickBooleanType IsFileResourceIdentityValid(const char *path)
775{
776 const struct stat
777 *temporary_attributes;
778
779 MagickBooleanType
780 status = MagickTrue;
781
782 struct stat
783 attributes;
784
785 if (temporary_resources == (SplayTreeInfo *) NULL)
786 return(MagickTrue);
787 LockSemaphoreInfo(resource_semaphore[FileResource]);
788 temporary_attributes=(const struct stat *) GetValueFromSplayTree(
789 temporary_resources,(const void *) path);
790 if (temporary_attributes != (const struct stat *) NULL)
791 {
792 status=GetPathAttributes(path,&attributes);
793 if (status != MagickFalse)
794 if ((attributes.st_dev != temporary_attributes->st_dev) ||
795 (attributes.st_ino != temporary_attributes->st_ino))
796 status=MagickFalse;
797 }
798 UnlockSemaphoreInfo(resource_semaphore[FileResource]);
799 return(status);
800}
801
802/*
803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
804% %
805% %
806% %
807% G e t M a g i c k R e s o u r c e L i m i t %
808% %
809% %
810% %
811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
812%
813% GetMagickResourceLimit() returns the specified resource limit.
814%
815% The format of the GetMagickResourceLimit() method is:
816%
817% MagickSizeType GetMagickResourceLimit(const ResourceType type)
818%
819% A description of each parameter follows:
820%
821% o type: the type of resource.
822%
823*/
824MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
825{
826 MagickSizeType
827 resource;
828
829 resource=0;
830 if (type >= NumberOfResourceTypes)
831 return(resource);
832 if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
833 ActivateSemaphoreInfo(&resource_semaphore[type]);
834 LockSemaphoreInfo(resource_semaphore[type]);
835 switch (type)
836 {
837 case AreaResource:
838 {
839 resource=resource_info.area_limit;
840 break;
841 }
842 case DiskResource:
843 {
844 resource=resource_info.disk_limit;
845 break;
846 }
847 case FileResource:
848 {
849 resource=resource_info.file_limit;
850 break;
851 }
852 case HeightResource:
853 {
854 resource=resource_info.height_limit;
855 break;
856 }
857 case ListLengthResource:
858 {
859 resource=resource_info.list_length_limit;
860 break;
861 }
862 case MemoryResource:
863 {
864 resource=resource_info.memory_limit;
865 break;
866 }
867 case MapResource:
868 {
869 resource=resource_info.map_limit;
870 break;
871 }
872 case ThreadResource:
873 {
874 resource=resource_info.thread_limit;
875 break;
876 }
877 case ThrottleResource:
878 {
879 resource=resource_info.throttle_limit;
880 break;
881 }
882 case TimeResource:
883 {
884 resource=resource_info.time_limit;
885 break;
886 }
887 case WidthResource:
888 {
889 resource=resource_info.width_limit;
890 break;
891 }
892 default:
893 break;
894 }
895 UnlockSemaphoreInfo(resource_semaphore[type]);
896 return(resource);
897}
898
899/*
900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
901% %
902% %
903% %
904% L i s t M a g i c k R e s o u r c e I n f o %
905% %
906% %
907% %
908%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
909%
910% ListMagickResourceInfo() lists the resource info to a file.
911%
912% The format of the ListMagickResourceInfo method is:
913%
914% MagickBooleanType ListMagickResourceInfo(FILE *file,
915% ExceptionInfo *exception)
916%
917% A description of each parameter follows.
918%
919% o file: An pointer to a FILE.
920%
921% o exception: return any errors or warnings in this structure.
922%
923*/
924
925static ssize_t FormatPixelSize(const MagickSizeType size,
926 const MagickBooleanType bi,char *format)
927{
928 const char
929 **units;
930
931 double
932 bytes,
933 length;
934
935 ssize_t
936 count,
937 i,
938 j;
939
940 static const char
941 *bi_units[] =
942 {
943 "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi", "Ri", "Qi", (char *) NULL
944 },
945 *traditional_units[] =
946 {
947 "", "K", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q", (char *) NULL
948 };
949
950 bytes=1000.0;
951 units=traditional_units;
952 if (bi != MagickFalse)
953 {
954 bytes=1024.0;
955 units=bi_units;
956 }
957#if defined(_MSC_VER) && (_MSC_VER == 1200)
958 length=(double) ((MagickOffsetType) size);
959#else
960 length=(double) size;
961#endif
962 for (i=0; (length >= bytes) && (units[i+1] != (const char *) NULL); i++)
963 length/=bytes;
964 count=0;
965 for (j=2; j < 12; j++)
966 {
967 count=FormatLocaleString(format,MaxTextExtent,"%.*g%sP",(int) (i+j),length,
968 units[i]);
969 if (strchr(format,'+') == (char *) NULL)
970 break;
971 }
972 return(count);
973}
974
975static void FormatTimeToLive(const MagickSizeType ttl,char *timeString)
976{
977 MagickSizeType
978 days,
979 hours,
980 minutes,
981 months,
982 seconds,
983 weeks,
984 years;
985
986 years=ttl/31536000;
987 seconds=ttl % 31536000;
988 if (seconds == 0)
989 {
990 (void) FormatLocaleString(timeString,MagickPathExtent,"%lld years",years);
991 return;
992 }
993 months=ttl/2628000;
994 seconds=ttl % 2628000;
995 if (seconds == 0)
996 {
997 (void) FormatLocaleString(timeString,MagickPathExtent,"%lld months",
998 months);
999 return;
1000 }
1001 weeks=ttl/604800;
1002 seconds=ttl % 604800;
1003 if (seconds == 0)
1004 {
1005 (void) FormatLocaleString(timeString,MagickPathExtent,"%lld weeks",weeks);
1006 return;
1007 }
1008 days=ttl/86400;
1009 seconds=ttl % 86400;
1010 if (seconds == 0)
1011 {
1012 (void) FormatLocaleString(timeString,MagickPathExtent,"%lld days",days);
1013 return;
1014 }
1015 hours=ttl/3600;
1016 seconds=ttl % 3600;
1017 if (seconds == 0)
1018 {
1019 (void) FormatLocaleString(timeString,MagickPathExtent,"%lld hours",hours);
1020 return;
1021 }
1022 minutes=ttl/60;
1023 seconds=ttl % 60;
1024 if (seconds == 0)
1025 {
1026 (void) FormatLocaleString(timeString,MagickPathExtent,"%lld minutes",
1027 minutes);
1028 return;
1029 }
1030 (void) FormatLocaleString(timeString,MagickPathExtent,"%lld seconds",ttl);
1031}
1032
1033MagickExport MagickBooleanType ListMagickResourceInfo(FILE *file,
1034 ExceptionInfo *magick_unused(exception))
1035{
1036 char
1037 area_limit[MaxTextExtent],
1038 disk_limit[MaxTextExtent],
1039 height_limit[MaxTextExtent],
1040 list_length_limit[MaxTextExtent],
1041 map_limit[MaxTextExtent],
1042 memory_limit[MaxTextExtent],
1043 time_limit[MaxTextExtent],
1044 width_limit[MaxTextExtent];
1045
1046 magick_unreferenced(exception);
1047
1048 if (file == (const FILE *) NULL)
1049 file=stdout;
1050 if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
1051 ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
1052 LockSemaphoreInfo(resource_semaphore[FileResource]);
1053 (void) FormatPixelSize(resource_info.width_limit,MagickFalse,width_limit);
1054 (void) FormatPixelSize(resource_info.height_limit,MagickFalse,height_limit);
1055 (void) FormatPixelSize(resource_info.area_limit,MagickFalse,area_limit);
1056 (void) CopyMagickString(list_length_limit,"unlimited",MaxTextExtent);
1057 if (resource_info.list_length_limit != MagickResourceInfinity)
1058 (void) FormatMagickSize(resource_info.list_length_limit,MagickTrue,
1059 list_length_limit);
1060 (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,memory_limit);
1061 (void) FormatMagickSize(resource_info.map_limit,MagickTrue,map_limit);
1062 (void) CopyMagickString(disk_limit,"unlimited",MaxTextExtent);
1063 if (resource_info.disk_limit != MagickResourceInfinity)
1064 (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,disk_limit);
1065 (void) CopyMagickString(time_limit,"unlimited",MaxTextExtent);
1066 if (resource_info.time_limit != MagickResourceInfinity)
1067 FormatTimeToLive(resource_info.time_limit,time_limit);
1068 (void) FormatLocaleFile(file,"Resource limits:\n");
1069 (void) FormatLocaleFile(file," Width: %s\n",width_limit);
1070 (void) FormatLocaleFile(file," Height: %s\n",height_limit);
1071 (void) FormatLocaleFile(file," List length: %s\n",list_length_limit);
1072 (void) FormatLocaleFile(file," Area: %s\n",area_limit);
1073 (void) FormatLocaleFile(file," Memory: %s\n",memory_limit);
1074 (void) FormatLocaleFile(file," Map: %s\n",map_limit);
1075 (void) FormatLocaleFile(file," Disk: %s\n",disk_limit);
1076 (void) FormatLocaleFile(file," File: %.20g\n",(double) ((MagickOffsetType)
1077 resource_info.file_limit));
1078 (void) FormatLocaleFile(file," Thread: %.20g\n",(double) ((MagickOffsetType)
1079 resource_info.thread_limit));
1080 (void) FormatLocaleFile(file," Throttle: %.20g\n",(double)
1081 ((MagickOffsetType) resource_info.throttle_limit));
1082 (void) FormatLocaleFile(file," Time: %s\n",time_limit);
1083 (void) fflush(file);
1084 UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1085 return(MagickTrue);
1086}
1087
1088/*
1089%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1090% %
1091% %
1092% %
1093% R e l i n q u i s h M a g i c k R e s o u r c e %
1094% %
1095% %
1096% %
1097%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1098%
1099% RelinquishMagickResource() relinquishes resources of the specified type.
1100%
1101% The format of the RelinquishMagickResource() method is:
1102%
1103% void RelinquishMagickResource(const ResourceType type,
1104% const MagickSizeType size)
1105%
1106% A description of each parameter follows:
1107%
1108% o type: the type of resource.
1109%
1110% o size: the size of the resource.
1111%
1112*/
1113MagickExport void RelinquishMagickResource(const ResourceType type,
1114 const MagickSizeType size)
1115{
1116 char
1117 resource_current[MaxTextExtent],
1118 resource_limit[MaxTextExtent],
1119 resource_request[MaxTextExtent];
1120
1121 MagickBooleanType
1122 logging;
1123
1124 logging=(GetLogEventMask() & ResourceEvent) != 0 ? MagickTrue : MagickFalse;
1125 if (logging != MagickFalse)
1126 (void) FormatMagickSize(size,MagickFalse,resource_request);
1127 switch (type)
1128 {
1129 case DiskResource:
1130 case FileResource:
1131 case MapResource:
1132 case MemoryResource:
1133 case TimeResource:
1134 {
1135 if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
1136 ActivateSemaphoreInfo(&resource_semaphore[type]);
1137 LockSemaphoreInfo(resource_semaphore[type]);
1138 break;
1139 }
1140 default: ;
1141 }
1142 switch (type)
1143 {
1144 case AreaResource:
1145 {
1146 resource_info.area=(MagickOffsetType) size;
1147 if (logging != MagickFalse)
1148 {
1149 (void) FormatMagickSize((MagickSizeType) resource_info.area,
1150 MagickFalse,resource_current);
1151 (void) FormatMagickSize(resource_info.area_limit,MagickFalse,
1152 resource_limit);
1153 }
1154 break;
1155 }
1156 case DiskResource:
1157 {
1158 resource_info.disk-=size;
1159 assert(resource_info.disk >= 0);
1160 if (logging != MagickFalse)
1161 {
1162 (void) FormatMagickSize((MagickSizeType) resource_info.disk,
1163 MagickTrue,resource_current);
1164 (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,
1165 resource_limit);
1166 }
1167 break;
1168 }
1169 case FileResource:
1170 {
1171 resource_info.file-=size;
1172 assert(resource_info.file >= 0);
1173 if (logging != MagickFalse)
1174 {
1175 (void) FormatMagickSize((MagickSizeType) resource_info.file,
1176 MagickFalse,resource_current);
1177 (void) FormatMagickSize((MagickSizeType) resource_info.file_limit,
1178 MagickFalse,resource_limit);
1179 }
1180 break;
1181 }
1182 case HeightResource:
1183 {
1184 resource_info.height=(MagickOffsetType) size;
1185 if (logging != MagickFalse)
1186 {
1187 (void) FormatMagickSize((MagickSizeType) resource_info.height,
1188 MagickFalse,resource_current);
1189 (void) FormatMagickSize(resource_info.height_limit,MagickFalse,
1190 resource_limit);
1191 }
1192 break;
1193 }
1194 case ListLengthResource:
1195 {
1196 resource_info.list_length=(MagickOffsetType) size;
1197 if (logging != MagickFalse)
1198 {
1199 (void) FormatMagickSize((MagickSizeType) resource_info.list_length,
1200 MagickFalse,resource_current);
1201 (void) FormatMagickSize(resource_info.list_length_limit,MagickFalse,
1202 resource_limit);
1203 }
1204 break;
1205 }
1206 case MapResource:
1207 {
1208 resource_info.map-=size;
1209 assert(resource_info.map >= 0);
1210 if (logging != MagickFalse)
1211 {
1212 (void) FormatMagickSize((MagickSizeType) resource_info.map,
1213 MagickTrue,resource_current);
1214 (void) FormatMagickSize(resource_info.map_limit,MagickTrue,
1215 resource_limit);
1216 }
1217 break;
1218 }
1219 case MemoryResource:
1220 {
1221 resource_info.memory-=size;
1222 assert(resource_info.memory >= 0);
1223 if (logging != MagickFalse)
1224 {
1225 (void) FormatMagickSize((MagickSizeType) resource_info.memory,
1226 MagickTrue,resource_current);
1227 (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,
1228 resource_limit);
1229 }
1230 break;
1231 }
1232 case ThreadResource:
1233 {
1234 if (logging != MagickFalse)
1235 {
1236 (void) FormatMagickSize((MagickSizeType) resource_info.thread,
1237 MagickFalse,resource_current);
1238 (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
1239 MagickFalse,resource_limit);
1240 }
1241 break;
1242 }
1243 case ThrottleResource:
1244 {
1245 if (logging != MagickFalse)
1246 {
1247 (void) FormatMagickSize((MagickSizeType) resource_info.throttle,
1248 MagickFalse,resource_current);
1249 (void) FormatMagickSize((MagickSizeType) resource_info.throttle_limit,
1250 MagickFalse,resource_limit);
1251 }
1252 break;
1253 }
1254 case TimeResource:
1255 {
1256 resource_info.time-=size;
1257 assert(resource_info.time >= 0);
1258 if (logging != MagickFalse)
1259 {
1260 (void) FormatMagickSize((MagickSizeType) resource_info.time,
1261 MagickFalse,resource_current);
1262 (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
1263 MagickFalse,resource_limit);
1264 }
1265 break;
1266 }
1267 case WidthResource:
1268 {
1269 resource_info.width=(MagickOffsetType) size;
1270 if (logging != MagickFalse)
1271 {
1272 (void) FormatMagickSize((MagickSizeType) resource_info.width,
1273 MagickFalse,resource_current);
1274 (void) FormatMagickSize(resource_info.width_limit,MagickFalse,
1275 resource_limit);
1276 }
1277 break;
1278 }
1279 default:
1280 break;
1281 }
1282 switch (type)
1283 {
1284 case DiskResource:
1285 case FileResource:
1286 case MapResource:
1287 case MemoryResource:
1288 case TimeResource:
1289 {
1290 UnlockSemaphoreInfo(resource_semaphore[type]);
1291 break;
1292 }
1293 default: ;
1294 }
1295 if (logging != MagickFalse)
1296 {
1297 (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
1298 CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
1299 resource_request,resource_current,resource_limit);
1300 }
1301}
1302
1303/*
1304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1305% %
1306% %
1307% %
1308% 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 %
1309% %
1310% %
1311% %
1312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1313%
1314% RelinquishUniqueFileResource() relinquishes a unique file resource.
1315%
1316% The format of the RelinquishUniqueFileResource() method is:
1317%
1318% MagickBooleanType RelinquishUniqueFileResource(const char *path)
1319%
1320% A description of each parameter follows:
1321%
1322% o name: the name of the temporary resource.
1323%
1324*/
1325MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
1326{
1327 char
1328 cache_path[MaxTextExtent];
1329
1330 MagickStatusType
1331 status;
1332
1333 assert(path != (const char *) NULL);
1334 status=MagickFalse;
1335 if ((GetLogEventMask() & ResourceEvent) != 0)
1336 (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"Relinquish %s",path);
1337 if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
1338 ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
1339 LockSemaphoreInfo(resource_semaphore[FileResource]);
1340 if (temporary_resources != (SplayTreeInfo *) NULL)
1341 status=DeleteNodeFromSplayTree(temporary_resources,(const void *) path);
1342 UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1343 (void) CopyMagickString(cache_path,path,MaxTextExtent);
1344 AppendImageFormat("cache",cache_path);
1345 if (access_utf8(cache_path,F_OK) == 0)
1346 {
1347 status=ShredFile(cache_path);
1348 status|=remove_utf8(cache_path);
1349 }
1350 if (status == MagickFalse)
1351 {
1352 status=ShredFile(path);
1353 status|=remove_utf8(path);
1354 }
1355 return(status == 0 ? MagickFalse : MagickTrue);
1356}
1357
1358/*
1359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360% %
1361% %
1362% %
1363+ R e s o u r c e C o m p o n e n t G e n e s i s %
1364% %
1365% %
1366% %
1367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1368%
1369% ResourceComponentGenesis() instantiates the resource component.
1370%
1371% The format of the ResourceComponentGenesis method is:
1372%
1373% MagickBooleanType ResourceComponentGenesis(void)
1374%
1375*/
1376MagickExport MagickBooleanType ResourceComponentGenesis(void)
1377{
1378 char
1379 *limit;
1380
1381 MagickSizeType
1382 memory;
1383
1384 ssize_t
1385 files,
1386 i,
1387 number_threads,
1388 pages,
1389 pagesize;
1390
1391 /*
1392 Set Magick resource limits.
1393 */
1394 for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1395 if (resource_semaphore[i] == (SemaphoreInfo *) NULL)
1396 ActivateSemaphoreInfo(&resource_semaphore[i]);
1397 (void) SetMagickResourceLimit(WidthResource,resource_info.width_limit);
1398 limit=GetEnvironmentValue("MAGICK_WIDTH_LIMIT");
1399 if (limit != (char *) NULL)
1400 {
1401 (void) SetMagickResourceLimit(WidthResource,StringToSizeType(limit,
1402 100.0));
1403 limit=DestroyString(limit);
1404 }
1405 (void) SetMagickResourceLimit(HeightResource,resource_info.height_limit);
1406 limit=GetEnvironmentValue("MAGICK_HEIGHT_LIMIT");
1407 if (limit != (char *) NULL)
1408 {
1409 (void) SetMagickResourceLimit(HeightResource,StringToSizeType(limit,
1410 100.0));
1411 limit=DestroyString(limit);
1412 }
1413 pagesize=GetMagickPageSize();
1414 pages=(-1);
1415#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
1416 pages=(ssize_t) sysconf(_SC_PHYS_PAGES);
1417#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1418 pages=pages/2;
1419#endif
1420#endif
1421 memory=(MagickSizeType) pages*pagesize;
1422 if ((pagesize <= 0) || (pages <= 0))
1423 memory=2048UL*1024UL*1024UL;
1424#if defined(MAGICKCORE_PixelCacheThreshold)
1425 memory=StringToMagickSizeType(MAGICKCORE_PixelCacheThreshold,100.0);
1426#endif
1427 (void) SetMagickResourceLimit(AreaResource,4*memory);
1428 limit=GetEnvironmentValue("MAGICK_AREA_LIMIT");
1429 if (limit != (char *) NULL)
1430 {
1431 (void) SetMagickResourceLimit(AreaResource,StringToSizeType(limit,100.0));
1432 limit=DestroyString(limit);
1433 }
1434 (void) SetMagickResourceLimit(MemoryResource,memory);
1435 limit=GetEnvironmentValue("MAGICK_MEMORY_LIMIT");
1436 if (limit != (char *) NULL)
1437 {
1438 (void) SetMagickResourceLimit(MemoryResource,
1439 StringToSizeType(limit,100.0));
1440 limit=DestroyString(limit);
1441 }
1442 (void) SetMagickResourceLimit(MapResource,2*memory);
1443 limit=GetEnvironmentValue("MAGICK_MAP_LIMIT");
1444 if (limit != (char *) NULL)
1445 {
1446 (void) SetMagickResourceLimit(MapResource,StringToSizeType(limit,100.0));
1447 limit=DestroyString(limit);
1448 }
1449 (void) SetMagickResourceLimit(DiskResource,MagickResourceInfinity);
1450 limit=GetEnvironmentValue("MAGICK_DISK_LIMIT");
1451 if (limit != (char *) NULL)
1452 {
1453 (void) SetMagickResourceLimit(DiskResource,StringToSizeType(limit,100.0));
1454 limit=DestroyString(limit);
1455 }
1456 files=(-1);
1457#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
1458 files=(ssize_t) sysconf(_SC_OPEN_MAX);
1459#endif
1460#if defined(MAGICKCORE_HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
1461 if (files < 0)
1462 {
1463 struct rlimit
1464 resources;
1465
1466 if (getrlimit(RLIMIT_NOFILE,&resources) != -1)
1467 files=(ssize_t) resources.rlim_cur;
1468 }
1469#endif
1470#if defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
1471 if (files < 0)
1472 files=(ssize_t) getdtablesize();
1473#endif
1474 if (files < 0)
1475 files=64;
1476 (void) SetMagickResourceLimit(FileResource,MagickMax((size_t)
1477 (3*files/4),64));
1478 limit=GetEnvironmentValue("MAGICK_FILE_LIMIT");
1479 if (limit != (char *) NULL)
1480 {
1481 (void) SetMagickResourceLimit(FileResource,StringToSizeType(limit,100.0));
1482 limit=DestroyString(limit);
1483 }
1484 number_threads=(ssize_t) GetOpenMPMaximumThreads();
1485 if (number_threads > 1)
1486 number_threads--; /* reserve core for OS */
1487 (void) SetMagickResourceLimit(ThreadResource,(size_t) number_threads);
1488 limit=GetEnvironmentValue("MAGICK_THREAD_LIMIT");
1489 if (limit != (char *) NULL)
1490 {
1491 (void) SetMagickResourceLimit(ThreadResource,StringToSizeType(limit,
1492 100.0));
1493 limit=DestroyString(limit);
1494 }
1495 (void) SetMagickResourceLimit(ThrottleResource,0);
1496 limit=GetEnvironmentValue("MAGICK_THROTTLE_LIMIT");
1497 if (limit != (char *) NULL)
1498 {
1499 (void) SetMagickResourceLimit(ThrottleResource,StringToSizeType(limit,
1500 100.0));
1501 limit=DestroyString(limit);
1502 }
1503 (void) SetMagickResourceLimit(TimeResource,MagickResourceInfinity);
1504 limit=GetEnvironmentValue("MAGICK_TIME_LIMIT");
1505 if (limit != (char *) NULL)
1506 {
1507 (void) SetMagickResourceLimit(TimeResource,(MagickSizeType)
1508 ParseMagickTimeToLive(limit));
1509 limit=DestroyString(limit);
1510 }
1511 (void) SetMagickResourceLimit(ListLengthResource,MagickResourceInfinity);
1512 limit=GetEnvironmentValue("MAGICK_LIST_LENGTH_LIMIT");
1513 if (limit != (char *) NULL)
1514 {
1515 (void) SetMagickResourceLimit(ListLengthResource,
1516 StringToSizeType(limit,100.0));
1517 limit=DestroyString(limit);
1518 }
1519 return(MagickTrue);
1520}
1521
1522/*
1523%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1524% %
1525% %
1526% %
1527+ 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 %
1528% %
1529% %
1530% %
1531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1532%
1533% ResourceComponentTerminus() destroys the resource component.
1534%
1535% The format of the ResourceComponentTerminus() method is:
1536%
1537% ResourceComponentTerminus(void)
1538%
1539*/
1540MagickExport void ResourceComponentTerminus(void)
1541{
1542 ssize_t
1543 i;
1544
1545 for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1546 if (resource_semaphore[i] == (SemaphoreInfo *) NULL)
1547 ActivateSemaphoreInfo(&resource_semaphore[i]);
1548 LockSemaphoreInfo(resource_semaphore[FileResource]);
1549 if (temporary_resources != (SplayTreeInfo *) NULL)
1550 temporary_resources=DestroySplayTree(temporary_resources);
1551 if (random_info != (RandomInfo *) NULL)
1552 random_info=DestroyRandomInfo(random_info);
1553 UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1554 for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1555 DestroySemaphoreInfo(&resource_semaphore[i]);
1556}
1557
1558/*
1559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1560% %
1561% %
1562% %
1563% S e t M a g i c k R e s o u r c e L i m i t %
1564% %
1565% %
1566% %
1567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1568%
1569% SetMagickResourceLimit() sets the limit for a particular resource.
1570%
1571% The format of the SetMagickResourceLimit() method is:
1572%
1573% MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1574% const MagickSizeType limit)
1575%
1576% A description of each parameter follows:
1577%
1578% o type: the type of resource.
1579%
1580% o limit: the maximum limit for the resource.
1581%
1582*/
1583
1584MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1585 const MagickSizeType limit)
1586{
1587 char
1588 *value;
1589
1590 MagickBooleanType
1591 status;
1592
1593 status=MagickTrue;
1594 if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
1595 ActivateSemaphoreInfo(&resource_semaphore[type]);
1596 LockSemaphoreInfo(resource_semaphore[type]);
1597 value=(char *) NULL;
1598 switch (type)
1599 {
1600 case AreaResource:
1601 {
1602 value=GetPolicyValue("resource:area");
1603 if (value == (char *) NULL)
1604 resource_info.area_limit=limit;
1605 else
1606 resource_info.area_limit=MagickMin(limit,StringToSizeType(value,100.0));
1607 break;
1608 }
1609 case DiskResource:
1610 {
1611 value=GetPolicyValue("resource:disk");
1612 if (value == (char *) NULL)
1613 resource_info.disk_limit=limit;
1614 else
1615 resource_info.disk_limit=MagickMin(limit,StringToSizeType(value,100.0));
1616 break;
1617 }
1618 case FileResource:
1619 {
1620 value=GetPolicyValue("resource:file");
1621 if (value == (char *) NULL)
1622 resource_info.file_limit=limit;
1623 else
1624 resource_info.file_limit=MagickMin(limit,StringToSizeType(value,100.0));
1625 break;
1626 }
1627 case HeightResource:
1628 {
1629 value=GetPolicyValue("resource:height");
1630 if (value == (char *) NULL)
1631 resource_info.height_limit=limit;
1632 else
1633 resource_info.height_limit=MagickMin(limit,StringToSizeType(value,
1634 100.0));
1635 resource_info.height_limit=MagickMin(resource_info.height_limit,
1636 (MagickSizeType) MAGICK_SSIZE_MAX);
1637 break;
1638 }
1639 case ListLengthResource:
1640 {
1641 value=GetPolicyValue("resource:list-length");
1642 if (value == (char *) NULL)
1643 resource_info.list_length_limit=limit;
1644 else
1645 resource_info.list_length_limit=MagickMin(limit,
1646 StringToSizeType(value,100.0));
1647 break;
1648 }
1649 case MapResource:
1650 {
1651 value=GetPolicyValue("resource:map");
1652 if (value == (char *) NULL)
1653 resource_info.map_limit=limit;
1654 else
1655 resource_info.map_limit=MagickMin(limit,StringToSizeType(value,100.0));
1656 break;
1657 }
1658 case MemoryResource:
1659 {
1660 value=GetPolicyValue("resource:memory");
1661 if (value == (char *) NULL)
1662 resource_info.memory_limit=limit;
1663 else
1664 resource_info.memory_limit=MagickMin(limit,StringToSizeType(value,
1665 100.0));
1666 break;
1667 }
1668 case ThreadResource:
1669 {
1670 value=GetPolicyValue("resource:thread");
1671 if (value == (char *) NULL)
1672 resource_info.thread_limit=limit;
1673 else
1674 resource_info.thread_limit=MagickMin(limit,StringToSizeType(value,
1675 100.0));
1676 if (resource_info.thread_limit > GetOpenMPMaximumThreads())
1677 resource_info.thread_limit=GetOpenMPMaximumThreads();
1678 else
1679 if (resource_info.thread_limit == 0)
1680 resource_info.thread_limit=1;
1681 break;
1682 }
1683 case ThrottleResource:
1684 {
1685 value=GetPolicyValue("resource:throttle");
1686 if (value == (char *) NULL)
1687 resource_info.throttle_limit=limit;
1688 else
1689 resource_info.throttle_limit=MagickMax(limit,StringToSizeType(value,
1690 100.0));
1691 break;
1692 }
1693 case TimeResource:
1694 {
1695 value=GetPolicyValue("resource:time");
1696 if (value == (char *) NULL)
1697 resource_info.time_limit=limit;
1698 else
1699 resource_info.time_limit=MagickMin(limit,(MagickSizeType)
1700 ParseMagickTimeToLive(value));
1701 break;
1702 }
1703 case WidthResource:
1704 {
1705 value=GetPolicyValue("resource:width");
1706 if (value == (char *) NULL)
1707 resource_info.width_limit=limit;
1708 else
1709 resource_info.width_limit=MagickMin(limit,StringToSizeType(value,
1710 100.0));
1711 resource_info.width_limit=MagickMin(resource_info.width_limit,
1712 (MagickSizeType) MAGICK_SSIZE_MAX);
1713 break;
1714 }
1715 default:
1716 {
1717 status=MagickFalse;
1718 break;
1719 }
1720 }
1721 if (value != (char *) NULL)
1722 value=DestroyString(value);
1723 UnlockSemaphoreInfo(resource_semaphore[type]);
1724 return(status);
1725}