|
@@ -0,0 +1,148 @@
|
|
|
|
|
+#include <stddef.h>
|
|
|
|
|
+#include <stdint.h>
|
|
|
|
|
+
|
|
|
|
|
+#include "task.h"
|
|
|
|
|
+#include "kernel.h"
|
|
|
|
|
+#include "scheduler.h"
|
|
|
|
|
+#include "zv_time.h"
|
|
|
|
|
+
|
|
|
|
|
+static bool __zv_scheduler_event_ready(
|
|
|
|
|
+ zv_kernel_t *,
|
|
|
|
|
+ zv_task_t *target
|
|
|
|
|
+) {
|
|
|
|
|
+ zv_event_t *event = &target->event;
|
|
|
|
|
+
|
|
|
|
|
+ if (event->type == ZV_EVENT_OBJECT || event->type == ZV_EVENT_DATA) {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (event->type == ZV_EVENT_TIMER) {
|
|
|
|
|
+ zv_time_t current_time = zv_platform_get_time();
|
|
|
|
|
+
|
|
|
|
|
+ if (event->content.time <= current_time) {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return false;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void __zv_scheduler_update_single_task(
|
|
|
|
|
+ zv_kernel_t *self,
|
|
|
|
|
+ zv_task_t *target
|
|
|
|
|
+) {
|
|
|
|
|
+ if (__zv_scheduler_event_ready(self, target)) {
|
|
|
|
|
+ target->state = ZV_TASK_READY;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (target->state == ZV_TASK_READY) {
|
|
|
|
|
+ ++target->age;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void __zv_scheduler_update_tasks(zv_kernel_t *self) {
|
|
|
|
|
+ for (zv_tid_t count = 0; count < self->tasks_count; ++count) {
|
|
|
|
|
+ __zv_scheduler_update_single_task(self, self->tasks + count);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static zv_task_t * __zv_scheduler_basic(zv_kernel_t *self) {
|
|
|
|
|
+ for (zv_tid_t count = 0; count < self->tasks_count; ++count) {
|
|
|
|
|
+ zv_task_t *current = self->tasks + count;
|
|
|
|
|
+
|
|
|
|
|
+ if (current->state == ZV_TASK_READY) {
|
|
|
|
|
+ return current;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static zv_task_t * __zv_scheduler_priority_strict(zv_kernel_t *self) {
|
|
|
|
|
+ zv_task_t *found = NULL;
|
|
|
|
|
+
|
|
|
|
|
+ for (zv_tid_t count = 0; count < self->tasks_count; ++count) {
|
|
|
|
|
+ zv_task_t *current = self->tasks + count;
|
|
|
|
|
+
|
|
|
|
|
+ if (current->state != ZV_TASK_READY) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (found == NULL) {
|
|
|
|
|
+ found = current;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (found->priority < current->priority) {
|
|
|
|
|
+ found = current;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return found;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static zv_task_t * __zv_scheduler_priority_aging(zv_kernel_t *self) {
|
|
|
|
|
+ zv_task_t *found = NULL;
|
|
|
|
|
+ zv_priority_t found_priority;
|
|
|
|
|
+
|
|
|
|
|
+ for (zv_tid_t count = 0; count < self->tasks_count; ++count) {
|
|
|
|
|
+ zv_task_t *current = self->tasks + count;
|
|
|
|
|
+
|
|
|
|
|
+ if (current->state != ZV_TASK_READY) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (found == NULL) {
|
|
|
|
|
+ found = current;
|
|
|
|
|
+ found_priority = found->priority + found->age;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (found_priority < (current->priority + current->age)) {
|
|
|
|
|
+ found = current;
|
|
|
|
|
+ found_priority = found->priority + found->age;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return found;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+zv_task_t * __zv_scheduler_find_task(zv_kernel_t *self) {
|
|
|
|
|
+ switch (self->scheduler) {
|
|
|
|
|
+ case ZV_SCHEDULER_BASIC:
|
|
|
|
|
+ return __zv_scheduler_basic(self);
|
|
|
|
|
+
|
|
|
|
|
+ case ZV_SCHEDULER_PRIORITY_STRICT:
|
|
|
|
|
+ return __zv_scheduler_priority_strict(self);
|
|
|
|
|
+
|
|
|
|
|
+ case ZV_SCHEDULER_PRIORITY_AGING:
|
|
|
|
|
+ return __zv_scheduler_priority_aging(self);
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void __zv_scheduler_run_task(zv_kernel_t *self, zv_task_t *target) {
|
|
|
|
|
+ target->state = ZV_TASK_RUNNING;
|
|
|
|
|
+ zv_event_t event_copy = target->event;
|
|
|
|
|
+
|
|
|
|
|
+ target->event.type = ZV_EVENT_EMPTY;
|
|
|
|
|
+ target->event.content.unumber = 0;
|
|
|
|
|
+
|
|
|
|
|
+ zv_state_t result = target->worker(
|
|
|
|
|
+ self,
|
|
|
|
|
+ &event_copy,
|
|
|
|
|
+ __zv_kernel_get_tid(self, target),
|
|
|
|
|
+ target->param
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if (result == ZV_TASK_READY || result == ZV_TASK_RUNNING) {
|
|
|
|
|
+ result = ZV_TASK_READY;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ target->state = result;
|
|
|
|
|
+ target->age = 0x00;
|
|
|
|
|
+}
|