Skip to content
Alexandru-Mihai Maftei edited this page Mar 27, 2019 · 6 revisions

IPC endpoints in Beelzebub are represented via handles.
A handle is an integer that makes sense only in the context of a handle table.
Each handle table will contain two types of handles: local and remote.
Local handles only make sense to the owner of the handle table, and remote handles point to local handles in another handle table.

Note: The following definitions will help understand this document more easily:

  • Handle: An IPC endpoint, represented by an integer.
  • Hart: A _har_dware _t_hread, such as a hyperthread in an Intel CPU with Hyperthreading, or a CPU core in a multi-core package, or the CPU in a single-core package. Term borrowed from Risc-V specs.
  • Hazard pointer: Andrei Alexandrescu's article on the matter explains this.

Handle domain

struct HandleDomain
{
    HazardHandle HazardList; // This is a dummy node, the doubly-linked list is circular.
};

A handle domain represents a set of handle tables and active hazard handles that allows messaging between handles in the handle tables.
In the predictable future, the system will only have one handle domain. This should change at some point.

Hazard Handles

struct HazardHandle
{
    HandleTableEntry * Handle;
    HandleDomain * Domain;
    HazardHandle * Next, Prev;
};

In order to help keep the handle tables efficient, memory safety needs to be established to mitigate the ABA problem when performing atomic operations.
For this, hazard handles are used. A hazard handle consists of a hazard pointer to a handle entry within a handle table.

Each hart needs to have only one hazard handle in its specific data. This piece of memory is assumed to never be deallocated or otherwise reused in any way.

When a hart knows it's about to work with a handle entry or handle table, it will put the handle table entry pointer and the handle domain pointer in its hazard handle, and then add the hazard handle to the domain's hazard list.
After this, the information is checked again (making sure that the chosen handle table entry is still the one it's meant to work with) and updated if necessary.

When the hart needs to work with another handle table entry (e.g. to resolve a remote handle), it just changes the pointer to the handle table entry in its hazard handle.
When it's done working with handles, it sets the pointer to null and removes the hazard handle from the list.

With this system, the hazard handles are going to be written to by multiple harts, which is an important difference between this system and Andrei's hazard pointer implementation.
This allows iterating through fewer pointers under predicted normal operation.

When a hart wants to determine if a handle table or handle table entry is in use, it iterates through the relevant domain's list until it either finds the list head/dummy node or a node that's in the list of another handle domain.

Note: This will rather likely be changed in the future for the sake of performance, probably using an array.

Handle Tables

A handle table is an array of handle table entries, which can either be local, remote, retired, or unallocated.
The unallocated entries form a singly-linked list, which is a stack of free handles.

Handle table resizing is still to be determined. Current plan involves using page faults and copy-on-write.

Handle Table Entries

Clone this wiki locally