Add resource.
authorbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Tue, 19 Sep 2006 19:56:16 +0000 (19:56 +0000)
committerbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Tue, 19 Sep 2006 19:56:16 +0000 (19:56 +0000)
git-svn-id: https://src.develer.com/svnoss/bertos/trunk@699 38d2e660-2303-0410-9eaa-f027e97ec537

mware/resource.c [new file with mode: 0755]
mware/resource.h [new file with mode: 0755]

diff --git a/mware/resource.c b/mware/resource.c
new file mode 100755 (executable)
index 0000000..c723bd6
--- /dev/null
@@ -0,0 +1,113 @@
+
+#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);
+}
+
diff --git a/mware/resource.h b/mware/resource.h
new file mode 100755 (executable)
index 0000000..f30b232
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef MWARE_RESOURCE_H
+#define MWARE_RESOURCE_H
+
+#include <drv/timer.h> // time_t
+#include <kern/sem.h>
+
+/*
+ * 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 <freertos.h>
+       #include <semphr.h>
+       #include <task.h> // 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 */