Writing Apache Modules with Perl and C
By:   Lincoln Stein and Doug MacEachern
Published:   O'Reilly & Associates, Inc.  - March 1999

Copyright © 1999 by O'Reilly & Associates, Inc.


 


   Show Contents   Previous Page   Next Page

Chapter 10 - C API Reference Guide, Part I
Memory Management and Resource Pools

In this section...

Introduction
Memory and String Allocation Routines
Subpool Management
Getting Information About Pools

Introduction

   Show Contents   Go to Top   Previous Page   Next Page

If you've ever developed a moderately complex C-language program, you've struggled with memory management. It's not easy to manage memory in C: failing to deallocate a data structure when you're through with it gives rise to memory leaks, and conversely, disposing of the same data structure twice is likely to lead to a crash. It's one thing to have a small memory leak in your own program. Unless the leak is very severe, the program will probably finish execution and exit normally before memory becomes tight. However, it's quite another issue to have memory management problems in a network server, which is expected to run for weeks or months at a time. Even small leaks can add up over time, and a dangling pointer or a doubly deallocated block can make the whole server crash.

The Apache server developers were aware of the challenge of memory management, and so they devised a system to make life easier both for themselves and for module writers. Instead of managing memory directly, Apache module developers take the memory they need from one or more resource pools. An Apache pool structure keeps track of all module memory allocations and releases all allocated blocks automatically when the lifetime of the pool has ended.

Different pools have different lifetimes: one lasts for the lifetime of a child, one for the lifetime of a request, another for the module configuration phase, and so forth. However, the nicest feature about pools is that the programmer generally doesn't need to know a pool's lifetime. Apache passes the appropriate pool pointer to your callback functions during the various start-up, configuration, and request phases. Depending on the context, sometimes the pool is passed directly to your subroutine as an argument, and sometimes it is tucked away inside one of the other data structures needed by the subroutine, such as the request_rec or conn_rec structures.

Most memory management is performed within the various request phase handlers. In this case, the resource pool to draw from will be found inside the request_rec. Any resources associated with this pool will not be released until the very end of a request (after logging). This arrangement may not be suited to certain very specialized modules. For example, the mod_autoindex module needs to make many short-lived memory allocations while it is generating directory listings. In this case, modules can create subpools, which are private resource pools allocated from within the main resource pool. The module can allocate blocks from within its subpool and destroy the subpool when it's no longer needed. If a module screws up and forgets to deallocate its subpool, no permanent harm is done. The subpool is deleted when its parent resource pool is cleaned up at the end of the request.

Once a memory block is allocated from a pool, there is no easy way to deallocate it. Normally you will wait for the pool to expire naturally. However, if you have created a subpool to work with, you can delete the whole subpool (and all its contained memory blocks) in one fell swoop.

Memory and String Allocation Routines

   Show Contents   Go to Top   Previous Page   Next Page

All memory-handling API routines are defined in the include file include/alloc.h, which is brought in automatically when you include include/httpd.h. The routines for allocating and freeing blocks of pool memory are all named after the familiar C library functions with the prefix ap_p tacked onto the front.

void *ap_palloc (struct pool *p, int nbytes)

This function works just like using malloc(), but you don't have to worry about calling free() (in fact, you should not). The memory will be cleaned up for you when the pool reaches the end of its lifetime. You must pass the ap_palloc() function a pointer to a preallocated pool, such as the one recovered from the request record. In this example, we create a C string large enough to accommodate len characters (plus terminating byte):

char *string = (char*)ap_palloc(r->pool, len + 1);

If there is insufficient memory to satisfy your request, ap_palloc() will return null. You should check for this condition and take appropriate action.

void *ap_pcalloc (struct pool *p, int nbytes)

This works just like the standard calloc() function; it calls memset() to initialize the memory to a block of '\0' bytes. In this example, we create a hello_dir_config structure (defined elsewhere) that is initially cleared out:

hello_dir_config *cfg =
    (hello_dir_config*)ap_pcalloc(p, sizeof(hello_dir_config));

char *ap_pstrdup (struct pool *p, const char *s)

This function works like the standard strdup() function to duplicate a string, but the new string is allocated from the indicated pool:

char *copy = ap_pstrdup(r->pool, string);

char *ap_pstrndup (struct pool *p, const char *s, int n)

This is a version of ap_pstrdup(), but it only allocates and copies n bytes.

char *copy = ap_pstrndup(r->pool, string, len);

char *ap_pstrcat (struct pool *p,...)

This function is similar to the standard strcat() function, but it accepts a variable list of string arguments to join together, returning the result as a newly allocated character string. The list of strings must be NULL-terminated:

char *string = ap_pstrcat(r->pool, "<", html_tag, ">", NULL);

char *ap_psprintf (struct pool *p, const char *fmt, ...)

This function works like the standard sprintf(), but it is much safer than the standard version because it allocates the requested memory from the pool, rather than writing the string into a static buffer. (Standard sprintf() has recently triggered a number of CERT advisories for some popular pieces of Internet software.) Here is an example of the function's usage:

char *string = ap_psprintf(r->pool, "<%s>", html_tag);

char *ap_cpystrn (char *dest, const char *source, size_t maxlen)

While this function is not tied to a pool, we list it here with the other string manipulation functions. In this version of the standard strncpy() function, the destination string is always guaranteed to be NULL-terminated, even if the entire source string was not copied. Furthermore, the return value points to the terminating '\0' byte rather than to the beginning of the string, allowing you to check more easily for truncation. Another difference from the standard function call is that ap_cpystrn() does not null-fill the string, although this will be rarely noticed in practice.

result = ap_cpystrn(to, from, len);
if ((result - to) == len) {
  ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
               server_rec, "truncation during ap_cpystrn()");
}

int ap_snprintf (char *dest, size_t len, const char *fmt, ...)

We again list this string manipulation function here, although it is not directly tied to a pool. This is a version of the snprintf() function, which comes with some versions of the standard C library. Because snprintf() isn't available on all platforms, the Apache version provides portability.

char string[MAX_STR_LEN];
ap_snprintf(string, sizeof(string), "<%s>", html_tag);

Subpool Management

   Show Contents   Go to Top   Previous Page   Next Page

You will probably never need to manage your own subpools, since there should always be a pool available during the various phases that will be cleaned up when the time is right. However, if your module is allocating a considerable amount of memory, you may need tighter management over when pools are released. This you can do by allocating and destroying private subpools.

struct pool *ap_make_sub_pool (struct pool *p)

Given an existing pool, this call returns a subpool. You can then allocate blocks of memory from within the subpool using the routines described above. When the parent pool is released, your subpool will be destroyed along with it, or you can destroy the pool yourself using the routine described next. A new pool can also be created without a parent pool by passing in a NULL argument. In this case, such code will be completely responsible for destroying the new pool.

void ap_destroy_pool (pool *p)

This function destroys the pool or subpool along with all its contents. Once a pool has been destroyed, be careful not to use any pointers to memory blocks that were allocated from within it!

void ap_clear_pool (struct pool *p)

ap_clear_pool() destroys the contents of the pool but leaves the pool itself intact. The pool is returned to its initial, empty state and can be used to allocate new blocks.

   Show Contents   Go to Top   Previous Page   Next Page
Copyright © 1999 by O'Reilly & Associates, Inc.

HIVE: All information for read only. Please respect copyright!
Hosted by hive КГБ: Киевская городская библиотека