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