1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 
11 
12 static ngx_inline void *ngx_palloc_small(ngx_pool_t *pool, size_t size,
13     ngx_uint_t align);
14 static void *ngx_palloc_block(ngx_pool_t *pool, size_t size);
15 static void *ngx_palloc_large(ngx_pool_t *pool, size_t size);
16 
17 
18 ngx_pool_t *
ngx_create_pool(size_t size,ngx_log_t * log)19 ngx_create_pool(size_t size, ngx_log_t *log)
20 {
21     ngx_pool_t  *p;
22 
23     p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
24     if (p == NULL) {
25         return NULL;
26     }
27 
28     p->d.last = (u_char *) p + sizeof(ngx_pool_t);
29     p->d.end = (u_char *) p + size;
30     p->d.next = NULL;
31     p->d.failed = 0;
32 
33     size = size - sizeof(ngx_pool_t);
34     p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
35 
36     p->current = p;
37     p->chain = NULL;
38     p->large = NULL;
39     p->cleanup = NULL;
40     p->log = log;
41 
42     return p;
43 }
44 
45 
46 void
ngx_destroy_pool(ngx_pool_t * pool)47 ngx_destroy_pool(ngx_pool_t *pool)
48 {
49     ngx_pool_t          *p, *n;
50     ngx_pool_large_t    *l;
51     ngx_pool_cleanup_t  *c;
52 
53     for (c = pool->cleanup; c; c = c->next) {
54         if (c->handler) {
55             ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
56                            "run cleanup: %p", c);
57             c->handler(c->data);
58         }
59     }
60 
61 #if (NGX_DEBUG)
62 
63     /*
64      * we could allocate the pool->log from this pool
65      * so we cannot use this log while free()ing the pool
66      */
67 
68     for (l = pool->large; l; l = l->next) {
69         ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);
70     }
71 
72     for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
73         ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
74                        "free: %p, unused: %uz", p, p->d.end - p->d.last);
75 
76         if (n == NULL) {
77             break;
78         }
79     }
80 
81 #endif
82 
83     for (l = pool->large; l; l = l->next) {
84         if (l->alloc) {
85             ngx_free(l->alloc);
86         }
87     }
88 
89     for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
90         ngx_free(p);
91 
92         if (n == NULL) {
93             break;
94         }
95     }
96 }
97 
98 
99 void
ngx_reset_pool(ngx_pool_t * pool)100 ngx_reset_pool(ngx_pool_t *pool)
101 {
102     ngx_pool_t        *p;
103     ngx_pool_large_t  *l;
104 
105     for (l = pool->large; l; l = l->next) {
106         if (l->alloc) {
107             ngx_free(l->alloc);
108         }
109     }
110 
111     for (p = pool; p; p = p->d.next) {
112         p->d.last = (u_char *) p + sizeof(ngx_pool_t);
113         p->d.failed = 0;
114     }
115 
116     pool->current = pool;
117     pool->chain = NULL;
118     pool->large = NULL;
119 }
120 
121 
122 void *
ngx_palloc(ngx_pool_t * pool,size_t size)123 ngx_palloc(ngx_pool_t *pool, size_t size)
124 {
125 #if !(NGX_DEBUG_PALLOC)
126     if (size <= pool->max) {
127         return ngx_palloc_small(pool, size, 1);
128     }
129 #endif
130 
131     return ngx_palloc_large(pool, size);
132 }
133 
134 
135 void *
ngx_pnalloc(ngx_pool_t * pool,size_t size)136 ngx_pnalloc(ngx_pool_t *pool, size_t size)
137 {
138 #if !(NGX_DEBUG_PALLOC)
139     if (size <= pool->max) {
140         return ngx_palloc_small(pool, size, 0);
141     }
142 #endif
143 
144     return ngx_palloc_large(pool, size);
145 }
146 
147 
148 static ngx_inline void *
ngx_palloc_small(ngx_pool_t * pool,size_t size,ngx_uint_t align)149 ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
150 {
151     u_char      *m;
152     ngx_pool_t  *p;
153 
154     p = pool->current;
155 
156     do {
157         m = p->d.last;
158 
159         if (align) {
160             m = ngx_align_ptr(m, NGX_ALIGNMENT);
161         }
162 
163         if ((size_t) (p->d.end - m) >= size) {
164             p->d.last = m + size;
165 
166             return m;
167         }
168 
169         p = p->d.next;
170 
171     } while (p);
172 
173     return ngx_palloc_block(pool, size);
174 }
175 
176 
177 static void *
ngx_palloc_block(ngx_pool_t * pool,size_t size)178 ngx_palloc_block(ngx_pool_t *pool, size_t size)
179 {
180     u_char      *m;
181     size_t       psize;
182     ngx_pool_t  *p, *new;
183 
184     psize = (size_t) (pool->d.end - (u_char *) pool);
185 
186     m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);
187     if (m == NULL) {
188         return NULL;
189     }
190 
191     new = (ngx_pool_t *) m;
192 
193     new->d.end = m + psize;
194     new->d.next = NULL;
195     new->d.failed = 0;
196 
197     m += sizeof(ngx_pool_data_t);
198     m = ngx_align_ptr(m, NGX_ALIGNMENT);
199     new->d.last = m + size;
200 
201     for (p = pool->current; p->d.next; p = p->d.next) {
202         if (p->d.failed++ > 4) {
203             pool->current = p->d.next;
204         }
205     }
206 
207     p->d.next = new;
208 
209     return m;
210 }
211 
212 
213 static void *
ngx_palloc_large(ngx_pool_t * pool,size_t size)214 ngx_palloc_large(ngx_pool_t *pool, size_t size)
215 {
216     void              *p;
217     ngx_uint_t         n;
218     ngx_pool_large_t  *large;
219 
220     p = ngx_alloc(size, pool->log);
221     if (p == NULL) {
222         return NULL;
223     }
224 
225     n = 0;
226 
227     for (large = pool->large; large; large = large->next) {
228         if (large->alloc == NULL) {
229             large->alloc = p;
230             return p;
231         }
232 
233         if (n++ > 3) {
234             break;
235         }
236     }
237 
238     large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
239     if (large == NULL) {
240         ngx_free(p);
241         return NULL;
242     }
243 
244     large->alloc = p;
245     large->next = pool->large;
246     pool->large = large;
247 
248     return p;
249 }
250 
251 
252 void *
ngx_pmemalign(ngx_pool_t * pool,size_t size,size_t alignment)253 ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment)
254 {
255     void              *p;
256     ngx_pool_large_t  *large;
257 
258     p = ngx_memalign(alignment, size, pool->log);
259     if (p == NULL) {
260         return NULL;
261     }
262 
263     large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
264     if (large == NULL) {
265         ngx_free(p);
266         return NULL;
267     }
268 
269     large->alloc = p;
270     large->next = pool->large;
271     pool->large = large;
272 
273     return p;
274 }
275 
276 
277 ngx_int_t
ngx_pfree(ngx_pool_t * pool,void * p)278 ngx_pfree(ngx_pool_t *pool, void *p)
279 {
280     ngx_pool_large_t  *l;
281 
282     for (l = pool->large; l; l = l->next) {
283         if (p == l->alloc) {
284             ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
285                            "free: %p", l->alloc);
286             ngx_free(l->alloc);
287             l->alloc = NULL;
288 
289             return NGX_OK;
290         }
291     }
292 
293     return NGX_DECLINED;
294 }
295 
296 
297 void *
ngx_pcalloc(ngx_pool_t * pool,size_t size)298 ngx_pcalloc(ngx_pool_t *pool, size_t size)
299 {
300     void *p;
301 
302     p = ngx_palloc(pool, size);
303     if (p) {
304         ngx_memzero(p, size);
305     }
306 
307     return p;
308 }
309 
310 
311 ngx_pool_cleanup_t *
ngx_pool_cleanup_add(ngx_pool_t * p,size_t size)312 ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
313 {
314     ngx_pool_cleanup_t  *c;
315 
316     c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));
317     if (c == NULL) {
318         return NULL;
319     }
320 
321     if (size) {
322         c->data = ngx_palloc(p, size);
323         if (c->data == NULL) {
324             return NULL;
325         }
326 
327     } else {
328         c->data = NULL;
329     }
330 
331     c->handler = NULL;
332     c->next = p->cleanup;
333 
334     p->cleanup = c;
335 
336     ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c);
337 
338     return c;
339 }
340 
341 
342 void
ngx_pool_run_cleanup_file(ngx_pool_t * p,ngx_fd_t fd)343 ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd)
344 {
345     ngx_pool_cleanup_t       *c;
346     ngx_pool_cleanup_file_t  *cf;
347 
348     for (c = p->cleanup; c; c = c->next) {
349         if (c->handler == ngx_pool_cleanup_file) {
350 
351             cf = c->data;
352 
353             if (cf->fd == fd) {
354                 c->handler(cf);
355                 c->handler = NULL;
356                 return;
357             }
358         }
359     }
360 }
361 
362 
363 void
ngx_pool_cleanup_file(void * data)364 ngx_pool_cleanup_file(void *data)
365 {
366     ngx_pool_cleanup_file_t  *c = data;
367 
368     ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d",
369                    c->fd);
370 
371     if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
372         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
373                       ngx_close_file_n " \"%s\" failed", c->name);
374     }
375 }
376 
377 
378 void
ngx_pool_delete_file(void * data)379 ngx_pool_delete_file(void *data)
380 {
381     ngx_pool_cleanup_file_t  *c = data;
382 
383     ngx_err_t  err;
384 
385     ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d %s",
386                    c->fd, c->name);
387 
388     if (ngx_delete_file(c->name) == NGX_FILE_ERROR) {
389         err = ngx_errno;
390 
391         if (err != NGX_ENOENT) {
392             ngx_log_error(NGX_LOG_CRIT, c->log, err,
393                           ngx_delete_file_n " \"%s\" failed", c->name);
394         }
395     }
396 
397     if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
398         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
399                       ngx_close_file_n " \"%s\" failed", c->name);
400     }
401 }
402 
403 
404 #if 0
405 
406 static void *
407 ngx_get_cached_block(size_t size)
408 {
409     void                     *p;
410     ngx_cached_block_slot_t  *slot;
411 
412     if (ngx_cycle->cache == NULL) {
413         return NULL;
414     }
415 
416     slot = &ngx_cycle->cache[(size + ngx_pagesize - 1) / ngx_pagesize];
417 
418     slot->tries++;
419 
420     if (slot->number) {
421         p = slot->block;
422         slot->block = slot->block->next;
423         slot->number--;
424         return p;
425     }
426 
427     return NULL;
428 }
429 
430 #endif
431