|
|
1.1 ! root 1: /* ! 2: * IPFlow Collector ! 3: * Copyright (c) 2003 Christophe Fillot. ! 4: * E-mail: [email protected] ! 5: * ! 6: * registry.c: Object Registry. ! 7: */ ! 8: ! 9: #define _GNU_SOURCE ! 10: #include <stdio.h> ! 11: #include <stdlib.h> ! 12: #include <string.h> ! 13: #include <stdarg.h> ! 14: #include <unistd.h> ! 15: #include <errno.h> ! 16: #include <signal.h> ! 17: #include <fcntl.h> ! 18: #include <ctype.h> ! 19: #include <time.h> ! 20: #include <pthread.h> ! 21: #include <sys/time.h> ! 22: #include <sys/stat.h> ! 23: #include <sys/types.h> ! 24: #include <sys/wait.h> ! 25: #include <assert.h> ! 26: ! 27: #include "utils.h" ! 28: #include "hash.h" ! 29: #include "mempool.h" ! 30: #include "registry.h" ! 31: ! 32: #define DEBUG_REGISTRY 0 ! 33: ! 34: static registry_t *registry = NULL; ! 35: ! 36: #define REGISTRY_LOCK() pthread_mutex_lock(®istry->lock) ! 37: #define REGISTRY_UNLOCK() pthread_mutex_unlock(®istry->lock) ! 38: ! 39: /* Initialize registry */ ! 40: int registry_init(void) ! 41: { ! 42: registry_entry_t *p; ! 43: pthread_mutexattr_t attr; ! 44: size_t len; ! 45: int i; ! 46: ! 47: registry = malloc(sizeof(*registry)); ! 48: assert(registry != NULL); ! 49: ! 50: pthread_mutexattr_init(&attr); ! 51: pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); ! 52: pthread_mutex_init(®istry->lock,&attr); ! 53: ! 54: /* initialize registry memory pool */ ! 55: mp_create_fixed_pool(®istry->mp,"registry"); ! 56: ! 57: registry->ht_name_entries = REGISTRY_HT_NAME_ENTRIES; ! 58: registry->ht_type_entries = REGISTRY_MAX_TYPES; ! 59: ! 60: /* initialize hash table for names, with sentinels */ ! 61: len = registry->ht_name_entries * sizeof(registry_entry_t); ! 62: registry->ht_names = mp_alloc(®istry->mp,len); ! 63: assert(registry->ht_names != NULL); ! 64: ! 65: for(i=0;i<registry->ht_name_entries;i++) { ! 66: p = ®istry->ht_names[i]; ! 67: p->hname_next = p->hname_prev = p; ! 68: } ! 69: ! 70: /* initialize hash table for types, with sentinels */ ! 71: len = registry->ht_type_entries * sizeof(registry_entry_t); ! 72: registry->ht_types = mp_alloc(®istry->mp,len); ! 73: assert(registry->ht_types != NULL); ! 74: ! 75: for(i=0;i<registry->ht_type_entries;i++) { ! 76: p = ®istry->ht_types[i]; ! 77: p->htype_next = p->htype_prev = p; ! 78: } ! 79: ! 80: return(0); ! 81: } ! 82: ! 83: /* Insert a new entry */ ! 84: static void registry_insert_entry(registry_entry_t *entry) ! 85: { ! 86: registry_entry_t *bucket; ! 87: u_int h_index; ! 88: ! 89: /* insert new entry in hash table for names */ ! 90: h_index = str_hash(entry->name) % registry->ht_name_entries; ! 91: bucket = ®istry->ht_names[h_index]; ! 92: ! 93: entry->hname_next = bucket->hname_next; ! 94: entry->hname_prev = bucket; ! 95: bucket->hname_next->hname_prev = entry; ! 96: bucket->hname_next = entry; ! 97: ! 98: /* insert new entry in hash table for object types */ ! 99: bucket = ®istry->ht_types[entry->object_type]; ! 100: ! 101: entry->htype_next = bucket->htype_next; ! 102: entry->htype_prev = bucket; ! 103: bucket->htype_next->htype_prev = entry; ! 104: bucket->htype_next = entry; ! 105: } ! 106: ! 107: /* Remove a registry entry */ ! 108: void registry_remove_entry(registry_entry_t *entry) ! 109: { ! 110: entry->hname_prev->hname_next = entry->hname_next; ! 111: entry->hname_next->hname_prev = entry->hname_prev; ! 112: ! 113: entry->htype_prev->htype_next = entry->htype_next; ! 114: entry->htype_next->htype_prev = entry->htype_prev; ! 115: ! 116: mp_free(entry); ! 117: } ! 118: ! 119: /* Locate an entry */ ! 120: static inline registry_entry_t *registry_find_entry(char *name,int object_type) ! 121: { ! 122: registry_entry_t *entry,*bucket; ! 123: u_int h_index; ! 124: ! 125: h_index = str_hash(name) % registry->ht_name_entries; ! 126: bucket = ®istry->ht_names[h_index]; ! 127: ! 128: for(entry=bucket->hname_next;entry!=bucket;entry=entry->hname_next) ! 129: if (!strcmp(entry->name,name) && (entry->object_type == object_type)) ! 130: return entry; ! 131: ! 132: return NULL; ! 133: } ! 134: ! 135: /* Add a new entry to the registry */ ! 136: int registry_add(char *name,int object_type,void *data) ! 137: { ! 138: registry_entry_t *entry; ! 139: ! 140: if (!name) ! 141: return(-1); ! 142: ! 143: REGISTRY_LOCK(); ! 144: ! 145: /* check if we have already a reference for this name */ ! 146: if ((entry = registry_find_entry(name,object_type))) { ! 147: REGISTRY_UNLOCK(); ! 148: return(-1); ! 149: } ! 150: ! 151: /* create a new entry */ ! 152: if (!(entry = mp_alloc(®istry->mp,sizeof(*entry)))) { ! 153: REGISTRY_UNLOCK(); ! 154: return(-1); ! 155: } ! 156: ! 157: entry->name = name; ! 158: entry->data = data; ! 159: entry->object_type = object_type; ! 160: entry->ref_count = 1; /* consider object is referenced by the caller */ ! 161: registry_insert_entry(entry); ! 162: ! 163: REGISTRY_UNLOCK(); ! 164: return(0); ! 165: } ! 166: ! 167: /* Delete an entry from the registry */ ! 168: int registry_delete(char *name,int object_type) ! 169: { ! 170: registry_entry_t *entry; ! 171: ! 172: if (!name) return(-1); ! 173: ! 174: REGISTRY_LOCK(); ! 175: ! 176: if (!(entry = registry_find_entry(name,object_type))) { ! 177: REGISTRY_UNLOCK(); ! 178: return(-1); ! 179: } ! 180: ! 181: /* if the entry is referenced, just decrement ref counter */ ! 182: if (--entry->ref_count > 0) { ! 183: REGISTRY_UNLOCK(); ! 184: return(0); ! 185: } ! 186: ! 187: registry_remove_entry(entry); ! 188: REGISTRY_UNLOCK(); ! 189: return(0); ! 190: } ! 191: ! 192: /* Find an entry (increment the reference count) */ ! 193: void *registry_find(char *name,int object_type) ! 194: { ! 195: registry_entry_t *entry; ! 196: void *data; ! 197: ! 198: if (!name) return NULL; ! 199: ! 200: REGISTRY_LOCK(); ! 201: ! 202: if ((entry = registry_find_entry(name,object_type))) { ! 203: entry->ref_count++; ! 204: data = entry->data; ! 205: } else ! 206: data = NULL; ! 207: ! 208: REGISTRY_UNLOCK(); ! 209: return data; ! 210: } ! 211: ! 212: /* Check if entry exists (does not change reference count) */ ! 213: void *registry_exists(char *name,int object_type) ! 214: { ! 215: registry_entry_t *entry; ! 216: void *data = NULL; ! 217: ! 218: if (!name) ! 219: return NULL; ! 220: ! 221: REGISTRY_LOCK(); ! 222: entry = registry_find_entry(name,object_type); ! 223: if (entry) ! 224: data = entry->data; ! 225: REGISTRY_UNLOCK(); ! 226: return data; ! 227: } ! 228: ! 229: /* Release a reference of an entry (decrement the reference count) */ ! 230: int registry_unref(char *name,int object_type) ! 231: { ! 232: registry_entry_t *entry; ! 233: int res = -1; ! 234: ! 235: if (!name) return(-1); ! 236: ! 237: REGISTRY_LOCK(); ! 238: ! 239: if ((entry = registry_find_entry(name,object_type))) ! 240: { ! 241: entry->ref_count--; ! 242: ! 243: #if DEBUG_REGISTRY ! 244: printf("Registry: object %s: ref_count = %d after unref.\n", ! 245: name, entry->ref_count); ! 246: #endif ! 247: ! 248: if (entry->ref_count < 0) { ! 249: fprintf(stderr,"Registry: object %s (type %d): negative ref_count.\n", ! 250: name, object_type); ! 251: } else ! 252: res = 0; ! 253: } ! 254: ! 255: REGISTRY_UNLOCK(); ! 256: return(res); ! 257: } ! 258: ! 259: /* ! 260: * Execute action on an object if its reference count is less or equal to ! 261: * the specified count. ! 262: */ ! 263: int registry_exec_refcount(char *name,int object_type,int max_ref,int reg_del, ! 264: registry_exec obj_action,void *opt_arg) ! 265: { ! 266: registry_entry_t *entry; ! 267: int res = -1; ! 268: int status; ! 269: ! 270: if (!name) return(-1); ! 271: ! 272: REGISTRY_LOCK(); ! 273: ! 274: entry = registry_find_entry(name,object_type); ! 275: ! 276: if (entry) ! 277: { ! 278: if (entry->ref_count <= max_ref) ! 279: { ! 280: status = TRUE; ! 281: ! 282: if (obj_action != NULL) ! 283: status = obj_action(entry->data,opt_arg); ! 284: ! 285: if (reg_del && status) ! 286: registry_remove_entry(entry); ! 287: ! 288: res = 1; ! 289: } else ! 290: res = 0; ! 291: } ! 292: ! 293: REGISTRY_UNLOCK(); ! 294: return(res); ! 295: } ! 296: ! 297: /* Delete object if unused */ ! 298: int registry_delete_if_unused(char *name,int object_type, ! 299: registry_exec obj_destructor,void *opt_arg) ! 300: { ! 301: return(registry_exec_refcount(name,object_type,0,TRUE, ! 302: obj_destructor,opt_arg)); ! 303: } ! 304: ! 305: /* Execute a callback function for all objects of specified type */ ! 306: int registry_foreach_type(int object_type,registry_foreach cb, ! 307: void *opt,int *err) ! 308: { ! 309: registry_entry_t *p,*bucket,*next; ! 310: int count = 0; ! 311: ! 312: REGISTRY_LOCK(); ! 313: ! 314: bucket = ®istry->ht_types[object_type]; ! 315: ! 316: for(p=bucket->htype_next;p!=bucket;p=next) { ! 317: next = p->htype_next; ! 318: if (cb) cb(p,opt,err); ! 319: count++; ! 320: } ! 321: ! 322: REGISTRY_UNLOCK(); ! 323: return(count); ! 324: } ! 325: ! 326: /* Delete all objects of the specified type */ ! 327: int registry_delete_type(int object_type,registry_exec cb,void *opt) ! 328: { ! 329: registry_entry_t *p,*bucket,*next; ! 330: int count = 0; ! 331: int status; ! 332: ! 333: REGISTRY_LOCK(); ! 334: ! 335: bucket = ®istry->ht_types[object_type]; ! 336: ! 337: for(p=bucket->htype_next;p!=bucket;p=next) { ! 338: next = p->htype_next; ! 339: ! 340: if (p->ref_count == 0) { ! 341: status = TRUE; ! 342: ! 343: if (cb != NULL) ! 344: status = cb(p->data,opt); ! 345: ! 346: if (status) { ! 347: registry_remove_entry(p); ! 348: count++; ! 349: } ! 350: } else { ! 351: fprintf(stderr,"registry_delete_type: object \"%s\" (type %d) still " ! 352: "referenced (count=%d)\n",p->name,object_type,p->ref_count); ! 353: } ! 354: } ! 355: ! 356: REGISTRY_UNLOCK(); ! 357: return(count); ! 358: } ! 359: ! 360: /* Dump the registry */ ! 361: void registry_dump(void) ! 362: { ! 363: registry_entry_t *p,*bucket; ! 364: int i; ! 365: ! 366: REGISTRY_LOCK(); ! 367: ! 368: printf("Registry dump:\n"); ! 369: ! 370: printf(" Objects (from name hash table):\n"); ! 371: ! 372: /* dump hash table of names */ ! 373: for(i=0;i<registry->ht_name_entries;i++) ! 374: { ! 375: bucket = ®istry->ht_names[i]; ! 376: ! 377: for(p=bucket->hname_next;p!=bucket;p=p->hname_next) ! 378: printf(" %s (type %d, ref_count=%d)\n", ! 379: p->name,p->object_type,p->ref_count); ! 380: } ! 381: ! 382: printf("\n Objects classed by types:\n"); ! 383: ! 384: /* dump hash table of types */ ! 385: for(i=0;i<registry->ht_type_entries;i++) ! 386: { ! 387: printf(" Type %d: ",i); ! 388: ! 389: bucket = ®istry->ht_types[i]; ! 390: for(p=bucket->htype_next;p!=bucket;p=p->htype_next) ! 391: printf("%s(%d) ",p->name,p->ref_count); ! 392: ! 393: printf("\n"); ! 394: } ! 395: ! 396: REGISTRY_UNLOCK(); ! 397: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.