0,0 → 1,224 |
/* |
* Copyright (c) 2007 Jan Hudecek |
* Copyright (c) 2006 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
|
/** @addtogroup genericddi |
* @{ |
*/ |
/** @file |
*/ |
|
#include <arch.h> |
#include <config.h> |
#include <arch/types.h> |
#include <arch/asm.h> |
#include <ddi/tasklet.h> |
#include <synch/spinlock.h> |
#include <time/delay.h> |
#include <proc/thread.h> |
#include <panic.h> |
#include <print.h> |
#include <synch/waitq.h> |
|
/** Timeout length in the tasklet thread */ |
#define TASKLET_THREAD_SLEEPDELAY 500 |
/** Priority of the tasklet thread */ |
#define TASKLET_THREAD_PRIORITY 10 |
|
|
/** Tasklet state enum */ |
typedef enum |
{ |
TASKLET_STATE_NOTACTIVE = 0, |
TASKLET_STATE_SCHEDULED = 1, |
TASKLET_STATE_RUNNING = 2, |
TASKLET_STATE_DISABLED = 4 |
} tasklet_state_enum; |
|
|
|
/** Spinlock protecting list of tasklets */ |
SPINLOCK_INITIALIZE(tasklet_lock); |
|
/** array of tasklet lists for every CPU */ |
tasklet_descriptor_t** tasklet_list; |
|
/** Initializes tasklets - except for the tasklet thread */ |
void tasklet_init(void) |
{ |
int i; |
tasklet_list=malloc(sizeof(tasklet_descriptor_t*)*config.cpu_count,0); |
if (tasklet_list==0) |
panic_printf("tasklet list mem not allocated\n"); |
for(i=0;i<config.cpu_count;i++) |
{ |
tasklet_list[i]=0; |
} |
spinlock_initialize(&tasklet_lock, "tasklet_lock"); |
} |
|
/** |
* Creates and runs the tasklet thread |
* |
* @param kernel_task Pointer to the kernel task - for create_thread |
*/ |
void tasklet_run_tasklet_thread(task_t * kernel_task) |
{ |
thread_t* t= thread_create(&tasklet_thread, NULL, kernel_task, 0, "tasklet_thread", false); |
if (t==NULL) |
{ |
//wtf? |
panic_printf("tasklet thread not created\n"); |
} |
else |
{ |
//dynamical priority should pick the best |
// t->priority = TASKLET_THREAD_PRIORITY; |
thread_ready(t); |
} |
} |
|
/** Thread which keeps executing scheduled enabled tasklets |
* @param data not used |
*/ |
void tasklet_thread(void* data) |
{ |
waitq_t wq; |
waitq_initialize(&wq); |
while (true) |
{ |
tasklet_do(); |
waitq_sleep_timeout(&wq,(uint32_t)TASKLET_THREAD_SLEEPDELAY,0); |
} |
} |
|
/** Initializes tasklet structure |
* @param func tasklet callback function to be called |
* @param data pointer to be passed to the tasklet function |
*/ |
tasklet_descriptor_t* tasklet_register(void (*func)(void* data), void* data) |
{ |
tasklet_descriptor_t* tasklet=malloc(sizeof(tasklet_descriptor_t),0); |
tasklet->data = data; |
tasklet->func = func; |
tasklet->state = TASKLET_STATE_NOTACTIVE; |
tasklet->next = 0; |
return tasklet; |
} |
|
/** Schedules the tasklet for execution on current CPU |
* @param t tasklet to be scheduled |
*/ |
void tasklet_schedule(tasklet_descriptor_t* t) |
{ |
spinlock_lock(&tasklet_lock); |
//clear notactive, running and scheduled flags |
t->state &= TASKLET_STATE_DISABLED; |
//set the scheduled flag |
t->state |= TASKLET_STATE_SCHEDULED; |
t->next=tasklet_list[CPU->id]; |
tasklet_list[CPU->id]=t; |
spinlock_unlock(&tasklet_lock); |
} |
|
/** Tasklet will not be run, even if scheduled |
* @param t tasklet to be disabled |
*/ |
void tasklet_disable(tasklet_descriptor_t* t) |
{ |
spinlock_lock(&tasklet_lock); |
//set the disabled flag |
t->state |= TASKLET_STATE_DISABLED; |
spinlock_unlock(&tasklet_lock); |
} |
|
/** Tasklet will be run if scheduled |
* @param t tasklet to be enabled |
*/ |
void tasklet_enable(tasklet_descriptor_t* t) |
{ |
spinlock_lock(&tasklet_lock); |
//clear the disabled flag |
t->state &= ~TASKLET_STATE_DISABLED; |
spinlock_unlock(&tasklet_lock); |
} |
|
|
|
|
/** Executes scheduled enabled tasklets */ |
void tasklet_do(void) |
{ |
int i; |
spinlock_lock(&tasklet_lock); |
for(i=0;i<config.cpu_count;i++) |
{ |
tasklet_descriptor_t* t = tasklet_list[CPU->id]; |
//empty the queue of tasklets |
tasklet_list[CPU->id]=0; |
while (t) |
{ |
if (!(t->state & TASKLET_STATE_DISABLED)) |
{ |
if (t->func) |
{ |
#ifdef DEBUG |
printf("tasklet - calling tasklet!!!\n"); |
delay((uint32_t)1000000); |
#endif |
t->state = TASKLET_STATE_RUNNING; |
t->func(t->data); |
t->state = TASKLET_STATE_NOTACTIVE; |
} |
else |
panic_printf("tasklet func NULL\n"); |
} |
else |
{ //return it back to the queue of scheduled tasklets |
t->next = tasklet_list[CPU->id]; |
tasklet_list[CPU->id] = t; |
} |
t=t->next; |
} |
//TODO: switch to another CPU, synched with kcpulb, |
} |
spinlock_unlock(&tasklet_lock); |
} |
|
/** Frees the tasklet structure when no longer needed |
* @param tasklet to be freed |
*/ |
void tasklet_free(tasklet_descriptor_t* t) |
{ |
if (t->state == TASKLET_STATE_NOTACTIVE) |
free(t); |
else |
panic_printf("attempting to free an active tasklet"); |
} |
|
|