Retry only for https protocol
[elinks.git] / src / util / memory.c
blob5c1a03d2d53822626fed7d024bb5f1c75c84a4b0
1 /** Memory allocation manager
2 * @file */
4 #ifndef _GNU_SOURCE
5 #define _GNU_SOURCE /* MREMAP_MAYMOVE */
6 #endif
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
12 #include <stdlib.h>
13 #include <sys/types.h>
14 #ifdef HAVE_MMAP
15 #include <sys/mman.h>
16 #endif
17 #include <unistd.h>
19 #include "elinks.h"
21 #include "util/error.h"
22 #include "util/memory.h"
25 #if !defined(DEBUG_MEMLEAK) && !defined(CONFIG_FASTMEM)
27 static int alloc_try = 0;
29 static int
30 patience(unsigned char *of)
32 ++alloc_try;
33 if (alloc_try < ALLOC_MAXTRIES) {
34 ERROR("Out of memory (%s returned NULL): retry #%d/%d, "
35 "I still exercise my patience and retry tirelessly.",
36 of, alloc_try, ALLOC_MAXTRIES);
37 sleep(ALLOC_DELAY);
38 return alloc_try;
41 #ifdef CRASH_IF_ALLOC_MAXTRIES
42 INTERNAL("Out of memory (%s returned NULL) after %d tries, "
43 "I give up. See ya on the other side.",
44 of, alloc_try);
45 #else
46 ERROR("Out of memory (%s returned NULL) after %d tries, "
47 "I give up and try to continue. Pray for me, please.",
48 of, alloc_try);
49 #endif
50 alloc_try = 0;
51 return 0;
54 void *
55 mem_alloc(size_t size)
57 if (size)
58 do {
59 void *p = malloc(size);
60 if (p) return p;
61 } while (patience("malloc"));
63 return NULL;
66 void *
67 mem_calloc(size_t count, size_t eltsize)
69 if (eltsize && count)
70 do {
71 void *p = calloc(count, eltsize);
72 if (p) return p;
73 } while (patience("calloc"));
75 return NULL;
78 void
79 mem_free(void *p)
81 if (!p) {
82 INTERNAL("mem_free(NULL)");
83 return;
85 free(p);
88 void *
89 mem_realloc(void *p, size_t size)
91 if (!p) return mem_alloc(size);
93 if (size)
94 do {
95 void *p2 = realloc(p, size);
96 if (p2) return p2;
97 } while (patience("realloc"));
98 else
99 mem_free(p);
101 return NULL;
104 #endif
107 /* TODO: Leak detector and the usual protection gear? patience()?
109 * We could just alias mem_mmap_* to mem_debug_* #if DEBUG_MEMLEAK, *WHEN* we are
110 * confident that the mmap() code is really bugless ;-). --pasky */
112 #ifdef HAVE_MMAP
114 static int page_size;
116 /** Round up to a full page.
117 * This tries to prevent useless reallocations, especially since they
118 * are quite expensive in the mremap()-less case. */
119 static size_t
120 round_size(size_t size)
122 #ifdef HAVE_SC_PAGE_SIZE
123 if (!page_size) page_size = sysconf(_SC_PAGE_SIZE);
124 #endif
125 if (page_size <= 0) page_size = 1;
126 return (size / page_size + 1) * page_size;
129 /** Some systems may not have MAP_ANON but MAP_ANONYMOUS instead. */
130 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
131 #define MAP_ANON MAP_ANONYMOUS
132 #endif
134 void *
135 mem_mmap_alloc(size_t size)
137 if (size) {
138 void *p = mmap(NULL, round_size(size), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
140 if (p != MAP_FAILED)
141 return p;
144 return NULL;
147 void
148 mem_mmap_free(void *p, size_t size)
150 if (!p) {
151 INTERNAL("mem_mmap_free(NULL)");
152 return;
155 munmap(p, round_size(size));
158 void *
159 mem_mmap_realloc(void *p, size_t old_size, size_t new_size)
161 if (!p) return mem_mmap_alloc(new_size);
163 if (round_size(old_size) == round_size(new_size))
164 return p;
166 if (new_size) {
167 #ifdef HAVE_MREMAP
168 void *p2 = mremap(p, round_size(old_size), round_size(new_size), MREMAP_MAYMOVE);
170 if (p2 != MAP_FAILED)
171 return p2;
172 #else
173 void *p2 = mem_mmap_alloc(new_size);
175 if (p2) {
176 memcpy(p2, p, MIN(old_size, new_size));
177 mem_mmap_free(p, old_size);
178 return p2;
180 #endif
181 } else {
182 mem_mmap_free(p, old_size);
185 return NULL;
188 #endif