ngx_palloc.c revision e18a033b
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
12static ngx_inline void *ngx_palloc_small(ngx_pool_t *pool, size_t size,
13    ngx_uint_t align);
14static void *ngx_palloc_block(ngx_pool_t *pool, size_t size);
15static void *ngx_palloc_large(ngx_pool_t *pool, size_t size);
16
17
18ngx_pool_t *
19ngx_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
46void
47ngx_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
99void
100ngx_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
122void *
123ngx_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
135void *
136ngx_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
148static ngx_inline void *
149ngx_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
177static void *
178ngx_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
213static void *
214ngx_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
252void *
253ngx_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
277ngx_int_t
278ngx_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
297void *
298ngx_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
311ngx_pool_cleanup_t *
312ngx_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
342void
343ngx_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
363void
364ngx_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
378void
379ngx_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
406static void *
407ngx_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