calog/libs/calogHandle.c

155 lines
4.3 KiB
C

// calogHandle.c -- thread-safe, typed integer handle table (see calogHandle.h).
#include "calogHandle.h"
#include <pthread.h>
#include <stdlib.h>
#define HANDLE_INITIAL_CAP 8
#define HANDLE_GROWTH 2
// A free slot has handle == 0; the monotonic nextHandle starts at 1, so 0 is never a
// live handle and doubles as the "invalid" sentinel a caller can test.
typedef struct HandleEntryT {
int64_t handle;
uint32_t type;
void *resource;
} HandleEntryT;
struct CalogHandleTableT {
pthread_mutex_t mutex;
HandleEntryT *entries;
int32_t count;
int32_t cap;
int64_t nextHandle;
};
int64_t calogHandleAdd(CalogHandleTableT *table, uint32_t type, void *resource) {
int64_t handle;
int32_t slot;
int32_t index;
pthread_mutex_lock(&table->mutex);
slot = -1;
for (index = 0; index < table->count; index++) {
if (table->entries[index].handle == 0) {
slot = index;
break;
}
}
if (slot < 0) {
if (table->count == table->cap) {
int32_t newCap;
HandleEntryT *grown;
newCap = (table->cap == 0) ? HANDLE_INITIAL_CAP : table->cap * HANDLE_GROWTH;
grown = (HandleEntryT *)realloc(table->entries, (size_t)newCap * sizeof(HandleEntryT));
if (grown == NULL) {
pthread_mutex_unlock(&table->mutex);
return 0;
}
table->entries = grown;
table->cap = newCap;
}
slot = table->count;
table->count++;
}
handle = table->nextHandle;
table->nextHandle++;
table->entries[slot].handle = handle;
table->entries[slot].type = type;
table->entries[slot].resource = resource;
pthread_mutex_unlock(&table->mutex);
return handle;
}
int32_t calogHandleCount(CalogHandleTableT *table, uint32_t type) {
int32_t count;
int32_t index;
count = 0;
pthread_mutex_lock(&table->mutex);
for (index = 0; index < table->count; index++) {
if (table->entries[index].handle != 0 && table->entries[index].type == type) {
count++;
}
}
pthread_mutex_unlock(&table->mutex);
return count;
}
void *calogHandleGet(CalogHandleTableT *table, int64_t handle, uint32_t type) {
void *resource;
int32_t index;
// Valid handles are >= 1; reject 0 (the free-slot sentinel) and negatives so a bogus or
// zero handle can never alias a freed slot.
if (handle <= 0) {
return NULL;
}
resource = NULL;
pthread_mutex_lock(&table->mutex);
for (index = 0; index < table->count; index++) {
if (table->entries[index].handle == handle && table->entries[index].type == type) {
resource = table->entries[index].resource;
break;
}
}
pthread_mutex_unlock(&table->mutex);
return resource;
}
void *calogHandleRemove(CalogHandleTableT *table, int64_t handle, uint32_t type) {
void *resource;
int32_t index;
if (handle <= 0) {
return NULL;
}
resource = NULL;
pthread_mutex_lock(&table->mutex);
for (index = 0; index < table->count; index++) {
if (table->entries[index].handle == handle && table->entries[index].type == type) {
resource = table->entries[index].resource;
table->entries[index].handle = 0;
table->entries[index].type = 0;
table->entries[index].resource = NULL;
break;
}
}
pthread_mutex_unlock(&table->mutex);
return resource;
}
CalogHandleTableT *calogHandleTableCreate(void) {
CalogHandleTableT *table;
table = (CalogHandleTableT *)calloc(1, sizeof(*table));
if (table == NULL) {
return NULL;
}
pthread_mutex_init(&table->mutex, NULL);
table->nextHandle = 1;
return table;
}
void calogHandleTableDestroy(CalogHandleTableT *table, CalogHandleCloserT closer) {
int32_t index;
if (table == NULL) {
return;
}
for (index = 0; index < table->count; index++) {
if (table->entries[index].handle != 0 && closer != NULL) {
closer(table->entries[index].type, table->entries[index].resource);
}
}
free(table->entries);
pthread_mutex_destroy(&table->mutex);
free(table);
}