From: bernie Date: Tue, 19 Sep 2006 19:56:16 +0000 (+0000) Subject: Add resource. X-Git-Tag: 1.0.0~542 X-Git-Url: https://codewiz.org/gitweb?a=commitdiff_plain;ds=sidebyside;h=564dbedb34c9f1422f59385071496af51ddc5910;p=bertos.git Add resource. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@699 38d2e660-2303-0410-9eaa-f027e97ec537 --- diff --git a/mware/resource.c b/mware/resource.c new file mode 100755 index 00000000..c723bd64 --- /dev/null +++ b/mware/resource.c @@ -0,0 +1,113 @@ + +#include "resource.h" +#include + +/** + * 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); +} + diff --git a/mware/resource.h b/mware/resource.h new file mode 100755 index 00000000..f30b232f --- /dev/null +++ b/mware/resource.h @@ -0,0 +1,75 @@ +#ifndef MWARE_RESOURCE_H +#define MWARE_RESOURCE_H + +#include // time_t +#include + +/* + * Abstract locking primitives used by host OS. + */ +#if CONFIG_KERNEL + + typedef Semaphore ResourceLock; + #define ResMan_sleep() timer_delay(1) + #define ResMan_time_t mtime_t + +#else /* FreeRTOS */ + + #include + #include + #include // vTaskDelay() + + #define ResMan_sleep() vTaskDelay((portTickType)1 * portTICK_RATE_MS) + #define ResMan_time_t portTickType +#endif + + +// Forward decl +struct Observer; + +/** + * Hold context information for a resource such as an audio channel. + * + * Each driver registers one or more Resource instances with the + * ResMan using ResMan_Register(). + * + * Clients can then allocate the resource through ResMan_Alloc() + * providing a desired priority and an Observer for asynchronous + * notification. + * + * Allocated resources can be stolen by other clients asking for a + * higher priority. ResMan notifies a preemption request by invoking + * the Observer of the current owner. + * + * The Observer callback must take whatever action is needed to + * release the resource as soon as possible to avoid blocking the + * new owner. + */ +typedef struct Resource +{ +//Private + /// Control access to fields below. + Semaphore lock; + + /// Pointer to current owner's observer. NULL if resource is free. + struct Observer *owner; + + /// Priority of current owner (higher values mean higher priority). + int pri; + + /// Queue of processes waiting to obtain the resource. + List queue; +} Resource; + +/// Event sent by ResMan to owners when to request resource release. +enum { EVENT_RELEASE = 1 }; + +/// Try to allocate a resource \a res with priority \a pri for at most \a timeout ticks. +bool ResMan_Alloc(Resource *res, int pri, ResMan_time_t timeout, struct Observer *releaseRequest); + +/// Free resource \a res. Will eventually wake-up other queued owners. +void ResMan_Free(Resource *res); + +void ResMan_Init(Resource *res); + +#endif /* MWARE_RESOURCE_H */