1 /*
2 * Copyright (c) 2008 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include <lk/debug.h>
9 #include <stddef.h>
10 #include <lk/list.h>
11 #include <malloc.h>
12 #include <lk/err.h>
13 #include <lib/dpc.h>
14 #include <kernel/thread.h>
15 #include <kernel/event.h>
16 #include <lk/init.h>
17
18 struct dpc {
19 struct list_node node;
20
21 dpc_callback cb;
22 void *arg;
23 };
24
25 static struct list_node dpc_list = LIST_INITIAL_VALUE(dpc_list);
26 static event_t dpc_event;
27
28 static int dpc_thread_routine(void *arg);
29
dpc_queue(dpc_callback cb,void * arg,uint flags)30 status_t dpc_queue(dpc_callback cb, void *arg, uint flags) {
31 struct dpc *dpc;
32
33 dpc = malloc(sizeof(struct dpc));
34
35 if (dpc == NULL)
36 return ERR_NO_MEMORY;
37
38 dpc->cb = cb;
39 dpc->arg = arg;
40 enter_critical_section();
41 list_add_tail(&dpc_list, &dpc->node);
42 event_signal(&dpc_event, (flags & DPC_FLAG_NORESCHED) ? false : true);
43 exit_critical_section();
44
45 return NO_ERROR;
46 }
47
dpc_thread_routine(void * arg)48 static int dpc_thread_routine(void *arg) {
49 for (;;) {
50 event_wait(&dpc_event);
51
52 enter_critical_section();
53 struct dpc *dpc = list_remove_head_type(&dpc_list, struct dpc, node);
54 if (!dpc)
55 event_unsignal(&dpc_event);
56 exit_critical_section();
57
58 if (dpc) {
59 // dprintf("dpc calling %p, arg %p\n", dpc->cb, dpc->arg);
60 dpc->cb(dpc->arg);
61
62 free(dpc);
63 }
64 }
65
66 return 0;
67 }
68
dpc_init(uint level)69 static void dpc_init(uint level) {
70 event_init(&dpc_event, false, 0);
71
72 thread_detach_and_resume(thread_create("dpc", &dpc_thread_routine, NULL, DPC_PRIORITY, DEFAULT_STACK_SIZE));
73 }
74
75 LK_INIT_HOOK(libdpc, &dpc_init, LK_INIT_LEVEL_THREADING);
76
77
78