// calogHandle.c -- thread-safe, typed integer handle table (see calogHandle.h). #include "calogHandle.h" #include #include #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); }