POSIX implementation of Porting Interfaces

Several platforms have POSIX-compatible native APIs; these can be used to implement some of our porting interfaces (see the pi module). Proliferating several copies of the Unix module's original implementation (as we did until 2007) made for inefficient maintenance: bugs fixed in one copy could remain unnoticed in the others. Consequently, this module provides a cleaned-up (and rather better maintained) version of the implementation, which can be shared between platforms. Even where there are better native APIs available, using this shared implementation based on POSIX can enable a project to get up and running faster, providing a reasonable quality of implementation for little early development cost.

As with any standard, it would be rash to assume that every POSIX implementation is complete and faithful. Even where it is, in the presence of better native APIs for some of what POSIX covers, platforms may wish to opt out of parts of this module's implementation. Consequently, this module can be configured using the API and tweak systems to match different platform needs. See its (extensive) module.tweaks and module.export files for details. See also: a rough (but not always up-to-date) list of system APIs actually in use by this module.

Once you've run doxygen suitably (e.g. via hardcore's doxyrun script or the Unix make files in unix-build), and documentation should also be available. Only APIs defined by header files in this module's top-level directory are (documented in or…) intended for use outside this module. If your project needs to access APIs defined in sub-directory header files, contact the module owner to discuss making those APIs public. Notably, this does apply to use of mixed socketry (see TWEAK_POSIX_MIXED_SOCKADDR): although support for this is contemplated, it is not yet supported. (The aim of this restriction is to avoid complications when the header files do move to the top-level directory; no external code should be referencing them before this, and thereby obliged to adapt its #include paths.)

See Peculiarities, below, for why most classes defined by this module are not exposed in header files: the lack of a header file declaring the implementation should not be mistaken for a sign that there is no implementation. See module.export for the API to import to have each interface implemented by posix (along with notes on limitations or peculiarities of the implementation) and the relevant modules/pi/ class for documentation.

While this module's primary goal is to implement porting interfaces, it also provides some utilities useful towards that implementation, but not actually specified by porting interfaces. It is arguable that some, at least, of these utilities should live elsewhere, e.g. in ../utilix/.

Coding Standards

General policy in the posix module is to follow core coding standards and the pre-PPP release process. When defining APIs it generally follows pi's guidelines (see pi's main page, section Design goals and scope, especially its sub-section Data types and macros).

This module is used by platforms with threading: it is therefore desirable that as much as possible be thread-safe. In particular, the use of TRAP and LEAVE should be avoided where possible.

Peculiarities

As a peculiarity of PI-implementation, the posix module defines many classes that are not declared in header files. This is a deliberate policy in support of information-hiding: as far as possible, nothing but the implementation of a porting interface should know the details of that implementation. Each porting interface's static OP_STATUS Create() method is defined in the same compilation unit as the implementation it instantiates; nothing else should need to see the class instantiated, so there is no reason to keep it textually separate (and keeping it all in one file simplifies version control). A few porting implementations are declared in separate header files: one, OpSystemInfo, is a partial implementation that must be sub-classed to be completed; one, OpLocale, is so trivial that it seems worth letting platforms instantiate it directly, as an auto variable, instead of bothering with Create(), like core. However, new porting interfaces should not do this without a compelling reason (e.g. due to providing significant extensions needed by the implementations of other porting interfaces in this module). As an example of the last, see PosixNetworkAddress, which extends PosixSocketAddress, the actual porting interface implementation, to provide facilities needed by other networking-related classes.

Note that care should be taken about presuming that pointers to the underlying porting interface type are actually pointers to the implementation provided by this module: some builds may also include other implementations. As a notable example, OpLowLevelFile * may also point to various kinds of virtual file defined in core; such pointers cannot, in general, safely be cast to PosixLowLevelFile * !

System Includes

This is not a core module: it is platform code (and should be checked out as platforms/posix/). In particular, it does not abide by core's policy against system includes: indeed, in includes a sub-directory, sys/, whose contents are intended to facilitate platform implementations of the system system, so #include various system headers. Aside from that, this module does endeavour to keep system includes to a minimum – essentially because the system system has usually pulled in what we need, which saves us lots of #if-ery to deal with platform idiosyncrasies about where particular things are found. All the same, the POSIX standards specify that particular symbols are defined by particular system header files; so being POSIX-compliant means having those header files accessible and this module reserves the right to #include them.

If platforms aren't pulling in some system header for other reasons, as part of their support for the system system, it is more appropriate for this module to #include the POSIX-mandated header, where needed, than for platforms to be obliged to pull it in just for this module's sake. If the platform lacks that POSIX header, it is more appropriate for it to pull in its equivalent via the system system than for this module to contain #if-ery to find the header in different places on different platforms. However this module shall endure #if-ing out any platform which lacks a POSIX header it does pull in; so having a #else that handles platform idiosyncrasies is negotiable (when this module is already pulling in the POSIX header).

Sometimes system headers neglect the extern "C" wrapping on system headers (e.g. Android in fnmatch.h), which can lead to linker errors if the source, from which the relevant object of the system library was compiled, is a C compilation unit; the library symbol will have the plain name but the C++ compiler, when compiling posix, shall reference it by its C++-mangled name. The linker error gives away that this is the problem when the symbol, that it complains it's missing, includes its prototype's parameter list. The remedy (if you can't get the system headers fixed) is to find where (commonly in your platform configuration of the system system) you first #include (possibly via some other header file, unistd.h in Android's case) the defective header; then wrap this in a suitable

#if __cplusplus
extern "C" {
#endif
#include culprit.h
#if __cplusplus
}
#endif

The POSIX standards

The Portable Operating System Interface (POSIX) standards are maintained by The Open Group and sporadically ratified by IEEE and ISO/IEC. They are available as Unix man pages (see the manpages-posix and manpages-posix-dev packages in Debian, for example) and online.

Particular vendors' implementations do not always live up to expectations; those deploying this module are encouraged to run Opera's extensive selftests, particularly posix's own and those of the pi and util modules (but all core modules are worth checking, especially those of the infrastructure, networking and external application groups). Failures of these tests and of assertions in this module should be investigated as possible indications that this module needs to code round platform idiosyncrasies. In many cases, this may already be provided for by a tweak. Some APIs (notably the OpSystemInfo implementation) are provided as base classes which may be partially over-ridden. Other parts of the module may simply be omitted, using the API system, and re-implemented by the platform: however, where such re-implementation is similar to this module's version, it is almost certainly better that this module adapt, to save the need for duplication.

Edward Welbourne