2 * Copyright 2007-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Philippe Houdoin, philippe.houdoin@free.fr
10 //! Deferred Procedure Call support kernel module
13 #include <KernelExport.h>
21 // Private DPC queue structures
37 // size * slots follow
40 #define DPC_QUEUE_SIZE 64
45 dpc_queue
*queue
= arg
;
48 // Let's wait forever/until semaphore death for new DPC slot to show up
49 while (acquire_sem(queue
->wakeup_sem
) == B_OK
) {
52 // grab the next dpc slot
53 former
= disable_interrupts();
54 acquire_spinlock(&queue
->lock
);
56 dpc
= queue
->slots
[queue
->head
];
57 queue
->head
= (queue
->head
+ 1) % queue
->size
;
60 release_spinlock(&queue
->lock
);
61 restore_interrupts(former
);
63 dpc
.function(dpc
.arg
);
66 // Let's finish the pending DPCs, if any.
67 // Otherwise, resource could leak...
68 while (queue
->count
--) {
69 dpc
= queue
->slots
[queue
->head
];
70 queue
->head
= (queue
->head
+ 1) % queue
->size
;
71 dpc
.function(dpc
.arg
);
74 // Now, let's die quietly, ignored by all... sigh.
79 // #pragma mark - public API
83 new_dpc_queue(void **handle
, const char *name
, int32 priority
)
91 queue
= malloc(sizeof(dpc_queue
) + DPC_QUEUE_SIZE
* sizeof(dpc_slot
));
95 queue
->head
= queue
->tail
= 0;
96 queue
->size
= DPC_QUEUE_SIZE
;
98 B_INITIALIZE_SPINLOCK(&queue
->lock
); // Init the spinlock
100 snprintf(str
, sizeof(str
), "%.*s_wakeup_sem",
101 (int) sizeof(str
) - 11, name
);
103 queue
->wakeup_sem
= create_sem(0, str
);
104 if (queue
->wakeup_sem
< B_OK
) {
105 status_t status
= queue
->wakeup_sem
;
110 // Fire a kernel thread to actually handle (aka call them!)
111 // the queued/deferred procedure calls
112 queue
->thread
= spawn_kernel_thread(dpc_thread
, name
, priority
, queue
);
113 if (queue
->thread
< 0) {
114 status_t status
= queue
->thread
;
115 delete_sem(queue
->wakeup_sem
);
119 resume_thread(queue
->thread
);
128 delete_dpc_queue(void *handle
)
130 dpc_queue
*queue
= handle
;
138 // Close the queue: queue_dpc() should know we're closing:
139 former
= disable_interrupts();
140 acquire_spinlock(&queue
->lock
);
142 thread
= queue
->thread
;
145 release_spinlock(&queue
->lock
);
146 restore_interrupts(former
);
148 // Wakeup the thread by murdering its favorite semaphore
149 delete_sem(queue
->wakeup_sem
);
150 wait_for_thread(thread
, &exit_value
);
159 queue_dpc(void *handle
, dpc_func function
, void *arg
)
161 dpc_queue
*queue
= handle
;
163 status_t status
= B_OK
;
165 if (!queue
|| !function
)
168 // Try to be safe being called from interrupt handlers:
169 former
= disable_interrupts();
170 acquire_spinlock(&queue
->lock
);
172 if (queue
->thread
< 0) {
173 // Queue thread is dying...
175 } else if (queue
->count
== queue
->size
)
176 // This DPC queue is full, sorry
177 status
= B_NO_MEMORY
;
179 queue
->slots
[queue
->tail
].function
= function
;
180 queue
->slots
[queue
->tail
].arg
= arg
;
181 queue
->tail
= (queue
->tail
+ 1) % queue
->size
;
185 release_spinlock(&queue
->lock
);
186 restore_interrupts(former
);
189 // Wake up the corresponding dpc thread
190 // Notice that interrupt handlers should return B_INVOKE_SCHEDULER to
191 // shorten DPC latency as much as possible...
192 status
= release_sem_etc(queue
->wakeup_sem
, 1, B_DO_NOT_RESCHEDULE
);
199 std_ops(int32 op
, ...)
204 case B_MODULE_UNINIT
:
213 static dpc_module_info sDPCModule
= {
226 module_info
*modules
[] = {
227 (module_info
*) &sDPCModule
,