feat:replace boost library with C++11 std library

This commit is contained in:
Livox-SDK
2020-04-01 20:53:55 +08:00
parent 6d06233944
commit d3258bbd97
1936 changed files with 241862 additions and 60153 deletions
+399
View File
@@ -0,0 +1,399 @@
<HTML>
<HEAD><TITLE>APR Design Document</TITLE></HEAD>
<BODY>
<h1>Design of APR</h1>
<p>The Apache Portable Run-time libraries have been designed to provide a common
interface to low level routines across any platform. The original goal of APR
was to combine all code in Apache to one common code base. This is not the
correct approach however, so the goal of APR has changed. There are places
where common code is not a good thing. For example, how to map requests
to either threads or processes should be platform specific. APR's place
is now to combine any code that can be safely combined without sacrificing
performance.</p>
<p>To this end we have created a set of operations that are required for cross
platform development. There may be other types that are desired and those
will be implemented in the future.</p>
<p>This document will discuss the structure of APR, and how best to contribute
code to the effort.</p>
<h2>APR On Windows and Netware</h2>
<p>APR on Windows and Netware is different from APR on all other systems,
because those platforms don't use autoconf. On Unix, apr_private.h (private to
APR) and apr.h (public, used by applications that use APR) are generated by
autoconf from acconfig.h and apr.h.in respectively. On Windows (and Netware),
apr_private.h and apr.h are created from apr_private.hw (apr_private.hwn)
and apr.hw (apr.hwn) respectively.</p>
<p> <strong>
If you add code to acconfig.h or tests to configure.in or aclocal.m4,
please give some thought to whether or not Windows and Netware need
these additions as well. A general rule of thumb, is that if it is
a feature macro, such as APR_HAS_THREADS, Windows and Netware need it.
In other words, if the definition is going to be used in a public APR
header file, such as apr_general.h, Windows needs it.
The only time it is safe to add a macro or test without also adding
the macro to apr*.h[n]w, is if the macro tells APR how to build. For
example, a test for a header file does not need to be added to Windows.
</strong></p>
<h2>APR Features</h2>
<p>One of the goals of APR is to provide a common set of features across all
platforms. This is an admirable goal, it is also not realistic. We cannot
expect to be able to implement ALL features on ALL platforms. So we are
going to do the next best thing. Provide a common interface to ALL APR
features on MOST platforms.</p>
<p>APR developers should create FEATURE MACROS for any feature that is not
available on ALL platforms. This should be a simple definition which has
the form:</p>
<code>APR_HAS_FEATURE</code>
<p>This macro should evaluate to true if APR has this feature on this platform.
For example, Linux and Windows have mmap'ed files, and APR is providing an
interface for mmapp'ing a file. On both Linux and Windows, APR_HAS_MMAP
should evaluate to one, and the ap_mmap_* functions should map files into
memory and return the appropriate status codes.</p>
<p>If your OS of choice does not have mmap'ed files, APR_HAS_MMAP should
evaluate to zero, and all ap_mmap_* functions should not be defined. The
second step is a precaution that will allow us to break at compile time if a
programmer tries to use unsupported functions.</p>
<h2>APR types</h2>
<p>The base types in APR</p>
<ul>
<li>dso<br>
Shared library routines
<li>mmap<br>
Memory-mapped files
<li>poll<br>
Polling I/O
<li>time<br>
Time
<li>user<br>
Users and groups
<li>locks<br>
Process and thread locks (critical sections)
<li>shmem<br>
Shared memory
<li>file_io<br>
File I/O, including pipes
<li>atomic<br>
Atomic integer operations
<li>strings<br>
String handling routines
<li>memory<br>
Pool-based memory allocation
<li>passwd<br>
Reading passwords from the terminal
<li>tables<br>
Tables and hashes
<li>network_io<br>
Network I/O
<li>threadproc<br>
Threads and processes
<li>misc<br>
Any APR type which doesn't have any other place to belong. This
should be used sparingly.
<li>support<br>
Functions meant to be used across multiple APR types. This area
is for internal functions only. If a function is exposed, it should
not be put here.
</ul>
<h2>Directory Structure</h2>
<p>Each type has a base directory. Inside this base directory, are
subdirectories, which contain the actual code. These subdirectories are named
after the platforms the are compiled on. Unix is also used as a common
directory. If the code you are writing is POSIX based, you should look at the
code in the unix directory. A good rule of thumb, is that if more than half
your code needs to be ifdef'ed out, and the structures required for your code
are substantively different from the POSIX code, you should create a new
directory.</p>
<p>Currently, the APR code is written for Unix, BeOS, Windows, and OS/2. An
example of the directory structure is the file I/O directory:</p>
<pre>
apr
|
-> file_io
|
-> unix The Unix and common base code
|
-> win32 The Windows code
|
-> os2 The OS/2 code
</pre>
<p>Obviously, BeOS does not have a directory. This is because BeOS is currently
using the Unix directory for it's file_io.</p>
<p>There are a few special top level directories. These are test and include.
Test is a directory which stores all test programs. It is expected
that if a new type is developed, there will also be a new test program, to
help people port this new type to different platforms. A small document
describing how to create new tests that integrate with the test suite can be
found in the test/ directory. Include is a directory which stores all
required APR header files for external use.</p>
<h2>Creating an APR Type</h2>
<p>The current design of APR requires that most APR types be incomplete.
It is not possible to write flexible portable code if programs can access
the internals of APR types. This is because different platforms are
likely to define different native types. There are only two exceptions to
this rule:</p>
<ul>
<li>The first exception to this rule is if the type can only reasonably be
implemented one way. For example, time is a complete type because there
is only one reasonable time implementation.
<li>The second exception to the incomplete type rule can be found in
apr_portable.h. This file defines the native types for each platform.
Using these types, it is possible to extract native types for any APR type.</p>
</ul>
<p>For this reason, each platform defines a structure in their own directories.
Those structures are then typedef'ed in an external header file. For example
in file_io/unix/fileio.h:</p>
<pre>
struct ap_file_t {
apr_pool_t *cntxt;
int filedes;
FILE *filehand;
...
}
</pre>
<p>In include/apr_file_io.h:</p>
</pre>
typedef struct ap_file_t ap_file_t;
</pre>
<p> This will cause a compiler error if somebody tries to access the filedes
field in this structure. Windows does not have a filedes field, so obviously,
it is important that programs not be able to access these.</p>
<p>You may notice the apr_pool_t field. Most APR types have this field. This
type is used to allocate memory within APR. Because every APR type has a pool,
any APR function can allocate memory if it needs to. This is very important
and it is one of the reasons that APR works. If you create a new type, you
must add a pool to it. If you do not, then all functions that operate on that
type will need a pool argument.</p>
<h2>New Function</h2>
<p>When creating a new function, please try to adhere to these rules.</p>
<ul>
<li> Result arguments should be the first arguments.
<li> If a function needs a pool, it should be the last argument.
<li> These rules are flexible, especially if it makes the code easier
to understand because it mimics a standard function.
</ul>
<h2>Documentation</h2>
<p>Whenever a new function is added to APR, it MUST be documented. New
functions will not be committed unless there are docs to go along with them.
The documentation should be a comment block above the function in the header
file.</p>
<p>The format for the comment block is:</p>
<pre>
/**
* Brief description of the function
* @param parma_1_name explanation
* @param parma_2_name explanation
* @param parma_n_name explanation
* @tip Any extra information people should know.
* @deffunc function prototype if required
*/
</pre>
<p>For an actual example, look at any file in the include directory. The
reason the docs are in the header files is to ensure that the docs always
reflect the current code. If you change parameters or return values for a
function, please be sure to update the documentation.</p>
<h2>APR Error reporting</h2>
<p>Most APR functions should return an ap_status_t type. The only time an
APR function does not return an ap_status_t is if it absolutely CAN NOT
fail. Examples of this would be filling out an array when you know you are
not beyond the array's range. If it cannot fail on your platform, but it
could conceivably fail on another platform, it should return an ap_status_t.
Unless you are sure, return an ap_status_t.</p>
<strong>
This includes functions that return TRUE/FALSE values. How that
is handled is discussed below
</strong>
<p>All platforms return errno values unchanged. Each platform can also have
one system error type, which can be returned after an offset is added.
There are five types of error values in APR, each with its own offset.</p>
<!-- This should be turned into a table, but I am lazy today -->
<pre>
Name Purpose
0) This is 0 for all platforms and isn't really defined
anywhere, but it is the offset for errno values.
(This has no name because it isn't actually defined,
but for completeness we are discussing it here).
1) APR_OS_START_ERROR This is platform dependent, and is the offset at which
APR errors start to be defined. Error values are
defined as anything which caused the APR function to
fail. APR errors in this range should be named
APR_E* (i.e. APR_ENOSOCKET)
2) APR_OS_START_STATUS This is platform dependent, and is the offset at which
APR status values start. Status values do not indicate
success or failure, and should be returned if
APR_SUCCESS does not make sense. APR status codes in
this range should be name APR_* (i.e. APR_DETACH)
4) APR_OS_START_USEERR This is platform dependent, and is the offset at which
APR apps can begin to add their own error codes.
3) APR_OS_START_SYSERR This is platform dependent, and is the offset at which
system error values begin.
</pre>
<strong>The difference in naming between APR_OS_START_ERROR and
APR_OS_START_STATUS mentioned above allows programmers to easily determine if
the error code indicates an error condition or a status condition.</strong>
<p>If your function has multiple return codes that all indicate success, but
with different results, or if your function can only return PASS/FAIL, you
should still return an apr_status_t. In the first case, define one
APR status code for each return value, an example of this is
<code>apr_proc_wait</code>, which can only return APR_CHILDDONE,
APR_CHILDNOTDONE, or an error code. In the second case, please return
APR_SUCCESS for PASS, and define a new APR status code for failure, an
example of this is <code>apr_compare_users</code>, which can only return
APR_SUCCESS, APR_EMISMATCH, or an error code.</p>
<p>All of these definitions can be found in apr_errno.h for all platforms. When
an error occurs in an APR function, the function must return an error code.
If the error occurred in a system call and that system call uses errno to
report an error, then the code is returned unchanged. For example: </p>
<pre>
if (open(fname, oflags, 0777) < 0)
return errno;
</pre>
<p>The next place an error can occur is a system call that uses some error value
other than the primary error value on a platform. This can also be handled
by APR applications. For example:</p>
<pre>
if (CreateFile(fname, oflags, sharemod, NULL,
createflags, attributes, 0) == INVALID_HANDLE_VALUE
return (GetLAstError() + APR_OS_START_SYSERR);
</pre>
<p>These two examples implement the same function for two different platforms.
Obviously even if the underlying problem is the same on both platforms, this
will result in two different error codes being returned. This is OKAY, and
is correct for APR. APR relies on the fact that most of the time an error
occurs, the program logs the error and continues, it does not try to
programatically solve the problem. This does not mean we have not provided
support for programmatically solving the problem, it just isn't the default
case. We'll get to how this problem is solved in a little while.</p>
<p>If the error occurs in an APR function but it is not due to a system call,
but it is actually an APR error or just a status code from APR, then the
appropriate code should be returned. These codes are defined in apr_errno.h
and should be self explanatory.</p>
<p>No APR code should ever return a code between APR_OS_START_USEERR and
APR_OS_START_SYSERR, those codes are reserved for APR applications.</p>
<p>To programmatically correct an error in a running application, the error
codes need to be consistent across platforms. This should make sense. APR
has provided macros to test for status code equivalency. For example, to
determine if the code that you received from the APR function means EOF, you
would use the macro APR_STATUS_IS_EOF().</p>
<p>Why did APR take this approach? There are two ways to deal with error
codes portably.</p>
<ol type=1>
<li> Return the same error code across all platforms.
<li> Return platform specific error codes and convert them when necessary.
</ol>
<p>The problem with option number one is that it takes time to convert error
codes to a common code, and most of the time programs want to just output
an error string. If we convert all errors to a common subset, we have four
steps to output an error string:</p>
<p>The second problem with option 1, is that it is a lossy conversion. For
example, Windows and OS/2 have a couple hundred error codes, but POSIX errno
only defines about 50 errno values. This means that if we convert to a
canonical error value immediately, there is no way for the programmer to
get the actual system error.</p>
<pre>
make syscall that fails
convert to common error code step 1
return common error code
check for success
call error output function step 2
convert back to system error step 3
output error string step 4
</pre>
<p>By keeping the errors platform specific, we can output error strings in two
steps.</p>
<pre>
make syscall that fails
return error code
check for success
call error output function step 1
output error string step 2
</pre>
<p>Less often, programs change their execution based on what error was returned.
This is no more expensive using option 2 than it is using option 1, but we
put the onus of converting the error code on the programmer themselves.
For example, using option 1:</p>
<pre>
make syscall that fails
convert to common error code
return common error code
decide execution based on common error code
</pre>
<p>Using option 2:</p>
<pre>
make syscall that fails
return error code
convert to common error code (using ap_canonical_error)
decide execution based on common error code
</pre>
<p>Finally, there is one more operation on error codes. You can get a string
that explains in human readable form what has happened. To do this using
APR, call ap_strerror().</p>
+156
View File
@@ -0,0 +1,156 @@
<HTML>
<HEAD><TITLE>APR Canonical Filenames</TITLE></HEAD>
<BODY>
<h1>APR Canonical Filename</h1>
<h2>Requirements</h2>
<p>APR porters need to address the underlying discrepancies between
file systems. To achieve a reasonable degree of security, the
program depending upon APR needs to know that two paths may be
compared, and that a mismatch is guaranteed to reflect that the
two paths do not return the same resource</p>.
<p>The first discrepancy is in volume roots. Unix and pure derivatives
have only one root path, "/". Win32 and OS2 share root paths of
the form "D:/", D: is the volume designation. However, this can
be specified as "//./D:/" as well, indicating D: volume of the
'this' machine. Win32 and OS2 also may employ a UNC root path,
of the form "//server/share/" where share is a share-point of the
specified network server. Finally, NetWare root paths are of the
form "server/volume:/", or the simpler "volume:/" syntax for 'this'
machine. All these non-Unix file systems accept volume:path,
without a slash following the colon, as a path relative to the
current working directory, which APR will treat as ambiguous, that
is, neither an absolute nor a relative path per se.</p>
<p>The second discrepancy is in the meaning of the 'this' directory.
In general, 'this' must be eliminated from the path where it occurs.
The syntax "path/./" and "path/" are both aliases to path. However,
this isn't file system independent, since the double slash "//" has
a special meaning on OS2 and Win32 at the start of the path name,
and is invalid on those platforms before the "//server/share/" UNC
root path is completed. Finally, as noted above, "//./volume/" is
legal root syntax on WinNT, and perhaps others.</p>
<p>The third discrepancy is in the context of the 'parent' directory.
When "parent/path/.." occurs, the path must be unwound to "parent".
It's also critical to simply truncate leading "/../" paths to "/",
since the parent of the root is root. This gets tricky on the
Win32 and OS2 platforms, since the ".." element is invalid before
the "//server/share/" is complete, and the "//server/share/../"
sequence is the complete UNC root "//server/share/". In relative
paths, leading ".." elements are significant, until they are merged
with an absolute path. The relative form must only retain the ".."
segments as leading segments, to be resolved once merged to another
relative or an absolute path.</p>
<p>The fourth discrepancy occurs with acceptance of alternate character
codes for the same element. Path separators are not retained within
the APR canonical forms. The OS filesystem and APR (slashed) forms
can both be returned as strings, to be used in the proper context.
Unix, Win32 and Netware all accept slashes and backslashes as the
same path separator symbol, although unix strictly accepts slashes.
While the APR form of the name strictly uses slashes, always consider
that there could be a platform that actually accepts slashes as a
character within a segment name.</p>
<p>The fifth and worst discrepancy plagues Win32, OS2, Netware, and some
filesystems mounted in Unix. Case insensitivity can permit the same
file to slip through in both it's proper case and alternate cases.
Simply changing the case is insufficient for any character set beyond
ASCII, since various dialectic forms of characters suffer from one to
many or many to one translations. An example would be u-umlaut, which
might be accepted as a single character u-umlaut, a two character
sequence u and the zero-width umlaut, the upper case form of the same,
or perhaps even a capital U alone. This can be handled in different
ways depending on the purposes of the APR based program, but the one
requirement is that the path must be absolute in order to resolve these
ambiguities. Methods employed include comparison of device and inode
file uniqifiers, which is a fairly fast operation, or querying the OS
for the true form of the name, which can be much slower. Only the
acknowledgement of the file names by the OS can validate the equality
of two different cases of the same filename.</p>
<p>The sixth discrepancy, illegal or insignificant characters, is especially
significant in non-unix file systems. Trailing periods are accepted
but never stored, therefore trailing periods must be ignored for any
form of comparison. And all OS's have certain expectations of what
characters are illegal (or undesirable due to confusion.)</p>
<p>A final warning, canonical functions don't transform or resolve case
or character ambiguity issues until they are resolved into an absolute
path. The relative canonical path, while useful, while useful for URL
or similar identifiers, cannot be used for testing or comparison of file
system objects.</p>
<hr>
<h2>Canonical API</h2>
Functions to manipulate the apr_canon_file_t (an opaque type) include:
<ul>
<li>Create canon_file_t (from char* path and canon_file_t parent path)
<li>Merged canon_file_t (from path and parent, both canon_file_t)
<li>Get char* path of all or some segments
<li>Get path flags of IsRelative, IsVirtualRoot, and IsAbsolute
<li>Compare two canon_file_t structures for file equality
</ul>
<p>The path is corrected to the file system case only if is in absolute
form. The apr_canon_file_t should be preserved as long as possible and
used as the parent to create child entries to reduce the number of expensive
stat and case canonicalization calls to the OS.</p>
<p>The comparison operation provides that the APR can postpone correction
of case by simply relying upon the device and inode for equivalence. The
stat implementation provides that two files are the same, while their
strings are not equivalent, and eliminates the need for the operating
system to return the proper form of the name.</p>
<p>In any case, returning the char* path, with a flag to request the proper
case, forces the OS calls to resolve the true names of each segment. Where
there is a penalty for this operation and the stat device and inode test
is faster, case correction is postponed until the char* result is requested.
On platforms that identify the inode, device, or proper name interchangably
with no penalties, this may occur when the name is initially processed.</p>
<hr>
<h2>Unix Example</h2>
<p>First the simplest case:</p>
<pre>
Parse Canonical Name
accepts parent path as canonical_t
this path as string
Split this path Segments on '/'
For each of this path Segments
If first Segment
If this Segment is Empty ([nothing]/)
Append this Root Segment (don't merge)
Continue to next Segment
Else is relative
Append parent Segments (to merge)
Continue with this Segment
If Segment is '.' or empty (2 slashes)
Discard this Segment
Continue with next Segment
If Segment is '..'
If no previous Segment or previous Segment is '..'
Append this Segment
Continue with next Segment
If previous Segment and previous is not Root Segment
Discard previous Segment
Discard this Segment
Continue with next Segment
Append this Relative Segment
Continue with next Segment
</pre>
</BODY>
</HTML>
+38
View File
@@ -0,0 +1,38 @@
PROJECT_NAME="Apache Portable Runtime"
INPUT=.
QUIET=YES
RECURSIVE=YES
FILE_PATTERNS=*.h
OUTPUT_DIRECTORY=docs/dox
MACRO_EXPANSION=YES
EXPAND_ONLY_PREDEF=YES
#EXPAND_AS_DEFINED=
# not sure why this doesn't work as EXPAND_AS_DEFINED, it should!
PREDEFINED="APR_DECLARE(x)=x" \
"APR_DECLARE_NONSTD(x)=x" \
"APR_DECLARE_DATA" \
"APR_POOL_DECLARE_ACCESSOR(x)=apr_pool_t* apr_##x##_pool_get (const apr_##x##_t *the##x)" \
"APR_DECLARE_INHERIT_SET(x)=apr_status_t apr_##x##_inherit_set(apr_##x##_t *the##x)" \
"APR_DECLARE_INHERIT_UNSET(x)=apr_status_t apr_##x##_inherit_unset(apr_##x##_t *the##x)" \
"APR_HAS_THREADS" \
"__attribute__(x)=" \
DOXYGEN=
OPTIMIZE_OUTPUT_FOR_C=YES
STRIP_CODE_COMMENTS=NO
FULL_PATH_NAMES=NO
CASE_SENSE_NAMES=NO
# some autoconf guru needs to make configure set this correctly...
# in the meantime, simply listing the headers should be alright
#STRIP_FROM_PATH=/buildpath/apr
EXCLUDE_PATTERNS="*/acconfig.h" \
"*/test/*" \
"*/arch/*"
GENERATE_TAGFILE=docs/dox/apr.tag
+84
View File
@@ -0,0 +1,84 @@
The question has been asked multiple times, "Why is APR using Incomplete
types?" This document will try to explain that.
Incomplete types are used in APR because they can enforce portability, and
they make the APR developers job easier, as well as allowing APR to use native
types on all platforms. Imagine a scenario where APR wasn't using incomplete
types. The ap_file_t type would have to be defined as:
typedef struct ap_file_t {
ap_pool_t *pool
char *fname;
int eof_hit;
int pipe;
ap_interval_time_t timeout;
#ifdef WIN32
HANDLE file_handle;
DWORD dwFileAttributes;
#elif defined(OS2)
HFILE filedes;
HEV PipeSem
#else
int filedes;
int ungetchar;
#endif
#ifndef WIN32
int buffered;
ap_int32_flags
int isopen;
/* Stuff for buffered mode */
char *buffer;
int bufpos;
unsigned long dataRead;
int direction;
unsigned long filePtr;
ap_lock_t *mutex;
#endif
} ap_file_t;
This captures the essence of what is currently being defined for ap_file_t
using incomplete types. However, using this structure leads developers to
believe that they are safe accessing any of the fields in this structure.
This is not true. On some platforms, such as Windows, about half of the
structure disappears. We could combine some of these definitions with
macros, for example:
#ifdef WIN32
#define filetype HANDLE
#elif OS2
#define filetype HFILE
#else
#define filetype int
#endif
And then in the definition for ap_file_t, we could say:
filetype filedes;
This gets rid of some of the complexity, by moving it off to the side, but
it is still not safe for a programmers to access the filedes field directly
outside of APR, because the programmer has no way of knowing what the actual
type is. So for example printing the filedes using printf would yield wildly
varying results on Windows and OS2 when compared to Unix.
Another option also presents itself. Stick strictly to POSIX. This means
that all code can be shared on any POSIX compliant platform. The problem
with this is performance. One of the benefits to APR, is that it allows
developers to easily use native types on all platforms with the same code.
This has proven to provide a substantial performance boost on most non-Unix
platforms.
Having said all of that, sometimes incomplete types just don't make sense.
For example, the first implementation of time functions used incomplete types,
which added a layer of complexity that turned out to be unnecessary. If
a platform cannot provide a simple number that represents the number of seconds
elapsed since a specified date and time, then APR doesn't really want to
provide support for that platform.
APR is trying hard to provide a balance of incomplete and complete types,
but like all things, sometimes the developers make mistakes. If you are
using APR and find that there is an incomplete type that doesn't need to be
an incomplete type, please let us know, we are more than willing to listen
and design parts of APR that do not use incomplete types.
+47
View File
@@ -0,0 +1,47 @@
How do I use APR'ized programs in connection with programs that don't
use APR? These darn incomplete types don't let me fill out the APR types.
The APR developers acknowledge that most programs are not using APR, and
we don't expect them to migrate to using APR just because APR has been
released. So, we have provided a way for non-APR'ized programs to interact
very cleanly with APR.
There are a set of functions, all documented in apr_portable.h, which allow
a programmer to either get a native type from an APR type, or to setup an
APR type from a native type.
For example, if you are writing an add-on to another program that does not use
APR for file I/O, but you (in your infinite wisdom) want to use APR to make
sure your section is portable. Assume the program provides a type foo_t with
a file descriptor in it (fd).
void function_using_apr(foo_t non_apr_struct, ap_pool_t *p)
{
ap_file_t *apr_file = NULL;
ap_put_os_file(&apr_file, &non_apr_struct->fd, p);
...
}
There are portable functions for each APR incomplete type. They are all
called ap_put_os_foobar(), and they each take the same basic arguments, a
pointer to a pointer to the incomplete type (the last pointer in that list
should be NULL), a pointer to the native type, and a pool. Each of these can
be found in apr_portable.h.
If you have to do the exact opposite (take an APR type and convert it to a
native type, there are functions for that too. For example:
void function_not_using_apr(apr_file_t *apr_file)
{
int unix_file_desc;
ap_get_os_file(&unix_file_desc, apr_file);
...
}
For each ap_put_os_foobar, there is a corresponding ap_get_os_file. These are
also documented in apr_portable.h.
+96
View File
@@ -0,0 +1,96 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<title>Using APR Pools</title>
</head>
<body>
<h1>Using APR Pools</h1>
<p>
From <a href="http://subversion.tigris.org/">Subversion</a>, we
have learned a <em>lot</em> about how to use pools in a heavily
structured/object-based environment.
<a href="http://httpd.apache.org/">Apache httpd</a> is a
completely different beast: "allocate a request pool. use
it. destroy it."
</p>
<p>
In a complex app, that request-style of behavior is not
present. Luckily, the "proper" use of pools can be described in
just a few rules:
</p>
<ul>
<li>
Objects should not have their own pools. An object is
allocated into a pool defined by the constructor's caller. The
<strong>caller</strong> knows the lifetime of the object and
will manage it via the pool. Generally, this also means that
objects will not have a "close" or a "free" since those
operations will happen implicitly as part of the destruction
of the pool the objects live within.
</li>
<li>
<p>
Functions should not create/destroy pools for their
operation; they should use a pool provided by the
caller. Again, the <strong>caller</strong> knows more about
how the function will be used, how often, how many times,
etc. Thus, it should be in charge of the function's memory
usage.
</p>
<p>
As an example, the caller might know that the app will exit
upon the function's return. Thus, the function would be
creating extra work if it built and destroyed a
pool. Instead, it should use the passed-in pool, which the
caller is going to be tossing as part of app-exit anyways.
</p>
</li>
<li>
<p>
Whenever an unbounded iteration occurs, a subpool should be
used. The general pattern is:
</p>
<blockquote>
<pre>
subpool = apr_create_subpool(pool);
for (i = 0; i < n; ++i) {
apr_pool_clear(subpool);
do_operation(..., subpool);
}
apr_pool_destroy(subpool);</pre>
</blockquote>
<p>
This pattern prevents the 'pool' from growing unbounded and
consuming all of memory. Note that it is slightly more
optimal to clear the pool on loop-entry. This pattern also
allows for a '<tt>continue</tt>' to occur within the loop,
yet still ensure the pool will be cleared.
</p>
</li>
<li>
Given all of the above, it is pretty well mandatory to pass a
pool to <em>every</em> function. Since objects are not
recording pools for themselves, and the caller is always
supposed to be managing memory, then each function needs a
pool, rather than relying on some hidden magic pool. In
limited cases, objects may record the pool used for their
construction so that they can construct sub-parts, but these
cases should be examined carefully. Internal pools can lead to
unbounded pool usage if the object is not careful.
</li>
</ul>
<hr>
<address>Greg Stein</address>
<!-- Created: Wed Jun 25 14:39:57 PDT 2003 -->
<!-- hhmts start -->
Last modified: Wed Jun 25 14:50:19 PDT 2003
<!-- hhmts end -->
</body></html>
+57
View File
@@ -0,0 +1,57 @@
<HTML>
<HEAD><TITLE>APR Win32 Builds and Debugging</TITLE></HEAD>
<BODY>
<h1>APR Win32 Builds and Debugging</h1>
<h2>Configuration and Flavors</h2>
<p>The Win32 APR Developer Studio projects consist of</p>
<dl>
<dt>apr/apr.dsp</dt>
<dd>Builds the static apr.lib library (-D APR_DECLARE_STATIC)</dd>
<dt>apr/libapr.dsp</dt>
<dd>Builds the dynamic libapr.dll library (no define required)</dd>
<dt>apr-util/aprutil.dsp</dt>
<dd>Builds the static aprutil.lib library (-D APU_DECLARE_STATIC)</dd>
<dt>apr-util/libaprutil.dsp</dt>
<dd>Builds the dynamic libaprutil.dll library (no define required)</dd>
<dt>apr-iconv/apriconv.dsp</dt>
<dd>Builds the static apriconv.lib library (-D API_DECLARE_STATIC)</dd>
<dt>apr-iconv/libapriconv.dsp</dt>
<dd>Builds the dynamic libapriconv.dll library (no define required)</dd>
</dl>
<p>In order to prepare to use one of the <em>static</em> libraries above,
your application must be compiled with the define shown above, so that the
correct linkage is created. The APR authors intended the use of dynamic
libraries by default, so application authors do not need any special
defines in order to link to the dynamic library flavors.</p>
<p>In order to build APR, you must use the proper dependencies. A good
example of those dependencies is given in the apr-util/aprutil.dsw
Developer Studio workspace. You can borrow the parts of that structure
your application needs, that workspace defines both the dynamic and static
library dependencies.</p>
<p>The APR libraries (dynamic and static) are compiled with debugging symbols,
even in Release builds. The dynamic library symbols are always usable,
simply keep the correspond .pdb file in the same path as the library .dll.
(E.g. both libapr.dll and libapr.pdb should be copied to the same path.)</p>
<p>The static symbols will only be fully usable if your application does <em>not<em>
link with the /pdbtype:sept flag! At the time your application links to
an APR library, the corresponding _src.pdb file should exist in the original
path the library was built, or it may be sufficient to keep the _src.pdb file
in the same path as the library file. (E.g. apr.lib and apr_src.pdb should
reside together in your lib directory.) The later option is unconfirmed.</p>
<p>In order to keep the symbols compiled into the static library, your application
must use the linker's /debug flag. If you do not want the application to be
debuggable with its corresponding .pdb file, omit the /debug flag and all debug
symbolic information is discarded. Note that your application can only be
debugged with the corresponding .pdb file created by the linker, unless you use
/debugtype:coff or /debugtype:both in your link options.</p>
</BODY>
</HTML>