/* * RES_CORE.C - Resource ownership class, implementation * * as defined here, a resource has a class and an id (value). one ULONG * of data may be attached to a resource. * * objects create a reference (handle) to the resource using res_create * and free it using res_destroy. multiple objects may create references * to the same object. * * ownership is aquired using res_own and released using res_unown. if * an object already owns a resource, it may own it again (class keeps * a refrence count). if an object (thread) asks for ownership of an * already owned resource, if is suspended (using NdisAquireSpinLock) */ #include #include #include #include #include #include #include #include #include #include #include /* system limits */ #define MAX_RES 128 /* assists */ //#define LOCK NdisAcquireSpinLock(&res__lock) //#define UNLOCK NdisReleaseSpinLock(&res__lock) /* global variables */ NDIS_SPIN_LOCK res__lock; /* management lock */ RES *res__tbl; /* initialize support */ INT res_init(VOID) { NDIS_PHYSICAL_ADDRESS pa = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1); /* allocate memory object */ NdisAllocateMemory((PVOID*)&res__tbl, (sizeof(RES) * MAX_RES), 0, pa); if ( !res__tbl ) { D_LOG(D_ALWAYS, ("res_init: memory allocate failed!")); return(RES_E_NOMEM); } D_LOG(D_ALWAYS, ("res_init: res__tbl: 0x%lx", res__tbl)); NdisZeroMemory (res__tbl, sizeof(RES) * MAX_RES); // NdisAllocateSpinLock(&res__lock); return(RES_E_SUCC); } /* terminate support */ VOID res_term(VOID) { // DbgPrint ("Resource Term: Entry\n"); // NdisFreeSpinLock(&res__lock); /* free memory */ NdisFreeMemory(res__tbl, (sizeof(RES) * MAX_RES), 0); } /* create a (refrence to a ) resource */ RES* res_create(ULONG class, ULONG id) { RES *res; INT n; // LOCK; // DbgPrint ("Resource Create: class: 0x%x, id: 0x%x\n",class, id); // DbgPrint ("IRQL: 0x%x\n",KeGetCurrentIrql()); /* scan for a matching slot */ for ( n = 0 ; n < MAX_RES ; n++ ) { res = res__tbl + n; if ( res->cre_ref && (res->class == class) && (res->id == id) ) { /* found an already existing resource */ // DbgPrint ("Resource Create: resource already exists!\n"); res->cre_ref++; break; } } /* if no such, try to create a new one */ if (n >= MAX_RES) for ( n = 0 ; n < MAX_RES ; n++ ) { res = res__tbl + n; if ( !res->cre_ref ) { // DbgPrint ("Resource Create: resource created!\n"); /* found a free slot, fill */ res->cre_ref++; res->class = class; res->id = id; res->data = 0; res->own_ref = 0; NdisAllocateSpinLock(&res->lock); /* init sema */ sema_init(&res->proc_sema); break; } } // UNLOCK; // DbgPrint ("Resource Create exit: res: 0x%lx refcount: %d\n",res, res->cre_ref); // DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql()); return(res); } /* free (a refrence to) a resource, return 1 if really destroyed */ INT res_destroy(VOID *res_1) { RES *res = (RES*)res_1; INT really = 0; // LOCK; // DbgPrint ("Resource Destroy: Entry res: 0x%lx, refcount: %d\n",res, res->cre_ref); // DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql()); /* decrement refrence count, if down to zero, free */ res->cre_ref--; if ( !res->cre_ref ) { NdisFreeSpinLock(&res->lock); sema_term (&res->proc_sema); really = 1; } // UNLOCK; // DbgPrint ("Resource Destroy: Exit\n"); // DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql()); return(really); } /* establish owership for a resource */ VOID res_own(VOID *res_1, VOID *owner) { RES *res = (RES*)res_1; // LOCK; // DbgPrint("res_own: enter, res: 0x%lx, owner: 0x%lx, owner ref: %d\n", res, res->owner, res->own_ref); // DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql()); /* if not owned, get it */ if ( !res->own_ref ) { NdisAcquireSpinLock(&res->lock); res->own_ref++; res->owner = owner; goto bye; } /* check if already owned by self */ if ( res->owner == owner ) goto bye; /* else we have to wait for it */ // UNLOCK; NdisAcquireSpinLock(&res->lock); // LOCK; /* no I have it, fill */ res->own_ref++; res->owner = owner; bye: // UNLOCK; // DbgPrint("res_own: exit, res: 0x%lx, owner: 0x%lx, owner ref: %d\n", res, res->owner, res->own_ref); // DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql()); return; } /* release ownership of a resource, it is assumed that owner is releasing */ VOID res_unown(VOID *res_1, VOID *owner) { RES *res = (RES*)res_1; // LOCK; // DbgPrint("res_unown: entry, res: 0x%lx, owner: 0x%lx owner ref: %d\n", res, owner, res->own_ref); // DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql()); if (!res->own_ref) { /* if free, onwership released */ // UNLOCK; return; } /* decrement ownership count, if not down to zero - still owned */ res->own_ref--; if ( res->own_ref ) { // UNLOCK; return; } res->owner = NULL; NdisReleaseSpinLock(&res->lock); /* if free, onwership released */ // UNLOCK; // DbgPrint("res_unown: exit, res: 0x%lx, owner ref: %d\n", res, res->own_ref); // DbgPrint (": IRQL: 0x%x\n",KeGetCurrentIrql()); } /* get private data for a resource */ VOID res_get_data(VOID *res_1, ULONG *data) { RES *res = (RES*)res_1; *data = res->data; } /* set private data for a resource */ VOID res_set_data(VOID *res_1, ULONG data) { RES *res = (RES*)res_1; res->data = data; } INT GetResourceSem (VOID *Resource) { RES *res = (RES*)Resource; if ( !sema_get(&res->proc_sema) ) return(RES_BUSY); else return(RES_FREE); } VOID FreeResourceSem (VOID *Resource) { RES *res = (RES*)Resource; sema_free(&res->proc_sema); }