c->next = p->cleanups;
p->cleanups = c;
}
注册过程非常简单,无非就是将函数的参数赋值给cleanup_t结构中的成员,同时将该结点插入到cleanup_t链表的首部。
apr_pool_cleanup_kill函数与apr_pool_cleanup_register相反,用于将指定的cleanup_t结构从链表中清除。
因此如果需要对一个内存池进行销毁清除操作,它所要做的事情就是遍历该内存池对应的cleanup_t结构,并调用plain_cleanup_fn函数,该功能有静态函数run_cleanups完成,其对应的代码如下:
static void run_cleanups(cleanup_t **cref){
cleanup_t *c = *cref;
while (c) {
*cref = c->next;
(*c->plain_cleanup_fn)((void *)c->data);
c = *cref;
}
}
2.4.5.2进程描述结构的释放
尽管关于APR进程的描述我们要到后面的部分才能详细讨论,不过在这部分,我们还是首先触及到该内容。APR中使用apr_proc_t数据结构来描述一个进程,同时使用apr_procattr_t结构来描述进程的属性。通常一个apr_proc_t对应系统中一个正在运行的进程。
由于Apache的几乎所有的内存都来自内存池,apr_proc_t结构的分配也毫不例外,比如下面的代码将从内存池p中分配apr_proc_t和apr_procattr_t结构:
apr_proc_t newproc;
apr_pool_t *p;
apr_procattr_t *attr;
rv = apr_pool_initialize();
rv = apr_pool_create(&p, NULL);
rv = apr_procattr_create(&attr, p);
问题是当内存池p被销毁的时候,newproc和attr的内存也将被销毁。系统应该如何处理与newproc对应的运行进程。Apache中支持五种处理策略,这五种策略封装在枚举类型apr_kill_conditions_e中:
typedef enum {
APR_KILL_NEVER, /**< process is never sent any signals */
APR_KILL_ALWAYS, /**< process is sent SIGKILL on apr_pool_t cleanup */
APR_KILL_AFTER_TIMEOUT, /**< SIGTERM, wait 3 seconds, SIGKILL */
APR_JUST_WAIT, /**< wait forever for the process to complete */
APR_KILL_ONLY_ONCE /**< send SIGTERM and then wait */
} apr_kill_conditions_e;
APR_KILL_NEVER:该策略意味着即使进程的描述结构apr_proc_t被释放销毁,该进程也不会退出,进程将忽略任何发送的关闭信号。
APR_KILL_ALWAYS:该策略意味着当进程的描述结构被销毁的时候,对应的进程必须退出,通知进程退出使用信号SIGKILL实现。
APR_KILL_AFTER_TIMEOUT:该策略意味着当描述结构被销毁的时候,进程必须退出,不过不是立即退出,而是等待3秒超时候再退出。
APR_JUST_WAIT:该策略意味着描述结构被销毁的时候,进城必须退出,但不是立即退出,而是持续等待,直到该进程完成为止。
APR_KILL_ONLY_ONCE:该策略意味着当结构被销毁的时候,只发送一个SIGTERM信号给进程,然后等待,不再发送信号。
现在我们回过头来看一下内存池中的subprocesses成员。该成员定义为process_chain类型:
struct process_chain {
/** The process ID */
apr_proc_t *proc;