xref: /unit/src/nxt_malloc.c (revision 2072:9697718d7022)
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