apr-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "William A. Rowe, Jr." <wr...@rowe-clan.net>
Subject Re: Re-architecture for 2.0 tree
Date Wed, 19 Jan 2005 19:16:10 GMT
At 12:33 PM 1/19/2005, Ryan Bloom wrote:

>One of my biggest mistakes when initially designing APR was that I
>forced each platform to have completely distinct implementations for
>simple functions if the structures were distinct.  This has led to a
>great amount of duplicate code in the library, and makes it harder to
>see where the differences between the platforms truly are.  I would
>love to see APR 2.0 solve this problem.

+1

>In another header file:
>#ifdef WIN32
>struct arch_file {
>    HANDLE filedes;
>}
>#else
>struct arch_file {
>    int filedes;
>}
>#endif

I still like the concept of doing something like

struct apr_foo_t {
    apr_pool_t *pool;
    void *      foodat;
    struct apr_foo_arch_t arch;
}

and defining struct apr_foo_arch_t within an include/arch/xxx/foo.h
file.  This gains you the transparency of common elements (pool,
foodat, etc) while leaving certain elements opaque.  Because the
arch element above is undefined, the structure remains incomplete.
(We can't anticipate the maximum size for the object.)

Right now, in 1.2.0, we could add an element onto the end of the
apr_foo_t opaque structure, and not break abi.  Entirely transparent
structures don't share that attribute, folks can determine the size
of the complete, transparent structure in their code, and force
minor version dependencies that don't exist today.

The bit that disturbed me was long #ifdef litanies which we
know (from apache-1.3/src/server/main.c) get illegible quickly.

>This can allow simple functions, like apr_file_get_name(), 
>to read the name of the file quickly (and only have one 
>implementation of that function), while still allowing native
>functions to be used for the more complex work.

Again +1.  I'd even suggest the structure

  apr/foo/common/*.c
  apr/foo/netware/*.c
  apr/foo/unix/*.c
  apr/foo/win32/*.c

where we drop the concept of '/unix/' as the 'common' impl,
and build apr/*/common/ on all platforms.

>If we don't want the apr_file_t structure to be incomplete, we can
>still provide the getters/setters for the internal structures, but
>also open up our structures, so that people can get the file's name by
>accessing fp->name directly.

Huge risks, garbage collection and modifying associated fields.
The more we let people diddle in the transparent elements, the 
less they recognize side effects that are only possible when
they invoke the set'ter function.  This will vary based on the
apr_xxx_t object we are talking about of course.

>This may also help us remove the depenance on pools throughout the
>code.  My least favorite part of APR is that all allocation _must_ be
>done through pools, even if pools don't make sense for your
>application (I take full blame for that).

Unfortuantely -we- perform allocations within our own operations
on these objects.  When that happens, we have to look at the pool
allocator.  I believe we can and should revisit allocator/free
indirection.  Yes, a small performance hit will result, but it
should not be substantial enough to invalidate the entire concept.

>With this model, end-users can allocate the space for apr_file_t 
>themselves, and all we need to do is figure out how to allocate 
>the arch_file structure correctly, a much smaller allocation, 
>and I believe we will find that we allocate less within APR and 
>allow developers to pass us pre-allocated structures.

Again, garbage collection is the primary issue.  If the user goes
and allocates our structures, how are our (critical) destructors 
then invoked?  And how are elements within the structure ultimately
freed?  This part of the approach scares me.

One alternative would be more reusable apr_xxx_t objects, which
would ensure we don't hit some of these issues.  To be able to
call an apr_xxx_clear() prior to reuse, or apr_xxx_free() that
invokes the cleanups might help here, even if they are mostly
no-ops until a destructor actually returns the memory.

In other works, clearly segregate what c++ users refer to as
a pre-destruction phase from the actual garbage collection,
and the allocation from the initialization phase.  This would 
help you realize your concept of detaching us (somewhat) from
pools all together.

Bill



Mime
View raw message