1*937a2000SPeter Wemm<HTML>
2*937a2000SPeter Wemm<HEAD><TITLE>APR Design Document</TITLE></HEAD>
3*937a2000SPeter Wemm<BODY>
4*937a2000SPeter Wemm<h1>Design of APR</h1>
5*937a2000SPeter Wemm
6*937a2000SPeter Wemm<p>The Apache Portable Run-time libraries have been designed to provide a common
7*937a2000SPeter Wemminterface to low level routines across any platform.  The original goal of APR
8*937a2000SPeter Wemmwas to combine all code in Apache to one common code base.  This is not the
9*937a2000SPeter Wemmcorrect approach however, so the goal of APR has changed.  There are places
10*937a2000SPeter Wemmwhere common code is not a good thing.  For example, how to map requests
11*937a2000SPeter Wemmto either threads or processes should be platform specific.  APR's place
12*937a2000SPeter Wemmis now to combine any code that can be safely combined without sacrificing
13*937a2000SPeter Wemmperformance.</p>
14*937a2000SPeter Wemm
15*937a2000SPeter Wemm<p>To this end we have created a set of operations that are required for cross
16*937a2000SPeter Wemmplatform development.  There may be other types that are desired and those
17*937a2000SPeter Wemmwill be implemented in the future.</p>
18*937a2000SPeter Wemm
19*937a2000SPeter Wemm<p>This document will discuss the structure of APR, and how best to contribute
20*937a2000SPeter Wemmcode to the effort.</p>
21*937a2000SPeter Wemm
22*937a2000SPeter Wemm<h2>APR On Windows and Netware</h2>
23*937a2000SPeter Wemm
24*937a2000SPeter Wemm<p>APR on Windows and Netware is different from APR on all other systems,
25*937a2000SPeter Wemmbecause those platforms don't use autoconf. On Unix, apr_private.h (private to
26*937a2000SPeter WemmAPR) and apr.h (public, used by applications that use APR) are generated by
27*937a2000SPeter Wemmautoconf from acconfig.h and apr.h.in respectively. On Windows (and Netware),
28*937a2000SPeter Wemmapr_private.h and apr.h are created from apr_private.hw (apr_private.hwn)
29*937a2000SPeter Wemmand apr.hw (apr.hwn) respectively.</p>
30*937a2000SPeter Wemm
31*937a2000SPeter Wemm<p> <strong>
32*937a2000SPeter Wemm        If you add code to acconfig.h or tests to configure.in or aclocal.m4,
33*937a2000SPeter Wemm        please give some thought to whether or not Windows and Netware need
34*937a2000SPeter Wemm	these additions as well.  A general rule of thumb, is that if it is
35*937a2000SPeter Wemm	a feature macro, such as APR_HAS_THREADS, Windows and Netware need it.
36*937a2000SPeter Wemm	In other words, if the definition is going to be used in a public APR
37*937a2000SPeter Wemm	header file, such as apr_general.h, Windows needs it.
38*937a2000SPeter Wemm
39*937a2000SPeter Wemm        The only time it is safe to add a macro or test without also adding
40*937a2000SPeter Wemm        the macro to apr*.h[n]w, is if the macro tells APR how to build.  For
41*937a2000SPeter Wemm        example, a test for a header file does not need to be added to Windows.
42*937a2000SPeter Wemm</strong></p>
43*937a2000SPeter Wemm
44*937a2000SPeter Wemm<h2>APR Features</h2>
45*937a2000SPeter Wemm
46*937a2000SPeter Wemm<p>One of the goals of APR is to provide a common set of features across all
47*937a2000SPeter Wemmplatforms.  This is an admirable goal, it is also not realistic.  We cannot
48*937a2000SPeter Wemmexpect to be able to implement ALL features on ALL platforms.  So we are
49*937a2000SPeter Wemmgoing to do the next best thing.  Provide a common interface to ALL APR
50*937a2000SPeter Wemmfeatures on MOST platforms.</p>
51*937a2000SPeter Wemm
52*937a2000SPeter Wemm<p>APR developers should create FEATURE MACROS for any feature that is not
53*937a2000SPeter Wemmavailable on ALL platforms.  This should be a simple definition which has
54*937a2000SPeter Wemmthe form:</p>
55*937a2000SPeter Wemm
56*937a2000SPeter Wemm<code>APR_HAS_FEATURE</code>
57*937a2000SPeter Wemm
58*937a2000SPeter Wemm<p>This macro should evaluate to true if APR has this feature on this platform.
59*937a2000SPeter WemmFor example, Linux and Windows have mmap'ed files, and APR is providing an
60*937a2000SPeter Wemminterface for mmapp'ing a file.  On both Linux and Windows, APR_HAS_MMAP
61*937a2000SPeter Wemmshould evaluate to one, and the ap_mmap_* functions should map files into
62*937a2000SPeter Wemmmemory and return the appropriate status codes.</p>
63*937a2000SPeter Wemm
64*937a2000SPeter Wemm<p>If your OS of choice does not have mmap'ed files, APR_HAS_MMAP should
65*937a2000SPeter Wemmevaluate to zero, and all ap_mmap_* functions should not be defined.  The
66*937a2000SPeter Wemmsecond step is a precaution that will allow us to break at compile time if a
67*937a2000SPeter Wemmprogrammer tries to use unsupported functions.</p>
68*937a2000SPeter Wemm
69*937a2000SPeter Wemm<h2>APR types</h2>
70*937a2000SPeter Wemm
71*937a2000SPeter Wemm<p>The base types in APR</p>
72*937a2000SPeter Wemm
73*937a2000SPeter Wemm<ul>
74*937a2000SPeter Wemm<li>dso<br>
75*937a2000SPeter Wemm	Shared library routines
76*937a2000SPeter Wemm<li>mmap<br>
77*937a2000SPeter Wemm	Memory-mapped files
78*937a2000SPeter Wemm<li>poll<br>
79*937a2000SPeter Wemm	Polling I/O
80*937a2000SPeter Wemm<li>time<br>
81*937a2000SPeter Wemm	Time
82*937a2000SPeter Wemm<li>user<br>
83*937a2000SPeter Wemm	Users and groups
84*937a2000SPeter Wemm<li>locks<br>
85*937a2000SPeter Wemm	Process and thread locks (critical sections)
86*937a2000SPeter Wemm<li>shmem<br>
87*937a2000SPeter Wemm	Shared memory
88*937a2000SPeter Wemm<li>file_io<br>
89*937a2000SPeter Wemm	File I/O, including pipes
90*937a2000SPeter Wemm<li>atomic<br>
91*937a2000SPeter Wemm	Atomic integer operations
92*937a2000SPeter Wemm<li>strings<br>
93*937a2000SPeter Wemm	String handling routines
94*937a2000SPeter Wemm<li>memory<br>
95*937a2000SPeter Wemm	Pool-based memory allocation
96*937a2000SPeter Wemm<li>passwd<br>
97*937a2000SPeter Wemm	Reading passwords from the terminal
98*937a2000SPeter Wemm<li>tables<br>
99*937a2000SPeter Wemm	Tables and hashes
100*937a2000SPeter Wemm<li>network_io<br>
101*937a2000SPeter Wemm	Network I/O
102*937a2000SPeter Wemm<li>threadproc<br>
103*937a2000SPeter Wemm	Threads and processes
104*937a2000SPeter Wemm<li>misc<br>
105*937a2000SPeter Wemm	Any APR type which doesn't have any other place to belong.  This
106*937a2000SPeter Wemm	should be used sparingly.
107*937a2000SPeter Wemm<li>support<br>
108*937a2000SPeter Wemm	Functions meant to be used across multiple APR types.  This area
109*937a2000SPeter Wemm	is for internal functions only.  If a function is exposed, it should
110*937a2000SPeter Wemm	not be put here.
111*937a2000SPeter Wemm</ul>
112*937a2000SPeter Wemm
113*937a2000SPeter Wemm<h2>Directory Structure</h2>
114*937a2000SPeter Wemm
115*937a2000SPeter Wemm<p>Each type has a base directory.  Inside this base directory, are
116*937a2000SPeter Wemmsubdirectories, which contain the actual code.  These subdirectories are named
117*937a2000SPeter Wemmafter the platforms the are compiled on.  Unix is also used as a common
118*937a2000SPeter Wemmdirectory.  If the code you are writing is POSIX based, you should look at the
119*937a2000SPeter Wemmcode in the unix directory.  A good rule of thumb, is that if more than half
120*937a2000SPeter Wemmyour code needs to be ifdef'ed out, and the structures required for your code
121*937a2000SPeter Wemmare substantively different from the POSIX code, you should create a new
122*937a2000SPeter Wemmdirectory.</p>
123*937a2000SPeter Wemm
124*937a2000SPeter Wemm<p>Currently, the APR code is written for Unix, BeOS, Windows, and OS/2.  An
125*937a2000SPeter Wemmexample of the directory structure is the file I/O directory:</p>
126*937a2000SPeter Wemm
127*937a2000SPeter Wemm<pre>
128*937a2000SPeter Wemmapr
129*937a2000SPeter Wemm  |
130*937a2000SPeter Wemm   ->  file_io
131*937a2000SPeter Wemm          |
132*937a2000SPeter Wemm           -> unix            The Unix and common base code
133*937a2000SPeter Wemm          |
134*937a2000SPeter Wemm           -> win32           The Windows code
135*937a2000SPeter Wemm          |
136*937a2000SPeter Wemm           -> os2             The OS/2 code
137*937a2000SPeter Wemm</pre>
138*937a2000SPeter Wemm
139*937a2000SPeter Wemm<p>Obviously, BeOS does not have a directory.  This is because BeOS is currently
140*937a2000SPeter Wemmusing the Unix directory for it's file_io.</p>
141*937a2000SPeter Wemm
142*937a2000SPeter Wemm<p>There are a few special top level directories.  These are test and include.
143*937a2000SPeter WemmTest is a directory which stores all test programs.  It is expected
144*937a2000SPeter Wemmthat if a new type is developed, there will also be a new test program, to
145*937a2000SPeter Wemmhelp people port this new type to different platforms.  A small document
146*937a2000SPeter Wemmdescribing how to create new tests that integrate with the test suite can be
147*937a2000SPeter Wemmfound in the test/ directory.  Include is a directory which stores all
148*937a2000SPeter Wemmrequired APR header files for external use.</p>
149*937a2000SPeter Wemm
150*937a2000SPeter Wemm<h2>Creating an APR Type</h2>
151*937a2000SPeter Wemm
152*937a2000SPeter Wemm<p>The current design of APR requires that most APR types be incomplete.
153*937a2000SPeter WemmIt is not possible to write flexible portable code if programs can access
154*937a2000SPeter Wemmthe internals of APR types.  This is because different platforms are
155*937a2000SPeter Wemmlikely to define different native types.  There are only two execptions to
156*937a2000SPeter Wemmthis rule:</p>
157*937a2000SPeter Wemm
158*937a2000SPeter Wemm<ul>
159*937a2000SPeter Wemm<li>The first exception to this rule is if the type can only reasonably be
160*937a2000SPeter Wemmimplemented one way.  For example, time is a complete type because there
161*937a2000SPeter Wemmis only one reasonable time implementation.
162*937a2000SPeter Wemm
163*937a2000SPeter Wemm<li>The second exception to the incomplete type rule can be found in
164*937a2000SPeter Wemmapr_portable.h.  This file defines the native types for each platform.
165*937a2000SPeter WemmUsing these types, it is possible to extract native types for any APR type.</p>
166*937a2000SPeter Wemm</ul>
167*937a2000SPeter Wemm
168*937a2000SPeter Wemm<p>For this reason, each platform defines a structure in their own directories.
169*937a2000SPeter WemmThose structures are then typedef'ed in an external header file.  For example
170*937a2000SPeter Wemmin file_io/unix/fileio.h:</p>
171*937a2000SPeter Wemm
172*937a2000SPeter Wemm<pre>
173*937a2000SPeter Wemm    struct ap_file_t {
174*937a2000SPeter Wemm        apr_pool_t *cntxt;
175*937a2000SPeter Wemm        int filedes;
176*937a2000SPeter Wemm        FILE *filehand;
177*937a2000SPeter Wemm        ...
178*937a2000SPeter Wemm    }
179*937a2000SPeter Wemm</pre>
180*937a2000SPeter Wemm
181*937a2000SPeter Wemm<p>In include/apr_file_io.h:</p>
182*937a2000SPeter Wemm    </pre>
183*937a2000SPeter Wemm    typedef struct ap_file_t    ap_file_t;
184*937a2000SPeter Wemm    </pre>
185*937a2000SPeter Wemm
186*937a2000SPeter Wemm<p> This will cause a compiler error if somebody tries to access the filedes
187*937a2000SPeter Wemmfield in this structure.  Windows does not have a filedes field, so obviously,
188*937a2000SPeter Wemmit is important that programs not be able to access these.</p>
189*937a2000SPeter Wemm
190*937a2000SPeter Wemm<p>You may notice the apr_pool_t field.  Most APR types have this field.  This
191*937a2000SPeter Wemmtype is used to allocate memory within APR.  Because every APR type has a pool,
192*937a2000SPeter Wemmany APR function can allocate memory if it needs to.  This is very important
193*937a2000SPeter Wemmand it is one of the reasons that APR works.  If you create a new type, you
194*937a2000SPeter Wemmmust add a pool to it.  If you do not, then all functions that operate on that
195*937a2000SPeter Wemmtype will need a pool argument.</p>
196*937a2000SPeter Wemm
197*937a2000SPeter Wemm<h2>New Function</h2>
198*937a2000SPeter Wemm
199*937a2000SPeter Wemm<p>When creating a new function, please try to adhere to these rules.</p>
200*937a2000SPeter Wemm
201*937a2000SPeter Wemm<ul>
202*937a2000SPeter Wemm<li>  Result arguments should be the first arguments.
203*937a2000SPeter Wemm<li>  If a function needs a pool, it should be the last argument.
204*937a2000SPeter Wemm<li>  These rules are flexible, especially if it makes the code easier
205*937a2000SPeter Wemm      to understand because it mimics a standard function.
206*937a2000SPeter Wemm</ul>
207*937a2000SPeter Wemm
208*937a2000SPeter Wemm<h2>Documentation</h2>
209*937a2000SPeter Wemm
210*937a2000SPeter Wemm<p>Whenever a new function is added to APR, it MUST be documented.  New
211*937a2000SPeter Wemmfunctions will not be committed unless there are docs to go along with them.
212*937a2000SPeter WemmThe documentation should be a comment block above the function in the header
213*937a2000SPeter Wemmfile.</p>
214*937a2000SPeter Wemm
215*937a2000SPeter Wemm<p>The format for the comment block is:</p>
216*937a2000SPeter Wemm
217*937a2000SPeter Wemm<pre>
218*937a2000SPeter Wemm    /**
219*937a2000SPeter Wemm     * Brief description of the function
220*937a2000SPeter Wemm     * @param parma_1_name explanation
221*937a2000SPeter Wemm     * @param parma_2_name explanation
222*937a2000SPeter Wemm     * @param parma_n_name explanation
223*937a2000SPeter Wemm     * @tip Any extra information people should know.
224*937a2000SPeter Wemm     * @deffunc function prototype if required
225*937a2000SPeter Wemm     */
226*937a2000SPeter Wemm</pre>
227*937a2000SPeter Wemm
228*937a2000SPeter Wemm<p>For an actual example, look at any file in the include directory.  The
229*937a2000SPeter Wemmreason the docs are in the header files is to ensure that the docs always
230*937a2000SPeter Wemmreflect the current code.  If you change paramters or return values for a
231*937a2000SPeter Wemmfunction, please be sure to update the documentation.</p>
232*937a2000SPeter Wemm
233*937a2000SPeter Wemm<h2>APR Error reporting</h2>
234*937a2000SPeter Wemm
235*937a2000SPeter Wemm<p>Most APR functions should return an ap_status_t type.  The only time an
236*937a2000SPeter WemmAPR function does not return an ap_status_t is if it absolutely CAN NOT
237*937a2000SPeter Wemmfail.  Examples of this would be filling out an array when you know you are
238*937a2000SPeter Wemmnot beyond the array's range.  If it cannot fail on your platform, but it
239*937a2000SPeter Wemmcould conceivably fail on another platform, it should return an ap_status_t.
240*937a2000SPeter WemmUnless you are sure, return an ap_status_t.</p>
241*937a2000SPeter Wemm
242*937a2000SPeter Wemm<strong>
243*937a2000SPeter Wemm        This includes functions that return TRUE/FALSE values.  How that
244*937a2000SPeter Wemm        is handled is discussed below
245*937a2000SPeter Wemm</strong>
246*937a2000SPeter Wemm
247*937a2000SPeter Wemm<p>All platforms return errno values unchanged.  Each platform can also have
248*937a2000SPeter Wemmone system error type, which can be returned after an offset is added.
249*937a2000SPeter WemmThere are five types of error values in APR, each with it's own offset.</p>
250*937a2000SPeter Wemm
251*937a2000SPeter Wemm<!--  This should be turned into a table, but I am lazy today -->
252*937a2000SPeter Wemm<pre>
253*937a2000SPeter Wemm    Name			Purpose
254*937a2000SPeter Wemm0) 			This is 0 for all platforms and isn't really defined
255*937a2000SPeter Wemm 			anywhere, but it is the offset for errno values.
256*937a2000SPeter Wemm			(This has no name because it isn't actually defined,
257*937a2000SPeter Wemm                        but for completeness we are discussing it here).
258*937a2000SPeter Wemm
259*937a2000SPeter Wemm1) APR_OS_START_ERROR	This is platform dependent, and is the offset at which
260*937a2000SPeter Wemm			APR errors start to be defined.  Error values are
261*937a2000SPeter Wemm			defined as anything which caused the APR function to
262*937a2000SPeter Wemm			fail.  APR errors in this range should be named
263*937a2000SPeter Wemm			APR_E* (i.e. APR_ENOSOCKET)
264*937a2000SPeter Wemm
265*937a2000SPeter Wemm2) APR_OS_START_STATUS	This is platform dependent, and is the offset at which
266*937a2000SPeter Wemm			APR status values start.  Status values do not indicate
267*937a2000SPeter Wemm			success or failure, and should be returned if
268*937a2000SPeter Wemm			APR_SUCCESS does not make sense.  APR status codes in
269*937a2000SPeter Wemm			this range should be name APR_* (i.e. APR_DETACH)
270*937a2000SPeter Wemm
271*937a2000SPeter Wemm4) APR_OS_START_USEERR	This is platform dependent, and is the offset at which
272*937a2000SPeter Wemm			APR apps can begin to add their own error codes.
273*937a2000SPeter Wemm
274*937a2000SPeter Wemm3) APR_OS_START_SYSERR	This is platform dependent, and is the offset at which
275*937a2000SPeter Wemm			system error values begin.
276*937a2000SPeter Wemm</pre>
277*937a2000SPeter Wemm
278*937a2000SPeter Wemm<strong>The difference in naming between APR_OS_START_ERROR and
279*937a2000SPeter WemmAPR_OS_START_STATUS mentioned above allows programmers to easily determine if
280*937a2000SPeter Wemmthe error code indicates an error condition or a status codition.</strong>
281*937a2000SPeter Wemm
282*937a2000SPeter Wemm<p>If your function has multiple return codes that all indicate success, but
283*937a2000SPeter Wemmwith different results, or if your function can only return PASS/FAIL, you
284*937a2000SPeter Wemmshould still return an apr_status_t.  In the first case, define one
285*937a2000SPeter WemmAPR status code for each return value, an example of this is
286*937a2000SPeter Wemm<code>apr_proc_wait</code>, which can only return APR_CHILDDONE,
287*937a2000SPeter WemmAPR_CHILDNOTDONE, or an error code.  In the second case, please return
288*937a2000SPeter WemmAPR_SUCCESS for PASS, and define a new APR status code for failure, an
289*937a2000SPeter Wemmexample of this is <code>apr_compare_users</code>, which can only return
290*937a2000SPeter WemmAPR_SUCCESS, APR_EMISMATCH, or an error code.</p>
291*937a2000SPeter Wemm
292*937a2000SPeter Wemm<p>All of these definitions can be found in apr_errno.h for all platforms.  When
293*937a2000SPeter Wemman error occurs in an APR function, the function must return an error code.
294*937a2000SPeter WemmIf the error occurred in a system call and that system call uses errno to
295*937a2000SPeter Wemmreport an error, then the code is returned unchanged.  For example: </p>
296*937a2000SPeter Wemm
297*937a2000SPeter Wemm<pre>
298*937a2000SPeter Wemm    if (open(fname, oflags, 0777) < 0)
299*937a2000SPeter Wemm        return errno;
300*937a2000SPeter Wemm</pre>
301*937a2000SPeter Wemm
302*937a2000SPeter Wemm<p>The next place an error can occur is a system call that uses some error value
303*937a2000SPeter Wemmother than the primary error value on a platform.  This can also be handled
304*937a2000SPeter Wemmby APR applications.  For example:</p>
305*937a2000SPeter Wemm
306*937a2000SPeter Wemm<pre>
307*937a2000SPeter Wemm    if (CreateFile(fname, oflags, sharemod, NULL,
308*937a2000SPeter Wemm                   createflags, attributes, 0) == INVALID_HANDLE_VALUE
309*937a2000SPeter Wemm        return (GetLAstError() + APR_OS_START_SYSERR);
310*937a2000SPeter Wemm</pre>
311*937a2000SPeter Wemm
312*937a2000SPeter Wemm<p>These two examples implement the same function for two different platforms.
313*937a2000SPeter WemmObviously even if the underlying problem is the same on both platforms, this
314*937a2000SPeter Wemmwill result in two different error codes being returned.  This is OKAY, and
315*937a2000SPeter Wemmis correct for APR.  APR relies on the fact that most of the time an error
316*937a2000SPeter Wemmoccurs, the program logs the error and continues, it does not try to
317*937a2000SPeter Wemmprogramatically solve the problem.  This does not mean we have not provided
318*937a2000SPeter Wemmsupport for programmatically solving the problem, it just isn't the default
319*937a2000SPeter Wemmcase.  We'll get to how this problem is solved in a little while.</p>
320*937a2000SPeter Wemm
321*937a2000SPeter Wemm<p>If the error occurs in an APR function but it is not due to a system call,
322*937a2000SPeter Wemmbut it is actually an APR error or just a status code from APR, then the
323*937a2000SPeter Wemmappropriate code should be returned.  These codes are defined in apr_errno.h
324*937a2000SPeter Wemmand should be self explanatory.</p>
325*937a2000SPeter Wemm
326*937a2000SPeter Wemm<p>No APR code should ever return a code between APR_OS_START_USEERR and
327*937a2000SPeter WemmAPR_OS_START_SYSERR, those codes are reserved for APR applications.</p>
328*937a2000SPeter Wemm
329*937a2000SPeter Wemm<p>To programmatically correct an error in a running application, the error
330*937a2000SPeter Wemmcodes need to be consistent across platforms.  This should make sense.  APR
331*937a2000SPeter Wemmhas provided macros to test for status code equivalency.  For example, to
332*937a2000SPeter Wemmdetermine if the code that you received from the APR function means EOF, you
333*937a2000SPeter Wemmwould use the macro APR_STATUS_IS_EOF().</p>
334*937a2000SPeter Wemm
335*937a2000SPeter Wemm<p>Why did APR take this approach?  There are two ways to deal with error
336*937a2000SPeter Wemmcodes portably.</p>
337*937a2000SPeter Wemm
338*937a2000SPeter Wemm<ol type=1>
339*937a2000SPeter Wemm<li>  Return the same error code across all platforms.
340*937a2000SPeter Wemm<li>  Return platform specific error codes and convert them when necessary.
341*937a2000SPeter Wemm</ol>
342*937a2000SPeter Wemm
343*937a2000SPeter Wemm<p>The problem with option number one is that it takes time to convert error
344*937a2000SPeter Wemmcodes to a common code, and most of the time programs want to just output
345*937a2000SPeter Wemman error string.  If we convert all errors to a common subset, we have four
346*937a2000SPeter Wemmsteps to output an error string:</p>
347*937a2000SPeter Wemm
348*937a2000SPeter Wemm<p>The seocnd problem with option 1, is that it is a lossy conversion.  For
349*937a2000SPeter Wemmexample, Windows and OS/2 have a couple hundred error codes, but POSIX errno
350*937a2000SPeter Wemmonly defines about 50 errno values.  This means that if we convert to a
351*937a2000SPeter Wemmcanonical error value immediately, there is no way for the programmer to
352*937a2000SPeter Wemmget the actual system error.</p>
353*937a2000SPeter Wemm
354*937a2000SPeter Wemm<pre>
355*937a2000SPeter Wemm    make syscall that fails
356*937a2000SPeter Wemm        convert to common error code                 step 1
357*937a2000SPeter Wemm        return common error code
358*937a2000SPeter Wemm            check for success
359*937a2000SPeter Wemm            call error output function               step 2
360*937a2000SPeter Wemm                convert back to system error         step 3
361*937a2000SPeter Wemm                output error string                  step 4
362*937a2000SPeter Wemm</pre>
363*937a2000SPeter Wemm
364*937a2000SPeter Wemm<p>By keeping the errors platform specific, we can output error strings in two
365*937a2000SPeter Wemmsteps.</p>
366*937a2000SPeter Wemm
367*937a2000SPeter Wemm<pre>
368*937a2000SPeter Wemm    make syscall that fails
369*937a2000SPeter Wemm        return error code
370*937a2000SPeter Wemm            check for success
371*937a2000SPeter Wemm            call error output function               step 1
372*937a2000SPeter Wemm                output error string                  step 2
373*937a2000SPeter Wemm</pre>
374*937a2000SPeter Wemm
375*937a2000SPeter Wemm<p>Less often, programs change their execution based on what error was returned.
376*937a2000SPeter WemmThis is no more expensive using option 2 than it is using option 1, but we
377*937a2000SPeter Wemmput the onus of converting the error code on the programmer themselves.
378*937a2000SPeter WemmFor example, using option 1:</p>
379*937a2000SPeter Wemm
380*937a2000SPeter Wemm<pre>
381*937a2000SPeter Wemm    make syscall that fails
382*937a2000SPeter Wemm        convert to common error code
383*937a2000SPeter Wemm        return common error code
384*937a2000SPeter Wemm            decide execution based on common error code
385*937a2000SPeter Wemm</pre>
386*937a2000SPeter Wemm
387*937a2000SPeter Wemm<p>Using option 2:</p>
388*937a2000SPeter Wemm
389*937a2000SPeter Wemm<pre>
390*937a2000SPeter Wemm    make syscall that fails
391*937a2000SPeter Wemm        return error code
392*937a2000SPeter Wemm            convert to common error code (using ap_canonical_error)
393*937a2000SPeter Wemm            decide execution based on common error code
394*937a2000SPeter Wemm</pre>
395*937a2000SPeter Wemm
396*937a2000SPeter Wemm<p>Finally, there is one more operation on error codes.  You can get a string
397*937a2000SPeter Wemmthat explains in human readable form what has happened.  To do this using
398*937a2000SPeter WemmAPR, call ap_strerror().</p>
399*937a2000SPeter Wemm
400