eo ptr ind: mostly cosmetic

- add and use SHIFT_* macros
- rename queue into fifo
- try to clarify the structure top table -> mid table -> table[entry]
This commit is contained in:
Jérémy Zurcher 2013-05-16 10:55:32 +02:00
parent ab505d5d23
commit a9e69d519c
1 changed files with 111 additions and 105 deletions

View File

@ -17,14 +17,16 @@
* the Eo object to supply a better memory management by preventing bad usage * the Eo object to supply a better memory management by preventing bad usage
* of the pointers. * of the pointers.
* *
* Eo * is no more a pointer but an index to an entry into a ids table. * Eo * is no more a pointer but indexes to an entry into an ids table.
* For a better memory usage, we don't allocate all the tables at the beginning, * For a better memory usage:
* but only when needed (i.e no more empty entries in allocated tables. * - a tree structure is used, composed of a top level table pointing at
* In addition, tables are composed of intermediate tables, this for memory * mid tables pointing at tables composed of entries.
* optimizations. Finding the different table, intermediate table and relative * - tables are allocated when needed (i.e no more empty entries in allocated tables.
* entry is done by bits manipulation of the id: * For now there is no mechanism to free empty tables.
* *
* id = Table | Inter_table | Entry | Generation * An Eo id is contructed by bits manipulation of table indexes and a generation.
*
* id = Mid Table | Table | Entry | Generation
* *
* Generation helps finding abuse of ids. When an entry is assigned to an * Generation helps finding abuse of ids. When an entry is assigned to an
* object, a generation is inserted into the id. If the developer uses this id * object, a generation is inserted into the id. If the developer uses this id
@ -32,69 +34,73 @@
* entry of the table, the generation will be different and an error will * entry of the table, the generation will be different and an error will
* occur when accessing with the old id. * occur when accessing with the old id.
* *
* Each table is composed of: * Each Table is composed of:
* - an index 'start' indicating which entry is the next one to use. * - an index 'start' indicating which free entry is the next one to use.
* - 2 indexes 'queue_head' and 'queue_tail' defining a queue (fifo), * - 2 indexes 'fifo_head' and 'fifo_tail' defining a fifo,
* that will help us to store the entries to be reused. It stores only the * that will help us to store the entries to be reused. It stores only the
* entries that have been used at least one time. The entries that have * entries that have been used at least one time. The entries that have
* never been used are "pointed" by the start parameter. * never been used are "pointed" by the start parameter.
* - entries composed of: * - entries composed of:
* - a pointer to the object * - a pointer to the object
* - an index 'next_in_fifo' used to chain the free entries in the fifo
* - a flag indicating if the entry is active * - a flag indicating if the entry is active
* - a generation assigned to the object * - a generation assigned to the object
* - an index 'next_in_queue' used to chain the entries in the queue
* *
* When an entry is searched into a table, we first use one of the entries that * When an entry is searched into a table, we first use one of the entries that
* has never been used. If there is none, we try to pop from the queue. * has never been used. If there is none, we try to pop from the fifo.
* If a such entry doesn't exist, we pass to the next table.
* When an entry is found, we reserve it to the object pointer
* then contruct and return the related Eo id.
*
* Assigning all the entries of a table before trying to reuse them from * Assigning all the entries of a table before trying to reuse them from
* the fifo ensures that we are not going to soon recycle a released entry, * the fifo ensures that we are not going to soon recycle a released entry,
* thus minimize the risks of an aggressive del() then use() on a single entry. * thus minimize the risks of an aggressive del() then use() on a single entry.
* If a such entry doesn't exist, we pass to the next table. *
* When an entry is found, we reserve it to the object pointer and create
* the id with the table id, the intermediate table id, the entry and a
* generation.
* The indexes and a reference to the last table which served an entry is kept * The indexes and a reference to the last table which served an entry is kept
* and is reused prior to the others untill it is full. * and is reused prior to the others untill it is full.
* When an object is freed, the entry into the table is released by appending * When an object is freed, the entry into the table is released by appending
* it to the queue. * it to the fifo.
*/ */
#if SIZEOF_UINTPTR_T == 4 #if SIZEOF_UINTPTR_T == 4
/* 32 bits */ /* 32 bits */
# define BITS_FOR_IDS_TABLE 5 # define BITS_MID_TABLE_ID 5
# define BITS_FOR_IDS_INTER_TABLE 5 # define BITS_TABLE_ID 5
# define BITS_FOR_ID_IN_TABLE 12 # define BITS_ENTRY_ID 12
# define BITS_FOR_GENERATION_COUNTER 10 # define BITS_GENERATION_COUNTER 10
typedef int16_t Table_Index; typedef int16_t Table_Index;
typedef uint16_t Generation_Counter; typedef uint16_t Generation_Counter;
#else #else
/* 64 bits */ /* 64 bits */
# define BITS_FOR_IDS_TABLE 11 # define BITS_MID_TABLE_ID 11
# define BITS_FOR_IDS_INTER_TABLE 11 # define BITS_TABLE_ID 11
# define BITS_FOR_ID_IN_TABLE 12 # define BITS_ENTRY_ID 12
# define BITS_FOR_GENERATION_COUNTER 30 # define BITS_GENERATION_COUNTER 30
typedef int16_t Table_Index; typedef int16_t Table_Index;
typedef uint32_t Generation_Counter; typedef uint32_t Generation_Counter;
#endif #endif
/* Shifts macros to manipulate the Eo id */ /* Shifts macros to manipulate the Eo id */
#define SHIFT_FOR_IDS_TABLE \ #define SHIFT_MID_TABLE_ID (BITS_TABLE_ID + \
(BITS_FOR_IDS_INTER_TABLE + BITS_FOR_ID_IN_TABLE + BITS_FOR_GENERATION_COUNTER) BITS_ENTRY_ID + BITS_GENERATION_COUNTER)
#define SHIFT_TABLE_ID (BITS_ENTRY_ID + BITS_GENERATION_COUNTER)
#define SHIFT_FOR_IDS_INTER_TABLE \ #define SHIFT_ENTRY_ID (BITS_GENERATION_COUNTER)
(BITS_FOR_ID_IN_TABLE + BITS_FOR_GENERATION_COUNTER)
#define SHIFT_FOR_ID_IN_TABLE (BITS_FOR_GENERATION_COUNTER)
/* Maximum ranges */ /* Maximum ranges */
#define MAX_IDS_TABLES (1 << BITS_FOR_IDS_TABLE) #define MAX_MID_TABLE_ID (1 << BITS_MID_TABLE_ID)
#define MAX_IDS_INTER_TABLES (1 << BITS_FOR_IDS_INTER_TABLE) #define MAX_TABLE_ID (1 << BITS_TABLE_ID)
#define MAX_IDS_PER_TABLE (1 << BITS_FOR_ID_IN_TABLE) #define MAX_ENTRY_ID (1 << BITS_ENTRY_ID)
#define MAX_GENERATIONS (1 << BITS_FOR_GENERATION_COUNTER) #define MAX_GENERATIONS (1 << BITS_GENERATION_COUNTER)
#define MEM_HEADER_SIZE 16 /* Masks */
#define MEM_PAGE_SIZE 4096 #define MASK_MID_TABLE_ID (MAX_MID_TABLE_ID - 1)
#define MEM_MAGIC 0x3f61ec8a #define MASK_TABLE_ID (MAX_TABLE_ID - 1)
#define MASK_ENTRY_ID (MAX_ENTRY_ID - 1)
#define MASK_GENERATIONS (MAX_GENERATIONS - 1)
#define MEM_HEADER_SIZE 16
#define MEM_PAGE_SIZE 4096
#define MEM_MAGIC 0x3f61ec8a
typedef struct _Mem_Header typedef struct _Mem_Header
{ {
@ -159,26 +165,26 @@ typedef struct
{ {
/* Pointer to the object */ /* Pointer to the object */
_Eo *ptr; _Eo *ptr;
/* Indicates where to find the next entry to recycle */
Table_Index next_in_fifo;
/* Active flag */ /* Active flag */
unsigned int active : 1; unsigned int active : 1;
/* Generation */ /* Generation */
unsigned int generation : BITS_FOR_GENERATION_COUNTER; unsigned int generation : BITS_GENERATION_COUNTER;
/* Indicates where to find the next entry to recycle */
Table_Index next_in_queue;
} _Eo_Id_Entry; } _Eo_Id_Entry;
/* Table */ /* Table */
typedef struct typedef struct
{ {
/* Entries of the table holding real pointers and generations */
_Eo_Id_Entry entries[MAX_IDS_PER_TABLE];
/* Indicates where start the "never used" entries */ /* Indicates where start the "never used" entries */
Table_Index start; Table_Index start;
/* Indicates where to find the next entry to recycle */ /* Indicates where to find the next entry to recycle */
Table_Index queue_head; Table_Index fifo_head;
/* Indicates where to add an entry to recycle */ /* Indicates where to add an entry to recycle */
Table_Index queue_tail; Table_Index fifo_tail;
/* Entries of the table holding real pointers and generations */
_Eo_Id_Entry entries[MAX_ENTRY_ID];
} _Eo_Ids_Table; } _Eo_Ids_Table;
/* Table Info */ /* Table Info */
@ -186,14 +192,14 @@ typedef struct
{ {
/* Table pointer */ /* Table pointer */
_Eo_Ids_Table *table; _Eo_Ids_Table *table;
/* Top table index */ /* Index of mid table in top table */
Table_Index mid_table_id;
/* Index of table in mid table */
Table_Index table_id; Table_Index table_id;
/* Intermediate table index */
Table_Index int_table_id;
} _Eo_Table_Info; } _Eo_Table_Info;
/* Tables handling pointers indirection */ /* Tables handling pointers indirection */
static _Eo_Ids_Table **_eo_ids_tables[MAX_IDS_TABLES] = { NULL }; static _Eo_Ids_Table **_eo_ids_tables[MAX_MID_TABLE_ID] = { NULL };
/* Current table used for following allocations */ /* Current table used for following allocations */
static _Eo_Table_Info current_table = { NULL, 0, 0 }; static _Eo_Table_Info current_table = { NULL, 0, 0 };
@ -202,21 +208,21 @@ static _Eo_Table_Info current_table = { NULL, 0, 0 };
Generation_Counter _eo_generation_counter; Generation_Counter _eo_generation_counter;
/* Macro used to compose an Eo id */ /* Macro used to compose an Eo id */
#define EO_COMPOSE_ID(TABLE, INTER_TABLE, ENTRY, GENERATION) \ #define EO_COMPOSE_ID(TABLE, INTER_TABLE, ENTRY, GENERATION) \
(((Eo_Id)(TABLE & (MAX_IDS_TABLES - 1)) << SHIFT_FOR_IDS_TABLE) | \ (((Eo_Id)(TABLE & MASK_MID_TABLE_ID) << SHIFT_MID_TABLE_ID) | \
((Eo_Id)(INTER_TABLE & (MAX_IDS_INTER_TABLES - 1)) << SHIFT_FOR_IDS_INTER_TABLE) | \ ((Eo_Id)(INTER_TABLE & MASK_TABLE_ID) << SHIFT_TABLE_ID) | \
((ENTRY & (MAX_IDS_PER_TABLE - 1)) << SHIFT_FOR_ID_IN_TABLE) | \ ((ENTRY & MASK_ENTRY_ID) << SHIFT_ENTRY_ID) | \
(GENERATION & (MAX_GENERATIONS - 1) )) (GENERATION & MASK_GENERATIONS ))
/* Macro to extract from an Eo id the indexes of the tables */ /* Macro to extract from an Eo id the indexes of the tables */
#define EO_DECOMPOSE_ID(ID, TABLE, INTER_TABLE, ENTRY, GENERATION) \ #define EO_DECOMPOSE_ID(ID, TABLE, INTER_TABLE, ENTRY, GENERATION) \
TABLE = (ID >> SHIFT_FOR_IDS_TABLE) & (MAX_IDS_TABLES - 1); \ TABLE = (ID >> SHIFT_MID_TABLE_ID) & MASK_MID_TABLE_ID; \
INTER_TABLE = (ID >> SHIFT_FOR_IDS_INTER_TABLE) & (MAX_IDS_INTER_TABLES - 1); \ INTER_TABLE = (ID >> SHIFT_TABLE_ID) & MASK_TABLE_ID; \
ENTRY = (ID >> SHIFT_FOR_ID_IN_TABLE) & (MAX_IDS_PER_TABLE - 1); \ ENTRY = (ID >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID; \
GENERATION = ID & (MAX_GENERATIONS - 1); \ GENERATION = ID & MASK_GENERATIONS;
/* Macro used for readability */ /* Macro used for readability */
#define ID_TABLE _eo_ids_tables[table_id][int_table_id] #define TABLE_FROM_IDS _eo_ids_tables[mid_table_id][table_id]
_Eo * _Eo *
_eo_obj_pointer_get(const Eo_Id obj_id) _eo_obj_pointer_get(const Eo_Id obj_id)
@ -224,14 +230,14 @@ _eo_obj_pointer_get(const Eo_Id obj_id)
#ifdef HAVE_EO_ID #ifdef HAVE_EO_ID
_Eo_Id_Entry *entry; _Eo_Id_Entry *entry;
Generation_Counter generation; Generation_Counter generation;
Table_Index table_id, int_table_id, entry_id; Table_Index mid_table_id, table_id, entry_id;
EO_DECOMPOSE_ID(obj_id, table_id, int_table_id, entry_id, generation); EO_DECOMPOSE_ID(obj_id, mid_table_id, table_id, entry_id, generation);
/* Checking the validity of the entry */ /* Checking the validity of the entry */
if (_eo_ids_tables[table_id] && ID_TABLE) if (_eo_ids_tables[mid_table_id] && TABLE_FROM_IDS)
{ {
entry = &(ID_TABLE->entries[entry_id]); entry = &(TABLE_FROM_IDS->entries[entry_id]);
if (entry && entry->active && (entry->generation == generation)) if (entry && entry->active && (entry->generation == generation))
return entry->ptr; return entry->ptr;
} }
@ -250,20 +256,20 @@ _get_available_entry(_Eo_Ids_Table *table)
{ {
_Eo_Id_Entry *entry = NULL; _Eo_Id_Entry *entry = NULL;
if (table->start != MAX_IDS_PER_TABLE) if (table->start != MAX_ENTRY_ID)
{ {
/* Serve never used entries first */ /* Serve never used entries first */
entry = &(table->entries[table->start]); entry = &(table->entries[table->start]);
table->start++; table->start++;
} }
else if (table->queue_head != -1) else if (table->fifo_head != -1)
{ {
/* Pop an unused entry from the queue */ /* Pop a free entry from the fifo */
entry = &(table->entries[table->queue_head]); entry = &(table->entries[table->fifo_head]);
if (entry->next_in_queue == -1) if (entry->next_in_fifo == -1)
table->queue_head = table->queue_tail = -1; table->fifo_head = table->fifo_tail = -1;
else else
table->queue_head = entry->next_in_queue; table->fifo_head = entry->next_in_fifo;
} }
return entry; return entry;
@ -275,25 +281,25 @@ _search_tables()
_Eo_Ids_Table *table; _Eo_Ids_Table *table;
_Eo_Id_Entry *entry; _Eo_Id_Entry *entry;
for (Table_Index table_id = 1; table_id < MAX_IDS_TABLES; table_id++) for (Table_Index mid_table_id = 1; mid_table_id < MAX_MID_TABLE_ID; mid_table_id++)
{ {
if (!_eo_ids_tables[table_id]) if (!_eo_ids_tables[mid_table_id])
{ {
/* Allocate a new intermediate table */ /* Allocate a new intermediate table */
_eo_ids_tables[table_id] = _eo_id_mem_calloc(MAX_IDS_INTER_TABLES, sizeof(_Eo_Ids_Table*)); _eo_ids_tables[mid_table_id] = _eo_id_mem_calloc(MAX_TABLE_ID, sizeof(_Eo_Ids_Table*));
} }
for (Table_Index int_table_id = 0; int_table_id < MAX_IDS_INTER_TABLES; int_table_id++) for (Table_Index table_id = 0; table_id < MAX_TABLE_ID; table_id++)
{ {
table = ID_TABLE; table = TABLE_FROM_IDS;
if (!table) if (!table)
{ {
/* Allocate a new table and reserve the first entry */ /* Allocate a new table and reserve the first entry */
table = _eo_id_mem_calloc(1, sizeof(_Eo_Ids_Table)); table = _eo_id_mem_calloc(1, sizeof(_Eo_Ids_Table));
table->start = 1; table->start = 1;
table->queue_head = table->queue_tail = -1; table->fifo_head = table->fifo_tail = -1;
ID_TABLE = table; TABLE_FROM_IDS = table;
entry = &(table->entries[0]); entry = &(table->entries[0]);
} }
else else
@ -303,8 +309,8 @@ _search_tables()
{ {
/* Store table info into current table */ /* Store table info into current table */
current_table.table = table; current_table.table = table;
current_table.mid_table_id = mid_table_id;
current_table.table_id = table_id; current_table.table_id = table_id;
current_table.int_table_id = int_table_id;
return entry; return entry;
} }
} }
@ -337,8 +343,8 @@ _eo_id_allocate(const _Eo *obj)
entry->generation = _eo_generation_counter; entry->generation = _eo_generation_counter;
_eo_generation_counter++; _eo_generation_counter++;
_eo_generation_counter %= MAX_GENERATIONS; _eo_generation_counter %= MAX_GENERATIONS;
return EO_COMPOSE_ID(current_table.table_id, return EO_COMPOSE_ID(current_table.mid_table_id,
current_table.int_table_id, current_table.table_id,
(entry - current_table.table->entries), (entry - current_table.table->entries),
entry->generation); entry->generation);
#else #else
@ -353,27 +359,27 @@ _eo_id_release(const Eo_Id obj_id)
_Eo_Ids_Table *table; _Eo_Ids_Table *table;
_Eo_Id_Entry *entry; _Eo_Id_Entry *entry;
Generation_Counter generation; Generation_Counter generation;
Table_Index table_id, int_table_id, entry_id; Table_Index mid_table_id, table_id, entry_id;
EO_DECOMPOSE_ID(obj_id, table_id, int_table_id, entry_id, generation); EO_DECOMPOSE_ID(obj_id, mid_table_id, table_id, entry_id, generation);
/* Checking the validity of the entry */ /* Checking the validity of the entry */
if (_eo_ids_tables[table_id] && (table = ID_TABLE)) if (_eo_ids_tables[mid_table_id] && (table = TABLE_FROM_IDS))
{ {
entry = &(table->entries[entry_id]); entry = &(table->entries[entry_id]);
if (entry && entry->active && (entry->generation == generation)) if (entry && entry->active && (entry->generation == generation))
{ {
/* Disable the entry */ /* Disable the entry */
entry->active = 0; entry->active = 0;
entry->next_in_queue = -1; entry->next_in_fifo = -1;
/* Push the entry into the queue */ /* Push the entry into the fifo */
if (table->queue_tail == -1) if (table->fifo_tail == -1)
{ {
table->queue_head = table->queue_tail = entry_id; table->fifo_head = table->fifo_tail = entry_id;
} }
else else
{ {
table->entries[table->queue_tail].next_in_queue = entry_id; table->entries[table->fifo_tail].next_in_fifo = entry_id;
table->queue_tail = entry_id; table->fifo_tail = entry_id;
} }
return; return;
} }
@ -388,20 +394,20 @@ _eo_id_release(const Eo_Id obj_id)
void void
_eo_free_ids_tables() _eo_free_ids_tables()
{ {
for (Table_Index table_id = 0; table_id < MAX_IDS_TABLES; table_id++) for (Table_Index mid_table_id = 0; mid_table_id < MAX_MID_TABLE_ID; mid_table_id++)
{ {
if (_eo_ids_tables[table_id]) if (_eo_ids_tables[mid_table_id])
{ {
for (Table_Index int_table_id = 0; int_table_id < MAX_IDS_INTER_TABLES; int_table_id++) for (Table_Index table_id = 0; table_id < MAX_TABLE_ID; table_id++)
{ {
if (ID_TABLE) if (TABLE_FROM_IDS)
{ {
_eo_id_mem_free(ID_TABLE); _eo_id_mem_free(TABLE_FROM_IDS);
} }
} }
_eo_id_mem_free(_eo_ids_tables[table_id]); _eo_id_mem_free(_eo_ids_tables[mid_table_id]);
} }
_eo_ids_tables[table_id] = NULL; _eo_ids_tables[mid_table_id] = NULL;
} }
current_table.table = NULL; current_table.table = NULL;
} }
@ -412,22 +418,22 @@ _eo_print()
{ {
_Eo_Id_Entry *entry; _Eo_Id_Entry *entry;
unsigned long obj_number = 0; unsigned long obj_number = 0;
for (Table_Index table_id = 0; table_id < MAX_IDS_TABLES; table_id++) for (Table_Index mid_table_id = 0; mid_table_id < MAX_MID_TABLE_ID; mid_table_id++)
{ {
if (_eo_ids_tables[table_id]) if (_eo_ids_tables[mid_table_id])
{ {
for (Table_Index int_table_id = 0; int_table_id < MAX_IDS_INTER_TABLES; int_table_id++) for (Table_Index table_id = 0; table_id < MAX_TABLE_ID; table_id++)
{ {
if (ID_TABLE) if (TABLE_FROM_IDS)
{ {
for (Table_Index entry_id = 0; entry_id < MAX_IDS_PER_TABLE; entry_id++) for (Table_Index entry_id = 0; entry_id < MAX_ENTRY_ID; entry_id++)
{ {
entry = &(ID_TABLE->entries[entry_id]); entry = &(TABLE_FROM_IDS->entries[entry_id]);
if (entry->active) if (entry->active)
{ {
printf("%ld: %p -> (%p, %p, %p, %p)\n", obj_number++, printf("%ld: %p -> (%p, %p, %p, %p)\n", obj_number++,
entry->ptr, entry->ptr,
(void *)table_id, (void *)int_table_id, (void *)entry_id, (void *)mid_table_id, (void *)table_id, (void *)entry_id,
(void *)entry->generation); (void *)entry->generation);
} }
} }