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/.
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.
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 * !
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 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.