blob: deb89d3a87a7427d2ef04336b1aa9231932d6994 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% RRRR EEEEE SSSSS OOO U U RRRR CCCC EEEEE %
7% R R E SS O O U U R R C E %
8% RRRR EEE SSS O O U U RRRR C EEE %
9% R R E SS O O U U R R C E %
10% R R EEEEE SSSSS OOO UUU R R CCCC EEEEE %
11% %
12% %
13% Get/Set MagickCore Resources %
14% %
15% Software Design %
16% John Cristy %
17% September 2002 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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
39/*
40 Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/cache.h"
44#include "magick/configure.h"
45#include "magick/exception.h"
46#include "magick/exception-private.h"
47#include "magick/hashmap.h"
48#include "magick/log.h"
49#include "magick/image.h"
50#include "magick/memory_.h"
51#include "magick/option.h"
52#include "magick/policy.h"
53#include "magick/random_.h"
54#include "magick/registry.h"
55#include "magick/resource_.h"
56#include "magick/semaphore.h"
57#include "magick/signature-private.h"
58#include "magick/string_.h"
cristyf2f27272009-12-17 14:48:46 +000059#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000060#include "magick/splay-tree.h"
61#include "magick/thread-private.h"
62#include "magick/token.h"
63#include "magick/utility.h"
64
65/*
66 Typedef declarations.
67*/
68typedef struct _ResourceInfo
69{
70 MagickOffsetType
71 area,
72 memory,
73 map,
74 disk,
75 file,
76 thread,
77 time;
78
79 MagickSizeType
80 area_limit,
81 memory_limit,
82 map_limit,
83 disk_limit,
84 file_limit,
85 thread_limit,
86 time_limit;
87} ResourceInfo;
88
89/*
90 Global declarations.
91*/
92static RandomInfo
93 *random_info = (RandomInfo *) NULL;
94
95static ResourceInfo
96 resource_info =
97 {
98 MagickULLConstant(0),
99 MagickULLConstant(0),
100 MagickULLConstant(0),
101 MagickULLConstant(0),
102 MagickULLConstant(0),
103 MagickULLConstant(0),
104 MagickULLConstant(0),
cristyb0a27eb2010-10-23 23:34:32 +0000105 MagickULLConstant(1536)*1024*1024/sizeof(PixelPacket),
cristy3ed852e2009-09-05 21:47:34 +0000106 MagickULLConstant(1536)*1024*1024,
cristy9bfdd582010-10-23 01:27:25 +0000107 MagickULLConstant(3072)*1024*1024,
cristy3ed852e2009-09-05 21:47:34 +0000108 MagickResourceInfinity,
109 MagickULLConstant(768),
cristy9bfdd582010-10-23 01:27:25 +0000110 MagickULLConstant(4),
cristy3ed852e2009-09-05 21:47:34 +0000111 MagickResourceInfinity
112 };
113
114static SemaphoreInfo
115 *resource_semaphore = (SemaphoreInfo *) NULL;
116
117static SplayTreeInfo
118 *temporary_resources = (SplayTreeInfo *) NULL;
119
120/*
121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122% %
123% %
124% %
125% A c q u i r e M a g i c k R e s o u r c e %
126% %
127% %
128% %
129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130%
131% AcquireMagickResource() acquires resources of the specified type.
132% MagickFalse is returned if the specified resource is exhausted otherwise
133% MagickTrue.
134%
135% The format of the AcquireMagickResource() method is:
136%
137% MagickBooleanType AcquireMagickResource(const ResourceType type,
138% const MagickSizeType size)
139%
140% A description of each parameter follows:
141%
142% o type: the type of resource.
143%
144% o size: the number of bytes needed from for this resource.
145%
146*/
147MagickExport MagickBooleanType AcquireMagickResource(const ResourceType type,
148 const MagickSizeType size)
149{
150 char
151 resource_current[MaxTextExtent],
152 resource_limit[MaxTextExtent],
153 resource_request[MaxTextExtent];
154
155 MagickBooleanType
156 status;
157
158 MagickSizeType
159 limit;
160
161 status=MagickFalse;
cristyb9080c92009-12-01 20:13:26 +0000162 (void) FormatMagickSize(size,MagickFalse,resource_request);
cristy18b17442009-10-25 18:36:48 +0000163 if (resource_semaphore == (SemaphoreInfo *) NULL)
164 AcquireSemaphoreInfo(&resource_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000165 LockSemaphoreInfo(resource_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000166 switch (type)
167 {
168 case AreaResource:
169 {
170 resource_info.area=(MagickOffsetType) size;
171 limit=resource_info.area_limit;
172 status=(resource_info.area_limit == MagickResourceInfinity) ||
173 (size < limit) ? MagickTrue : MagickFalse;
cristyb9080c92009-12-01 20:13:26 +0000174 (void) FormatMagickSize((MagickSizeType) resource_info.area,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000175 resource_current);
cristyb9080c92009-12-01 20:13:26 +0000176 (void) FormatMagickSize(resource_info.area_limit,MagickFalse,
177 resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000178 break;
179 }
180 case MemoryResource:
181 {
182 resource_info.memory+=size;
183 limit=resource_info.memory_limit;
184 status=(resource_info.memory_limit == MagickResourceInfinity) ||
185 ((MagickSizeType) resource_info.memory < limit) ?
186 MagickTrue : MagickFalse;
cristyb9080c92009-12-01 20:13:26 +0000187 (void) FormatMagickSize((MagickSizeType) resource_info.memory,MagickTrue,
cristy3ed852e2009-09-05 21:47:34 +0000188 resource_current);
cristyb9080c92009-12-01 20:13:26 +0000189 (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,
cristy3ed852e2009-09-05 21:47:34 +0000190 resource_limit);
191 break;
192 }
193 case MapResource:
194 {
195 resource_info.map+=size;
196 limit=resource_info.map_limit;
197 status=(resource_info.map_limit == MagickResourceInfinity) ||
198 ((MagickSizeType) resource_info.map < limit) ?
199 MagickTrue : MagickFalse;
cristyb9080c92009-12-01 20:13:26 +0000200 (void) FormatMagickSize((MagickSizeType) resource_info.map,MagickTrue,
cristy3ed852e2009-09-05 21:47:34 +0000201 resource_current);
cristyb9080c92009-12-01 20:13:26 +0000202 (void) FormatMagickSize(resource_info.map_limit,MagickTrue,
cristy3ed852e2009-09-05 21:47:34 +0000203 resource_limit);
204 break;
205 }
206 case DiskResource:
207 {
208 resource_info.disk+=size;
209 limit=resource_info.disk_limit;
210 status=(resource_info.disk_limit == MagickResourceInfinity) ||
211 ((MagickSizeType) resource_info.disk < limit) ?
212 MagickTrue : MagickFalse;
cristyb9080c92009-12-01 20:13:26 +0000213 (void) FormatMagickSize((MagickSizeType) resource_info.disk,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000214 resource_current);
cristyb9080c92009-12-01 20:13:26 +0000215 (void) FormatMagickSize(resource_info.disk_limit,MagickFalse,
216 resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000217 break;
218 }
219 case FileResource:
220 {
221 resource_info.file+=size;
222 limit=resource_info.file_limit;
223 status=(resource_info.file_limit == MagickResourceInfinity) ||
224 ((MagickSizeType) resource_info.file < limit) ?
225 MagickTrue : MagickFalse;
cristyb9080c92009-12-01 20:13:26 +0000226 (void) FormatMagickSize((MagickSizeType) resource_info.file,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000227 resource_current);
228 (void) FormatMagickSize((MagickSizeType) resource_info.file_limit,
cristyb9080c92009-12-01 20:13:26 +0000229 MagickFalse,resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000230 break;
231 }
232 case ThreadResource:
233 {
234 resource_info.thread+=size;
235 limit=resource_info.thread_limit;
236 status=(resource_info.thread_limit == MagickResourceInfinity) ||
237 ((MagickSizeType) resource_info.thread < limit) ?
238 MagickTrue : MagickFalse;
cristyb9080c92009-12-01 20:13:26 +0000239 (void) FormatMagickSize((MagickSizeType) resource_info.thread,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000240 resource_current);
241 (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
cristyb9080c92009-12-01 20:13:26 +0000242 MagickFalse,resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000243 break;
244 }
245 case TimeResource:
246 {
247 resource_info.time+=size;
248 limit=resource_info.time_limit;
249 status=(resource_info.time_limit == MagickResourceInfinity) ||
250 ((MagickSizeType) resource_info.time < limit) ?
251 MagickTrue : MagickFalse;
cristyb9080c92009-12-01 20:13:26 +0000252 (void) FormatMagickSize((MagickSizeType) resource_info.time,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000253 resource_current);
254 (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
cristyb9080c92009-12-01 20:13:26 +0000255 MagickFalse,resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000256 break;
257 }
258 default:
259 break;
260 }
cristyf84a1932010-01-03 18:00:18 +0000261 UnlockSemaphoreInfo(resource_semaphore);
cristy9bfdd582010-10-23 01:27:25 +0000262 (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
cristya21afde2010-07-02 00:45:40 +0000263 MagickOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
264 resource_request,resource_current,resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000265 return(status);
266}
267
268/*
269%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
270% %
271% %
272% %
cristycfffdac2010-09-30 03:05:09 +0000273+ 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 %
cristy3ed852e2009-09-05 21:47:34 +0000274% %
275% %
276% %
277%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
278%
cristyf34a1452009-10-24 22:29:27 +0000279% AsynchronousResourceComponentTerminus() destroys the resource environment.
280% It differs from ResourceComponentTerminus() in that it can be called from a
cristy3ed852e2009-09-05 21:47:34 +0000281% asynchronous signal handler.
282%
cristyf34a1452009-10-24 22:29:27 +0000283% The format of the ResourceComponentTerminus() method is:
cristy3ed852e2009-09-05 21:47:34 +0000284%
cristyf34a1452009-10-24 22:29:27 +0000285% ResourceComponentTerminus(void)
cristy3ed852e2009-09-05 21:47:34 +0000286%
287*/
cristyf34a1452009-10-24 22:29:27 +0000288MagickExport void AsynchronousResourceComponentTerminus(void)
cristy3ed852e2009-09-05 21:47:34 +0000289{
290 const char
291 *path;
292
293 if (temporary_resources == (SplayTreeInfo *) NULL)
294 return;
295 /*
296 Remove any lingering temporary files.
297 */
298 ResetSplayTreeIterator(temporary_resources);
299 path=(const char *) GetNextKeyInSplayTree(temporary_resources);
300 while (path != (const char *) NULL)
301 {
302 (void) remove(path);
303 path=(const char *) GetNextKeyInSplayTree(temporary_resources);
304 }
305}
306
307/*
308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309% %
310% %
311% %
312% 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 %
313% %
314% %
315% %
316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317%
318% AcquireUniqueFileResource() returns a unique file name, and returns a file
319% descriptor for the file open for reading and writing.
320%
321% The format of the AcquireUniqueFileResource() method is:
322%
323% int AcquireUniqueFileResource(char *path)
324%
325% A description of each parameter follows:
326%
327% o path: Specifies a pointer to an array of characters. The unique path
328% name is returned in this array.
329%
330*/
331
332static void *DestroyTemporaryResources(void *temporary_resource)
333{
334 (void) remove((char *) temporary_resource);
cristycfbec6a2010-09-28 18:27:51 +0000335 temporary_resource=DestroyString((char *) temporary_resource);
cristy3ed852e2009-09-05 21:47:34 +0000336 return((void *) NULL);
337}
338
339static MagickBooleanType GetPathTemplate(char *path)
340{
341 char
342 *directory;
343
344 ExceptionInfo
345 *exception;
346
347 MagickBooleanType
348 status;
349
350 register char
351 *p;
352
353 struct stat
354 attributes;
355
356 (void) CopyMagickString(path,"magick-XXXXXXXX",MaxTextExtent);
357 exception=AcquireExceptionInfo();
358 directory=(char *) GetImageRegistry(StringRegistryType,"temporary-path",
359 exception);
360 exception=DestroyExceptionInfo(exception);
361 if (directory == (char *) NULL)
362 directory=GetEnvironmentValue("MAGICK_TEMPORARY_PATH");
363 if (directory == (char *) NULL)
364 directory=GetEnvironmentValue("MAGICK_TMPDIR");
365 if (directory == (char *) NULL)
366 directory=GetPolicyValue("temporary-path");
367 if (directory == (char *) NULL)
368 directory=GetEnvironmentValue("TMPDIR");
cristy0157aea2010-04-24 21:12:18 +0000369#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__)
cristy3ed852e2009-09-05 21:47:34 +0000370 if (directory == (char *) NULL)
371 directory=GetEnvironmentValue("TMP");
372 if (directory == (char *) NULL)
373 directory=GetEnvironmentValue("TEMP");
374#endif
375#if defined(__VMS)
376 if (directory == (char *) NULL)
377 directory=GetEnvironmentValue("MTMPDIR");
378#endif
379#if defined(P_tmpdir)
380 if (directory == (char *) NULL)
381 directory=ConstantString(P_tmpdir);
382#endif
383 if (directory == (char *) NULL)
384 return(MagickTrue);
385 if (strlen(directory) > (MaxTextExtent-15))
386 {
387 directory=DestroyString(directory);
388 return(MagickTrue);
389 }
390 status=GetPathAttributes(directory,&attributes);
391 if ((status == MagickFalse) || !S_ISDIR(attributes.st_mode))
392 {
393 directory=DestroyString(directory);
394 return(MagickTrue);
395 }
396 if (directory[strlen(directory)-1] == *DirectorySeparator)
397 (void) FormatMagickString(path,MaxTextExtent,"%smagick-XXXXXXXX",directory);
398 else
399 (void) FormatMagickString(path,MaxTextExtent,"%s%smagick-XXXXXXXX",
400 directory,DirectorySeparator);
401 directory=DestroyString(directory);
402 if (*DirectorySeparator != '/')
403 for (p=path; *p != '\0'; p++)
404 if (*p == *DirectorySeparator)
405 *p='/';
406 return(MagickTrue);
407}
408
409MagickExport int AcquireUniqueFileResource(char *path)
410{
411#if !defined(O_NOFOLLOW)
412#define O_NOFOLLOW 0
413#endif
414#if !defined(TMP_MAX)
415# define TMP_MAX 238328
416#endif
417
cristy3ed852e2009-09-05 21:47:34 +0000418 int
419 c,
420 file;
421
422 register char
423 *p;
424
cristybb503372010-05-27 20:51:26 +0000425 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000426 i;
427
428 static const char
429 portable_filename[65] =
430 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
431
432 StringInfo
433 *key;
434
435 unsigned char
436 *datum;
437
438 assert(path != (char *) NULL);
439 (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
440 if (random_info == (RandomInfo *) NULL)
441 random_info=AcquireRandomInfo();
442 file=(-1);
cristycee97112010-05-28 00:44:52 +0000443 for (i=0; i < (ssize_t) TMP_MAX; i++)
cristy3ed852e2009-09-05 21:47:34 +0000444 {
445 /*
446 Get temporary pathname.
447 */
448 (void) GetPathTemplate(path);
449#if defined(MAGICKCORE_HAVE_MKSTEMP)
450 file=mkstemp(path);
451#if defined(__OS2__)
452 setmode(file,O_BINARY);
453#endif
454 if (file != -1)
455 break;
456#endif
457 key=GetRandomKey(random_info,8);
458 p=path+strlen(path)-8;
459 datum=GetStringInfoDatum(key);
460 for (i=0; i < 8; i++)
461 {
462 c=(int) (datum[i] & 0x3f);
463 *p++=portable_filename[c];
464 }
465 key=DestroyStringInfo(key);
466 file=open(path,O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_NOFOLLOW,S_MODE);
467 if ((file > 0) || (errno != EEXIST))
468 break;
469 }
470 (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
471 if (file == -1)
472 return(file);
cristy18b17442009-10-25 18:36:48 +0000473 if (resource_semaphore == (SemaphoreInfo *) NULL)
474 AcquireSemaphoreInfo(&resource_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000475 LockSemaphoreInfo(resource_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000476 if (temporary_resources == (SplayTreeInfo *) NULL)
477 temporary_resources=NewSplayTree(CompareSplayTreeString,
cristyf77fa462010-09-28 18:35:53 +0000478 DestroyTemporaryResources,(void *(*)(void *)) NULL);
cristyf84a1932010-01-03 18:00:18 +0000479 UnlockSemaphoreInfo(resource_semaphore);
cristycfbec6a2010-09-28 18:27:51 +0000480 (void) AddValueToSplayTree(temporary_resources,ConstantString(path),
cristyf77fa462010-09-28 18:35:53 +0000481 (const void *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000482 return(file);
483}
484
485/*
486%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
487% %
488% %
489% %
cristy3ed852e2009-09-05 21:47:34 +0000490% G e t M a g i c k R e s o u r c e %
491% %
492% %
493% %
494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
495%
496% GetMagickResource() returns the specified resource.
497%
498% The format of the GetMagickResource() method is:
499%
500% MagickSizeType GetMagickResource(const ResourceType type)
501%
502% A description of each parameter follows:
503%
504% o type: the type of resource.
505%
506*/
507MagickExport MagickSizeType GetMagickResource(const ResourceType type)
508{
509 MagickSizeType
510 resource;
511
512 resource=0;
cristyf84a1932010-01-03 18:00:18 +0000513 LockSemaphoreInfo(resource_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000514 switch (type)
515 {
516 case AreaResource:
517 {
518 resource=(MagickSizeType) resource_info.area;
519 break;
520 }
521 case MemoryResource:
522 {
523 resource=(MagickSizeType) resource_info.memory;
524 break;
525 }
526 case MapResource:
527 {
528 resource=(MagickSizeType) resource_info.map;
529 break;
530 }
531 case DiskResource:
532 {
533 resource=(MagickSizeType) resource_info.disk;
534 break;
535 }
536 case FileResource:
537 {
538 resource=(MagickSizeType) resource_info.file;
539 break;
540 }
541 case ThreadResource:
542 {
543 resource=(MagickSizeType) resource_info.thread;
544 break;
545 }
546 case TimeResource:
547 {
548 resource=(MagickSizeType) resource_info.time;
549 break;
550 }
551 default:
552 break;
553 }
cristyf84a1932010-01-03 18:00:18 +0000554 UnlockSemaphoreInfo(resource_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000555 return(resource);
556}
557
558/*
559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560% %
561% %
562% %
563% G e t M a g i c k R e s o u r c e L i m i t %
564% %
565% %
566% %
567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
568%
569% GetMagickResource() returns the specified resource limit.
570%
571% The format of the GetMagickResourceLimit() method is:
572%
cristy50a10922010-02-15 18:35:25 +0000573% MagickSizeType GetMagickResourceLimit(const ResourceType type)
cristy3ed852e2009-09-05 21:47:34 +0000574%
575% A description of each parameter follows:
576%
577% o type: the type of resource.
578%
579*/
580MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
581{
582 MagickSizeType
583 resource;
584
585 resource=0;
cristy18b17442009-10-25 18:36:48 +0000586 if (resource_semaphore == (SemaphoreInfo *) NULL)
587 AcquireSemaphoreInfo(&resource_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000588 LockSemaphoreInfo(resource_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000589 switch (type)
590 {
591 case AreaResource:
592 {
593 resource=resource_info.area_limit;
594 break;
595 }
596 case MemoryResource:
597 {
598 resource=resource_info.memory_limit;
599 break;
600 }
601 case MapResource:
602 {
603 resource=resource_info.map_limit;
604 break;
605 }
606 case DiskResource:
607 {
608 resource=resource_info.disk_limit;
609 break;
610 }
611 case FileResource:
612 {
613 resource=resource_info.file_limit;
614 break;
615 }
616 case ThreadResource:
617 {
618 resource=resource_info.thread_limit;
619 break;
620 }
621 case TimeResource:
622 {
623 resource=resource_info.time_limit;
624 break;
625 }
626 default:
627 break;
628 }
cristyf84a1932010-01-03 18:00:18 +0000629 UnlockSemaphoreInfo(resource_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000630 return(resource);
631}
632
633/*
634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
635% %
636% %
637% %
cristy3ed852e2009-09-05 21:47:34 +0000638% L i s t M a g i c k R e s o u r c e I n f o %
639% %
640% %
641% %
642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
643%
644% ListMagickResourceInfo() lists the resource info to a file.
645%
646% The format of the ListMagickResourceInfo method is:
647%
648% MagickBooleanType ListMagickResourceInfo(FILE *file,
649% ExceptionInfo *exception)
650%
651% A description of each parameter follows.
652%
653% o file: An pointer to a FILE.
654%
655% o exception: return any errors or warnings in this structure.
656%
657*/
658MagickExport MagickBooleanType ListMagickResourceInfo(FILE *file,
659 ExceptionInfo *magick_unused(exception))
660{
661 char
662 area_limit[MaxTextExtent],
663 disk_limit[MaxTextExtent],
664 map_limit[MaxTextExtent],
665 memory_limit[MaxTextExtent],
666 time_limit[MaxTextExtent];
667
668 if (file == (const FILE *) NULL)
669 file=stdout;
cristy18b17442009-10-25 18:36:48 +0000670 if (resource_semaphore == (SemaphoreInfo *) NULL)
671 AcquireSemaphoreInfo(&resource_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000672 LockSemaphoreInfo(resource_semaphore);
cristyb9080c92009-12-01 20:13:26 +0000673 (void) FormatMagickSize(resource_info.area_limit,MagickFalse,area_limit);
674 (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,memory_limit);
675 (void) FormatMagickSize(resource_info.map_limit,MagickTrue,map_limit);
cristy9bfdd582010-10-23 01:27:25 +0000676 (void) CopyMagickString(disk_limit,"unlimited",MaxTextExtent);
677 if (resource_info.disk_limit != MagickResourceInfinity)
678 (void) FormatMagickSize(resource_info.disk_limit,MagickFalse,disk_limit);
cristy3ed852e2009-09-05 21:47:34 +0000679 (void) CopyMagickString(time_limit,"unlimited",MaxTextExtent);
680 if (resource_info.time_limit != MagickResourceInfinity)
cristye8c25f92010-06-03 00:53:06 +0000681 (void) FormatMagickString(time_limit,MaxTextExtent,"%.20g",(double)
cristy3ed852e2009-09-05 21:47:34 +0000682 resource_info.time_limit);
cristyb9080c92009-12-01 20:13:26 +0000683 (void) fprintf(file,"File Area Memory Map"
cristyf0bfc582009-12-05 15:09:34 +0000684 " Disk Thread Time\n");
685 (void) fprintf(file,"--------------------------------------------------------"
cristyb9080c92009-12-01 20:13:26 +0000686 "-----------------------\n");
cristy9bfdd582010-10-23 01:27:25 +0000687 (void) fprintf(file,"%4g %10s %10s %10s %10s %6g %11s\n",(double)
cristye8c25f92010-06-03 00:53:06 +0000688 resource_info.file_limit,area_limit,memory_limit,map_limit,disk_limit,
689 (double) resource_info.thread_limit,time_limit);
cristy3ed852e2009-09-05 21:47:34 +0000690 (void) fflush(file);
cristyf84a1932010-01-03 18:00:18 +0000691 UnlockSemaphoreInfo(resource_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000692 return(MagickTrue);
693}
694
695/*
696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
697% %
698% %
699% %
700% R e l i n q u i s h M a g i c k R e s o u r c e %
701% %
702% %
703% %
704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
705%
706% RelinquishMagickResource() relinquishes resources of the specified type.
707%
708% The format of the RelinquishMagickResource() method is:
709%
710% void RelinquishMagickResource(const ResourceType type,
711% const MagickSizeType size)
712%
713% A description of each parameter follows:
714%
715% o type: the type of resource.
716%
717% o size: the size of the resource.
718%
719*/
720MagickExport void RelinquishMagickResource(const ResourceType type,
721 const MagickSizeType size)
722{
723 char
724 resource_current[MaxTextExtent],
725 resource_limit[MaxTextExtent],
726 resource_request[MaxTextExtent];
727
cristyb9080c92009-12-01 20:13:26 +0000728 (void) FormatMagickSize(size,MagickFalse,resource_request);
cristy18b17442009-10-25 18:36:48 +0000729 if (resource_semaphore == (SemaphoreInfo *) NULL)
730 AcquireSemaphoreInfo(&resource_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000731 LockSemaphoreInfo(resource_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000732 switch (type)
733 {
734 case AreaResource:
735 {
736 resource_info.area=(MagickOffsetType) size;
cristyb9080c92009-12-01 20:13:26 +0000737 (void) FormatMagickSize((MagickSizeType) resource_info.area,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000738 resource_current);
cristyb9080c92009-12-01 20:13:26 +0000739 (void) FormatMagickSize(resource_info.area_limit,MagickFalse,
740 resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000741 break;
742 }
743 case MemoryResource:
744 {
745 resource_info.memory-=size;
746 (void) FormatMagickSize((MagickSizeType) resource_info.memory,
cristyb9080c92009-12-01 20:13:26 +0000747 MagickTrue,resource_current);
748 (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,
749 resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000750 break;
751 }
752 case MapResource:
753 {
754 resource_info.map-=size;
cristyb9080c92009-12-01 20:13:26 +0000755 (void) FormatMagickSize((MagickSizeType) resource_info.map,MagickTrue,
cristy3ed852e2009-09-05 21:47:34 +0000756 resource_current);
cristyb9080c92009-12-01 20:13:26 +0000757 (void) FormatMagickSize(resource_info.map_limit,MagickTrue,
758 resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000759 break;
760 }
761 case DiskResource:
762 {
763 resource_info.disk-=size;
cristyb9080c92009-12-01 20:13:26 +0000764 (void) FormatMagickSize((MagickSizeType) resource_info.disk,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000765 resource_current);
cristyb9080c92009-12-01 20:13:26 +0000766 (void) FormatMagickSize(resource_info.disk_limit,MagickFalse,
767 resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000768 break;
769 }
770 case FileResource:
771 {
772 resource_info.file-=size;
cristyb9080c92009-12-01 20:13:26 +0000773 (void) FormatMagickSize((MagickSizeType) resource_info.file,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000774 resource_current);
775 (void) FormatMagickSize((MagickSizeType) resource_info.file_limit,
cristyb9080c92009-12-01 20:13:26 +0000776 MagickFalse,resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000777 break;
778 }
779 case ThreadResource:
780 {
781 resource_info.thread-=size;
cristyb9080c92009-12-01 20:13:26 +0000782 (void) FormatMagickSize((MagickSizeType) resource_info.thread,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000783 resource_current);
784 (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
cristyb9080c92009-12-01 20:13:26 +0000785 MagickFalse,resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000786 break;
787 }
788 case TimeResource:
789 {
790 resource_info.time-=size;
cristyb9080c92009-12-01 20:13:26 +0000791 (void) FormatMagickSize((MagickSizeType) resource_info.time,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000792 resource_current);
793 (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
cristyb9080c92009-12-01 20:13:26 +0000794 MagickFalse,resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000795 break;
796 }
797 default:
798 break;
799 }
cristyf84a1932010-01-03 18:00:18 +0000800 UnlockSemaphoreInfo(resource_semaphore);
cristy9bfdd582010-10-23 01:27:25 +0000801 (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
cristya21afde2010-07-02 00:45:40 +0000802 MagickOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
803 resource_request,resource_current,resource_limit);
cristy3ed852e2009-09-05 21:47:34 +0000804}
805
806/*
807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
808% %
809% %
810% %
811% 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 %
812% %
813% %
814% %
815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
816%
817% RelinquishUniqueFileResource() relinquishes a unique file resource.
818%
819% The format of the RelinquishUniqueFileResource() method is:
820%
821% MagickBooleanType RelinquishUniqueFileResource(const char *path)
822%
823% A description of each parameter follows:
824%
825% o name: the name of the temporary resource.
826%
827*/
828MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
829{
830 char
831 cache_path[MaxTextExtent];
832
833 assert(path != (const char *) NULL);
834 (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
835 if (temporary_resources != (SplayTreeInfo *) NULL)
836 {
837 register char
838 *p;
839
840 ResetSplayTreeIterator(temporary_resources);
841 p=(char *) GetNextKeyInSplayTree(temporary_resources);
842 while (p != (char *) NULL)
843 {
844 if (LocaleCompare(p,path) == 0)
845 break;
846 p=(char *) GetNextKeyInSplayTree(temporary_resources);
847 }
848 if (p != (char *) NULL)
849 (void) DeleteNodeFromSplayTree(temporary_resources,p);
850 }
851 (void) CopyMagickString(cache_path,path,MaxTextExtent);
852 AppendImageFormat("cache",cache_path);
853 (void) remove(cache_path);
854 return(remove(path) == 0 ? MagickTrue : MagickFalse);
855}
856
857/*
858%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
859% %
860% %
861% %
cristyf34a1452009-10-24 22:29:27 +0000862+ R e s o u r c e C o m p o n e n t G e n e s i s %
863% %
864% %
865% %
866%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867%
868% ResourceComponentGenesis() instantiates the resource component.
869%
870% The format of the ResourceComponentGenesis method is:
871%
872% MagickBooleanType ResourceComponentGenesis(void)
873%
874*/
875
cristybb503372010-05-27 20:51:26 +0000876static inline size_t MagickMax(const size_t x,
877 const size_t y)
cristyf34a1452009-10-24 22:29:27 +0000878{
879 if (x > y)
880 return(x);
881 return(y);
882}
883
884static inline MagickSizeType StringToSizeType(const char *string,
885 const double interval)
886{
887 double
888 value;
889
cristyf2f27272009-12-17 14:48:46 +0000890 value=SiPrefixToDouble(string,interval);
cristyf34a1452009-10-24 22:29:27 +0000891 if (value >= (double) MagickULLConstant(~0))
892 return(MagickULLConstant(~0));
893 return((MagickSizeType) value);
894}
895
896MagickExport MagickBooleanType ResourceComponentGenesis(void)
897{
898 char
899 *limit;
900
cristybb503372010-05-27 20:51:26 +0000901 ssize_t
cristyf34a1452009-10-24 22:29:27 +0000902 files,
903 pages,
904 pagesize;
905
906 MagickSizeType
907 memory;
908
909 /*
910 Set Magick resource limits.
911 */
cristy165b6092009-10-26 13:52:10 +0000912 AcquireSemaphoreInfo(&resource_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000913 pagesize=GetMagickPageSize();
914 pages=(-1);
915#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
cristycee97112010-05-28 00:44:52 +0000916 pages=(ssize_t) sysconf(_SC_PHYS_PAGES);
cristyf34a1452009-10-24 22:29:27 +0000917#endif
918 memory=(MagickSizeType) pages*pagesize;
919 if ((pagesize <= 0) || (pages <= 0))
920 memory=2048UL*1024UL*1024UL;
921#if defined(PixelCacheThreshold)
922 memory=PixelCacheThreshold;
923#endif
cristyb0a27eb2010-10-23 23:34:32 +0000924 (void) SetMagickResourceLimit(AreaResource,memory/sizeof(PixelPacket));
925 (void) SetMagickResourceLimit(MemoryResource,memory);
926 (void) SetMagickResourceLimit(MapResource,2*memory);
cristyf34a1452009-10-24 22:29:27 +0000927 limit=GetEnvironmentValue("MAGICK_AREA_LIMIT");
928 if (limit == (char *) NULL)
929 limit=GetPolicyValue("area");
930 if (limit != (char *) NULL)
931 {
932 (void) SetMagickResourceLimit(AreaResource,StringToSizeType(limit,100.0));
933 limit=DestroyString(limit);
934 }
935 limit=GetEnvironmentValue("MAGICK_MEMORY_LIMIT");
936 if (limit == (char *) NULL)
937 limit=GetPolicyValue("memory");
938 if (limit != (char *) NULL)
939 {
940 (void) SetMagickResourceLimit(MemoryResource,
941 StringToSizeType(limit,100.0));
942 limit=DestroyString(limit);
943 }
944 limit=GetEnvironmentValue("MAGICK_MAP_LIMIT");
945 if (limit == (char *) NULL)
946 limit=GetPolicyValue("map");
947 if (limit != (char *) NULL)
948 {
949 (void) SetMagickResourceLimit(MapResource,StringToSizeType(limit,100.0));
950 limit=DestroyString(limit);
951 }
952 limit=GetEnvironmentValue("MAGICK_DISK_LIMIT");
953 if (limit == (char *) NULL)
954 limit=GetPolicyValue("disk");
955 if (limit != (char *) NULL)
956 {
957 (void) SetMagickResourceLimit(DiskResource,StringToSizeType(limit,100.0));
958 limit=DestroyString(limit);
959 }
960 files=(-1);
961#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
cristycee97112010-05-28 00:44:52 +0000962 files=(ssize_t) sysconf(_SC_OPEN_MAX);
cristyf34a1452009-10-24 22:29:27 +0000963#endif
964#if defined(MAGICKCORE_HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
965 if (files < 0)
966 {
967 struct rlimit
968 resources;
969
970 if (getrlimit(RLIMIT_NOFILE,&resources) != -1)
cristybb503372010-05-27 20:51:26 +0000971 files=(ssize_t) resources.rlim_cur;
cristyf34a1452009-10-24 22:29:27 +0000972 }
973#endif
974#if defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
975 if (files < 0)
cristy6d0ee3e2010-09-28 18:36:50 +0000976 files=(ssize_t) getdtablesize();
cristyf34a1452009-10-24 22:29:27 +0000977#endif
978 if (files < 0)
979 files=64;
cristybb503372010-05-27 20:51:26 +0000980 (void) SetMagickResourceLimit(FileResource,MagickMax((size_t)
cristyf34a1452009-10-24 22:29:27 +0000981 (3*files/4),64));
982 limit=GetEnvironmentValue("MAGICK_FILE_LIMIT");
983 if (limit == (char *) NULL)
984 limit=GetPolicyValue("file");
985 if (limit != (char *) NULL)
986 {
987 (void) SetMagickResourceLimit(FileResource,StringToSizeType(limit,100.0));
988 limit=DestroyString(limit);
989 }
990 (void) SetMagickResourceLimit(ThreadResource,GetOpenMPMaximumThreads());
991 limit=GetEnvironmentValue("MAGICK_THREAD_LIMIT");
992 if (limit == (char *) NULL)
993 limit=GetPolicyValue("thread");
994 if (limit != (char *) NULL)
995 {
cristyd99b0962010-05-29 23:14:26 +0000996 SetOpenMPMaximumThreads((int) StringToUnsignedLong(limit));
cristyf34a1452009-10-24 22:29:27 +0000997 (void) SetMagickResourceLimit(ThreadResource,StringToSizeType(limit,
998 100.0));
999 limit=DestroyString(limit);
1000 }
1001 limit=GetEnvironmentValue("MAGICK_TIME_LIMIT");
1002 if (limit == (char *) NULL)
1003 limit=GetPolicyValue("time");
1004 if (limit != (char *) NULL)
1005 {
1006 (void) SetMagickResourceLimit(TimeResource,StringToSizeType(limit,100.0));
1007 limit=DestroyString(limit);
1008 }
1009 return(MagickTrue);
1010}
1011
1012/*
1013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1014% %
1015% %
1016% %
1017+ 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 %
1018% %
1019% %
1020% %
1021%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1022%
1023% ResourceComponentTerminus() destroys the resource component.
1024%
1025% The format of the ResourceComponentTerminus() method is:
1026%
1027% ResourceComponentTerminus(void)
1028%
1029*/
1030MagickExport void ResourceComponentTerminus(void)
1031{
cristy18b17442009-10-25 18:36:48 +00001032 if (resource_semaphore == (SemaphoreInfo *) NULL)
1033 AcquireSemaphoreInfo(&resource_semaphore);
cristyf84a1932010-01-03 18:00:18 +00001034 LockSemaphoreInfo(resource_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001035 if (temporary_resources != (SplayTreeInfo *) NULL)
1036 temporary_resources=DestroySplayTree(temporary_resources);
1037 if (random_info != (RandomInfo *) NULL)
1038 random_info=DestroyRandomInfo(random_info);
cristyf84a1932010-01-03 18:00:18 +00001039 UnlockSemaphoreInfo(resource_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001040 DestroySemaphoreInfo(&resource_semaphore);
1041}
1042
1043/*
1044%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1045% %
1046% %
1047% %
cristy3ed852e2009-09-05 21:47:34 +00001048% S e t M a g i c k R e s o u r c e L i m i t %
1049% %
1050% %
1051% %
1052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053%
1054% SetMagickResourceLimit() sets the limit for a particular resource.
1055%
1056% The format of the SetMagickResourceLimit() method is:
1057%
1058% MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1059% const MagickSizeType limit)
1060%
1061% A description of each parameter follows:
1062%
1063% o type: the type of resource.
1064%
1065% o limit: the maximum limit for the resource.
1066%
1067*/
1068MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1069 const MagickSizeType limit)
1070{
cristy18b17442009-10-25 18:36:48 +00001071 if (resource_semaphore == (SemaphoreInfo *) NULL)
1072 AcquireSemaphoreInfo(&resource_semaphore);
cristyf84a1932010-01-03 18:00:18 +00001073 LockSemaphoreInfo(resource_semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001074 switch (type)
1075 {
1076 case AreaResource:
1077 {
1078 resource_info.area_limit=limit;
1079 break;
1080 }
1081 case MemoryResource:
1082 {
1083 resource_info.memory_limit=limit;
1084 break;
1085 }
1086 case MapResource:
1087 {
1088 resource_info.map_limit=limit;
1089 break;
1090 }
1091 case DiskResource:
1092 {
1093 resource_info.disk_limit=limit;
1094 break;
1095 }
1096 case FileResource:
1097 {
1098 resource_info.file_limit=limit;
1099 break;
1100 }
1101 case ThreadResource:
1102 {
cristyd99b0962010-05-29 23:14:26 +00001103 SetOpenMPMaximumThreads((int) limit);
cristy01e36dc2010-10-21 17:26:42 +00001104 resource_info.thread_limit=limit;
cristy3ed852e2009-09-05 21:47:34 +00001105 break;
1106 }
1107 case TimeResource:
1108 {
1109 resource_info.time_limit=limit;
1110 break;
1111 }
1112 default:
1113 break;
1114 }
cristyf84a1932010-01-03 18:00:18 +00001115 UnlockSemaphoreInfo(resource_semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001116 return(MagickTrue);
1117}