void kobj_class_free(kobj_class_t cls) { void* ops = NULL; KOBJ_ASSERT(MA_NOTOWNED); KOBJ_LOCK(); /* * Protect against a race between kobj_create and * kobj_delete. */ if (cls->refs == 0) { /* * For now we don't do anything to unregister any methods * which are no longer used. */ /* * Free memory and clean up. */ ops = cls->ops; cls->ops = NULL; } KOBJ_UNLOCK(); if (ops) free(ops, M_KOBJ); }
void kobj_init(kobj_t obj, kobj_class_t cls) { KOBJ_ASSERT(MA_NOTOWNED); retry: KOBJ_LOCK(); /* * Consider compiling the class' method table. */ if (!cls->ops) { /* * kobj_class_compile doesn't want the lock held * because of the call to malloc - we drop the lock * and re-try. */ KOBJ_UNLOCK(); kobj_class_compile(cls); goto retry; } kobj_init_common(obj, cls); KOBJ_UNLOCK(); }
static int kobj_class_compile1(kobj_class_t cls, int mflags) { kobj_ops_t ops; KOBJ_ASSERT(MA_NOTOWNED); ops = malloc(sizeof(struct kobj_ops), M_KOBJ, mflags); if (ops == NULL) return (ENOMEM); /* * We may have lost a race for kobj_class_compile here - check * to make sure someone else hasn't already compiled this * class. */ KOBJ_LOCK(); if (cls->ops) { KOBJ_UNLOCK(); free(ops, M_KOBJ); return (0); } kobj_class_compile_common(cls, ops); KOBJ_UNLOCK(); return (0); }
void kobj_class_compile(kobj_class_t cls) { kobj_ops_t ops; KOBJ_ASSERT(MA_NOTOWNED); /* * Allocate space for the compiled ops table. */ ops = malloc(sizeof(struct kobj_ops), M_KOBJ, M_NOWAIT); if (!ops) panic("%s: out of memory", __func__); KOBJ_LOCK(); /* * We may have lost a race for kobj_class_compile here - check * to make sure someone else hasn't already compiled this * class. */ if (cls->ops) { KOBJ_UNLOCK(); free(ops, M_KOBJ); return; } kobj_class_compile_common(cls, ops); KOBJ_UNLOCK(); }
void kobj_class_free(kobj_class_t cls) { int i; kobj_method_t *m; void* ops = NULL; KOBJ_ASSERT(MA_NOTOWNED); KOBJ_LOCK(); /* * Protect against a race between kobj_create and * kobj_delete. */ if (cls->refs == 0) { /* * Unregister any methods which are no longer used. */ for (i = 0, m = cls->methods; m->desc; i++, m++) kobj_unregister_method(m->desc); /* * Free memory and clean up. */ ops = cls->ops; cls->ops = NULL; } KOBJ_UNLOCK(); if (ops) free(ops, M_KOBJ); }
static void kobj_class_compile_common(kobj_class_t cls, kobj_ops_t ops) { kobj_method_t *m; int i; KOBJ_ASSERT(MA_OWNED); /* * Don't do anything if we are already compiled. */ if (cls->ops) return; /* * First register any methods which need it. */ for (i = 0, m = cls->methods; m->desc; i++, m++) kobj_register_method(m->desc); /* * Then initialise the ops table. */ for (i = 0; i < KOBJ_CACHE_SIZE; i++) ops->cache[i] = &null_method; ops->cls = cls; cls->ops = ops; }
static void kobj_register_method(struct kobjop_desc *desc) { KOBJ_ASSERT(MA_OWNED); if (desc->id == 0) { desc->id = kobj_next_id++; } }
void kobj_class_compile_static(kobj_class_t cls, kobj_ops_t ops) { KOBJ_ASSERT(MA_NOTOWNED); /* * Increment refs to make sure that the ops table is not freed. */ KOBJ_LOCK(); cls->refs++; kobj_class_compile_common(cls, ops); KOBJ_UNLOCK(); }
void kobj_delete(kobj_t obj, struct malloc_type *mtype) { kobj_class_t cls = obj->ops->cls; int refs; /* * Consider freeing the compiled method table for the class * after its last instance is deleted. As an optimisation, we * should defer this for a short while to avoid thrashing. */ KOBJ_ASSERT(MA_NOTOWNED); KOBJ_LOCK(); cls->refs--; refs = cls->refs; KOBJ_UNLOCK(); if (!refs) kobj_class_free(cls); obj->ops = NULL; if (mtype) free(obj, mtype); }