|  | /* Copyright (c) 2015 Google Inc | 
|  | * Barret Rhoden <brho@cs.berkeley.edu> | 
|  | * See LICENSE for details. | 
|  | * | 
|  | * 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. */ | 
|  |  | 
|  | #include <taskqueue.h> | 
|  | #include <trap.h> | 
|  | #include <kthread.h> | 
|  |  | 
|  | /* BSD Taskqueue wrappers. */ | 
|  | int taskqueue_enqueue(struct taskqueue *queue, struct task *task) | 
|  | { | 
|  | run_as_rkm(task->ta_func, task->ta_context, 0); | 
|  | 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); | 
|  | } | 
|  |  | 
|  | /* Linux callers use jiffies as the unit of delay.  We pretend to be a 1000 HZ | 
|  | * machine with 1 msec jiffies. */ | 
|  | 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 * 1000); | 
|  | 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; | 
|  | } |