114 lines
2.0 KiB
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);
|
|
}
|
|
|