Linux workqueue wrappers
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 5 Feb 2015 15:35:38 +0000 (10:35 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sun, 1 Mar 2015 14:36:01 +0000 (09:36 -0500)
Dropped them in with the BSD taskqueues.

kern/include/taskqueue.h
kern/src/taskqueue.c

index a9b853a..60ed694 100644 (file)
@@ -4,7 +4,18 @@
  *
  * Hacked BSD taskqueues.  In lieu of actually running a kproc or something that
  * sleeps on a queue of tasks, we'll just blast out a kmsg.  We can always
  *
  * Hacked BSD taskqueues.  In lieu of actually running a kproc or something that
  * sleeps on a queue of tasks, we'll just blast out a kmsg.  We can always
- * change the implementation if we need more control. */
+ * change the implementation if we need more control.
+ * 
+ * 
+ * Linux workqueue wrappers:
+ *
+ * Caveats:
+ * - Workqueues have no core affinity or anything.  queued work goes to the
+ * calling core.  Scheduled work goes to core 0.
+ * - There are no extra delays in time.  All work are RKMs.
+ * - You can't cancel a message.  The differences btw work and delayed_work
+ * aren't entirely clear.
+ */
 
 #ifndef ROS_KERN_TASKQUEUE_H
 #define ROS_KERN_TASKQUEUE_H
 
 #ifndef ROS_KERN_TASKQUEUE_H
 #define ROS_KERN_TASKQUEUE_H
@@ -29,4 +40,37 @@ int taskqueue_enqueue(struct taskqueue *queue, struct task *task);
        (str)->ta_func = func;                                                     \
        (str)->ta_context = (void*)arg;
 
        (str)->ta_func = func;                                                     \
        (str)->ta_context = (void*)arg;
 
+struct workqueue_struct {
+};
+
+struct work_struct {
+       void (*func)(struct work_struct *);
+       /* TODO: args and bookkeeping to support cancel{,_sync}. */
+       void *arg;
+};
+
+/* Delayed work is embedded in other structs.  Handlers will expect to get a
+ * work_struct pointer. */
+struct delayed_work {
+       struct work_struct                      work;
+       /* TODO: support for the actual alarm / timer */
+};
+
+#define INIT_DELAYED_WORK(dwp, funcp) (dwp)->work.func = (funcp)
+#define INIT_WORK(wp, funcp) (wp)->func = (funcp)
+void flush_workqueue(struct workqueue_struct *wq);
+void destroy_workqueue(struct workqueue_struct *wq);
+struct workqueue_struct *create_singlethread_workqueue(char *name);
+
+bool queue_work(struct workqueue_struct *wq, struct work_struct *dwork);
+bool schedule_work(struct work_struct *dwork);
+bool cancel_work(struct work_struct *dwork);
+bool cancel_work_sync(struct work_struct *dwork);
+
+bool queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork,
+                        unsigned long delay);
+bool schedule_delayed_work(struct delayed_work *dwork, unsigned long delay);
+bool cancel_delayed_work(struct delayed_work *dwork);
+bool cancel_delayed_work_sync(struct delayed_work *dwork);
+
 #endif /* ROS_KERN_TASKQUEUE_H */
 #endif /* ROS_KERN_TASKQUEUE_H */
index 27606ee..4e868aa 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <taskqueue.h>
 #include <trap.h>
 
 #include <taskqueue.h>
 #include <trap.h>
+#include <kthread.h>
 
 /* BSD Taskqueue wrappers. */
 static void __tq_wrapper(uint32_t srcid, long a0, long a1, long a2)
 
 /* BSD Taskqueue wrappers. */
 static void __tq_wrapper(uint32_t srcid, long a0, long a1, long a2)
@@ -23,3 +24,90 @@ int taskqueue_enqueue(struct taskqueue *queue, struct task *task)
                            (long)task->ta_context, 0, KMSG_ROUTINE);
        return 0;
 }
                            (long)task->ta_context, 0, KMSG_ROUTINE);
        return 0;
 }
+
+
+/* Linux workqueue wrappers */
+void flush_workqueue(struct workqueue_struct *wq)
+{
+}
+
+void destroy_workqueue(struct workqueue_struct *wq)
+{
+}
+
+struct workqueue_struct *create_singlethread_workqueue(char *name)
+{
+       /* Non-canonical addr on AMD64.  No one should be derefing this. */
+       return (void*)0xf0f0f0f0f0f0f0f0;
+}
+
+static void __wq_wrapper(uint32_t srcid, long a0, long a1, long a2)
+{
+       struct work_struct *work = (struct work_struct*)a0;
+       work->func(work);
+}
+
+static void __wq_wrapper_delay(uint32_t srcid, long a0, long a1, long a2)
+{
+       struct work_struct *work = (struct work_struct*)a0;
+       unsigned long delay = (unsigned long)a1;
+       kthread_usleep(delay * 10000);
+       work->func(work);
+}
+
+static void send_work(int coreid, struct work_struct *work)
+{
+       send_kernel_message(coreid, __wq_wrapper, (long)work, 0, 0, KMSG_ROUTINE);
+}
+
+static void send_work_delay(int coreid, struct delayed_work *work,
+                            unsigned long delay)
+{
+       send_kernel_message(coreid, __wq_wrapper_delay, (long)work, (long)delay, 0,
+                           KMSG_ROUTINE);
+}
+
+bool queue_work(struct workqueue_struct *wq, struct work_struct *work)
+{
+       send_work(core_id(), work);
+       return TRUE;
+}
+
+bool schedule_work(struct work_struct *work)
+{
+       send_work(0, work);
+       return TRUE;
+}
+
+bool cancel_work(struct work_struct *dwork)
+{
+       return FALSE;
+}
+
+bool cancel_work_sync(struct work_struct *dwork)
+{
+       return FALSE;
+}
+
+bool queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork,
+                        unsigned long delay)
+{
+       send_work_delay(core_id(), dwork, delay);
+       return TRUE;
+}
+
+bool schedule_delayed_work(struct delayed_work *dwork, unsigned long delay)
+{
+       send_work_delay(0, dwork, delay);
+       return TRUE;
+}
+
+bool cancel_delayed_work(struct delayed_work *dwork)
+{
+       return FALSE;
+}
+
+bool cancel_delayed_work_sync(struct delayed_work *dwork)
+{
+       return FALSE;
+}