stas 2004/01/31 02:06:59
Modified: lib/ModPerl WrapXS.pm
t/response/TestAPR pool.pm
xs typemap
xs/APR/Pool APR__Pool.h
xs/maps apr_functions.map
xs/tables/current/ModPerl FunctionTable.pm
. Changes
Log:
In order to make Apache-Test compatible with the rest of Perl testing
frameworks, we no longer chdir into t/, but run from the root of the
project (where t/ resides). A test needing to know where it's running
from (e.g. to read/write files/dirs on the filesystem), should do that
relative to the serverroot, documentroot and other server
configuration variables, available via
Apache::Test::vars('serverroot'), Apache::Test::vars('documentroot'),
etc.
Revision Changes Path
1.64 +4 -3 modperl-2.0/lib/ModPerl/WrapXS.pm
Index: WrapXS.pm
===================================================================
RCS file: /home/cvs/modperl-2.0/lib/ModPerl/WrapXS.pm,v
retrieving revision 1.63
retrieving revision 1.64
diff -u -u -r1.63 -r1.64
--- WrapXS.pm 17 Dec 2003 21:21:28 -0000 1.63
+++ WrapXS.pm 31 Jan 2004 10:06:59 -0000 1.64
@@ -524,9 +524,10 @@
my %typemap = (
'Apache::RequestRec' => 'T_APACHEOBJ',
- 'apr_time_t' => 'T_APR_TIME',
- 'APR::Table' => 'T_HASHOBJ',
- 'APR::OS::Thread' => 'T_UVOBJ',
+ 'apr_time_t' => 'T_APR_TIME',
+ 'APR::Table' => 'T_HASHOBJ',
+ 'APR::Pool' => 'T_POOLOBJ',
+ 'APR::OS::Thread' => 'T_UVOBJ',
);
sub write_typemap {
1.8 +175 -2 modperl-2.0/t/response/TestAPR/pool.pm
Index: pool.pm
===================================================================
RCS file: /home/cvs/modperl-2.0/t/response/TestAPR/pool.pm,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -u -r1.7 -r1.8
--- pool.pm 26 Sep 2003 08:56:11 -0000 1.7
+++ pool.pm 31 Jan 2004 10:06:59 -0000 1.8
@@ -16,7 +16,7 @@
sub handler {
my $r = shift;
- plan $r, tests => 38;
+ plan $r, tests => 62;
### native pools ###
@@ -39,6 +39,7 @@
$r->notes->clear;
}
+
# implicit DESTROY shouldn't destroy native pools
{
{
@@ -84,6 +85,9 @@
}
+
+
+
# test: lexical scoping DESTROYs the custom pool
{
{
@@ -132,6 +136,7 @@
}
+
# test: destroying a sub-pool before the parent pool
{
my ($pp, $sp) = both_pools_create_ok($r);
@@ -145,8 +150,10 @@
}
+ # test: destroying a sub-pool explicitly after the parent pool destroy
- # test: destroying a sub-pool explicitly after the parent pool
+ # the parent pool should have already destroyed the child pool, so
+ # the object is invalid
{
my ($pp, $sp) = both_pools_create_ok($r);
@@ -158,9 +165,175 @@
$r->notes->clear;
}
+
+ # test: destroying a sub-pool before the parent pool and trying to
+ # call APR::Pool methods on the a subpool object which points to a
+ # destroyed pool
+ {
+ my ($pp, $sp) = both_pools_create_ok($r);
+
+ # parent pool destroys child pool
+ $pp->DESTROY;
+
+ # this should "gracefully" fail, since $sp's guts were
+ # destroyed when the parent pool was destroyed
+ eval { $pp = $sp->parent_get };
+ ok t_cmp(qr/invalid pool object/,
+ $@,
+ "parent pool destroys child pool");
+
+ # since pool $sp now contains 0 pointer, if we try to make a
+ # new pool out of it, it's the same as APR->new (i.e. it'll
+ # use the global top level pool for it), so the resulting pool
+ # should have an ancestry length of exactly 1
+ my $ssp = $sp->new;
+ ok t_cmp(1, ancestry_count($ssp),
+ "a new pool has one ancestor: the global pool");
+
+
+ both_pools_destroy_ok($r);
+
+ $r->notes->clear;
+ }
+
+ # test: make sure that one pool won't destroy/affect another pool,
+ # which happened to be allocated at the same memory address after
+ # the pointer to the first pool was destroyed
+ {
+ my $pp2;
+ {
+ my $pp = APR::Pool->new;
+ $pp->DESTROY;
+ # $pp2 ideally should take the exact place of apr_pool
+ # previously pointed to by $pp
+ $pp2 = APR::Pool->new;
+ # $pp object didn't go away yet (it'll when exiting this
+ # scope). in the previous implementation, $pp will be
+ # DESTROY'ed second time on the exit of the scope and it
+ # could happen to work, because $pp2 pointer has allocated
+ # exactly the same address. and if so it would have killed
+ # the pool that $pp2 points to
+
+ # this should "gracefully" fail, since $pp's guts were
+ # destroyed when the parent pool was destroyed
+ # must make sure that it won't try to hijack the new pool
+ # $pp2 that (hopefully) took over $pp's place
+ eval { $pp->parent_get };
+ ok t_cmp(qr/invalid pool object/,
+ $@,
+ "a dead pool is a dead pool");
+ }
+
+ # next make sure that $pp2's pool is still alive
+ $pp2->cleanup_register(\&set_cleanup, [$r, 'overtake']);
+ $pp2->DESTROY;
+
+ my @notes = $r->notes->get('cleanup');
+
+ ok t_cmp(1, scalar(@notes), "should be 1 note");
+ ok t_cmp('overtake', $notes[0]);
+
+ $r->notes->clear;
+
+ }
+
+ # test: similar to the previous test, but this time, the parent
+ # pool destroys the child pool. a second allocation of a new pair
+ # of the parent and child pools take over exactly the same
+ # allocations. so if there are any ghost objects, they must not
+ # find the other pools and use them as they own. for example they
+ # could destroy the pools, and the perl objects of the pair would
+ # have no idea that someone has destroyed the pools without their
+ # knowledge. the previous implementation suffered from this
+ # problem. the new implementation uses an SV which is stored in
+ # the object and in the pool. when the pool is destroyed the SV
+ # gets its IVX pointer set to 0, which affects any perl object
+ # that is a ref to that SV. so once an apr pool is destroyed all
+ # perl objects pointing to it get automatically invalidated and
+ # there is no risk of hijacking newly created pools that happen to
+ # be at the same memory address.
+
+ {
+ my ($pp2, $sp2);
+ {
+ my $pp = APR::Pool->new;
+ my $sp = $pp->new;
+ # parent destroys $sp
+ $pp->DESTROY;
+
+ # hopefully these pool will take over the $pp and $sp
+ # allocations
+ ($pp2, $sp2) = both_pools_create_ok($r);
+ }
+
+ # $pp and $sp shouldn't have triggered any cleanups
+ my @notes = $r->notes->get('cleanup');
+ ok t_cmp(0, scalar(@notes), "should be 0 notes");
+ $r->notes->clear;
+
+ # parent pool destroys child pool
+ $pp2->DESTROY;
+
+ both_pools_destroy_ok($r);
+
+ $r->notes->clear;
+ }
+
+ # test: only when the last references to the pool object is gone
+ # it should get destroyed
+ {
+
+ my $cp;
+
+ {
+ my $sp = $r->pool->new;
+
+ $sp->cleanup_register(\&set_cleanup, [$r, 'several references']);
+
+ $cp = $sp;
+ # destroy of $sp shouldn't call apr_pool_destroy, because
+ # $cp still references to it
+ }
+
+ my @notes = $r->notes->get('cleanup');
+ ok t_cmp(0, scalar(@notes), "should be 0 notes");
+ $r->notes->clear;
+
+ # now the last copy is gone and the cleanup hooks will be called
+ $cp->DESTROY;
+
+ @notes = $r->notes->get('cleanup');
+ ok t_cmp(1, scalar(@notes), "should be 1 note");
+ ok t_cmp('several references', $notes[0]);
+ }
+
+ {
+ # and another variation
+ my $pp = $r->pool->new;
+ my $sp = $pp->new;
+
+ my $gp = $pp->parent_get;
+ my $pp2 = $sp->parent_get;
+
+ # parent destroys children
+ $pp->DESTROY;
+
+ # grand parent ($r->pool) is undestroyable (core pool)
+ $gp->DESTROY;
+
+ # now all custom pools are destroyed - $sp and $pp2 point nowhere
+ $pp2->DESTROY;
+ $sp->DESTROY;
+
+ ok 1;
+ }
+
# other stuff
{
my $p = APR::Pool->new;
+
+ # find some method that wants a pool object and try to pass it
+ # an object that was already destroyed e.g. APR::Table::make($p, 2);
# only available with -DAPR_POOL_DEBUG
#my $num_bytes = $p->num_bytes;
1.10 +17 -1 modperl-2.0/xs/typemap
Index: typemap
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/typemap,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -u -r1.9 -r1.10
--- typemap 11 Jul 2002 06:14:10 -0000 1.9
+++ typemap 31 Jan 2004 10:06:59 -0000 1.10
@@ -5,6 +5,9 @@
######################################################################
OUTPUT
+T_POOLOBJ
+ sv_setref_pv($arg, \"${ntype}\", (void*)$var);
+
T_APACHEOBJ
sv_setref_pv($arg, \"${ntype}\", (void*)$var);
@@ -33,7 +36,20 @@
\"$var is not a blessed reference\");
}
-INPUT
+T_POOLOBJ
+ if (SvROK($arg) && sv_derived_from($arg, \"${ntype}\")) {
+ IV tmp = SvIV((SV*)SvRV($arg));
+ if (tmp == 0) {
+ Perl_croak(aTHX_ \"invalid pool object (already destroyed?)\");
+ }
+ $var = INT2PTR($type,tmp);
+ }
+ else {
+ Perl_croak(aTHX_ SvROK($arg) ?
+ \"$var is not of type ${ntype}\" :
+ \"$var is not a blessed reference\");
+ }
+
T_UVOBJ
if (SvROK($arg) && sv_derived_from($arg, \"${ntype}\")) {
UV tmp = SvUV((SV*)SvRV($arg));
1.9 +121 -126 modperl-2.0/xs/APR/Pool/APR__Pool.h
Index: APR__Pool.h
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/APR/Pool/APR__Pool.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -u -r1.8 -r1.9
--- APR__Pool.h 30 Sep 2003 21:18:39 -0000 1.8
+++ APR__Pool.h 31 Jan 2004 10:06:59 -0000 1.9
@@ -1,10 +1,24 @@
#define MP_APR_POOL_NEW "APR::Pool::new"
typedef struct {
- int destroyable;
- int ref_count;
+ SV *sv;
+ PerlInterpreter *perl;
} mpxs_pool_account_t;
+/* XXX: this implementation has a problem with perl ithreads. if a
+ * custom pool is allocated, and then a thread is spawned we now have
+ * two copies of the pool object, each living in a different perl
+ * interpreter, both pointing to the same memory address of the apr
+ * pool.
+ *
+ * need to write a CLONE class method could properly clone the
+ * thread's copied object, but it's tricky:
+ * - it needs to call parent_get() on the copied object and allocate a
+ * new pool from that parent's pool
+ * - it needs to reinstall any registered cleanup callbacks (can we do
+ * that?) may be we can skip those?
+ */
+
/* XXX: should we make it a new global tracing category
* MOD_PERL_TRACE=p for tracing pool management? */
#define MP_POOL_TRACE_DO 0
@@ -15,92 +29,34 @@
#define MP_POOL_TRACE if (0) modperl_trace
#endif
-
-static MP_INLINE int mpxs_apr_pool_ref_count_inc(apr_pool_t *p)
-{
- mpxs_pool_account_t *data;
-
- apr_pool_userdata_get((void **)&data, MP_APR_POOL_NEW, p);
- if (!data) {
- data = (mpxs_pool_account_t *)apr_pcalloc(p, sizeof(*data));
- }
-
- data->ref_count++;
-
- apr_pool_userdata_set(data, MP_APR_POOL_NEW, NULL, p);
-
- return data->ref_count;
-}
-
-static MP_INLINE int mpxs_apr_pool_ref_count_dec(apr_pool_t *p)
-{
- mpxs_pool_account_t *data;
-
- apr_pool_userdata_get((void **)&data, MP_APR_POOL_NEW, p);
- if (!data) {
- /* if there is no data, there is nothing to decrement */
- return 0;
- }
-
- if (data->ref_count > 0) {
- data->ref_count--;
- }
-
- apr_pool_userdata_set(data, MP_APR_POOL_NEW, NULL, p);
-
- return data->ref_count;
-}
-
-static MP_INLINE void mpxs_apr_pool_destroyable_set(apr_pool_t *p)
-{
- mpxs_pool_account_t *data;
-
- apr_pool_userdata_get((void **)&data, MP_APR_POOL_NEW, p);
- if (!data) {
- data = (mpxs_pool_account_t *)apr_pcalloc(p, sizeof(*data));
- }
-
- data->destroyable++;
-
- apr_pool_userdata_set(data, MP_APR_POOL_NEW, NULL, p);
-}
-
-static MP_INLINE void mpxs_apr_pool_destroyable_unset(apr_pool_t *p)
+/* invalidate all Perl objects referencing the data sv stored in the
+ * pool and the sv itself. this is needed when a parent pool triggers
+ * apr_pool_destroy on its child pools
+ */
+static MP_INLINE apr_status_t
+mpxs_apr_pool_cleanup(void *cleanup_data)
{
mpxs_pool_account_t *data;
-
- apr_pool_userdata_get((void **)&data, MP_APR_POOL_NEW, p);
- if (!data) {
+ apr_pool_userdata_get((void **)&data, MP_APR_POOL_NEW,
+ (apr_pool_t *)cleanup_data);
+ if (!(data && data->sv)) {
/* if there is no data, there is nothing to unset */
- return;
+ MP_POOL_TRACE(MP_FUNC, "this pool seems to be destroyed already");
}
-
- data->destroyable = 0;
-
- apr_pool_userdata_set(data, MP_APR_POOL_NEW, NULL, p);
-}
-
-static MP_INLINE int mpxs_apr_pool_is_pool_destroyable(apr_pool_t *p)
-{
- mpxs_pool_account_t *data;
-
- apr_pool_userdata_get((void **)&data, MP_APR_POOL_NEW, p);
- if (!data) {
- /* pools with no special data weren't created by us and
- * therefore shouldn't be destroyed */
- return 0;
+ else {
+ dTHXa(data->perl);
+ MP_POOL_TRACE(MP_FUNC,
+ "pool 0x%lx contains a valid sv 0x%lx, invalidating it",
+ (unsigned long)data->sv, (unsigned long)cleanup_data);
+
+ /* invalidate all Perl objects referencing this sv */
+ SvIVX(data->sv) = 0;
+
+ /* invalidate the reference stored in the pool */
+ data->sv = NULL;
+ /* data->sv will go away by itself when all objects will go away */
}
- return data->destroyable && !data->ref_count;
-}
-
-static MP_INLINE apr_status_t
-mpxs_apr_pool_cleanup_destroyable_unset(void *data)
-{
- /* unset the flag for the key MP_APR_POOL_NEW to prevent from
- * apr_pool_destroy being called twice */
- mpxs_apr_pool_destroyable_unset((apr_pool_t *)data);
-
return APR_SUCCESS;
}
@@ -109,13 +65,13 @@
* @param parent_pool_obj an APR::Pool object or an "APR::Pool" class
* @return a new pool or subpool
*/
-static MP_INLINE apr_pool_t *mpxs_apr_pool_create(pTHX_ SV *parent_pool_obj)
+static MP_INLINE SV *mpxs_apr_pool_create(pTHX_ SV *parent_pool_obj)
{
apr_pool_t *parent_pool = mpxs_sv_object_deref(parent_pool_obj, apr_pool_t);
apr_pool_t *child_pool = NULL;
-
+
+ MP_POOL_TRACE(MP_FUNC, "parent pool 0x%lx\n", (unsigned long)parent_pool);
(void)apr_pool_create(&child_pool, parent_pool);
- MP_POOL_TRACE(MP_FUNC, "new pool 0x%lx\n", child_pool);
#if APR_POOL_DEBUG
/* useful for pools debugging, can grep for APR::Pool::new */
@@ -131,12 +87,6 @@
(unsigned long)child_pool, (unsigned long)parent_pool);
}
- /* mark the pool eligible for destruction. We aren't suppose to
- * destroy pools not created by APR::Pool::new().
- * see mpxs_apr_pool_DESTROY
- */
- mpxs_apr_pool_destroyable_set(child_pool);
-
/* Each newly created pool must be destroyed only once. Calling
* apr_pool_destroy will destroy the pool and its children pools,
* however a perl object for a sub-pool will still keep a pointer
@@ -146,10 +96,15 @@
* case it'll destroy a different valid pool which has been given
* the same memory allocation wrecking havoc. Therefore we must
* ensure that when sub-pools are destroyed via the parent pool,
- * their cleanup callbacks will destroy their perl objects
+ * their cleanup callbacks will destroy the guts of their perl
+ * objects, so when those perl objects, pointing to memory
+ * previously allocated by destroyed sub-pools or re-used already
+ * by new pools, will get their time to DESTROY, they won't make a
+ * mess, trying to destroy an already destroyed pool or even worse
+ * a pool allocate in the place of the old one.
*/
apr_pool_cleanup_register(child_pool, (void *)child_pool,
- mpxs_apr_pool_cleanup_destroyable_unset,
+ mpxs_apr_pool_cleanup,
apr_pool_cleanup_null);
#if APR_POOL_DEBUG
/* child <-> parent <-> ... <-> top ancestry traversal */
@@ -170,8 +125,23 @@
}
#endif
- mpxs_apr_pool_ref_count_inc(child_pool);
- return child_pool;
+ {
+ mpxs_pool_account_t *data =
+ (mpxs_pool_account_t *)apr_pcalloc(child_pool, sizeof(*data));
+
+ SV *rv = sv_setref_pv(NEWSV(0, 0), "APR::Pool", (void*)child_pool);
+
+ data->sv = SvRV(rv);
+#ifdef USE_ITHREADS
+ data->perl = aTHX;
+#endif
+ MP_POOL_TRACE(MP_FUNC, "sub-pool p: 0x%lx, sv: 0x%lx, rv: 0x%lx",
+ (unsigned long)child_pool, data->sv, rv);
+
+ apr_pool_userdata_set(data, MP_APR_POOL_NEW, NULL, child_pool);
+
+ return rv;
+ }
}
typedef struct {
@@ -267,10 +237,11 @@
}
-static MP_INLINE apr_pool_t *
+static MP_INLINE SV *
mpxs_apr_pool_parent_get(pTHX_ apr_pool_t *child_pool)
{
apr_pool_t *parent_pool = apr_pool_parent_get(child_pool);
+
if (parent_pool) {
/* ideally this should be done by mp_xs_APR__Pool_2obj. Though
* since most of the time we don't use custom pools, we don't
@@ -281,45 +252,69 @@
* reference to a custom pool, they must do the ref-counting
* as well.
*/
- mpxs_apr_pool_ref_count_inc(parent_pool);
+ mpxs_pool_account_t *data;
+ apr_pool_userdata_get((void **)&data, MP_APR_POOL_NEW, parent_pool);
+ if (data && data->sv) {
+ MP_POOL_TRACE(MP_FUNC,
+ "parent pool (0x%lx) is a custom pool, sv 0x%lx",
+ (unsigned long)parent_pool,
+ (unsigned long)data->sv);
+
+ return newRV_inc(data->sv);
+ }
+ else {
+ MP_POOL_TRACE(MP_FUNC, "parent pool (0x%lx) is a core pool",
+ (unsigned long)parent_pool);
+ return SvREFCNT_inc(mp_xs_APR__Pool_2obj(parent_pool));
+ }
+ }
+ else {
+ MP_POOL_TRACE(MP_FUNC, "pool (0x%lx) has no parents",
+ (unsigned long)child_pool);
+ return SvREFCNT_inc(mp_xs_APR__Pool_2obj(parent_pool));
}
-
- return parent_pool;
}
-
+
/**
* destroy a pool
* @param obj an APR::Pool object
*/
-static MP_INLINE void mpxs_apr_pool_DESTROY(pTHX_ SV *obj) {
-
+static MP_INLINE void mpxs_apr_pool_DESTROY(pTHX_ SV *obj)
+{
apr_pool_t *p;
+ SV *sv = SvRV(obj);
- p = mpxs_sv_object_deref(obj, apr_pool_t);
+ /* MP_POOL_TRACE(MP_FUNC, "DESTROY 0x%lx-0x%lx", */
+ /* (unsigned long)obj,(unsigned long)sv); */
+ /* do_sv_dump(0, Perl_debug_log, obj, 0, 4, FALSE, 0); */
- mpxs_apr_pool_ref_count_dec(p);
-
- /* APR::Pool::DESTROY
- * we only want to call DESTROY on objects created by
- * APR::Pool->new(), not objects representing native pools
- * like r->pool. native pools can be destroyed using
- * apr_pool_destroy ($p->destroy)
- */
- if (mpxs_apr_pool_is_pool_destroyable(p)) {
- MP_POOL_TRACE(MP_FUNC, "DESTROY pool 0x%lx\n", (unsigned long)p);
- apr_pool_destroy(p);
- /* mpxs_apr_pool_cleanup_destroyable_unset called by
- * apr_pool_destroy takes care of marking this pool as
- * undestroyable, so we do it only once */
+ p = mpxs_sv_object_deref(obj, apr_pool_t);
+ if (!p) {
+ /* non-custom pool */
+ MP_POOL_TRACE(MP_FUNC, "skip apr_pool_destroy: not a custom pool");
+ return;
}
- else {
- /* either because we didn't create this pool (e.g., r->pool),
- * or because this pool has already been destroyed via the
- * destruction of the parent pool
- */
- MP_POOL_TRACE(MP_FUNC, "skipping DESTROY, "
- "this object is not eligible to destroy pool 0x%lx\n",
- (unsigned long)p);
-
+
+ if (sv && SvOK(sv)) {
+ mpxs_pool_account_t *data;
+
+ apr_pool_userdata_get((void **)&data, MP_APR_POOL_NEW, p);
+ if (!(data && data->sv)) {
+ MP_POOL_TRACE(MP_FUNC, "skip apr_pool_destroy: no sv found");
+ return;
+ }
+
+ if (SvREFCNT(sv) == 1) {
+ MP_POOL_TRACE(MP_FUNC, "call apr_pool_destroy: last reference");
+ apr_pool_destroy(p);
+ }
+ else {
+ /* when the pool object dies, sv's ref count decrements
+ * itself automatically */
+ MP_POOL_TRACE(MP_FUNC,
+ "skip apr_pool_destroy: refcount > 1 (%d)",
+ SvREFCNT(sv));
+ }
}
}
+
1.70 +2 -2 modperl-2.0/xs/maps/apr_functions.map
Index: apr_functions.map
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/maps/apr_functions.map,v
retrieving revision 1.69
retrieving revision 1.70
diff -u -u -r1.69 -r1.70
--- apr_functions.map 29 Jan 2004 01:26:49 -0000 1.69
+++ apr_functions.map 31 Jan 2004 10:06:59 -0000 1.70
@@ -157,7 +157,7 @@
apr_pool_destroy
DEFINE_DESTROY | mpxs_apr_pool_DESTROY | SV *:obj
>apr_pool_destroy_debug
- apr_pool_t *:DEFINE_new | mpxs_apr_pool_create | SV *:parent_pool_obj
+ SV *:DEFINE_new | mpxs_apr_pool_create | SV *:parent_pool_obj
-apr_pool_create_ex
>apr_pool_create_ex_debug
!apr_pool_userdata_get
@@ -175,7 +175,7 @@
-apr_pmemdup
!apr_pool_child_cleanup_set
!apr_pool_abort_get
- apr_pool_parent_get | mpxs_
+ SV *:apr_pool_parent_get | mpxs_
apr_pool_is_ancestor
-apr_pool_abort_set
>apr_pool_initialize
1.143 +2 -2 modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm
Index: FunctionTable.pm
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm,v
retrieving revision 1.142
retrieving revision 1.143
diff -u -u -r1.142 -r1.143
--- FunctionTable.pm 29 Jan 2004 01:32:58 -0000 1.142
+++ FunctionTable.pm 31 Jan 2004 10:06:59 -0000 1.143
@@ -6586,7 +6586,7 @@
]
},
{
- 'return_type' => 'apr_pool_t *',
+ 'return_type' => 'SV *',
'name' => 'mpxs_apr_pool_parent_get',
'attr' => [
'static',
@@ -6618,7 +6618,7 @@
]
},
{
- 'return_type' => 'apr_pool_t *',
+ 'return_type' => 'SV *',
'name' => 'mpxs_apr_pool_create',
'attr' => [
'static',
1.317 +12 -0 modperl-2.0/Changes
Index: Changes
===================================================================
RCS file: /home/cvs/modperl-2.0/Changes,v
retrieving revision 1.316
retrieving revision 1.317
diff -u -u -r1.316 -r1.317
--- Changes 31 Jan 2004 07:17:17 -0000 1.316
+++ Changes 31 Jan 2004 10:06:59 -0000 1.317
@@ -12,6 +12,18 @@
=item 1.99_13-dev
+APR.xs has been reimplemented. The problem with the previous
+implementation is that a dead perl pool object could hijack a newly
+created pool, which didn't belong to that object, but which happened
+to be allocated at the same memory location. The problem is that
+apr_pool_user_data_set/get has no mechanism to check whether the pool
+has changed since it was last assigned to (it does but only in the
+debug mode). It really needs some signature mechanism which can be
+verified that the pool is still the same pool. Since apr_pool doesn't
+have this feature, the reference counting has been reimplemented using
+a plain sv reference. Several new (mainly hijacking) tests which badly
+fail with the previous impelementation have been added. [Stas]
+
fix calling $r->subprocess_env() in a void context so that it only
populates %ENV if also called with no arguments. also, make sure it
can be called more than once and still populate %ENV.