OpenModem/bertos/mware/resource.c

114 lines
2.0 KiB
C

#include "resource.h"
#include <mware/observer.h>
/**
* Internal structure for building a priority queue
* of processes waiting for the resource to become free.
*/
typedef struct ResourceWaiter
{
PriNode link;
struct Observer *owner;
} ResourceWaiter;
bool ResMan_Alloc(Resource *res, int pri, ResMan_time_t timeout, struct Observer *releaseRequest)
{
bool success = false;
ASSERT(releaseRequest);
sem_obtain(&res->lock);
if (res->owner == releaseRequest)
{
// Already ours
res->pri = pri;
success = true;
}
else if (!res->owner)
{
// Trivial acquire: nobody was owning the resource
res->pri = pri;
res->owner = releaseRequest;
success = true;
}
else
{
ResourceWaiter waiter;
// Setup waiter structure and enqueue it to resource
waiter.owner = releaseRequest;
waiter.link.pri = pri;
LIST_ENQUEUE(&res->queue, &waiter.link);
// Resource busy: are we eligible for preemption?
if ((res->pri < pri) && res->owner->event)
res->owner->event(EVENT_RELEASE, res);
// Wait in the queue until the timeout occurs.
do
{
sem_release(&res->lock);
// TODO: use a semaphore here instead
ResMan_sleep();
sem_obtain(&res->lock);
// Check for ownership
if (res->owner == releaseRequest)
{
success = true;
break;
}
}
while (timeout--);
// Remove pending waiter
if (!success)
REMOVE(&waiter.link.link);
}
sem_release(&res->lock);
return success;
}
void ResMan_Free(Resource *res)
{
ResourceWaiter *waiter;
sem_obtain(&res->lock);
ASSERT(res->owner);
//TODO: check for real owner calling free
// Check for new owner candidates.
if ((waiter = (ResourceWaiter *)list_remHead(&res->queue)))
{
// Transfer ownership of the resource
res->owner = waiter->owner;
res->pri = waiter->link.pri;
//ResMan_wakeup(waiter);
}
else
{
// Nobody waiting, free the resource
res->owner = NULL;
res->pri = -1;
}
sem_release(&res->lock);
}
void ResMan_Init(Resource *res)
{
res->owner = NULL;
res->pri = -1;
sem_init(&res->lock);
LIST_INIT(&res->queue);
}