From f13cc8cde720db09e2820392e29bc3d7a5fd0f07 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Thu, 21 Jul 2022 11:12:34 +0000 Subject: apr_thread: Provide apr_threadattr_max_free_set(). When creating a thread, this allows to specify the "max_free" of its pool allocator (i.e. apr_allocator_max_free_set), so that one can create thread local subpools and have their memory usage regulated on cleanup/destroy. One could achieve that already with: apr_allocator_max_free_set(apr_thread_pool_get(thread), max_free); in the thread startup function, but it's more convenient, simpler and race free to handle that in the thread attribute itself at creation time. Merge r1902715 from trunk. git-svn-id: https://svn.apache.org/repos/asf/apr/apr/branches/1.8.x@1902908 13f79535-47bb-0310-9956-ffa450edef68 --- include/apr_thread_proc.h | 9 +++++++++ include/arch/beos/apr_arch_threadproc.h | 1 + include/arch/netware/apr_arch_threadproc.h | 1 + include/arch/os2/apr_arch_threadproc.h | 1 + include/arch/unix/apr_arch_threadproc.h | 1 + include/arch/win32/apr_arch_threadproc.h | 1 + threadproc/beos/thread.c | 22 ++++++++++++---------- threadproc/netware/thread.c | 22 ++++++++++++---------- threadproc/os2/thread.c | 22 ++++++++++++---------- threadproc/unix/thread.c | 22 ++++++++++++---------- threadproc/win32/thread.c | 22 ++++++++++++---------- 11 files changed, 74 insertions(+), 50 deletions(-) diff --git a/include/apr_thread_proc.h b/include/apr_thread_proc.h index fe5e3206e..d285861a4 100644 --- a/include/apr_thread_proc.h +++ b/include/apr_thread_proc.h @@ -277,6 +277,15 @@ APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr, APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, apr_size_t guardsize); +/** + * Set the threshold at which the thread pool allocator should start + * giving blocks back to the system. + * @param attr The threadattr to affect + * @param on Non-zero if detached threads should be created. + */ +APR_DECLARE(apr_status_t) apr_threadattr_max_free_set(apr_threadattr_t *attr, + apr_size_t size); + /** * Create a new thread of execution * @param new_thread The newly created thread handle. diff --git a/include/arch/beos/apr_arch_threadproc.h b/include/arch/beos/apr_arch_threadproc.h index b7db0a300..46a869eee 100644 --- a/include/arch/beos/apr_arch_threadproc.h +++ b/include/arch/beos/apr_arch_threadproc.h @@ -53,6 +53,7 @@ struct apr_threadattr_t { int32 attr; int detached; int joinable; + apr_size_t max_free; }; struct apr_threadkey_t { diff --git a/include/arch/netware/apr_arch_threadproc.h b/include/arch/netware/apr_arch_threadproc.h index ce217aaba..d726b34f7 100644 --- a/include/arch/netware/apr_arch_threadproc.h +++ b/include/arch/netware/apr_arch_threadproc.h @@ -44,6 +44,7 @@ struct apr_threadattr_t { apr_size_t stack_size; apr_int32_t detach; char *thread_name; + apr_size_t max_free; }; struct apr_threadkey_t { diff --git a/include/arch/os2/apr_arch_threadproc.h b/include/arch/os2/apr_arch_threadproc.h index c8017adbf..5e6b6a40d 100644 --- a/include/arch/os2/apr_arch_threadproc.h +++ b/include/arch/os2/apr_arch_threadproc.h @@ -29,6 +29,7 @@ struct apr_threadattr_t { apr_pool_t *pool; unsigned long attr; apr_size_t stacksize; + apr_size_t max_free; }; struct apr_thread_t { diff --git a/include/arch/unix/apr_arch_threadproc.h b/include/arch/unix/apr_arch_threadproc.h index adeb51c8a..c39aeaa8f 100644 --- a/include/arch/unix/apr_arch_threadproc.h +++ b/include/arch/unix/apr_arch_threadproc.h @@ -65,6 +65,7 @@ struct apr_thread_t { struct apr_threadattr_t { apr_pool_t *pool; pthread_attr_t attr; + apr_size_t max_free; }; struct apr_threadkey_t { diff --git a/include/arch/win32/apr_arch_threadproc.h b/include/arch/win32/apr_arch_threadproc.h index b39fdbbea..ea6556472 100644 --- a/include/arch/win32/apr_arch_threadproc.h +++ b/include/arch/win32/apr_arch_threadproc.h @@ -38,6 +38,7 @@ struct apr_threadattr_t { apr_pool_t *pool; apr_int32_t detach; apr_size_t stacksize; + apr_size_t max_free; }; struct apr_threadkey_t { diff --git a/threadproc/beos/thread.c b/threadproc/beos/thread.c index 39a5e366c..0ca7131da 100644 --- a/threadproc/beos/thread.c +++ b/threadproc/beos/thread.c @@ -62,6 +62,13 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, return APR_ENOTIMPL; } +APR_DECLARE(apr_status_t) apr_threadattr_max_free_set(apr_threadattr_t *attr, + apr_size_t size) +{ + attr->max_free = size; + return APR_SUCCESS; +} + #if APR_HAS_THREAD_LOCAL static APR_THREAD_LOCAL apr_thread_t *current_thread = NULL; #endif @@ -90,27 +97,22 @@ static apr_status_t alloc_thread(apr_thread_t **new, { apr_status_t stat; apr_abortfunc_t abort_fn = apr_pool_abort_get(pool); - apr_allocator_t *allocator; apr_pool_t *p; /* The thread can be detached anytime (from the creation or later with * apr_thread_detach), so it needs its own pool and allocator to not * depend on a parent pool which could be destroyed before the thread * exits. The allocator needs no mutex obviously since the pool should - * not be used nor create children pools outside the thread. + * not be used nor create children pools outside the thread. Passing + * NULL allocator will create one like that. */ - stat = apr_allocator_create(&allocator); + stat = apr_pool_create_unmanaged_ex(&p, abort_fn, NULL); if (stat != APR_SUCCESS) { - if (abort_fn) - abort_fn(stat); return stat; } - stat = apr_pool_create_unmanaged_ex(&p, abort_fn, allocator); - if (stat != APR_SUCCESS) { - apr_allocator_destroy(allocator); - return stat; + if (attr && attr->max_free) { + apr_allocator_max_free_set(apr_pool_allocator_get(p), attr->max_free); } - apr_allocator_owner_set(allocator, p); (*new) = (apr_thread_t *)apr_pcalloc(p, sizeof(apr_thread_t)); if ((*new) == NULL) { diff --git a/threadproc/netware/thread.c b/threadproc/netware/thread.c index fd74a9685..0672d4af6 100644 --- a/threadproc/netware/thread.c +++ b/threadproc/netware/thread.c @@ -64,6 +64,13 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, return APR_ENOTIMPL; } +APR_DECLARE(apr_status_t) apr_threadattr_max_free_set(apr_threadattr_t *attr, + apr_size_t size) +{ + attr->max_free = size; + return APR_SUCCESS; +} + #if APR_HAS_THREAD_LOCAL static APR_THREAD_LOCAL apr_thread_t *current_thread = NULL; #endif @@ -92,27 +99,22 @@ static apr_status_t alloc_thread(apr_thread_t **new, { apr_status_t stat; apr_abortfunc_t abort_fn = apr_pool_abort_get(pool); - apr_allocator_t *allocator; apr_pool_t *p; /* The thread can be detached anytime (from the creation or later with * apr_thread_detach), so it needs its own pool and allocator to not * depend on a parent pool which could be destroyed before the thread * exits. The allocator needs no mutex obviously since the pool should - * not be used nor create children pools outside the thread. + * not be used nor create children pools outside the thread. Passing + * NULL allocator will create one like that. */ - stat = apr_allocator_create(&allocator); + stat = apr_pool_create_unmanaged_ex(&p, abort_fn, NULL); if (stat != APR_SUCCESS) { - if (abort_fn) - abort_fn(stat); return stat; } - stat = apr_pool_create_unmanaged_ex(&p, abort_fn, allocator); - if (stat != APR_SUCCESS) { - apr_allocator_destroy(allocator); - return stat; + if (attr && attr->max_free) { + apr_allocator_max_free_set(apr_pool_allocator_get(p), attr->max_free); } - apr_allocator_owner_set(allocator, p); (*new) = (apr_thread_t *)apr_pcalloc(p, sizeof(apr_thread_t)); if ((*new) == NULL) { diff --git a/threadproc/os2/thread.c b/threadproc/os2/thread.c index 79b24f535..1f693950d 100644 --- a/threadproc/os2/thread.c +++ b/threadproc/os2/thread.c @@ -68,6 +68,13 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, return APR_ENOTIMPL; } +APR_DECLARE(apr_status_t) apr_threadattr_max_free_set(apr_threadattr_t *attr, + apr_size_t size) +{ + attr->max_free = size; + return APR_SUCCESS; +} + #if APR_HAS_THREAD_LOCAL static APR_THREAD_LOCAL apr_thread_t *current_thread = NULL; #endif @@ -94,27 +101,22 @@ static apr_status_t alloc_thread(apr_thread_t **new, { apr_status_t stat; apr_abortfunc_t abort_fn = apr_pool_abort_get(pool); - apr_allocator_t *allocator; apr_pool_t *p; /* The thread can be detached anytime (from the creation or later with * apr_thread_detach), so it needs its own pool and allocator to not * depend on a parent pool which could be destroyed before the thread * exits. The allocator needs no mutex obviously since the pool should - * not be used nor create children pools outside the thread. + * not be used nor create children pools outside the thread. Passing + * NULL allocator will create one like that. */ - stat = apr_allocator_create(&allocator); + stat = apr_pool_create_unmanaged_ex(&p, abort_fn, NULL); if (stat != APR_SUCCESS) { - if (abort_fn) - abort_fn(stat); return stat; } - stat = apr_pool_create_unmanaged_ex(&p, abort_fn, allocator); - if (stat != APR_SUCCESS) { - apr_allocator_destroy(allocator); - return stat; + if (attr && attr->max_free) { + apr_allocator_max_free_set(apr_pool_allocator_get(p), attr->max_free); } - apr_allocator_owner_set(allocator, p); (*new) = (apr_thread_t *)apr_pcalloc(p, sizeof(apr_thread_t)); if ((*new) == NULL) { diff --git a/threadproc/unix/thread.c b/threadproc/unix/thread.c index d84d5ef0d..5ec219e23 100644 --- a/threadproc/unix/thread.c +++ b/threadproc/unix/thread.c @@ -136,6 +136,13 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, #endif } +APR_DECLARE(apr_status_t) apr_threadattr_max_free_set(apr_threadattr_t *attr, + apr_size_t size) +{ + attr->max_free = size; + return APR_SUCCESS; +} + #if APR_HAS_THREAD_LOCAL static APR_THREAD_LOCAL apr_thread_t *current_thread = NULL; #endif @@ -164,27 +171,22 @@ static apr_status_t alloc_thread(apr_thread_t **new, { apr_status_t stat; apr_abortfunc_t abort_fn = apr_pool_abort_get(pool); - apr_allocator_t *allocator; apr_pool_t *p; /* The thread can be detached anytime (from the creation or later with * apr_thread_detach), so it needs its own pool and allocator to not * depend on a parent pool which could be destroyed before the thread * exits. The allocator needs no mutex obviously since the pool should - * not be used nor create children pools outside the thread. + * not be used nor create children pools outside the thread. Passing + * NULL allocator will create one like that. */ - stat = apr_allocator_create(&allocator); + stat = apr_pool_create_unmanaged_ex(&p, abort_fn, NULL); if (stat != APR_SUCCESS) { - if (abort_fn) - abort_fn(stat); return stat; } - stat = apr_pool_create_unmanaged_ex(&p, abort_fn, allocator); - if (stat != APR_SUCCESS) { - apr_allocator_destroy(allocator); - return stat; + if (attr && attr->max_free) { + apr_allocator_max_free_set(apr_pool_allocator_get(p), attr->max_free); } - apr_allocator_owner_set(allocator, p); (*new) = (apr_thread_t *)apr_pcalloc(p, sizeof(apr_thread_t)); if ((*new) == NULL) { diff --git a/threadproc/win32/thread.c b/threadproc/win32/thread.c index 19ba008aa..04b08b107 100644 --- a/threadproc/win32/thread.c +++ b/threadproc/win32/thread.c @@ -72,6 +72,13 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, return APR_ENOTIMPL; } +APR_DECLARE(apr_status_t) apr_threadattr_max_free_set(apr_threadattr_t *attr, + apr_size_t size) +{ + attr->max_free = size; + return APR_SUCCESS; +} + #if APR_HAS_THREAD_LOCAL static APR_THREAD_LOCAL apr_thread_t *current_thread = NULL; #endif @@ -101,27 +108,22 @@ static apr_status_t alloc_thread(apr_thread_t **new, { apr_status_t stat; apr_abortfunc_t abort_fn = apr_pool_abort_get(pool); - apr_allocator_t *allocator; apr_pool_t *p; /* The thread can be detached anytime (from the creation or later with * apr_thread_detach), so it needs its own pool and allocator to not * depend on a parent pool which could be destroyed before the thread * exits. The allocator needs no mutex obviously since the pool should - * not be used nor create children pools outside the thread. + * not be used nor create children pools outside the thread. Passing + * NULL allocator will create one like that. */ - stat = apr_allocator_create(&allocator); + stat = apr_pool_create_unmanaged_ex(&p, abort_fn, NULL); if (stat != APR_SUCCESS) { - if (abort_fn) - abort_fn(stat); return stat; } - stat = apr_pool_create_unmanaged_ex(&p, abort_fn, allocator); - if (stat != APR_SUCCESS) { - apr_allocator_destroy(allocator); - return stat; + if (attr && attr->max_free) { + apr_allocator_max_free_set(apr_pool_allocator_get(p), attr->max_free); } - apr_allocator_owner_set(allocator, p); (*new) = (apr_thread_t *)apr_pcalloc(p, sizeof(apr_thread_t)); if ((*new) == NULL) { -- cgit v1.2.1