1937a2000SPeter Wemm<HTML>
2937a2000SPeter Wemm<HEAD><TITLE>APR Design Document</TITLE></HEAD>
3937a2000SPeter Wemm<BODY>
4937a2000SPeter Wemm<h1>Design of APR</h1>
5937a2000SPeter Wemm
6937a2000SPeter Wemm<p>The Apache Portable Run-time libraries have been designed to provide a common
7937a2000SPeter Wemminterface to low level routines across any platform.  The original goal of APR
8937a2000SPeter Wemmwas to combine all code in Apache to one common code base.  This is not the
9937a2000SPeter Wemmcorrect approach however, so the goal of APR has changed.  There are places
10937a2000SPeter Wemmwhere common code is not a good thing.  For example, how to map requests
11937a2000SPeter Wemmto either threads or processes should be platform specific.  APR's place
12937a2000SPeter Wemmis now to combine any code that can be safely combined without sacrificing
13937a2000SPeter Wemmperformance.</p>
14937a2000SPeter Wemm
15937a2000SPeter Wemm<p>To this end we have created a set of operations that are required for cross
16937a2000SPeter Wemmplatform development.  There may be other types that are desired and those
17937a2000SPeter Wemmwill be implemented in the future.</p>
18937a2000SPeter Wemm
19937a2000SPeter Wemm<p>This document will discuss the structure of APR, and how best to contribute
20937a2000SPeter Wemmcode to the effort.</p>
21937a2000SPeter Wemm
22937a2000SPeter Wemm<h2>APR On Windows and Netware</h2>
23937a2000SPeter Wemm
24937a2000SPeter Wemm<p>APR on Windows and Netware is different from APR on all other systems,
25937a2000SPeter Wemmbecause those platforms don't use autoconf. On Unix, apr_private.h (private to
26937a2000SPeter WemmAPR) and apr.h (public, used by applications that use APR) are generated by
27937a2000SPeter Wemmautoconf from acconfig.h and apr.h.in respectively. On Windows (and Netware),
28937a2000SPeter Wemmapr_private.h and apr.h are created from apr_private.hw (apr_private.hwn)
29937a2000SPeter Wemmand apr.hw (apr.hwn) respectively.</p>
30937a2000SPeter Wemm
31937a2000SPeter Wemm<p> <strong>
32937a2000SPeter Wemm        If you add code to acconfig.h or tests to configure.in or aclocal.m4,
33937a2000SPeter Wemm        please give some thought to whether or not Windows and Netware need
34937a2000SPeter Wemm	these additions as well.  A general rule of thumb, is that if it is
35937a2000SPeter Wemm	a feature macro, such as APR_HAS_THREADS, Windows and Netware need it.
36937a2000SPeter Wemm	In other words, if the definition is going to be used in a public APR
37937a2000SPeter Wemm	header file, such as apr_general.h, Windows needs it.
38937a2000SPeter Wemm
39937a2000SPeter Wemm        The only time it is safe to add a macro or test without also adding
40937a2000SPeter Wemm        the macro to apr*.h[n]w, is if the macro tells APR how to build.  For
41937a2000SPeter Wemm        example, a test for a header file does not need to be added to Windows.
42937a2000SPeter Wemm</strong></p>
43937a2000SPeter Wemm
44937a2000SPeter Wemm<h2>APR Features</h2>
45937a2000SPeter Wemm
46937a2000SPeter Wemm<p>One of the goals of APR is to provide a common set of features across all
47937a2000SPeter Wemmplatforms.  This is an admirable goal, it is also not realistic.  We cannot
48937a2000SPeter Wemmexpect to be able to implement ALL features on ALL platforms.  So we are
49937a2000SPeter Wemmgoing to do the next best thing.  Provide a common interface to ALL APR
50937a2000SPeter Wemmfeatures on MOST platforms.</p>
51937a2000SPeter Wemm
52937a2000SPeter Wemm<p>APR developers should create FEATURE MACROS for any feature that is not
53937a2000SPeter Wemmavailable on ALL platforms.  This should be a simple definition which has
54937a2000SPeter Wemmthe form:</p>
55937a2000SPeter Wemm
56937a2000SPeter Wemm<code>APR_HAS_FEATURE</code>
57937a2000SPeter Wemm
58937a2000SPeter Wemm<p>This macro should evaluate to true if APR has this feature on this platform.
59937a2000SPeter WemmFor example, Linux and Windows have mmap'ed files, and APR is providing an
60937a2000SPeter Wemminterface for mmapp'ing a file.  On both Linux and Windows, APR_HAS_MMAP
61937a2000SPeter Wemmshould evaluate to one, and the ap_mmap_* functions should map files into
62937a2000SPeter Wemmmemory and return the appropriate status codes.</p>
63937a2000SPeter Wemm
64937a2000SPeter Wemm<p>If your OS of choice does not have mmap'ed files, APR_HAS_MMAP should
65937a2000SPeter Wemmevaluate to zero, and all ap_mmap_* functions should not be defined.  The
66937a2000SPeter Wemmsecond step is a precaution that will allow us to break at compile time if a
67937a2000SPeter Wemmprogrammer tries to use unsupported functions.</p>
68937a2000SPeter Wemm
69937a2000SPeter Wemm<h2>APR types</h2>
70937a2000SPeter Wemm
71937a2000SPeter Wemm<p>The base types in APR</p>
72937a2000SPeter Wemm
73937a2000SPeter Wemm<ul>
74937a2000SPeter Wemm<li>dso<br>
75937a2000SPeter Wemm	Shared library routines
76937a2000SPeter Wemm<li>mmap<br>
77937a2000SPeter Wemm	Memory-mapped files
78937a2000SPeter Wemm<li>poll<br>
79937a2000SPeter Wemm	Polling I/O
80937a2000SPeter Wemm<li>time<br>
81937a2000SPeter Wemm	Time
82937a2000SPeter Wemm<li>user<br>
83937a2000SPeter Wemm	Users and groups
84937a2000SPeter Wemm<li>locks<br>
85937a2000SPeter Wemm	Process and thread locks (critical sections)
86937a2000SPeter Wemm<li>shmem<br>
87937a2000SPeter Wemm	Shared memory
88937a2000SPeter Wemm<li>file_io<br>
89937a2000SPeter Wemm	File I/O, including pipes
90937a2000SPeter Wemm<li>atomic<br>
91937a2000SPeter Wemm	Atomic integer operations
92937a2000SPeter Wemm<li>strings<br>
93937a2000SPeter Wemm	String handling routines
94937a2000SPeter Wemm<li>memory<br>
95937a2000SPeter Wemm	Pool-based memory allocation
96937a2000SPeter Wemm<li>passwd<br>
97937a2000SPeter Wemm	Reading passwords from the terminal
98937a2000SPeter Wemm<li>tables<br>
99937a2000SPeter Wemm	Tables and hashes
100937a2000SPeter Wemm<li>network_io<br>
101937a2000SPeter Wemm	Network I/O
102937a2000SPeter Wemm<li>threadproc<br>
103937a2000SPeter Wemm	Threads and processes
104937a2000SPeter Wemm<li>misc<br>
105937a2000SPeter Wemm	Any APR type which doesn't have any other place to belong.  This
106937a2000SPeter Wemm	should be used sparingly.
107937a2000SPeter Wemm<li>support<br>
108937a2000SPeter Wemm	Functions meant to be used across multiple APR types.  This area
109937a2000SPeter Wemm	is for internal functions only.  If a function is exposed, it should
110937a2000SPeter Wemm	not be put here.
111937a2000SPeter Wemm</ul>
112937a2000SPeter Wemm
113937a2000SPeter Wemm<h2>Directory Structure</h2>
114937a2000SPeter Wemm
115937a2000SPeter Wemm<p>Each type has a base directory.  Inside this base directory, are
116937a2000SPeter Wemmsubdirectories, which contain the actual code.  These subdirectories are named
117937a2000SPeter Wemmafter the platforms the are compiled on.  Unix is also used as a common
118937a2000SPeter Wemmdirectory.  If the code you are writing is POSIX based, you should look at the
119937a2000SPeter Wemmcode in the unix directory.  A good rule of thumb, is that if more than half
120937a2000SPeter Wemmyour code needs to be ifdef'ed out, and the structures required for your code
121937a2000SPeter Wemmare substantively different from the POSIX code, you should create a new
122937a2000SPeter Wemmdirectory.</p>
123937a2000SPeter Wemm
124937a2000SPeter Wemm<p>Currently, the APR code is written for Unix, BeOS, Windows, and OS/2.  An
125937a2000SPeter Wemmexample of the directory structure is the file I/O directory:</p>
126937a2000SPeter Wemm
127937a2000SPeter Wemm<pre>
128937a2000SPeter Wemmapr
129937a2000SPeter Wemm  |
130937a2000SPeter Wemm   ->  file_io
131937a2000SPeter Wemm          |
132937a2000SPeter Wemm           -> unix            The Unix and common base code
133937a2000SPeter Wemm          |
134937a2000SPeter Wemm           -> win32           The Windows code
135937a2000SPeter Wemm          |
136937a2000SPeter Wemm           -> os2             The OS/2 code
137937a2000SPeter Wemm</pre>
138937a2000SPeter Wemm
139937a2000SPeter Wemm<p>Obviously, BeOS does not have a directory.  This is because BeOS is currently
140937a2000SPeter Wemmusing the Unix directory for it's file_io.</p>
141937a2000SPeter Wemm
142937a2000SPeter Wemm<p>There are a few special top level directories.  These are test and include.
143937a2000SPeter WemmTest is a directory which stores all test programs.  It is expected
144937a2000SPeter Wemmthat if a new type is developed, there will also be a new test program, to
145937a2000SPeter Wemmhelp people port this new type to different platforms.  A small document
146937a2000SPeter Wemmdescribing how to create new tests that integrate with the test suite can be
147937a2000SPeter Wemmfound in the test/ directory.  Include is a directory which stores all
148937a2000SPeter Wemmrequired APR header files for external use.</p>
149937a2000SPeter Wemm
150937a2000SPeter Wemm<h2>Creating an APR Type</h2>
151937a2000SPeter Wemm
152937a2000SPeter Wemm<p>The current design of APR requires that most APR types be incomplete.
153937a2000SPeter WemmIt is not possible to write flexible portable code if programs can access
154937a2000SPeter Wemmthe internals of APR types.  This is because different platforms are
155*b081c245SDimitry Andriclikely to define different native types.  There are only two exceptions to
156937a2000SPeter Wemmthis rule:</p>
157937a2000SPeter Wemm
158937a2000SPeter Wemm<ul>
159937a2000SPeter Wemm<li>The first exception to this rule is if the type can only reasonably be
160937a2000SPeter Wemmimplemented one way.  For example, time is a complete type because there
161937a2000SPeter Wemmis only one reasonable time implementation.
162937a2000SPeter Wemm
163937a2000SPeter Wemm<li>The second exception to the incomplete type rule can be found in
164937a2000SPeter Wemmapr_portable.h.  This file defines the native types for each platform.
165937a2000SPeter WemmUsing these types, it is possible to extract native types for any APR type.</p>
166937a2000SPeter Wemm</ul>
167937a2000SPeter Wemm
168937a2000SPeter Wemm<p>For this reason, each platform defines a structure in their own directories.
169937a2000SPeter WemmThose structures are then typedef'ed in an external header file.  For example
170937a2000SPeter Wemmin file_io/unix/fileio.h:</p>
171937a2000SPeter Wemm
172937a2000SPeter Wemm<pre>
173937a2000SPeter Wemm    struct ap_file_t {
174937a2000SPeter Wemm        apr_pool_t *cntxt;
175937a2000SPeter Wemm        int filedes;
176937a2000SPeter Wemm        FILE *filehand;
177937a2000SPeter Wemm        ...
178937a2000SPeter Wemm    }
179937a2000SPeter Wemm</pre>
180937a2000SPeter Wemm
181937a2000SPeter Wemm<p>In include/apr_file_io.h:</p>
182937a2000SPeter Wemm    </pre>
183937a2000SPeter Wemm    typedef struct ap_file_t    ap_file_t;
184937a2000SPeter Wemm    </pre>
185937a2000SPeter Wemm
186937a2000SPeter Wemm<p> This will cause a compiler error if somebody tries to access the filedes
187937a2000SPeter Wemmfield in this structure.  Windows does not have a filedes field, so obviously,
188937a2000SPeter Wemmit is important that programs not be able to access these.</p>
189937a2000SPeter Wemm
190937a2000SPeter Wemm<p>You may notice the apr_pool_t field.  Most APR types have this field.  This
191937a2000SPeter Wemmtype is used to allocate memory within APR.  Because every APR type has a pool,
192937a2000SPeter Wemmany APR function can allocate memory if it needs to.  This is very important
193937a2000SPeter Wemmand it is one of the reasons that APR works.  If you create a new type, you
194937a2000SPeter Wemmmust add a pool to it.  If you do not, then all functions that operate on that
195937a2000SPeter Wemmtype will need a pool argument.</p>
196937a2000SPeter Wemm
197937a2000SPeter Wemm<h2>New Function</h2>
198937a2000SPeter Wemm
199937a2000SPeter Wemm<p>When creating a new function, please try to adhere to these rules.</p>
200937a2000SPeter Wemm
201937a2000SPeter Wemm<ul>
202937a2000SPeter Wemm<li>  Result arguments should be the first arguments.
203937a2000SPeter Wemm<li>  If a function needs a pool, it should be the last argument.
204937a2000SPeter Wemm<li>  These rules are flexible, especially if it makes the code easier
205937a2000SPeter Wemm      to understand because it mimics a standard function.
206937a2000SPeter Wemm</ul>
207937a2000SPeter Wemm
208937a2000SPeter Wemm<h2>Documentation</h2>
209937a2000SPeter Wemm
210937a2000SPeter Wemm<p>Whenever a new function is added to APR, it MUST be documented.  New
211937a2000SPeter Wemmfunctions will not be committed unless there are docs to go along with them.
212937a2000SPeter WemmThe documentation should be a comment block above the function in the header
213937a2000SPeter Wemmfile.</p>
214937a2000SPeter Wemm
215937a2000SPeter Wemm<p>The format for the comment block is:</p>
216937a2000SPeter Wemm
217937a2000SPeter Wemm<pre>
218937a2000SPeter Wemm    /**
219937a2000SPeter Wemm     * Brief description of the function
220937a2000SPeter Wemm     * @param parma_1_name explanation
221937a2000SPeter Wemm     * @param parma_2_name explanation
222937a2000SPeter Wemm     * @param parma_n_name explanation
223937a2000SPeter Wemm     * @tip Any extra information people should know.
224937a2000SPeter Wemm     * @deffunc function prototype if required
225937a2000SPeter Wemm     */
226937a2000SPeter Wemm</pre>
227937a2000SPeter Wemm
228937a2000SPeter Wemm<p>For an actual example, look at any file in the include directory.  The
229937a2000SPeter Wemmreason the docs are in the header files is to ensure that the docs always
230*b081c245SDimitry Andricreflect the current code.  If you change parameters or return values for a
231937a2000SPeter Wemmfunction, please be sure to update the documentation.</p>
232937a2000SPeter Wemm
233937a2000SPeter Wemm<h2>APR Error reporting</h2>
234937a2000SPeter Wemm
235937a2000SPeter Wemm<p>Most APR functions should return an ap_status_t type.  The only time an
236937a2000SPeter WemmAPR function does not return an ap_status_t is if it absolutely CAN NOT
237937a2000SPeter Wemmfail.  Examples of this would be filling out an array when you know you are
238937a2000SPeter Wemmnot beyond the array's range.  If it cannot fail on your platform, but it
239937a2000SPeter Wemmcould conceivably fail on another platform, it should return an ap_status_t.
240937a2000SPeter WemmUnless you are sure, return an ap_status_t.</p>
241937a2000SPeter Wemm
242937a2000SPeter Wemm<strong>
243937a2000SPeter Wemm        This includes functions that return TRUE/FALSE values.  How that
244937a2000SPeter Wemm        is handled is discussed below
245937a2000SPeter Wemm</strong>
246937a2000SPeter Wemm
247937a2000SPeter Wemm<p>All platforms return errno values unchanged.  Each platform can also have
248937a2000SPeter Wemmone system error type, which can be returned after an offset is added.
249*b081c245SDimitry AndricThere are five types of error values in APR, each with its own offset.</p>
250937a2000SPeter Wemm
251937a2000SPeter Wemm<!--  This should be turned into a table, but I am lazy today -->
252937a2000SPeter Wemm<pre>
253937a2000SPeter Wemm    Name			Purpose
254937a2000SPeter Wemm0) 			This is 0 for all platforms and isn't really defined
255937a2000SPeter Wemm 			anywhere, but it is the offset for errno values.
256937a2000SPeter Wemm			(This has no name because it isn't actually defined,
257937a2000SPeter Wemm                        but for completeness we are discussing it here).
258937a2000SPeter Wemm
259937a2000SPeter Wemm1) APR_OS_START_ERROR	This is platform dependent, and is the offset at which
260937a2000SPeter Wemm			APR errors start to be defined.  Error values are
261937a2000SPeter Wemm			defined as anything which caused the APR function to
262937a2000SPeter Wemm			fail.  APR errors in this range should be named
263937a2000SPeter Wemm			APR_E* (i.e. APR_ENOSOCKET)
264937a2000SPeter Wemm
265937a2000SPeter Wemm2) APR_OS_START_STATUS	This is platform dependent, and is the offset at which
266937a2000SPeter Wemm			APR status values start.  Status values do not indicate
267937a2000SPeter Wemm			success or failure, and should be returned if
268937a2000SPeter Wemm			APR_SUCCESS does not make sense.  APR status codes in
269937a2000SPeter Wemm			this range should be name APR_* (i.e. APR_DETACH)
270937a2000SPeter Wemm
271937a2000SPeter Wemm4) APR_OS_START_USEERR	This is platform dependent, and is the offset at which
272937a2000SPeter Wemm			APR apps can begin to add their own error codes.
273937a2000SPeter Wemm
274937a2000SPeter Wemm3) APR_OS_START_SYSERR	This is platform dependent, and is the offset at which
275937a2000SPeter Wemm			system error values begin.
276937a2000SPeter Wemm</pre>
277937a2000SPeter Wemm
278937a2000SPeter Wemm<strong>The difference in naming between APR_OS_START_ERROR and
279937a2000SPeter WemmAPR_OS_START_STATUS mentioned above allows programmers to easily determine if
280*b081c245SDimitry Andricthe error code indicates an error condition or a status condition.</strong>
281937a2000SPeter Wemm
282937a2000SPeter Wemm<p>If your function has multiple return codes that all indicate success, but
283937a2000SPeter Wemmwith different results, or if your function can only return PASS/FAIL, you
284937a2000SPeter Wemmshould still return an apr_status_t.  In the first case, define one
285937a2000SPeter WemmAPR status code for each return value, an example of this is
286937a2000SPeter Wemm<code>apr_proc_wait</code>, which can only return APR_CHILDDONE,
287937a2000SPeter WemmAPR_CHILDNOTDONE, or an error code.  In the second case, please return
288937a2000SPeter WemmAPR_SUCCESS for PASS, and define a new APR status code for failure, an
289937a2000SPeter Wemmexample of this is <code>apr_compare_users</code>, which can only return
290937a2000SPeter WemmAPR_SUCCESS, APR_EMISMATCH, or an error code.</p>
291937a2000SPeter Wemm
292937a2000SPeter Wemm<p>All of these definitions can be found in apr_errno.h for all platforms.  When
293937a2000SPeter Wemman error occurs in an APR function, the function must return an error code.
294937a2000SPeter WemmIf the error occurred in a system call and that system call uses errno to
295937a2000SPeter Wemmreport an error, then the code is returned unchanged.  For example: </p>
296937a2000SPeter Wemm
297937a2000SPeter Wemm<pre>
298937a2000SPeter Wemm    if (open(fname, oflags, 0777) < 0)
299937a2000SPeter Wemm        return errno;
300937a2000SPeter Wemm</pre>
301937a2000SPeter Wemm
302937a2000SPeter Wemm<p>The next place an error can occur is a system call that uses some error value
303937a2000SPeter Wemmother than the primary error value on a platform.  This can also be handled
304937a2000SPeter Wemmby APR applications.  For example:</p>
305937a2000SPeter Wemm
306937a2000SPeter Wemm<pre>
307937a2000SPeter Wemm    if (CreateFile(fname, oflags, sharemod, NULL,
308937a2000SPeter Wemm                   createflags, attributes, 0) == INVALID_HANDLE_VALUE
309937a2000SPeter Wemm        return (GetLAstError() + APR_OS_START_SYSERR);
310937a2000SPeter Wemm</pre>
311937a2000SPeter Wemm
312937a2000SPeter Wemm<p>These two examples implement the same function for two different platforms.
313937a2000SPeter WemmObviously even if the underlying problem is the same on both platforms, this
314937a2000SPeter Wemmwill result in two different error codes being returned.  This is OKAY, and
315937a2000SPeter Wemmis correct for APR.  APR relies on the fact that most of the time an error
316937a2000SPeter Wemmoccurs, the program logs the error and continues, it does not try to
317937a2000SPeter Wemmprogramatically solve the problem.  This does not mean we have not provided
318937a2000SPeter Wemmsupport for programmatically solving the problem, it just isn't the default
319937a2000SPeter Wemmcase.  We'll get to how this problem is solved in a little while.</p>
320937a2000SPeter Wemm
321937a2000SPeter Wemm<p>If the error occurs in an APR function but it is not due to a system call,
322937a2000SPeter Wemmbut it is actually an APR error or just a status code from APR, then the
323937a2000SPeter Wemmappropriate code should be returned.  These codes are defined in apr_errno.h
324937a2000SPeter Wemmand should be self explanatory.</p>
325937a2000SPeter Wemm
326937a2000SPeter Wemm<p>No APR code should ever return a code between APR_OS_START_USEERR and
327937a2000SPeter WemmAPR_OS_START_SYSERR, those codes are reserved for APR applications.</p>
328937a2000SPeter Wemm
329937a2000SPeter Wemm<p>To programmatically correct an error in a running application, the error
330937a2000SPeter Wemmcodes need to be consistent across platforms.  This should make sense.  APR
331937a2000SPeter Wemmhas provided macros to test for status code equivalency.  For example, to
332937a2000SPeter Wemmdetermine if the code that you received from the APR function means EOF, you
333937a2000SPeter Wemmwould use the macro APR_STATUS_IS_EOF().</p>
334937a2000SPeter Wemm
335937a2000SPeter Wemm<p>Why did APR take this approach?  There are two ways to deal with error
336937a2000SPeter Wemmcodes portably.</p>
337937a2000SPeter Wemm
338937a2000SPeter Wemm<ol type=1>
339937a2000SPeter Wemm<li>  Return the same error code across all platforms.
340937a2000SPeter Wemm<li>  Return platform specific error codes and convert them when necessary.
341937a2000SPeter Wemm</ol>
342937a2000SPeter Wemm
343937a2000SPeter Wemm<p>The problem with option number one is that it takes time to convert error
344937a2000SPeter Wemmcodes to a common code, and most of the time programs want to just output
345937a2000SPeter Wemman error string.  If we convert all errors to a common subset, we have four
346937a2000SPeter Wemmsteps to output an error string:</p>
347937a2000SPeter Wemm
348*b081c245SDimitry Andric<p>The second problem with option 1, is that it is a lossy conversion.  For
349937a2000SPeter Wemmexample, Windows and OS/2 have a couple hundred error codes, but POSIX errno
350937a2000SPeter Wemmonly defines about 50 errno values.  This means that if we convert to a
351937a2000SPeter Wemmcanonical error value immediately, there is no way for the programmer to
352937a2000SPeter Wemmget the actual system error.</p>
353937a2000SPeter Wemm
354937a2000SPeter Wemm<pre>
355937a2000SPeter Wemm    make syscall that fails
356937a2000SPeter Wemm        convert to common error code                 step 1
357937a2000SPeter Wemm        return common error code
358937a2000SPeter Wemm            check for success
359937a2000SPeter Wemm            call error output function               step 2
360937a2000SPeter Wemm                convert back to system error         step 3
361937a2000SPeter Wemm                output error string                  step 4
362937a2000SPeter Wemm</pre>
363937a2000SPeter Wemm
364937a2000SPeter Wemm<p>By keeping the errors platform specific, we can output error strings in two
365937a2000SPeter Wemmsteps.</p>
366937a2000SPeter Wemm
367937a2000SPeter Wemm<pre>
368937a2000SPeter Wemm    make syscall that fails
369937a2000SPeter Wemm        return error code
370937a2000SPeter Wemm            check for success
371937a2000SPeter Wemm            call error output function               step 1
372937a2000SPeter Wemm                output error string                  step 2
373937a2000SPeter Wemm</pre>
374937a2000SPeter Wemm
375937a2000SPeter Wemm<p>Less often, programs change their execution based on what error was returned.
376937a2000SPeter WemmThis is no more expensive using option 2 than it is using option 1, but we
377937a2000SPeter Wemmput the onus of converting the error code on the programmer themselves.
378937a2000SPeter WemmFor example, using option 1:</p>
379937a2000SPeter Wemm
380937a2000SPeter Wemm<pre>
381937a2000SPeter Wemm    make syscall that fails
382937a2000SPeter Wemm        convert to common error code
383937a2000SPeter Wemm        return common error code
384937a2000SPeter Wemm            decide execution based on common error code
385937a2000SPeter Wemm</pre>
386937a2000SPeter Wemm
387937a2000SPeter Wemm<p>Using option 2:</p>
388937a2000SPeter Wemm
389937a2000SPeter Wemm<pre>
390937a2000SPeter Wemm    make syscall that fails
391937a2000SPeter Wemm        return error code
392937a2000SPeter Wemm            convert to common error code (using ap_canonical_error)
393937a2000SPeter Wemm            decide execution based on common error code
394937a2000SPeter Wemm</pre>
395937a2000SPeter Wemm
396937a2000SPeter Wemm<p>Finally, there is one more operation on error codes.  You can get a string
397937a2000SPeter Wemmthat explains in human readable form what has happened.  To do this using
398937a2000SPeter WemmAPR, call ap_strerror().</p>
399937a2000SPeter Wemm
400