mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-30 04:10:54 -08:00
389 lines
15 KiB
ReStructuredText
389 lines
15 KiB
ReStructuredText
.. mode: -*- rst -*-
|
||
|
||
C interface design
|
||
==================
|
||
|
||
:Tag: design.mps.interface.c
|
||
:Author: Richard Brooksby
|
||
:Date: 1996-07-29
|
||
:Status: incomplete document
|
||
:Revision: $Id$
|
||
:Copyright: See `Copyright and License`_.
|
||
|
||
|
||
Introduction
|
||
------------
|
||
|
||
_`.scope`: This document is the design for the Memory Pool System
|
||
(MPS) interface to the C Language, impl.h.mps.
|
||
|
||
_`.bg`: See mail.richard.1996-07-24.10-57.
|
||
|
||
|
||
Analysis
|
||
--------
|
||
|
||
Goals
|
||
.....
|
||
|
||
_`.goal.c`: The file impl.h.mps is the C external interface to the
|
||
MPS. It is the default interface between client code written in C and
|
||
the MPS. _`.goal.cpp`: impl.h.mps is not specifically designed to be
|
||
an interface to C++, but should be usable from C++.
|
||
|
||
|
||
Requirements
|
||
............
|
||
|
||
_`.req`: The interface must provide an interface from client code
|
||
written in C to the functionality of the MPS required by the product
|
||
(see req.product), Dylan (req.dylan), and the Core RIP (req.epcore).
|
||
|
||
``mps.h`` may not include internal MPS header files (such as
|
||
``pool.h``).
|
||
|
||
It is essential that the interface cope well with change, in order to
|
||
avoid restricting possible future MPS developments. This means that
|
||
the interface must be "open ended" in its definitions. This accounts
|
||
for some of the apparently tortuous methods of doing things
|
||
(``mps_fmt_A_t``, for example). The requirement is that the MPS should
|
||
be able to add new functionality, or alter the implementation of
|
||
existing functionality, without affecting existing client code. A
|
||
stronger requirement is that the MPS should be able to change without
|
||
*recompiling* client code. This is not always possible.
|
||
|
||
.. note::
|
||
|
||
`.naming.global` was presumably done in response to unwritten
|
||
requirements regarding the use of the name spaces in C, perhaps
|
||
these:
|
||
|
||
- _`.req.name.iso`: The interface shall not conflict in terms of
|
||
naming with any interfaces specified by ISO C and all reasonable
|
||
future versions.
|
||
|
||
- _`.req.name.general`: The interface shall use a documented and
|
||
reasonably small portion of the namespace so that clients can
|
||
interoperate easily.
|
||
|
||
David Jones, 1998-10-01.
|
||
|
||
|
||
Architecture
|
||
------------
|
||
|
||
_`.fig.arch`: The architecture of the MPS Interface
|
||
|
||
[missing figure]
|
||
|
||
Just behind ``mps.h`` is the file ``mpsi.c``, the "MPS interface
|
||
layer" which does the job of converting types and checking parameters
|
||
before calling through to the MPS proper, using internal MPS methods.
|
||
|
||
|
||
General conventions
|
||
-------------------
|
||
|
||
_`.naming`: The external interface names should adhere to the
|
||
documented interface conventions; these are found in
|
||
doc.mps.ref-man.if-conv(0).naming. They are paraphrased/recreated
|
||
here.
|
||
|
||
_`.naming.unixy`: The external interface does not follow the same
|
||
naming conventions as the internal code. The interface is designed to
|
||
resemble a more conventional C, Unix, or Posix naming convention.
|
||
|
||
_`.naming.case`: Identifiers are in lower case, except
|
||
non-function-like macros, which are in upper case.
|
||
|
||
_`.naming.global`: All publicised identifiers are
|
||
prefixed ``mps_`` or ``MPS_``.
|
||
|
||
_`.naming.all`: All identifiers defined by the MPS
|
||
should begin ``mps_`` or ``MPS_`` or ``_mps_``.
|
||
|
||
_`.naming.type`: Types are suffixed ``_t``.
|
||
|
||
_`.naming.struct`: Structure types and tags are suffixed ``_s``.
|
||
|
||
_`.naming.union`: Unions types and tags are suffixed ``_u``.
|
||
|
||
_`.naming.scope`: The naming conventions apply to all identifiers (see
|
||
ISO C §6.1.2); this includes names of functions, variables, types
|
||
(through typedef), structure and union tags, enumeration members,
|
||
structure and union members, macros, macro parameters, labels.
|
||
|
||
_`.naming.scope.labels`: labels (for ``goto`` statements) should be
|
||
rare, only in special block macros and probably not even then.
|
||
|
||
.. note::
|
||
|
||
This principle is not adhered to in the source code, which uses
|
||
``goto`` for handling error cases. Gareth Rees, 2013-05-27.
|
||
|
||
_`.naming.scope.other`: The naming convention would also extend to
|
||
enumeration types and parameters in functions prototypes but both of
|
||
those are prohibited from having names in an interface file.
|
||
|
||
_`.type.gen`: The interface defines memory addresses as ``void *`` and
|
||
sizes as ``size_t`` for compatibility with standard C (in particular,
|
||
with ``malloc()``). These types must be binary compatible with the
|
||
internal types ``Addr`` and ``Size`` respectively. Note that this
|
||
restricts the definitions of the internal types ``Addr`` and ``Size``
|
||
when the MPS is interfaced with C, but does not restrict the MPS in
|
||
general.
|
||
|
||
_`.type.opaque`: Opaque types are defined as pointers to structures
|
||
which are never defined. These types are cast to the corresponding
|
||
internal types in ``mpsi.c``.
|
||
|
||
_`.type.trans`: Some transparent structures are defined. The client is
|
||
expected to read these, or poke about in them, under restrictions
|
||
which should be documented. The most important is probably the
|
||
allocation point (``mps_ap_s``) which is part of allocation buffers.
|
||
The transparent structures must be binary compatible with
|
||
corresponding internal structures. For example, the fields of
|
||
``mps_ap_s`` must correspond with ``APStruct`` internally. This is
|
||
checked by ``mpsi.c`` in ``mps_check()``.
|
||
|
||
_`.type.pseudo`: Some pseudo-opaque structures are defined. These only
|
||
exist so that code can be inlined using macros. The client code
|
||
shouldn't mess with them. The most important case of this is the scan
|
||
state (``mps_ss_s``) which is accessed by the in-line scanning macros,
|
||
``MPS_SCAN_*`` and ``MPS_FIX*``.
|
||
|
||
_`.type.enum`: There should be no enumeration types in the interface.
|
||
Note that enum specifiers (to declare integer constants) are fine as
|
||
long as no type is declared. See guide.impl.c.misc.enum.type.
|
||
|
||
_`.type.fun`: Whenever function types or derived function types (such
|
||
as pointer to function) are declared a prototype should be used and
|
||
the parameters to the function should not be named. This includes the
|
||
case where you are declaring the prototype for an interface function.
|
||
|
||
_`.type.fun.example`: So use::
|
||
|
||
extern mps_res_t mps_alloc(mps_addr_t *, mps_pool_t, size_t, ...);
|
||
|
||
rather than::
|
||
|
||
extern mps_res_t mps_alloc(mps_addr_t *addr_return, mps_pool_t pool , size_t size, ...);
|
||
|
||
and::
|
||
|
||
typedef mps_addr_t (*mps_fmt_class_t)(mps_addr_t);
|
||
|
||
rather than::
|
||
|
||
typedef mps_addr_t (*mps_fmt_class_t)(mps_addr_t object);
|
||
|
||
See guide.impl.c.misc.prototype.parameters.
|
||
|
||
|
||
Checking
|
||
--------
|
||
|
||
_`.check.space`: When the arena needs to be recovered from a parameter
|
||
it is check using ``AVERT(Foo, foo)`` before any attempt to call
|
||
``FooArena(foo)``. The macro ``AVERT()`` in impl.h.assert performs
|
||
simple thread-safe checking of ``foo``, so it can be called outside of
|
||
``ArenaEnter()`` and ``ArenaLeave()``.
|
||
|
||
_`.check.types`: We use definitions of types in both our external
|
||
interface and our internal code, and we want to make sure that they
|
||
are compatible. (The external interface changes less often and hides
|
||
more information.) At first, we were just checking their sizes, which
|
||
wasn't very good, but I've come up with some macros which check the
|
||
assignment compatibility of the types too. This is a sufficiently
|
||
useful trick that I thought I'd send it round. It may be useful in
|
||
other places where types and structures need to be checked for
|
||
compatibility at compile time.
|
||
|
||
These macros don't generate warnings on the compilers I've tried.
|
||
|
||
``COMPATLVALUE(lvalue1, lvalue2)``
|
||
|
||
This macro checks the assignment compatibility of two lvalues. It uses
|
||
``sizeof()`` to ensure that the assignments have no effect. ::
|
||
|
||
#define COMPATLVALUE(lv1, lv2) \
|
||
((void)sizeof((lv1) = (lv2)), (void)sizeof((lv2) = (lv1)), TRUE)
|
||
|
||
``COMPATTYPE(type1, type2)``
|
||
|
||
This macro checks that two types are assignment-compatible and equal
|
||
in size. The hack here is that it generates an lvalue for each type by
|
||
casting zero to a pointer to the type. The use of ``sizeof()`` avoids
|
||
the undefined behaviour that would otherwise result from dereferencing
|
||
a null pointer. ::
|
||
|
||
#define COMPATTYPE(t1, t2) \
|
||
(sizeof(t1) == sizeof(t2) && \
|
||
COMPATLVALUE(*((t1 *)0), *((t2 *)0)))
|
||
|
||
``COMPATFIELDAPPROX(structure1, field1, structure2, field2)``
|
||
|
||
This macro checks that the offset and size of two fields in two
|
||
structure types are the same. ::
|
||
|
||
#define COMPATFIELDAPPROX(s1, f1, s2, f2) \
|
||
(sizeof(((s1 *)0)->f1) == sizeof(((s2 *)0)->f2) && \
|
||
offsetof(s1, f1) == offsetof(s2, f2))
|
||
|
||
``COMPATFIELD(structure1, field1, structure2, field2)``
|
||
|
||
This macro checks the offset, size, and assignment-compatibility of
|
||
two fields in two structure types. ::
|
||
|
||
#define COMPATFIELD(s1, f1, s2, f2) \
|
||
(COMPATFIELDAPPROX(s1, f1, s2, f2) && \
|
||
COMPATLVALUE(((s1 *)0)->f1, ((s2 *)0)->f2))
|
||
|
||
|
||
Binary compatibility issues
|
||
---------------------------
|
||
|
||
As in, "Enumeration types are not allowed" (see
|
||
mail.richard.1995-09-08.09-28).
|
||
|
||
There are two main aspects to run-time compatibility: binary interface
|
||
and protocol. The binary interface is all the information needed to
|
||
correctly use the library, and includes external symbol linkage,
|
||
calling conventions, type representation compatibility, structure
|
||
layouts, etc. The protocol is how the library is actually used by the
|
||
client code -- whether this is called before that -- and determines
|
||
the semantic correctness of the client with respect to the library.
|
||
|
||
The binary interface is determined completely by the header file and
|
||
the target. The header file specifies the external names and the
|
||
types, and the target platform specifies calling conventions and type
|
||
representation. There is therefore a many-to-one mapping between the
|
||
header file version and the binary interface.
|
||
|
||
The protocol is determined by the implementation of the library.
|
||
|
||
|
||
Constraints
|
||
-----------
|
||
|
||
_`.cons`: The MPS C Interface constrains the MPS in order to provide
|
||
useful memory management services to a C or C++ program.
|
||
|
||
_`.cons.addr`: The interface constrains the MPS address type, Addr
|
||
(design.mps.type.addr), to being the same as C's generic pointer type,
|
||
``void *``, so that the MPS can manage C objects in the natural way.
|
||
|
||
_`.pun.addr`: We pun the type of ``mps_addr_t`` (which is ``void *``)
|
||
into ``Addr`` (an incomplete type, see design.mps.type.addr). This
|
||
happens in the call to the scan state's fix function, for example.
|
||
|
||
_`.cons.size`: The interface constrains the MPS size type, ``Size``
|
||
(design.mps.type.size), to being the same as C's size type,
|
||
``size_t``, so that the MPS can manage C objects in the natural way.
|
||
|
||
_`.pun.size`: We pun the type of ``size_t`` in mps.h into ``Size`` in
|
||
the MPM, as an argument to the format methods. We assume this works.
|
||
|
||
_`.cons.word`: The MPS assumes that ``Word`` (design.mps.type.word)
|
||
and ``Addr`` (design.mps.type.addr) are the same size, and the
|
||
interface constrains ``Word`` to being the same size as C's generic
|
||
pointer type, ``void *``.
|
||
|
||
|
||
Notes
|
||
-----
|
||
|
||
The file ``mpstd.h`` is the MPS target detection header. It decodes
|
||
preprocessor symbols which are predefined by build environments in
|
||
order to determine the target platform, and then defines uniform
|
||
symbols, such as ``MPS_ARCH_I3``, for use internally by the MPS.
|
||
|
||
There is a design document for the mps interface,
|
||
design.mps.interface, but it was written before we had the idea of
|
||
having a C interface layer. It is quite relevant, though, and could be
|
||
updated. We should use it during the review.
|
||
|
||
All exported identifiers and file names should begin with ``mps_`` or
|
||
``MPS_`` so that they don't clash with other systems.
|
||
|
||
We should probably have a specialized set of rules and a special
|
||
checklist for this interface.
|
||
|
||
_`.fmt.extend`: This paragraph should be an explanation of why
|
||
``mps_fmt_A_t`` is so called. The underlying reason is future
|
||
extensibility.
|
||
|
||
_`.thread-safety`: Most calls through this interface lock the space
|
||
and therefore make the MPM single-threaded. In order to do this they
|
||
must recover the space from their parameters. Methods such as
|
||
``ThreadSpace()`` must therefore be callable when the space is *not*
|
||
locked. These methods are tagged with the tag of this note.
|
||
|
||
_`.lock-free`: Certain functions inside the MPM are thread-safe and do
|
||
not need to be serialized by using locks. They are marked with the tag
|
||
of this note.
|
||
|
||
_`.form`: Almost all functions in this implementation simply cast
|
||
their arguments to the equivalent internal types, and cast results
|
||
back to the external type, where necessary. Only exceptions are noted
|
||
in comments.
|
||
|
||
|
||
Document History
|
||
----------------
|
||
|
||
- 1996-07-29 RB_ Incomplete document. The first draft of this document
|
||
was generated in response to review.impl.h.mps.10 which revealed the
|
||
lack of a detailed design document and also the lack of conventions
|
||
for external interfaces. The aim of the draft was to record this
|
||
information, even if it isn't terribly well structured.
|
||
|
||
- 2002-06-07 RB_ Converted from MMInfo database design document.
|
||
|
||
- 2013-05-23 GDR_ Converted to reStructuredText.
|
||
|
||
.. _RB: http://www.ravenbrook.com/consultants/rb/
|
||
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
|
||
|
||
|
||
Copyright and License
|
||
---------------------
|
||
|
||
Copyright © 2013 Ravenbrook Limited. All rights reserved.
|
||
<http://www.ravenbrook.com/>. This is an open source license. Contact
|
||
Ravenbrook for commercial licensing options.
|
||
|
||
Redistribution and use in source and binary forms, with or without
|
||
modification, are permitted provided that the following conditions are
|
||
met:
|
||
|
||
1. Redistributions of source code must retain the above copyright
|
||
notice, this list of conditions and the following disclaimer.
|
||
|
||
2. Redistributions in binary form must reproduce the above copyright
|
||
notice, this list of conditions and the following disclaimer in the
|
||
documentation and/or other materials provided with the distribution.
|
||
|
||
3. Redistributions in any form must be accompanied by information on how
|
||
to obtain complete source code for this software and any
|
||
accompanying software that uses this software. The source code must
|
||
either be included in the distribution or be available for no more than
|
||
the cost of distribution plus a nominal fee, and must be freely
|
||
redistributable under reasonable conditions. For an executable file,
|
||
complete source code means the source code for all modules it contains.
|
||
It does not include source code for modules or files that typically
|
||
accompany the major components of the operating system on which the
|
||
executable file runs.
|
||
|
||
**This software is provided by the copyright holders and contributors
|
||
"as is" and any express or implied warranties, including, but not
|
||
limited to, the implied warranties of merchantability, fitness for a
|
||
particular purpose, or non-infringement, are disclaimed. In no event
|
||
shall the copyright holders and contributors be liable for any direct,
|
||
indirect, incidental, special, exemplary, or consequential damages
|
||
(including, but not limited to, procurement of substitute goods or
|
||
services; loss of use, data, or profits; or business interruption)
|
||
however caused and on any theory of liability, whether in contract,
|
||
strict liability, or tort (including negligence or otherwise) arising in
|
||
any way out of the use of this software, even if advised of the
|
||
possibility of such damage.**
|