155 lines
4.3 KiB
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);
|
|
}
|