Welcome to LIBFIPC!

A fast, asynchronous IPC library using shared memory.

Source Code


Concept

The main object here is a duplex, ring channel, used by two threads or processes.

There are a couple things to note here.

  1. The ring channel consists of two buffers in shared memory and two distinct headers on each side. These headers do not need to be in a region of memory shared by the two threads.
  2. Memory buffer 1 is used by Thread 2 to send messages to Thread 1; memory buffer 2 is used by Thread 1 to send message to Thread 2. This allows data to flow in both directions.
  3. The memory buffers are treated as circular buffers.

Usage

Function Documentation

Ring Channel Initialization

There are few steps:

  1. Allocate the shared memory buffers.
  2. Initialize the shared memory buffers.
  3. Allocate the headers. These can be statically allocated i.e. global variables.
  4. Initialize the headers

In a typical scenario, Thread 1 will allocate both memory buffers and share them with Thread 2; how this is done depends on the environment. Thread 1 and Thread 2 will allocate their private headers, and initialize them to point to the allocated memory buffers.

Example

This example illustrates a typical Thread 1 using the libfipc interface. The return values are ignored.

// Allocate shared memory buffers.
unsigned int buf_order = // Buffers are 2^buf_order bytes.
char *buffer_1         = // Allocate memory buffer 1.
char *buffer_2         = // Allocate memory buffer 2.

// Initialize the shared buffers.
fipc_prep_buffers( buf_order, buffer_1, buffer_2 );

// Share buffers with Thread 2.
// ...

// Allocate and initialize Thread 1's channel header.
struct fipc_ring_channel t1_chnl_header;
fipc_ring_channel_init( &t1_chnl_header, buf_order, buffer_1, buffer_2 );

Send/Receive

Important Note

The functions "fipc_send_msg_start, fipc_recv_msg_start, fipc_recv_msg_if" are not thread safe. If you plan to share the same tx or rx header on one side of the channel among multiple threads, you should wrap calls to these functions in locks as necessary. Since some libfipc users may not require synchronization, we don't do any internally. See the individual function documentation for more details. Of course, communication across the channel to the other side does not require explicit synchronization of threads on opposite sides.

Example

This example illustrates a typical send/receive sequence, assuming the headers have been initialized already.

Thread 1

struct fipc_message *msg;
int ret;

do
{

   // Allocate a slot to put message in.
   ret = fipc_send_msg_start( t1_chnl_header, &msg );

} while ( ret == -EWOULDBLOCK );

msg->regs[0] = 1;
msg->regs[1] = 2;
// ...

// Mark message as sent, so the receiver will see a status change.
fipc_send_msg_end( t1_chnl_header, msg );

Thread 2

struct fipc_message *msg;
int ret;

do
{

   // Wait for message to be received.
   ret = fipc_recv_msg_start( t2_chnl_header, &msg );

} while ( ret == -EWOULDBLOCK );

// Do something with message.
// ...

// Mark message as received, so the sender will see the slot as available.
fipc_recv_msg_end( t2_chnl_header, msg );

Ring Channel Tear down

There is no tear down required because you allocated the headers and buffers; therefore, you need to tear them down yourself. It is recommended that you wait until both threads are done using some other mechanism.