Add several extra scheduler hook functions to allow the scheduler(s) to maintain private housekeeping data on the thread structs. These hooks are called on thread creation/destruction and when prepping a thread for use. Review welcome.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29721 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -18,7 +18,18 @@ struct scheduler_ops {
|
|||||||
void (*enqueue_in_run_queue)(struct thread* thread);
|
void (*enqueue_in_run_queue)(struct thread* thread);
|
||||||
void (*reschedule)(void);
|
void (*reschedule)(void);
|
||||||
void (*set_thread_priority)(struct thread* thread, int32 priority);
|
void (*set_thread_priority)(struct thread* thread, int32 priority);
|
||||||
|
// called when the thread structure is first created -
|
||||||
|
// initialization of per-thread housekeeping data structures should
|
||||||
|
// be done here
|
||||||
|
void (*on_thread_create)(struct thread* thread);
|
||||||
|
// called when a thread structure is initialized and made ready for
|
||||||
|
// use - should be used to reset the housekeeping data structures
|
||||||
|
// if needed
|
||||||
|
void (*on_thread_init)(struct thread* thread);
|
||||||
|
// called when a thread structure is freed - freeing up any allocated
|
||||||
|
// mem on the scheduler's part should be done here
|
||||||
|
void (*on_thread_destroy)(struct thread* thread);
|
||||||
|
|
||||||
void (*start)(void);
|
void (*start)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -30,7 +41,12 @@ extern struct scheduler_ops* gScheduler;
|
|||||||
gScheduler->set_thread_priority(thread, priority)
|
gScheduler->set_thread_priority(thread, priority)
|
||||||
#define scheduler_reschedule() gScheduler->reschedule()
|
#define scheduler_reschedule() gScheduler->reschedule()
|
||||||
#define scheduler_start() gScheduler->start()
|
#define scheduler_start() gScheduler->start()
|
||||||
|
#define scheduler_on_thread_create(thread) \
|
||||||
|
gScheduler->on_thread_create(thread)
|
||||||
|
#define scheduler_on_thread_init(thread) \
|
||||||
|
gScheduler->on_thread_init(thread)
|
||||||
|
#define scheduler_on_thread_destroy(thread) \
|
||||||
|
gScheduler->on_thread_destroy(thread)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|||||||
@@ -158,6 +158,10 @@ struct free_user_thread {
|
|||||||
struct user_thread* thread;
|
struct user_thread* thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct scheduler_thread_data {
|
||||||
|
// empty, left up to the individual schedulers to subclass / define
|
||||||
|
};
|
||||||
|
|
||||||
struct team {
|
struct team {
|
||||||
struct team *next; // next in hash
|
struct team *next; // next in hash
|
||||||
struct team *siblings_next;
|
struct team *siblings_next;
|
||||||
@@ -248,6 +252,7 @@ struct thread {
|
|||||||
|
|
||||||
bool in_kernel;
|
bool in_kernel;
|
||||||
bool was_yielded;
|
bool was_yielded;
|
||||||
|
struct scheduler_thread_data* scheduler_data;
|
||||||
|
|
||||||
struct user_thread* user_thread;
|
struct user_thread* user_thread;
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,23 @@ static struct thread* sRunQueue[B_MAX_CPU_COUNT];
|
|||||||
static struct thread* sIdleThreads;
|
static struct thread* sIdleThreads;
|
||||||
static cpu_mask_t sIdleCPUs = 0;
|
static cpu_mask_t sIdleCPUs = 0;
|
||||||
|
|
||||||
|
struct affine_scheduler_data : public scheduler_thread_data
|
||||||
|
{
|
||||||
|
affine_scheduler_data(void)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
memset(fLastThreadQuantums, 0, sizeof(fLastThreadQuantums));
|
||||||
|
fLastQuantumSlot = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 fLastThreadQuantums[5];
|
||||||
|
int16 fLastQuantumSlot;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_rand(void)
|
_rand(void)
|
||||||
@@ -441,6 +458,29 @@ affine_reschedule(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
affine_on_thread_create(struct thread* thread)
|
||||||
|
{
|
||||||
|
thread->scheduler_data = new(std::nothrow) affine_scheduler_data();
|
||||||
|
if (thread->scheduler_data == NULL)
|
||||||
|
panic("affine_scheduler: Unable to allocate scheduling data structure for thread %ld\n", thread->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
affine_on_thread_init(struct thread* thread)
|
||||||
|
{
|
||||||
|
((affine_scheduler_data *)(thread->scheduler_data))->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
affine_on_thread_destroy(struct thread* thread)
|
||||||
|
{
|
||||||
|
delete thread->scheduler_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! This starts the scheduler. Must be run under the context of
|
/*! This starts the scheduler. Must be run under the context of
|
||||||
the initial idle thread.
|
the initial idle thread.
|
||||||
*/
|
*/
|
||||||
@@ -461,6 +501,9 @@ static scheduler_ops kAffineOps = {
|
|||||||
affine_enqueue_in_run_queue,
|
affine_enqueue_in_run_queue,
|
||||||
affine_reschedule,
|
affine_reschedule,
|
||||||
affine_set_thread_priority,
|
affine_set_thread_priority,
|
||||||
|
affine_on_thread_create,
|
||||||
|
affine_on_thread_init,
|
||||||
|
affine_on_thread_destroy,
|
||||||
affine_start
|
affine_start
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -380,6 +380,27 @@ simple_reschedule(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
simple_on_thread_create(struct thread* thread)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
simple_on_thread_init(struct thread* thread)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
simple_on_thread_destroy(struct thread* thread)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! This starts the scheduler. Must be run under the context of
|
/*! This starts the scheduler. Must be run under the context of
|
||||||
the initial idle thread.
|
the initial idle thread.
|
||||||
*/
|
*/
|
||||||
@@ -400,6 +421,9 @@ static scheduler_ops kSimpleOps = {
|
|||||||
simple_enqueue_in_run_queue,
|
simple_enqueue_in_run_queue,
|
||||||
simple_reschedule,
|
simple_reschedule,
|
||||||
simple_set_thread_priority,
|
simple_set_thread_priority,
|
||||||
|
simple_on_thread_create,
|
||||||
|
simple_on_thread_init,
|
||||||
|
simple_on_thread_destroy,
|
||||||
simple_start
|
simple_start
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ create_thread_struct(struct thread *inthread, const char *name,
|
|||||||
struct thread *thread;
|
struct thread *thread;
|
||||||
cpu_status state;
|
cpu_status state;
|
||||||
char temp[64];
|
char temp[64];
|
||||||
|
bool recycled = false;
|
||||||
|
|
||||||
if (inthread == NULL) {
|
if (inthread == NULL) {
|
||||||
// try to recycle one from the dead queue first
|
// try to recycle one from the dead queue first
|
||||||
@@ -209,10 +210,15 @@ create_thread_struct(struct thread *inthread, const char *name,
|
|||||||
thread = (struct thread *)malloc(sizeof(struct thread));
|
thread = (struct thread *)malloc(sizeof(struct thread));
|
||||||
if (thread == NULL)
|
if (thread == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
} else {
|
||||||
|
recycled = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thread = inthread;
|
thread = inthread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!recycled)
|
||||||
|
scheduler_on_thread_create(thread);
|
||||||
|
|
||||||
if (name != NULL)
|
if (name != NULL)
|
||||||
strlcpy(thread->name, name, B_OS_NAME_LENGTH);
|
strlcpy(thread->name, name, B_OS_NAME_LENGTH);
|
||||||
@@ -253,7 +259,7 @@ create_thread_struct(struct thread *inthread, const char *name,
|
|||||||
thread->select_infos = NULL;
|
thread->select_infos = NULL;
|
||||||
thread->post_interrupt_callback = NULL;
|
thread->post_interrupt_callback = NULL;
|
||||||
thread->post_interrupt_data = NULL;
|
thread->post_interrupt_data = NULL;
|
||||||
|
|
||||||
sprintf(temp, "thread_%ld_retcode_sem", thread->id);
|
sprintf(temp, "thread_%ld_retcode_sem", thread->id);
|
||||||
thread->exit.sem = create_sem(0, temp);
|
thread->exit.sem = create_sem(0, temp);
|
||||||
if (thread->exit.sem < B_OK)
|
if (thread->exit.sem < B_OK)
|
||||||
@@ -271,7 +277,7 @@ create_thread_struct(struct thread *inthread, const char *name,
|
|||||||
|
|
||||||
if (arch_thread_init_thread_struct(thread) < B_OK)
|
if (arch_thread_init_thread_struct(thread) < B_OK)
|
||||||
goto err4;
|
goto err4;
|
||||||
|
|
||||||
return thread;
|
return thread;
|
||||||
|
|
||||||
err4:
|
err4:
|
||||||
@@ -282,8 +288,10 @@ err2:
|
|||||||
delete_sem(thread->exit.sem);
|
delete_sem(thread->exit.sem);
|
||||||
err1:
|
err1:
|
||||||
// ToDo: put them in the dead queue instead?
|
// ToDo: put them in the dead queue instead?
|
||||||
if (inthread == NULL)
|
if (inthread == NULL) {
|
||||||
free(thread);
|
free(thread);
|
||||||
|
scheduler_on_thread_destroy(thread);
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,6 +303,8 @@ delete_thread_struct(struct thread *thread)
|
|||||||
delete_sem(thread->msg.write_sem);
|
delete_sem(thread->msg.write_sem);
|
||||||
delete_sem(thread->msg.read_sem);
|
delete_sem(thread->msg.read_sem);
|
||||||
|
|
||||||
|
scheduler_on_thread_destroy(thread);
|
||||||
|
|
||||||
// ToDo: put them in the dead queue instead?
|
// ToDo: put them in the dead queue instead?
|
||||||
free(thread);
|
free(thread);
|
||||||
}
|
}
|
||||||
@@ -446,6 +456,7 @@ create_thread(thread_creation_attributes& attributes, bool kernel)
|
|||||||
// insert into global list
|
// insert into global list
|
||||||
hash_insert(sThreadHash, thread);
|
hash_insert(sThreadHash, thread);
|
||||||
sUsedThreads++;
|
sUsedThreads++;
|
||||||
|
scheduler_on_thread_init(thread);
|
||||||
RELEASE_THREAD_LOCK();
|
RELEASE_THREAD_LOCK();
|
||||||
|
|
||||||
GRAB_TEAM_LOCK();
|
GRAB_TEAM_LOCK();
|
||||||
|
|||||||
Reference in New Issue
Block a user