1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7 #include <nxt_main.h>
8
9
10 static nxt_log_moderation_t nxt_malloc_log_moderation = {
11 NXT_LOG_ALERT, 2, "memory allocation failed", NXT_LOG_MODERATION
12 };
13
14
15 static nxt_log_t *
nxt_malloc_log(void)16 nxt_malloc_log(void)
17 {
18 nxt_thread_t *thr;
19
20 thr = nxt_thread();
21
22 if (thr != NULL && thr->log != NULL) {
23 return thr->log;
24 }
25
26 return &nxt_main_log;
27 }
28
29
30 void *
nxt_malloc(size_t size)31 nxt_malloc(size_t size)
32 {
33 void *p;
34
35 p = malloc(size);
36
37 if (nxt_fast_path(p != NULL)) {
38 nxt_log_debug(nxt_malloc_log(), "malloc(%uz): %p", size, p);
39
40 } else {
41 nxt_log_alert_moderate(&nxt_malloc_log_moderation, nxt_malloc_log(),
42 "malloc(%uz) failed %E", size, nxt_errno);
43 }
44
45 return p;
46 }
47
48
49 void *
nxt_zalloc(size_t size)50 nxt_zalloc(size_t size)
51 {
52 void *p;
53
54 p = nxt_malloc(size);
55
56 if (nxt_fast_path(p != NULL)) {
57 nxt_memzero(p, size);
58 }
59
60 return p;
61 }
62
63
64 void *
nxt_realloc(void * p,size_t size)65 nxt_realloc(void *p, size_t size)
66 {
67 void *n;
68 uintptr_t ptr;
69
70 /*
71 * Workaround for a warning on GCC 12 about using "p" pointer in debug log
72 * after realloc().
73 */
74 ptr = (uintptr_t) p;
75
76 n = realloc(p, size);
77
78 if (nxt_fast_path(n != NULL)) {
79 nxt_log_debug(nxt_malloc_log(), "realloc(%p, %uz): %p", ptr, size, n);
80
81 } else {
82 nxt_log_alert_moderate(&nxt_malloc_log_moderation, nxt_malloc_log(),
83 "realloc(%p, %uz) failed %E",
84 ptr, size, nxt_errno);
85 }
86
87 return n;
88 }
89
90
91 /* nxt_lvlhsh_* functions moved here to avoid references from nxt_lvlhsh.c. */
92
93 void *
nxt_lvlhsh_alloc(void * data,size_t size)94 nxt_lvlhsh_alloc(void *data, size_t size)
95 {
96 return nxt_memalign(size, size);
97 }
98
99
100 void
nxt_lvlhsh_free(void * data,void * p)101 nxt_lvlhsh_free(void *data, void *p)
102 {
103 nxt_free(p);
104 }
105
106
107 #if (NXT_DEBUG)
108
109 void
nxt_free(void * p)110 nxt_free(void *p)
111 {
112 nxt_log_debug(nxt_malloc_log(), "free(%p)", p);
113
114 free(p);
115 }
116
117
118 #endif
119
120
121 #if (NXT_HAVE_POSIX_MEMALIGN)
122
123 /*
124 * posix_memalign() presents in Linux glibc 2.1.91, FreeBSD 7.0,
125 * Solaris 11, MacOSX 10.6 (Snow Leopard), NetBSD 5.0.
126 */
127
128 void *
nxt_memalign(size_t alignment,size_t size)129 nxt_memalign(size_t alignment, size_t size)
130 {
131 void *p;
132 nxt_err_t err;
133
134 err = posix_memalign(&p, alignment, size);
135
136 if (nxt_fast_path(err == 0)) {
137 nxt_thread_log_debug("posix_memalign(%uz, %uz): %p",
138 alignment, size, p);
139 return p;
140 }
141
142 nxt_log_alert_moderate(&nxt_malloc_log_moderation, nxt_malloc_log(),
143 "posix_memalign(%uz, %uz) failed %E",
144 alignment, size, err);
145 return NULL;
146 }
147
148 #elif (NXT_HAVE_MEMALIGN)
149
150 /* memalign() presents in Solaris, HP-UX. */
151
152 void *
nxt_memalign(size_t alignment,size_t size)153 nxt_memalign(size_t alignment, size_t size)
154 {
155 void *p;
156
157 p = memalign(alignment, size);
158
159 if (nxt_fast_path(p != NULL)) {
160 nxt_thread_log_debug("memalign(%uz, %uz): %p",
161 alignment, size, p);
162 return p;
163 }
164
165 nxt_log_alert_moderate(&nxt_malloc_log_moderation, nxt_malloc_log(),
166 "memalign(%uz, %uz) failed %E",
167 alignment, size, nxt_errno);
168 return NULL;
169 }
170
171 #elif (NXT_FREEBSD)
172
173 /*
174 * FreeBSD prior to 7.0 lacks posix_memalign(), but if a requested size
175 * is lesser than or equal to 4K, then phkmalloc aligns the size to the
176 * next highest power of 2 and allocates memory with the same alignment.
177 * Allocations larger than 2K are always aligned to 4K.
178 */
179
180 void *
nxt_memalign(size_t alignment,size_t size)181 nxt_memalign(size_t alignment, size_t size)
182 {
183 size_t aligned_size;
184 u_char *p;
185 nxt_err_t err;
186
187 if (nxt_slow_path((alignment - 1) & alignment) != 0) {
188 /* Alignment must be a power of 2. */
189 err = NXT_EINVAL;
190 goto fail;
191 }
192
193 if (nxt_slow_path(alignment > 4096)) {
194 err = NXT_EOPNOTSUPP;
195 goto fail;
196 }
197
198 if (nxt_fast_path(size <= 2048)) {
199 aligned_size = nxt_max(size, alignment);
200
201 } else {
202 /* Align to 4096. */
203 aligned_size = size;
204 }
205
206 p = malloc(aligned_size);
207
208 if (nxt_fast_path(p != NULL)) {
209 nxt_thread_log_debug("nxt_memalign(%uz, %uz): %p", alignment, size, p);
210
211 } else {
212 nxt_log_alert_moderate(&nxt_malloc_log_moderation, nxt_malloc_log(),
213 "malloc(%uz) failed %E", size, nxt_errno);
214 }
215
216 return p;
217
218 fail:
219
220 nxt_thread_log_alert("nxt_memalign(%uz, %uz) failed %E",
221 alignment, size, err);
222 return NULL;
223 }
224
225 #else
226
227 #error no memalign() implementation.
228
229 #endif
230