[pisa-src] r1102 - trunk/libpisa

  • From: Thomas Jansen <mithi@xxxxxxxxx>
  • To: pisa-src@xxxxxxxxxxxxx
  • Date: Tue, 13 Oct 2009 13:01:37 +0200

Author: tjansen
Date: Tue Oct 13 13:01:37 2009
New Revision: 1102

Log:
First draft of the scheduler. Do not add tasks yet, it's not tested.

Modified:
   trunk/libpisa/scheduler.c

Modified: trunk/libpisa/scheduler.c
==============================================================================
--- trunk/libpisa/scheduler.c   Tue Oct 13 13:00:13 2009        (r1101)
+++ trunk/libpisa/scheduler.c   Tue Oct 13 13:01:37 2009        (r1102)
@@ -11,6 +11,7 @@
  */
 
 #include <pthread.h>
+#include <sys/time.h>
 
 #include "scheduler.h"
 
@@ -26,21 +27,63 @@
 static pthread_t thread;
 
 /**
+ * Mutex for locking the task list
+ */
+static pthread_mutex_t mutex_list;
+
+/**
  * Head of the task list.
  */
 static pisa_sched_task *head = NULL;
 
 /**
+ * Pipe indicates that the scheduler should wake up before the first task
+ */
+static int pipefd[2];
+
+static int pisa_time_before(struct timeval *t1, struct timeval *t2)
+{
+       if (t1->tv_sec == t2->tv_sec)
+               return t1->tv_usec < t2->tv_usec;
+       return t1->tv_sec < t2->tv_sec;
+}
+
+/**
  * Main function of the scheduler thread
  */
 static void *pisa_sched_main(void *arg)
 {
-       /* TODO: sleep until first element is due. */
+       fd_set fds;
+       struct timeval timeout, now;
+
+       timerclear(&timeout);
+
        while (1) {
-               if (head == NULL)
-                       sleep(1);
-               else
-                       sleep(2);
+               FD_ZERO(&fds);
+               FD_SET(pipefd[0], &fds);
+
+               select(pipefd[0] + 1, &fds, NULL, NULL, &timeout);
+               if (FD_ISSET(pipefd[0], &fds)) {
+                       /* Someone woke us up to reschedule, read the bytes */
+                       char c;
+                       read(pipefd[0], &c, 1);
+               }
+
+               pthread_mutex_lock(&mutex_list);
+               gettimeofday(&now, NULL);
+               if (pisa_time_before(&head->due, &now)) {
+                       /* (at least) the first action is due now, raise the
+                        * flag. As we have to reschedule afterwards, sleep
+                        * for a _long_ time. We don't care about tv_usec. */
+                       *flag = 1;
+                       timeout.tv_sec = 1000000;
+               } else {
+                       /* No action is due now, sleep until the head is due
+                        * (or we are woken up for rescheduling). */
+                       *flag = 0;
+                       timersub(&head->due, &now, &timeout);
+               }
+               pthread_mutex_unlock(&mutex_list);
        }
 
        return NULL;
@@ -58,6 +101,14 @@
 
        flag = shared;
 
+       result = pipe(pipefd);
+       if (result != 0)
+               PISA_ERROR("Could not create pipe for scheduler.\n");
+
+       result = pthread_mutex_init(&mutex_list, NULL);
+       if (result != 0)
+               PISA_ERROR("Could not create mutex for scheduler.\n");
+
        result = pthread_create(&thread, NULL, pisa_sched_main, NULL);
        if (result != 0)
                PISA_ERROR("Could not create maintenance thread.\n");
@@ -71,19 +122,62 @@
 {
        pthread_cancel(thread);
 
-       /* TODO: free the task list */
+       close(pipefd[0]);
+       close(pipefd[1]);
+
+       pthread_mutex_destroy(&mutex_list);
+
+       while (head)
+               pisa_sched_remove(head);
 
        *flag = 0;
 }
 
 /**
+ * Remove a task from the list. This function assumes that the mutex is
+ * locked.
+ *
+ * @param task task to be removed from the schedule
+ */
+static void pisa_sched_remove_internal(pisa_sched_task *task)
+{
+       pisa_sched_task *cur = head;
+
+       if (task == head) {
+               head = head->next;
+       } else {
+               while (task != cur->next) {
+                       cur = cur->next;
+                       if (cur == NULL)
+                               return;
+               }
+               cur->next = cur->next->next;
+       }
+
+       free(task);
+}
+
+/**
  * Run scheduled actions. Called by the main thread eventually if we set the
  * shared variable to a value != 0. Handle all actions that are due and reset
  * the shared variable.
  */
 void pisa_sched_run(void)
 {
+       struct timeval now;
+
+       pthread_mutex_lock(&mutex_list);
+
+       gettimeofday(&now, NULL);
+       while (head && pisa_time_before(&head->due, &now)) {
+               head->func(head->data);
+               pisa_sched_remove_internal(head);
+       }
+
        *flag = 0;
+       write(pipefd[1], "0", 1);
+
+       pthread_mutex_unlock(&mutex_list);
 }
 
 /**
@@ -95,8 +189,32 @@
  */
 pisa_sched_task *pisa_sched_add(pisa_sched_func func, struct timeval delay, 
void *data)
 {
-       /* TODO: malloc new task, fill it, add it to the list (ordered) */
-       return NULL;
+       pisa_sched_task *cur = head, *task = malloc(sizeof(pisa_sched_task));
+       struct timeval now;
+
+       pthread_mutex_lock(&mutex_list);
+
+       gettimeofday(&now, NULL);
+
+       task->func = func;
+       task->data = data;
+       timeradd(&now, &delay, &task->due);
+
+       if (head == NULL || pisa_time_before(&task->due, &head->due)) {
+               task->next = head;
+               head = task;
+       } else {
+               while (cur->next && pisa_time_before(&cur->next->due, 
&task->due))
+                       cur = cur->next;
+               task->next = cur->next;
+               cur->next = task;
+       
+       }
+       write(pipefd[1], "0", 1);
+
+       pthread_mutex_unlock(&mutex_list);
+
+       return task;
 }
 
 /**
@@ -106,5 +224,10 @@
  */
 void pisa_sched_remove(pisa_sched_task *task)
 {
-       /* TODO: remove from list, free */
+       pthread_mutex_unlock(&mutex_list);
+
+       pisa_sched_remove_internal(task);
+       write(pipefd[1], "0", 1);
+
+       pthread_mutex_unlock(&mutex_list);
 }

Other related posts: