../sos-code-article6.5/sos/kthread.c (2005-01-04 04:13:49.000000000 +0100
) |
|
../sos-code-article6.75/sos/kthread.c (2005-01-04 04:13:53.000000000 +0100
) |
|
|
|
/* Initialize the thread attributes */ | /* Initialize the thread attributes */ |
strzcpy(myself->name, "[kinit]", SOS_KTHR_MAX_NAMELEN); | strzcpy(myself->name, "[kinit]", SOS_KTHR_MAX_NAMELEN); |
myself->state = SOS_KTHR_CREATED; | myself->state = SOS_KTHR_CREATED; |
| myself->priority = SOS_SCHED_PRIO_LOWEST; |
myself->stack_base_addr = init_thread_stack_base_addr; | myself->stack_base_addr = init_thread_stack_base_addr; |
myself->stack_size = init_thread_stack_size; | myself->stack_size = init_thread_stack_size; |
| |
|
|
| |
struct sos_kthread *sos_kthread_create(const char *name, | struct sos_kthread *sos_kthread_create(const char *name, |
sos_kthread_start_routine_t start_func, | sos_kthread_start_routine_t start_func, |
void *start_arg) | void *start_arg, |
| sos_sched_priority_t priority) |
__label__ undo_creation; | __label__ undo_creation; |
struct sos_kthread *new_thread; | struct sos_kthread *new_thread; |
| |
if (! start_func) | if (! start_func) |
return NULL; | return NULL; |
| if (! SOS_SCHED_PRIO_IS_VALID(priority)) |
| return NULL; |
| |
/* Allocate a new kthread structure for the current running thread */ | /* Allocate a new kthread structure for the current running thread */ |
new_thread | new_thread |
|
|
/* Initialize the thread attributes */ | /* Initialize the thread attributes */ |
strzcpy(new_thread->name, ((name)?name:"[NONAME]"), SOS_KTHR_MAX_NAMELEN); | strzcpy(new_thread->name, ((name)?name:"[NONAME]"), SOS_KTHR_MAX_NAMELEN); |
new_thread->state = SOS_KTHR_CREATED; | new_thread->state = SOS_KTHR_CREATED; |
| new_thread->priority = priority; |
| |
/* Allocate the stack for the new thread */ | /* Allocate the stack for the new thread */ |
new_thread->stack_base_addr = sos_kmalloc(SOS_KTHREAD_STACK_SIZE, 0); | new_thread->stack_base_addr = sos_kmalloc(SOS_KTHREAD_STACK_SIZE, 0); |
|
|
} | } |
| |
| |
| sos_sched_priority_t sos_kthread_get_priority(struct sos_kthread *thr) |
| { |
| if (! thr) |
| thr = (struct sos_kthread*)current_kthread; |
| |
| return thr->priority; |
| } |
| |
| |
sos_kthread_state_t sos_kthread_get_state(struct sos_kthread *thr) | sos_kthread_state_t sos_kthread_get_state(struct sos_kthread *thr) |
{ | { |
if (! thr) | if (! thr) |
|
|
} | } |
| |
| |
| /** |
| * Helper function to change the thread's priority in all the |
| * waitqueues associated with the thread. |
| */ |
| static sos_ret_t _change_waitq_priorities(struct sos_kthread *thr, |
| sos_sched_priority_t priority) |
| { |
| struct sos_kwaitq_entry *kwq_entry; |
| int nb_waitqs; |
| |
| list_foreach_forward_named(thr->kwaitq_list, kwq_entry, nb_waitqs, |
| prev_entry_for_kthread, next_entry_for_kthread) |
| { |
| SOS_ASSERT_FATAL(SOS_OK == sos_kwaitq_change_priority(kwq_entry->kwaitq, |
| kwq_entry, |
| priority)); |
| } |
| |
| return SOS_OK; |
| } |
| |
| |
| sos_ret_t sos_kthread_set_priority(struct sos_kthread *thr, |
| sos_sched_priority_t priority) |
| { |
| __label__ exit_set_prio; |
| sos_ui32_t flags; |
| sos_ret_t retval; |
| |
| |
| if (! SOS_SCHED_PRIO_IS_VALID(priority)) |
| return -SOS_EINVAL; |
| |
| if (! thr) |
| thr = (struct sos_kthread*)current_kthread; |
| |
| sos_disable_IRQs(flags); |
| |
| /* Signal kwaitq subsystem that the priority of the thread in all |
| the waitq it is waiting in should be updated */ |
| retval = _change_waitq_priorities(thr, priority); |
| if (SOS_OK != retval) |
| goto exit_set_prio; |
| |
| /* Signal scheduler that the thread, currently in a waiting list, |
| should take into account the change of priority */ |
| if (SOS_KTHR_READY == thr->state) |
| retval = sos_sched_change_priority(thr, priority); |
| |
| /* Update priority */ |
| thr->priority = priority; |
| |
| exit_set_prio: |
| sos_restore_IRQs(flags); |
| return retval; |
| } |
| |
| |
sos_ret_t sos_kthread_yield() | sos_ret_t sos_kthread_yield() |
{ | { |
sos_ui32_t flags; | sos_ui32_t flags; |
| |
../sos-code-article6.5/sos/kthread.h (2005-01-04 04:13:49.000000000 +0100
) |
|
../sos-code-article6.75/sos/kthread.h (2005-01-04 04:13:53.000000000 +0100
) |
|
|
|
char name[SOS_KTHR_MAX_NAMELEN]; | char name[SOS_KTHR_MAX_NAMELEN]; |
| |
sos_kthread_state_t state; | sos_kthread_state_t state; |
| sos_sched_priority_t priority; |
| |
/* The hardware context of the thread */ | /* The hardware context of the thread */ |
struct sos_cpu_kstate *cpu_kstate; | struct sos_cpu_kstate *cpu_kstate; |
|
|
{ | { |
struct | struct |
{ | { |
| struct sos_sched_queue *rdy_queue; |
struct sos_kthread *rdy_prev, *rdy_next; | struct sos_kthread *rdy_prev, *rdy_next; |
} ready; | } ready; |
}; /* Anonymous union (gcc extenion) */ | }; /* Anonymous union (gcc extenion) */ |
|
|
*/ | */ |
struct sos_kthread *sos_kthread_create(const char *name, | struct sos_kthread *sos_kthread_create(const char *name, |
sos_kthread_start_routine_t start_func, | sos_kthread_start_routine_t start_func, |
void *start_arg); | void *start_arg, |
| sos_sched_priority_t priority); |
| |
/** | /** |
|
|
| |
| |
/** | /** |
| * If thr == NULL, set the priority of the current thread. Trivial |
| * function. |
| * |
| * @note NOT protected against interrupts |
| */ |
| sos_sched_priority_t sos_kthread_get_priority(struct sos_kthread *thr); |
| |
| |
| /** |
* If thr == NULL, get the state of the current thread. Trivial | * If thr == NULL, get the state of the current thread. Trivial |
* function. | * function. |
* | * |
|
|
| |
| |
/** | /** |
| * If thr == NULL, set the priority of the current thread |
| * |
| * @note NO context-switch ever occurs in this function ! |
| */ |
| sos_ret_t sos_kthread_set_priority(struct sos_kthread *thr, |
| sos_sched_priority_t priority); |
| |
| |
| /** |
* Yield CPU to another ready thread. | * Yield CPU to another ready thread. |
* | * |
* @note This is a BLOCKING FUNCTION | * @note This is a BLOCKING FUNCTION |
| |
../sos-code-article6.5/sos/kwaitq.c (2005-01-04 04:13:49.000000000 +0100
) |
|
../sos-code-article6.75/sos/kwaitq.c (2005-01-04 04:13:53.000000000 +0100
) |
|
|
|
| |
| |
sos_ret_t sos_kwaitq_init(struct sos_kwaitq *kwq, | sos_ret_t sos_kwaitq_init(struct sos_kwaitq *kwq, |
const char *name) | const char *name, |
| sos_kwaitq_ordering_t ordering) |
memset(kwq, 0x0, sizeof(struct sos_kwaitq)); | memset(kwq, 0x0, sizeof(struct sos_kwaitq)); |
| |
|
|
name = "<unknown>"; | name = "<unknown>"; |
strzcpy(kwq->name, name, SOS_KWQ_DEBUG_MAX_NAMELEN); | strzcpy(kwq->name, name, SOS_KWQ_DEBUG_MAX_NAMELEN); |
#endif | #endif |
| kwq->ordering = ordering; |
list_init_named(kwq->waiting_list, | list_init_named(kwq->waiting_list, |
prev_entry_in_kwaitq, next_entry_in_kwaitq); | prev_entry_in_kwaitq, next_entry_in_kwaitq); |
| |
|
|
| |
| |
/** Internal helper function equivalent to sos_kwaitq_add_entry(), but | /** Internal helper function equivalent to sos_kwaitq_add_entry(), but |
without interrupt protection scheme, and explicit priority | without interrupt protection scheme */ |
ordering */ | inline static sos_ret_t |
inline static sos_ret_t _kwaitq_add_entry(struct sos_kwaitq *kwq, | _kwaitq_add_entry(struct sos_kwaitq *kwq, |
struct sos_kwaitq_entry *kwq_entry) | struct sos_kwaitq_entry *kwq_entry, |
| sos_sched_priority_t prio) |
| struct sos_kwaitq_entry *next_entry = NULL, *entry; |
| int nb_entries; |
| |
/* This entry is already added in the kwaitq ! */ | /* This entry is already added in the kwaitq ! */ |
SOS_ASSERT_FATAL(NULL == kwq_entry->kwaitq); | SOS_ASSERT_FATAL(NULL == kwq_entry->kwaitq); |
| |
|
|
kwq_entry->wakeup_triggered = FALSE; | kwq_entry->wakeup_triggered = FALSE; |
kwq_entry->wakeup_status = SOS_OK; | kwq_entry->wakeup_status = SOS_OK; |
| |
/* Add the thread in the list */ | /* Insert this entry in the kwaitq waiting list */ |
list_add_tail_named(kwq->waiting_list, kwq_entry, | switch (kwq->ordering) |
prev_entry_in_kwaitq, next_entry_in_kwaitq); | { |
| case SOS_KWQ_ORDER_FIFO: |
| /* Insertion in the list in FIFO order */ |
| { |
| /* Add the thread in the list */ |
| list_add_tail_named(kwq->waiting_list, kwq_entry, |
| prev_entry_in_kwaitq, next_entry_in_kwaitq); |
| } |
| break; |
| |
| case SOS_KWQ_ORDER_PRIO: |
| /* Priority-driven insertion in the list */ |
| { |
| /* Look for the place where to insert the thread in the queue (we |
| want to order them in order of increasing priorities) */ |
| list_foreach_forward_named(kwq->waiting_list, entry, nb_entries, |
| prev_entry_in_kwaitq, next_entry_in_kwaitq) |
| { |
| /* Does the thread we want to insert have higher priority than |
| the given thread in the queue ? */ |
| if (SOS_SCHED_PRIO_CMP(prio, |
| sos_kthread_get_priority(entry->kthread)) |
| > 0) |
| { |
| /* Yes: we insert before this given thread */ |
| next_entry = entry; |
| break; |
| } |
| } |
| |
| /* Actually insert the entry in the list */ |
| if (next_entry != NULL) |
| { |
| list_insert_before_named(kwq->waiting_list, kwq_entry, next_entry, |
| prev_entry_in_kwaitq, |
| next_entry_in_kwaitq); |
| } |
| else |
| { |
| /* The thread we want to insert has less priority than any |
| other in the list */ |
| list_add_tail_named(kwq->waiting_list, kwq_entry, |
| prev_entry_in_kwaitq, next_entry_in_kwaitq); |
| } |
| } |
| break; |
| |
| default: |
| SOS_FATAL_ERROR("Invalid kwq ordering %d !\n", kwq->ordering); |
| break; |
| } |
/* Update the list of waitqueues for the thread */ | /* Update the list of waitqueues for the thread */ |
list_add_tail_named(kwq_entry->kthread->kwaitq_list, kwq_entry, | list_add_tail_named(kwq_entry->kthread->kwaitq_list, kwq_entry, |
prev_entry_for_kthread, next_entry_for_kthread); | prev_entry_for_kthread, next_entry_for_kthread); |
| |
kwq_entry->kwaitq = kwq; | kwq_entry->kwaitq = kwq; |
| |
} | } |
| |
|
|
sos_ret_t retval; | sos_ret_t retval; |
| |
sos_disable_IRQs(flags); | sos_disable_IRQs(flags); |
retval = _kwaitq_add_entry(kwq, kwq_entry); | retval = _kwaitq_add_entry(kwq, kwq_entry, |
| sos_kthread_get_priority(kwq_entry->kthread)); |
| |
return retval; | return retval; |
|
|
| |
sos_disable_IRQs(flags); | sos_disable_IRQs(flags); |
| |
retval = _kwaitq_add_entry(kwq, & kwq_entry); | retval = _kwaitq_add_entry(kwq, & kwq_entry, |
| sos_kthread_get_priority(kwq_entry.kthread)); |
/* Wait for wakeup or timeout */ | /* Wait for wakeup or timeout */ |
sos_kthread_sleep(timeout); | sos_kthread_sleep(timeout); |
|
|
sos_disable_IRQs(flags); | sos_disable_IRQs(flags); |
| |
/* Wake up as much threads waiting in waitqueue as possible (up to | /* Wake up as much threads waiting in waitqueue as possible (up to |
nb_kthreads), scanning the list in FIFO order */ | nb_kthreads), scanning the list in FIFO/decreasing priority order |
| (depends on the kwaitq ordering) */ |
prev_entry_in_kwaitq, next_entry_in_kwaitq)) | prev_entry_in_kwaitq, next_entry_in_kwaitq)) |
{ | { |
|
|
| |
return SOS_OK; | return SOS_OK; |
} | } |
| |
| |
| /* Internal function (callback for kthread subsystem) */ |
| sos_ret_t sos_kwaitq_change_priority(struct sos_kwaitq *kwq, |
| struct sos_kwaitq_entry *kwq_entry, |
| sos_sched_priority_t priority) |
| { |
| /* Reorder the waiting list */ |
| _kwaitq_remove_entry(kwq, kwq_entry); |
| _kwaitq_add_entry(kwq, kwq_entry, priority); |
| |
| return SOS_OK; |
| } |
| |
../sos-code-article6.5/sos/kwaitq.h (2005-01-04 04:13:49.000000000 +0100
) |
|
../sos-code-article6.75/sos/kwaitq.h (2005-01-04 04:13:53.000000000 +0100
) |
|
|
|
#include <sos/errno.h> | #include <sos/errno.h> |
#include <sos/kthread.h> | #include <sos/kthread.h> |
#include <sos/time.h> | #include <sos/time.h> |
#include <sos/sched.h> | |
| |
/** | /** |
* @kwaitq.h | * @kwaitq.h |
* | * |
* Low-level functions to manage queues of threads waiting for a | * Low-level functions to manage queues of threads waiting for a |
* resource. These functions are public. For higher-level | * resource. These functions are public, except |
* synchronization primitives such as mutex, semaphores, conditions, | * sos_kwaitq_change_priority() that is a callback for the kthread |
* ... prefer looking at the corresponding libraries. | * subsystem. However, for higher-level synchronization primitives |
| * such as mutex, semaphores, conditions, ... prefer to look at the |
| * corresponding libraries. |
| |
| |
|
|
| |
| |
/** | /** |
* Definition of a waitqueue. In a kwaitq, the threads are ordererd in | * The threads in the kwaitqs can be ordered in FIFO or in decreasing |
* FIFO order. | * priority order. |
| */ |
| typedef enum { SOS_KWQ_ORDER_FIFO, SOS_KWQ_ORDER_PRIO } sos_kwaitq_ordering_t; |
| |
| |
| #include <sos/sched.h> |
| |
| |
| /** |
| * Definition of a waitqueue. In a kwaitq, the threads can be ordererd |
| * either in FIFO order (SOS_KWQ_ORDER_FIFO) or in decreasing priority |
| * order (SOS_KWQ_ORDER_PRIO ; with FIFO ordering for same-prio |
| * threads). |
| * |
| * A more efficient method to store the threads ordered by their |
| * priority would have been to use 1 list for each priority level. But |
| * we have to be careful to the size of a kwaitq structure here: |
| * potentially there are thousands of kwaitq in a running system |
| * (basically: 1 per opened file !). The algorithm we use to order the |
| * threads in the kwaitq in this case is highly under-optimal (naive |
| * linear insertion): as an exercise, one can implement a more |
| * efficient algorithm (think of a heap). |
struct sos_kwaitq | struct sos_kwaitq |
{ | { |
|
|
# define SOS_KWQ_DEBUG_MAX_NAMELEN 32 | # define SOS_KWQ_DEBUG_MAX_NAMELEN 32 |
char name[SOS_KWQ_DEBUG_MAX_NAMELEN]; | char name[SOS_KWQ_DEBUG_MAX_NAMELEN]; |
#endif | #endif |
| sos_kwaitq_ordering_t ordering; |
struct sos_kwaitq_entry *waiting_list; | struct sos_kwaitq_entry *waiting_list; |
}; | }; |
| |
|
|
* copied]) | * copied]) |
*/ | */ |
sos_ret_t sos_kwaitq_init(struct sos_kwaitq *kwq, | sos_ret_t sos_kwaitq_init(struct sos_kwaitq *kwq, |
const char *name); | const char *name, |
| sos_kwaitq_ordering_t ordering); |
| |
/** | /** |
|
|
| |
/** | /** |
* Wake up as much as nb_kthread threads (SOS_KWQ_WAKEUP_ALL to wake | * Wake up as much as nb_kthread threads (SOS_KWQ_WAKEUP_ALL to wake |
* up all threads) in the kwaitq kwq, in FIFO order. | * up all threads) in the kwaitq kwq, in FIFO or decreasing priority |
| * order (depends on the ordering scheme selected at kwaitq |
| * initialization time). |
* @param wakeup_status The value returned by sos_kwaitq_wait() when | * @param wakeup_status The value returned by sos_kwaitq_wait() when |
* the thread will effectively woken up due to this wakeup. | * the thread will effectively woken up due to this wakeup. |
|
|
#define SOS_KWQ_WAKEUP_ALL (~((unsigned int)0)) | #define SOS_KWQ_WAKEUP_ALL (~((unsigned int)0)) |
| |
| |
| /** |
| * @note INTERNAL function (in particular: interrupts not disabled) ! |
| * |
| * @note: The use of this function is RESERVED (to kthread.c). Do not |
| * call it directly: use sos_kthread_set_priority() for that ! |
| */ |
| sos_ret_t sos_kwaitq_change_priority(struct sos_kwaitq *kwq, |
| struct sos_kwaitq_entry *kwq_entry, |
| sos_sched_priority_t priority); |
| |
#endif /* _SOS_KWAITQ_H_ */ | #endif /* _SOS_KWAITQ_H_ */ |
| |
../sos-code-article6.5/sos/main.c (2005-01-04 04:13:49.000000000 +0100
) |
|
../sos-code-article6.75/sos/main.c (2005-01-04 04:13:53.000000000 +0100
) |
|
|
|
sos_disable_IRQs(flags); | sos_disable_IRQs(flags); |
| |
arg_b = (struct thr_arg) { .character='b', .col=0, .row=21, .color=0x14 }; | arg_b = (struct thr_arg) { .character='b', .col=0, .row=21, .color=0x14 }; |
sos_kthread_create("YO[b]", demo_thread, (void*)&arg_b); | sos_kthread_create("YO[b]", demo_thread, (void*)&arg_b, SOS_SCHED_PRIO_TS_LOWEST); |
arg_c = (struct thr_arg) { .character='c', .col=46, .row=21, .color=0x14 }; | arg_c = (struct thr_arg) { .character='c', .col=46, .row=21, .color=0x14 }; |
sos_kthread_create("YO[c]", demo_thread, (void*)&arg_c); | sos_kthread_create("YO[c]", demo_thread, (void*)&arg_c, SOS_SCHED_PRIO_TS_LOWEST); |
arg_d = (struct thr_arg) { .character='d', .col=0, .row=20, .color=0x14 }; | arg_d = (struct thr_arg) { .character='d', .col=0, .row=20, .color=0x14 }; |
sos_kthread_create("YO[d]", demo_thread, (void*)&arg_d); | sos_kthread_create("YO[d]", demo_thread, (void*)&arg_d, SOS_SCHED_PRIO_TS_LOWEST-1); |
arg_e = (struct thr_arg) { .character='e', .col=0, .row=19, .color=0x14 }; | arg_e = (struct thr_arg) { .character='e', .col=0, .row=19, .color=0x14 }; |
sos_kthread_create("YO[e]", demo_thread, (void*)&arg_e); | sos_kthread_create("YO[e]", demo_thread, (void*)&arg_e, SOS_SCHED_PRIO_TS_LOWEST-2); |
arg_R = (struct thr_arg) { .character='R', .col=0, .row=17, .color=0x1c }; | arg_R = (struct thr_arg) { .character='R', .col=0, .row=17, .color=0x1c }; |
sos_kthread_create("YO[R]", demo_thread, (void*)&arg_R); | sos_kthread_create("YO[R]", demo_thread, (void*)&arg_R, SOS_SCHED_PRIO_RT_LOWEST); |
arg_S = (struct thr_arg) { .character='S', .col=0, .row=16, .color=0x1c }; | arg_S = (struct thr_arg) { .character='S', .col=0, .row=16, .color=0x1c }; |
sos_kthread_create("YO[S]", demo_thread, (void*)&arg_S); | sos_kthread_create("YO[S]", demo_thread, (void*)&arg_S, SOS_SCHED_PRIO_RT_LOWEST-1); |
sos_restore_IRQs(flags); | sos_restore_IRQs(flags); |
} | } |
|
|
sos_sched_subsystem_setup(); | sos_sched_subsystem_setup(); |
| |
/* Declare the IDLE thread */ | /* Declare the IDLE thread */ |
SOS_ASSERT_FATAL(sos_kthread_create("idle", idle_kthread, NULL) != NULL); | SOS_ASSERT_FATAL(sos_kthread_create("idle", idle_kthread, NULL, |
| SOS_SCHED_PRIO_TS_LOWEST) != NULL); |
| |
/* Enabling the HW interrupts here, this will make the timer HW | /* Enabling the HW interrupts here, this will make the timer HW |
| |
../sos-code-article6.5/sos/mouse_sim.c (2005-01-04 04:13:49.000000000 +0100
) |
|
../sos-code-article6.75/sos/mouse_sim.c (2005-01-04 04:13:53.000000000 +0100
) |
|
|
|
void MouseSim(void) | void MouseSim(void) |
{ | { |
//Creation du semaphore de protection de la carte | //Creation du semaphore de protection de la carte |
SOS_ASSERT_FATAL(SOS_OK == sos_ksema_init(& SemMap, "SemMap", 1)); | SOS_ASSERT_FATAL(SOS_OK == sos_ksema_init(& SemMap, "SemMap", 1, |
| SOS_KWQ_ORDER_FIFO)); |
//Creation du semaphore de creation de souris | //Creation du semaphore de creation de souris |
SOS_ASSERT_FATAL(SOS_OK == sos_ksema_init(& SemMouse, "SemMouse", 2)); | SOS_ASSERT_FATAL(SOS_OK == sos_ksema_init(& SemMouse, "SemMouse", 2, |
| SOS_KWQ_ORDER_FIFO)); |
//Creation de la carte | //Creation de la carte |
SOS_ASSERT_FATAL(SOS_OK == CreateMap()); | SOS_ASSERT_FATAL(SOS_OK == CreateMap()); |
|
|
//Creation du thread createur de souris | //Creation du thread createur de souris |
SOS_ASSERT_FATAL(sos_kthread_create("MouseCreator", | SOS_ASSERT_FATAL(sos_kthread_create("MouseCreator", |
(sos_kthread_start_routine_t)MouseCreator, | (sos_kthread_start_routine_t)MouseCreator, |
0) != NULL); | 0, SOS_SCHED_PRIO_TS_LOWEST-1) != NULL); |
} | } |
| |
|
|
pElement->Color = SOS_X86_VIDEO_FG_LTRED; | pElement->Color = SOS_X86_VIDEO_FG_LTRED; |
pElement->P = p; | pElement->P = p; |
pElement->Way = 0; | pElement->Way = 0; |
pElement->ThreadID = sos_kthread_create("Mouse", (sos_kthread_start_routine_t)Mouse, pElement); | pElement->ThreadID = sos_kthread_create("Mouse", (sos_kthread_start_routine_t)Mouse, pElement, SOS_SCHED_PRIO_TS_LOWEST-1); |
{ | { |
sos_kfree((sos_vaddr_t)pElement); | sos_kfree((sos_vaddr_t)pElement); |
| |
../sos-code-article6.5/sos/sched.c (2005-01-04 04:13:49.000000000 +0100
) |
|
../sos-code-article6.75/sos/sched.c (2005-01-04 04:13:53.000000000 +0100
) |
|
|
|
| |
/** | /** |
* The definition of the scheduler queue. We could have used a normal | * The definition of the scheduler queue. We could have used a normal |
* kwaitq here, it would have had the same properties. But, in the | * kwaitq here, it would have had the same properties (regarding |
* definitive version (O(1) scheduler), the structure has to be a bit | * priority ordering mainly). But we don't bother with size |
* more complicated. So, in order to keep the changes as small as | * considerations here (in kwaitq, we had better make the kwaitq |
* possible between this version and the definitive one, we don't use | * structure as small as possible because there are a lot of kwaitq in |
* kwaitq here. | * the system: at least 1 per opened file), so that we can implement a |
| * much faster way of handling the prioritized jobs. |
static struct | struct sos_sched_queue |
unsigned int nr_threads; | unsigned int nr_threads; |
struct sos_kthread *kthread_list; | struct sos_kthread *kthread_list[SOS_SCHED_NUM_PRIO]; |
} ready_queue; | }; |
| |
| |
| /** |
| * We manage 2 queues: a queue being scanned for ready threads |
| * (active_queue) and a queue to store the threads the threads having |
| * expired their time quantuum. |
| */ |
| static struct sos_sched_queue *active_queue, *expired_queue; |
| |
| |
| /** |
| * The instances for the active/expired queues |
| */ |
| static struct sos_sched_queue sched_queue[2]; |
| |
sos_ret_t sos_sched_subsystem_setup() | sos_ret_t sos_sched_subsystem_setup() |
{ | { |
memset(& ready_queue, 0x0, sizeof(ready_queue)); | memset(sched_queue, 0x0, sizeof(sched_queue)); |
| active_queue = & sched_queue[0]; |
| expired_queue = & sched_queue[1]; |
return SOS_OK; | return SOS_OK; |
} | } |
|
|
* @param insert_at_tail TRUE to tell to add the thread at the end of | * @param insert_at_tail TRUE to tell to add the thread at the end of |
* the ready list. Otherwise it is added at the head of it. | * the ready list. Otherwise it is added at the head of it. |
*/ | */ |
static sos_ret_t add_in_ready_queue(struct sos_kthread *thr, | static sos_ret_t add_in_ready_queue(struct sos_sched_queue *q, |
| struct sos_kthread *thr, |
{ | { |
| sos_sched_priority_t prio; |
| |
SOS_ASSERT_FATAL( (SOS_KTHR_CREATED == thr->state) | SOS_ASSERT_FATAL( (SOS_KTHR_CREATED == thr->state) |
|| (SOS_KTHR_RUNNING == thr->state) /* Yield */ | || (SOS_KTHR_RUNNING == thr->state) /* Yield */ |
|| (SOS_KTHR_BLOCKED == thr->state) ); | || (SOS_KTHR_BLOCKED == thr->state) ); |
| |
/* Add the thread to the CPU queue */ | /* Add the thread to the CPU queue */ |
| prio = sos_kthread_get_priority(thr); |
if (insert_at_tail) | if (insert_at_tail) |
list_add_tail_named(ready_queue.kthread_list, thr, | list_add_tail_named(q->kthread_list[prio], thr, |
else | else |
list_add_head_named(ready_queue.kthread_list, thr, | list_add_head_named(q->kthread_list[prio], thr, |
ready_queue.nr_threads ++; | thr->ready.rdy_queue = q; |
| q->nr_threads ++; |
/* Ok, thread is now really ready to be (re)started */ | /* Ok, thread is now really ready to be (re)started */ |
thr->state = SOS_KTHR_READY; | thr->state = SOS_KTHR_READY; |
|
|
if (SOS_KTHR_READY == thr->state) | if (SOS_KTHR_READY == thr->state) |
return SOS_OK; | return SOS_OK; |
| |
/* Real-time thread: schedule it for the present turn */ | if (SOS_SCHED_PRIO_IS_RT(sos_kthread_get_priority(thr))) |
retval = add_in_ready_queue(thr, TRUE); | { |
| /* Real-time thread: schedule it for the present turn */ |
| retval = add_in_ready_queue(active_queue, thr, TRUE); |
| } |
| else |
| { |
| /* Non real-time thread: schedule it for next turn */ |
| retval = add_in_ready_queue(expired_queue, thr, TRUE); |
| } |
return retval; | return retval; |
} | } |
| |
| |
| sos_ret_t sos_sched_change_priority(struct sos_kthread *thr, |
| sos_sched_priority_t priority) |
| { |
| struct sos_kthread *kthread_list; |
| SOS_ASSERT_FATAL(SOS_KTHR_READY == thr->state); |
| |
| /* Temp variable */ |
| kthread_list |
| = thr->ready.rdy_queue->kthread_list[sos_kthread_get_priority(thr)]; |
| |
| list_delete_named(kthread_list, thr, ready.rdy_prev, ready.rdy_next); |
| |
| /* Update lists */ |
| kthread_list = thr->ready.rdy_queue->kthread_list[priority]; |
| list_add_tail_named(kthread_list, thr, ready.rdy_prev, ready.rdy_next); |
| thr->ready.rdy_queue->kthread_list[priority] = kthread_list; |
| |
| return SOS_OK; |
| } |
| |
| |
struct sos_kthread * sos_reschedule(struct sos_kthread *current_kthread, | struct sos_kthread * sos_reschedule(struct sos_kthread *current_kthread, |
sos_bool_t do_yield) | sos_bool_t do_yield) |
{ | { |
| sos_sched_priority_t prio; |
| |
if (SOS_KTHR_ZOMBIE == current_kthread->state) | if (SOS_KTHR_ZOMBIE == current_kthread->state) |
{ | { |
|
|
/* Take into account the current executing thread unless it is | /* Take into account the current executing thread unless it is |
marked blocked */ | marked blocked */ |
if (do_yield) | if (do_yield) |
/* Ok, reserve it for next turn */ | { |
add_in_ready_queue(current_kthread, TRUE); | /* Ok, reserve it for next turn */ |
| if (SOS_SCHED_PRIO_IS_RT(sos_kthread_get_priority(current_kthread))) |
| add_in_ready_queue(active_queue, current_kthread, TRUE); |
| else |
| add_in_ready_queue(expired_queue, current_kthread, TRUE); |
| } |
/* Put it at the head of the active list */ | { |
add_in_ready_queue(current_kthread, FALSE); | /* Put it at the head of the active list */ |
| add_in_ready_queue(active_queue, current_kthread, FALSE); |
| } |
| } |
| |
| |
| /* Active queue is empty ? */ |
| if (active_queue->nr_threads <= 0) |
| { |
| /* Yes: Exchange it with the expired queue */ |
| struct sos_sched_queue *q; |
| q = active_queue; |
| active_queue = expired_queue; |
| expired_queue = q; |
| |
/* The next thread is that at the head of the ready list */ | /* Now loop over the priorities in the active queue, looking for a |
if (ready_queue.nr_threads > 0) | non-empty queue */ |
| for (prio = SOS_SCHED_PRIO_HIGHEST ; prio <= SOS_SCHED_PRIO_LOWEST ; prio ++) |
struct sos_kthread *next_thr; | struct sos_kthread *next_thr; |
| |
| if (list_is_empty_named(active_queue->kthread_list[prio], |
| ready.rdy_prev, ready.rdy_next)) |
| continue; |
| |
/* Queue is not empty: take the thread at its head */ | /* Queue is not empty: take the thread at its head */ |
next_thr = list_pop_head_named(ready_queue.kthread_list, | next_thr = list_pop_head_named(active_queue->kthread_list[prio], |
ready_queue.nr_threads --; | active_queue->nr_threads --; |
return next_thr; | return next_thr; |
} | } |
| |
| |
SOS_FATAL_ERROR("No kernel thread ready ?!"); | SOS_FATAL_ERROR("No kernel thread ready ?!"); |
return NULL; | return NULL; |
} | } |
| |
../sos-code-article6.5/sos/sched.h (2005-01-04 04:13:49.000000000 +0100
) |
|
../sos-code-article6.75/sos/sched.h (2005-01-04 04:13:53.000000000 +0100
) |
|
|
|
/** | /** |
* @file sched.h | * @file sched.h |
* | * |
* A basic scheduler with simple FIFO threads' ordering. | * A basic scheduler inspired from the O(1) Linux scheduler. Supports |
| * 2 classes of thread priorities: |
| * - so-called 'real-time' threads scheduled according to a simple |
| * traditional static priority real-time scheduler. "Real-time" round |
| * robin scheduling is not supported. |
| * - "fair" time-sharing scheduling for non real-time threads. "fair" |
| * because no starvation among the non real-time threads is |
| * possible. Contrary to the original O(1) Linux scheduler, the |
| * on-line adjustment of the scheduling priorities to cope with |
| * interactive/non interactive threads discrimination is not |
| * supported: threads keep having the same priority as long as the |
| * user does not change it. |
* The functions below manage CPU queues, and are NEVER responsible | * The functions below manage CPU queues, and are NEVER responsible |
* for context switches (see kthread.h for that) or synchronizations | * for context switches (see kthread.h for that) or synchronizations |
|
|
#include <sos/errno.h> | #include <sos/errno.h> |
| |
| |
| /** |
| * The definition of a priority |
| */ |
| typedef unsigned char sos_sched_priority_t; |
| |
| |
#include <sos/kthread.h> | #include <sos/kthread.h> |
| |
| |
/** | /** |
| * Valid priority interval ("real-time" and non real-time threads altogether) |
| */ |
| #define SOS_SCHED_PRIO_HIGHEST 0 |
| #define SOS_SCHED_PRIO_LOWEST 63 |
| #define SOS_SCHED_NUM_PRIO 64 |
| |
| |
| /** |
| * Class-specific priorities |
| */ |
| #define SOS_SCHED_PRIO_RT_HIGHEST 0 /**< Highest 'real-time' static prio. */ |
| #define SOS_SCHED_PRIO_RT_LOWEST 15 /**< Lowest 'real-time' static priority */ |
| #define SOS_SCHED_PRIO_TS_HIGHEST 16 /**< Highest time-sharing priority */ |
| #define SOS_SCHED_PRIO_TS_LOWEST 63 /**< Lowest time-sharing priority */ |
| |
| #define SOS_SCHED_PRIO_DEFAULT 40 /**< Default priority */ |
| |
| |
| /** |
| * Helper macros (Yes, priorities ordered in decreasing numerical value) |
| * |
| * @note: The use of this function is RESERVED |
| */ |
| #define SOS_SCHED_PRIO_CMP(prio1,prio2) ((prio1) - (prio2)) |
| |
| #define SOS_SCHED_PRIO_IS_VALID(prio) \ |
| ({ int __prio = (int)(prio); \ |
| ((__prio) <= SOS_SCHED_PRIO_LOWEST) \ |
| && \ |
| ((__prio) >= SOS_SCHED_PRIO_HIGHEST); }) |
| |
| #define SOS_SCHED_PRIO_IS_RT(prio) \ |
| ({ int __prio = (int)(prio); \ |
| ((__prio) <= SOS_SCHED_PRIO_RT_LOWEST) \ |
| && \ |
| ((__prio) >= SOS_SCHED_PRIO_RT_HIGHEST); }) |
| |
| |
| /** |
* Initialize the scheduler | * Initialize the scheduler |
* | * |
* @note: The use of this function is RESERVED | * @note: The use of this function is RESERVED |
|
|
struct sos_kthread * sos_reschedule(struct sos_kthread * current_kthread, | struct sos_kthread * sos_reschedule(struct sos_kthread * current_kthread, |
sos_bool_t do_yield); | sos_bool_t do_yield); |
| |
| /** |
| * Called by kthread subsystem each time a READY thread's priority is |
| * changed |
| * |
| * @note: The use of this function is RESERVED (to kthread.c) |
| */ |
| sos_ret_t sos_sched_change_priority(struct sos_kthread * thr, |
| sos_sched_priority_t priority); |
| |
| |
#endif /* _SOS_WAITQUEUE_H_ */ | #endif /* _SOS_WAITQUEUE_H_ */ |
| |