1251875Speter<HTML>
2251875Speter<HEAD><TITLE>APR Design Document</TITLE></HEAD>
3251875Speter<BODY>
4251875Speter<h1>Design of APR</h1>
5251875Speter
6251875Speter<p>The Apache Portable Run-time libraries have been designed to provide a common
7251875Speterinterface to low level routines across any platform.  The original goal of APR
8251875Speterwas to combine all code in Apache to one common code base.  This is not the
9251875Spetercorrect approach however, so the goal of APR has changed.  There are places 
10251875Speterwhere common code is not a good thing.  For example, how to map requests 
11251875Speterto either threads or processes should be platform specific.  APR's place 
12251875Speteris now to combine any code that can be safely combined without sacrificing 
13251875Speterperformance.</p>
14251875Speter
15251875Speter<p>To this end we have created a set of operations that are required for cross
16251875Speterplatform development.  There may be other types that are desired and those
17251875Speterwill be implemented in the future.</p>
18251875Speter
19251875Speter<p>This document will discuss the structure of APR, and how best to contribute
20251875Spetercode to the effort.</p>
21251875Speter
22251875Speter<h2>APR On Windows and Netware</h2>
23251875Speter
24251875Speter<p>APR on Windows and Netware is different from APR on all other systems, 
25251875Speterbecause those platforms don't use autoconf. On Unix, apr_private.h (private to 
26251875SpeterAPR) and apr.h (public, used by applications that use APR) are generated by 
27251875Speterautoconf from acconfig.h and apr.h.in respectively. On Windows (and Netware), 
28251875Speterapr_private.h and apr.h are created from apr_private.hw (apr_private.hwn) 
29251875Speterand apr.hw (apr.hwn) respectively.</p>
30251875Speter
31251875Speter<p> <strong>
32251875Speter        If you add code to acconfig.h or tests to configure.in or aclocal.m4,
33251875Speter        please give some thought to whether or not Windows and Netware need 
34251875Speter	these additions as well.  A general rule of thumb, is that if it is 
35251875Speter	a feature macro, such as APR_HAS_THREADS, Windows and Netware need it.
36251875Speter	In other words, if the definition is going to be used in a public APR 
37251875Speter	header file, such as apr_general.h, Windows needs it.
38251875Speter        
39251875Speter        The only time it is safe to add a macro or test without also adding 
40251875Speter        the macro to apr*.h[n]w, is if the macro tells APR how to build.  For
41251875Speter        example, a test for a header file does not need to be added to Windows.
42251875Speter</strong></p>
43251875Speter
44251875Speter<h2>APR Features</h2>
45251875Speter
46251875Speter<p>One of the goals of APR is to provide a common set of features across all 
47251875Speterplatforms.  This is an admirable goal, it is also not realistic.  We cannot
48251875Speterexpect to be able to implement ALL features on ALL platforms.  So we are
49251875Spetergoing to do the next best thing.  Provide a common interface to ALL APR 
50251875Speterfeatures on MOST platforms.</p>
51251875Speter
52251875Speter<p>APR developers should create FEATURE MACROS for any feature that is not
53251875Speteravailable on ALL platforms.  This should be a simple definition which has
54251875Speterthe form:</p>
55251875Speter
56251875Speter<code>APR_HAS_FEATURE</code>
57251875Speter
58251875Speter<p>This macro should evaluate to true if APR has this feature on this platform.
59251875SpeterFor example, Linux and Windows have mmap'ed files, and APR is providing an
60251875Speterinterface for mmapp'ing a file.  On both Linux and Windows, APR_HAS_MMAP
61251875Spetershould evaluate to one, and the ap_mmap_* functions should map files into
62251875Spetermemory and return the appropriate status codes.</p>
63251875Speter
64251875Speter<p>If your OS of choice does not have mmap'ed files, APR_HAS_MMAP should 
65251875Speterevaluate to zero, and all ap_mmap_* functions should not be defined.  The 
66251875Spetersecond step is a precaution that will allow us to break at compile time if a 
67251875Speterprogrammer tries to use unsupported functions.</p>
68251875Speter
69251875Speter<h2>APR types</h2>
70251875Speter
71251875Speter<p>The base types in APR</p>
72251875Speter
73251875Speter<ul>
74251875Speter<li>dso<br>
75251875Speter	Shared library routines
76251875Speter<li>mmap<br>
77251875Speter	Memory-mapped files
78251875Speter<li>poll<br>
79251875Speter	Polling I/O
80251875Speter<li>time<br>
81251875Speter	Time
82251875Speter<li>user<br>
83251875Speter	Users and groups
84251875Speter<li>locks<br>
85251875Speter	Process and thread locks (critical sections)
86251875Speter<li>shmem<br>
87251875Speter	Shared memory
88251875Speter<li>file_io<br>
89251875Speter	File I/O, including pipes
90251875Speter<li>atomic<br>
91251875Speter	Atomic integer operations
92251875Speter<li>strings<br>
93251875Speter	String handling routines
94251875Speter<li>memory<br>
95251875Speter	Pool-based memory allocation
96251875Speter<li>passwd<br>
97251875Speter	Reading passwords from the terminal
98251875Speter<li>tables<br>
99251875Speter	Tables and hashes
100251875Speter<li>network_io<br>
101251875Speter	Network I/O
102251875Speter<li>threadproc<br>
103251875Speter	Threads and processes
104251875Speter<li>misc<br>
105251875Speter	Any APR type which doesn't have any other place to belong.  This
106251875Speter	should be used sparingly.
107251875Speter<li>support<br>
108251875Speter	Functions meant to be used across multiple APR types.  This area
109251875Speter	is for internal functions only.  If a function is exposed, it should
110251875Speter	not be put here.
111251875Speter</ul>
112251875Speter
113251875Speter<h2>Directory Structure</h2>
114251875Speter
115251875Speter<p>Each type has a base directory.  Inside this base directory, are
116251875Spetersubdirectories, which contain the actual code.  These subdirectories are named
117251875Speterafter the platforms the are compiled on.  Unix is also used as a common
118251875Speterdirectory.  If the code you are writing is POSIX based, you should look at the
119251875Spetercode in the unix directory.  A good rule of thumb, is that if more than half
120251875Speteryour code needs to be ifdef'ed out, and the structures required for your code
121251875Speterare substantively different from the POSIX code, you should create a new
122251875Speterdirectory.</p>
123251875Speter
124251875Speter<p>Currently, the APR code is written for Unix, BeOS, Windows, and OS/2.  An
125251875Speterexample of the directory structure is the file I/O directory:</p>
126251875Speter
127251875Speter<pre>
128251875Speterapr
129251875Speter  |
130251875Speter   ->  file_io
131251875Speter          |
132251875Speter           -> unix            The Unix and common base code
133251875Speter          |
134251875Speter           -> win32           The Windows code
135251875Speter          | 
136251875Speter           -> os2             The OS/2 code
137251875Speter</pre>
138251875Speter
139251875Speter<p>Obviously, BeOS does not have a directory.  This is because BeOS is currently
140251875Speterusing the Unix directory for it's file_io.</p>
141251875Speter
142251875Speter<p>There are a few special top level directories.  These are test and include.
143251875SpeterTest is a directory which stores all test programs.  It is expected
144251875Speterthat if a new type is developed, there will also be a new test program, to
145251875Speterhelp people port this new type to different platforms.  A small document
146251875Speterdescribing how to create new tests that integrate with the test suite can be
147251875Speterfound in the test/ directory.  Include is a directory which stores all 
148251875Speterrequired APR header files for external use.</p>
149251875Speter
150251875Speter<h2>Creating an APR Type</h2>
151251875Speter
152251875Speter<p>The current design of APR requires that most APR types be incomplete.  
153251875SpeterIt is not possible to write flexible portable code if programs can access 
154251875Speterthe internals of APR types.  This is because different platforms are 
155251875Speterlikely to define different native types.  There are only two execptions to
156251875Speterthis rule:</p>
157251875Speter
158251875Speter<ul>
159251875Speter<li>The first exception to this rule is if the type can only reasonably be 
160251875Speterimplemented one way.  For example, time is a complete type because there 
161251875Speteris only one reasonable time implementation.
162251875Speter
163251875Speter<li>The second exception to the incomplete type rule can be found in 
164251875Speterapr_portable.h.  This file defines the native types for each platform.  
165251875SpeterUsing these types, it is possible to extract native types for any APR type.</p>
166251875Speter</ul>
167251875Speter
168251875Speter<p>For this reason, each platform defines a structure in their own directories. 
169251875SpeterThose structures are then typedef'ed in an external header file.  For example
170251875Speterin file_io/unix/fileio.h:</p>
171251875Speter
172251875Speter<pre>
173251875Speter    struct ap_file_t {
174251875Speter        apr_pool_t *cntxt;
175251875Speter        int filedes;
176251875Speter        FILE *filehand;
177251875Speter        ...
178251875Speter    }
179251875Speter</pre>
180251875Speter
181251875Speter<p>In include/apr_file_io.h:</p>
182251875Speter    </pre>
183251875Speter    typedef struct ap_file_t    ap_file_t;
184251875Speter    </pre>
185251875Speter
186251875Speter<p> This will cause a compiler error if somebody tries to access the filedes 
187251875Speterfield in this structure.  Windows does not have a filedes field, so obviously, 
188251875Speterit is important that programs not be able to access these.</p>
189251875Speter
190251875Speter<p>You may notice the apr_pool_t field.  Most APR types have this field.  This
191251875Spetertype is used to allocate memory within APR.  Because every APR type has a pool,
192251875Speterany APR function can allocate memory if it needs to.  This is very important
193251875Speterand it is one of the reasons that APR works.  If you create a new type, you
194251875Spetermust add a pool to it.  If you do not, then all functions that operate on that
195251875Spetertype will need a pool argument.</p>
196251875Speter
197251875Speter<h2>New Function</h2>
198251875Speter
199251875Speter<p>When creating a new function, please try to adhere to these rules.</p>
200251875Speter
201251875Speter<ul>
202251875Speter<li>  Result arguments should be the first arguments.
203251875Speter<li>  If a function needs a pool, it should be the last argument.
204251875Speter<li>  These rules are flexible, especially if it makes the code easier
205251875Speter      to understand because it mimics a standard function.
206251875Speter</ul>
207251875Speter
208251875Speter<h2>Documentation</h2>
209251875Speter
210251875Speter<p>Whenever a new function is added to APR, it MUST be documented.  New 
211251875Speterfunctions will not be committed unless there are docs to go along with them.
212251875SpeterThe documentation should be a comment block above the function in the header
213251875Speterfile.</p>
214251875Speter
215251875Speter<p>The format for the comment block is:</p>
216251875Speter
217251875Speter<pre>
218251875Speter    /**
219251875Speter     * Brief description of the function
220251875Speter     * @param parma_1_name explanation
221251875Speter     * @param parma_2_name explanation
222251875Speter     * @param parma_n_name explanation
223251875Speter     * @tip Any extra information people should know.
224251875Speter     * @deffunc function prototype if required
225251875Speter     */ 
226251875Speter</pre>
227251875Speter
228251875Speter<p>For an actual example, look at any file in the include directory.  The 
229251875Speterreason the docs are in the header files is to ensure that the docs always
230251875Speterreflect the current code.  If you change paramters or return values for a 
231251875Speterfunction, please be sure to update the documentation.</p>
232251875Speter
233251875Speter<h2>APR Error reporting</h2>
234251875Speter
235251875Speter<p>Most APR functions should return an ap_status_t type.  The only time an
236251875SpeterAPR function does not return an ap_status_t is if it absolutely CAN NOT
237251875Speterfail.  Examples of this would be filling out an array when you know you are
238251875Speternot beyond the array's range.  If it cannot fail on your platform, but it
239251875Spetercould conceivably fail on another platform, it should return an ap_status_t.
240251875SpeterUnless you are sure, return an ap_status_t.</p>
241251875Speter
242251875Speter<strong>
243251875Speter        This includes functions that return TRUE/FALSE values.  How that 
244251875Speter        is handled is discussed below
245251875Speter</strong>
246251875Speter
247251875Speter<p>All platforms return errno values unchanged.  Each platform can also have
248251875Speterone system error type, which can be returned after an offset is added.  
249251875SpeterThere are five types of error values in APR, each with it's own offset.</p>
250251875Speter
251251875Speter<!--  This should be turned into a table, but I am lazy today -->
252251875Speter<pre>
253251875Speter    Name			Purpose
254251875Speter0) 			This is 0 for all platforms and isn't really defined
255251875Speter 			anywhere, but it is the offset for errno values.
256251875Speter			(This has no name because it isn't actually defined, 
257251875Speter                        but for completeness we are discussing it here).
258251875Speter
259251875Speter1) APR_OS_START_ERROR	This is platform dependent, and is the offset at which
260251875Speter			APR errors start to be defined.  Error values are 
261251875Speter			defined as anything which caused the APR function to 
262251875Speter			fail.  APR errors in this range should be named 
263251875Speter			APR_E* (i.e. APR_ENOSOCKET)
264251875Speter
265251875Speter2) APR_OS_START_STATUS	This is platform dependent, and is the offset at which
266251875Speter			APR status values start.  Status values do not indicate
267251875Speter			success or failure, and should be returned if 
268251875Speter			APR_SUCCESS does not make sense.  APR status codes in 
269251875Speter			this range should be name APR_* (i.e. APR_DETACH)
270251875Speter
271251875Speter4) APR_OS_START_USEERR	This is platform dependent, and is the offset at which
272251875Speter			APR apps can begin to add their own error codes.
273251875Speter
274251875Speter3) APR_OS_START_SYSERR	This is platform dependent, and is the offset at which
275251875Speter			system error values begin.
276251875Speter</pre>
277251875Speter
278251875Speter<strong>The difference in naming between APR_OS_START_ERROR and 
279251875SpeterAPR_OS_START_STATUS mentioned above allows programmers to easily determine if
280251875Speterthe error code indicates an error condition or a status codition.</strong>
281251875Speter
282251875Speter<p>If your function has multiple return codes that all indicate success, but
283251875Speterwith different results, or if your function can only return PASS/FAIL, you 
284251875Spetershould still return an apr_status_t.  In the first case, define one
285251875SpeterAPR status code for each return value, an example of this is
286251875Speter<code>apr_proc_wait</code>, which can only return APR_CHILDDONE, 
287251875SpeterAPR_CHILDNOTDONE, or an error code.  In the second case, please return 
288251875SpeterAPR_SUCCESS for PASS, and define a new APR status code for failure, an 
289251875Speterexample of this is <code>apr_compare_users</code>, which can only return
290251875SpeterAPR_SUCCESS, APR_EMISMATCH, or an error code.</p>
291251875Speter
292251875Speter<p>All of these definitions can be found in apr_errno.h for all platforms.  When
293251875Speteran error occurs in an APR function, the function must return an error code.
294251875SpeterIf the error occurred in a system call and that system call uses errno to
295251875Speterreport an error, then the code is returned unchanged.  For example: </p>
296251875Speter
297251875Speter<pre>
298251875Speter    if (open(fname, oflags, 0777) < 0)
299251875Speter        return errno;
300251875Speter</pre>
301251875Speter
302251875Speter<p>The next place an error can occur is a system call that uses some error value
303251875Speterother than the primary error value on a platform.  This can also be handled
304251875Speterby APR applications.  For example:</p>
305251875Speter
306251875Speter<pre>
307251875Speter    if (CreateFile(fname, oflags, sharemod, NULL, 
308251875Speter                   createflags, attributes, 0) == INVALID_HANDLE_VALUE
309251875Speter        return (GetLAstError() + APR_OS_START_SYSERR);
310251875Speter</pre>
311251875Speter
312251875Speter<p>These two examples implement the same function for two different platforms.
313251875SpeterObviously even if the underlying problem is the same on both platforms, this
314251875Speterwill result in two different error codes being returned.  This is OKAY, and
315251875Speteris correct for APR.  APR relies on the fact that most of the time an error
316251875Speteroccurs, the program logs the error and continues, it does not try to
317251875Speterprogramatically solve the problem.  This does not mean we have not provided
318251875Spetersupport for programmatically solving the problem, it just isn't the default
319251875Spetercase.  We'll get to how this problem is solved in a little while.</p>
320251875Speter
321251875Speter<p>If the error occurs in an APR function but it is not due to a system call,
322251875Speterbut it is actually an APR error or just a status code from APR, then the
323251875Speterappropriate code should be returned.  These codes are defined in apr_errno.h
324251875Speterand should be self explanatory.</p>
325251875Speter
326251875Speter<p>No APR code should ever return a code between APR_OS_START_USEERR and 
327251875SpeterAPR_OS_START_SYSERR, those codes are reserved for APR applications.</p>
328251875Speter
329251875Speter<p>To programmatically correct an error in a running application, the error 
330251875Spetercodes need to be consistent across platforms.  This should make sense.  APR
331251875Speterhas provided macros to test for status code equivalency.  For example, to
332251875Speterdetermine if the code that you received from the APR function means EOF, you
333251875Speterwould use the macro APR_STATUS_IS_EOF().</p>
334251875Speter
335251875Speter<p>Why did APR take this approach?  There are two ways to deal with error 
336251875Spetercodes portably.</p>
337251875Speter
338251875Speter<ol type=1>
339251875Speter<li>  Return the same error code across all platforms.
340251875Speter<li>  Return platform specific error codes and convert them when necessary.  
341251875Speter</ol>
342251875Speter
343251875Speter<p>The problem with option number one is that it takes time to convert error 
344251875Spetercodes to a common code, and most of the time programs want to just output 
345251875Speteran error string.  If we convert all errors to a common subset, we have four 
346251875Spetersteps to output an error string:</p>
347251875Speter
348251875Speter<p>The seocnd problem with option 1, is that it is a lossy conversion.  For
349251875Speterexample, Windows and OS/2 have a couple hundred error codes, but POSIX errno
350251875Speteronly defines about 50 errno values.  This means that if we convert to a
351251875Spetercanonical error value immediately, there is no way for the programmer to
352251875Speterget the actual system error.</p>
353251875Speter
354251875Speter<pre>
355251875Speter    make syscall that fails
356251875Speter        convert to common error code                 step 1
357251875Speter        return common error code
358251875Speter            check for success
359251875Speter            call error output function               step 2
360251875Speter                convert back to system error         step 3
361251875Speter                output error string                  step 4
362251875Speter</pre>
363251875Speter
364251875Speter<p>By keeping the errors platform specific, we can output error strings in two
365251875Spetersteps.</p>
366251875Speter
367251875Speter<pre>
368251875Speter    make syscall that fails
369251875Speter        return error code
370251875Speter            check for success
371251875Speter            call error output function               step 1
372251875Speter                output error string                  step 2
373251875Speter</pre>
374251875Speter
375251875Speter<p>Less often, programs change their execution based on what error was returned.
376251875SpeterThis is no more expensive using option 2 than it is using option 1, but we
377251875Speterput the onus of converting the error code on the programmer themselves.
378251875SpeterFor example, using option 1:</p>
379251875Speter
380251875Speter<pre>
381251875Speter    make syscall that fails
382251875Speter        convert to common error code
383251875Speter        return common error code
384251875Speter            decide execution based on common error code
385251875Speter</pre>
386251875Speter
387251875Speter<p>Using option 2:</p>
388251875Speter    
389251875Speter<pre>
390251875Speter    make syscall that fails
391251875Speter        return error code
392251875Speter            convert to common error code (using ap_canonical_error)
393251875Speter            decide execution based on common error code
394251875Speter</pre>
395251875Speter
396251875Speter<p>Finally, there is one more operation on error codes.  You can get a string
397251875Speterthat explains in human readable form what has happened.  To do this using 
398251875SpeterAPR, call ap_strerror().</p>
399251875Speter
400