Porting Guide (liblfds)

From liblfds.org
Jump to navigation Jump to search

Introduction

To permit liblfds to work on a range of platforms a porting abstraction layer has been written. Porting simply involves implementing the porting abstraction layer; the library will then compile and work. Implementation involves providing values to a small set defines, macros and typedefs.

The Porting Abstraction Layer

Each of the compiler, the operating system and the processor turns out to be a source of information for a porting abstraction layer and so the porting abstraction layer is arranged as three header files, one for each, thus;

└───liblfds710
    └───inc
        └───liblfds710
                lfds710_porting_abstraction_layer_compiler.h
                lfds710_porting_abstraction_layer_operating_system.h
                lfds710_porting_abstraction_layer_processor.h

Each header file uses #ifdefs and compiler defined macros to select the appropriate porting abstraction layer implementation for the local platform.

So, for example, in lfds710_porting_abstraction_layer_compiler.h, for MSVC version 1400 and higher, we see the following;

#if( defined _MSC_VER && _MSC_VER >= 1400 )
  [snip porting abstraction layer implementation]
#endif

Accordingly, to add a new platform, introduce a new #ifdef, which matches the appropriate compiler defined macros for your platform.

lfds710_porting_abstraction_layer_compiler.h

#define LFDS710_PAL_COMPILER_STRING
#define LFDS710_PAL_ALIGN( alignment )
#define LFDS710_PAL_INLINE
#define LFDS710_PAL_BARRIER_COMPILER_LOAD
#define LFDS710_PAL_BARRIER_COMPILER_STORE
#define LFDS710_PAL_BARRIER_COMPILER_FULL
#define LFDS710_PAL_BARRIER_PROCESSOR_LOAD
#define LFDS710_PAL_BARRIER_PROCESSOR_STORE
#define LFDS710_PAL_BARRIER_PROCESSOR_FULL
#define LFDS710_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )
#define LFDS710_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )
#define LFDS710_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )
#define LFDS710_PAL_ATOMIC_EXCHANGE( pointer_to_destination, pointer_to_exchange )
#define LFDS710_PAL_ATOMIC_SET( pointer_to_destination, exchange )

lfds710_porting_abstraction_layer_operating_system.h

#define LFDS710_PAL_OS_STRING
#define LFDS710_PAL_ASSERT( expression )

lfds710_porting_abstraction_layer_processor.h

typedef [type] lfds710_pal_int_t;
typedef [type] lfds710_pal_uint_t;
#define LFDS710_PAL_PROCESSOR_STRING
#define LFDS710_PAL_ALIGN_SINGLE_POINTER
#define LFDS710_PAL_ALIGN_DOUBLE_POINTER
#define LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES

Partial Implementatons

It is not necessary to fully implement a porting abstraction layer; very little in the porting abstraction layer is mandatory, and everything non-mandatory has a dummy version provided, for the purpose of allowing the library to compile even if that particular part of the porting abstraction layer has not been implemented or is not available on the platform (which is necessary anyway, as not all atomic operations are available on all processors). Naturally, if a data structure depends on a given part or parts of the porting abstraction layer and those parts have not been implemented, then that data structure will not work.

Atomic Operation Support by Processor
  Memory
Barriers
Add CAS DWCAS Exchange Set
ARM32/64, x86, x64
Alpha, Itanium, MIPS32/64, PowerPC32/64, SPARC32/64

The data structures have the following requirements;

Data Structure by Atomic Operations
  Memory
Barriers
Add CAS DWCAS Exchange Set
Binary Tree (add-only, unbalanced)
Freelist
Hash (add-only)
List (add-only, ordered, singly-linked)
List (add-only, singly-linked, unordered)
PRNG
Queue, bounded, single producer, single consumer
Queue, bounded, many producer, many consumer
Queue, unbounded, many producer, many consumer
Ringbuffer
Stack

Which means you end up with the following;

Data Structures by Processors
  ARM32/64, x86, x64 Alpha, Itanium, MIPS32/64, PowerPC32/64, SPARC32/64
Binary Tree (add-only, unbalanced)
Freelist
Hash (add-only)
List (add-only, ordered, singly-linked)
List (add-only, singly-linked, unordered)
PRNG
Queue, bounded, single producer, single consumer
Queue, bounded, many producer, many consumer
Queue, unbounded, many producer, many consumer
Ringbuffer
Stack

So, for example, if you port to some new x86 based platform and implement only memory barriers and DWCAS, then you can use the bounded, single producer, single consumer queue, the unbounded queue, the ringbuffer and the stack.

The library will compile fully, but if you try to use the other data structures, you will call a dummy version of one of the other atomic operations, where those dummy functions try to write 0 to memory location 0.

See Also