diff --git a/headers/private/kernel/kscheduler.h b/headers/private/kernel/kscheduler.h index b4682be4cb..49a3189009 100644 --- a/headers/private/kernel/kscheduler.h +++ b/headers/private/kernel/kscheduler.h @@ -18,7 +18,18 @@ struct scheduler_ops { void (*enqueue_in_run_queue)(struct thread* thread); void (*reschedule)(void); 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); }; @@ -30,7 +41,12 @@ extern struct scheduler_ops* gScheduler; gScheduler->set_thread_priority(thread, priority) #define scheduler_reschedule() gScheduler->reschedule() #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 extern "C" { diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h index aa8bc0524f..0a4d0a2ee1 100644 --- a/headers/private/kernel/thread_types.h +++ b/headers/private/kernel/thread_types.h @@ -158,6 +158,10 @@ struct free_user_thread { struct user_thread* thread; }; +struct scheduler_thread_data { + // empty, left up to the individual schedulers to subclass / define +}; + struct team { struct team *next; // next in hash struct team *siblings_next; @@ -248,6 +252,7 @@ struct thread { bool in_kernel; bool was_yielded; + struct scheduler_thread_data* scheduler_data; struct user_thread* user_thread; diff --git a/src/system/kernel/scheduler/scheduler_affine.cpp b/src/system/kernel/scheduler/scheduler_affine.cpp index 2fa03b19b9..a663a2a345 100644 --- a/src/system/kernel/scheduler/scheduler_affine.cpp +++ b/src/system/kernel/scheduler/scheduler_affine.cpp @@ -40,6 +40,23 @@ static struct thread* sRunQueue[B_MAX_CPU_COUNT]; static struct thread* sIdleThreads; 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 _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 the initial idle thread. */ @@ -461,6 +501,9 @@ static scheduler_ops kAffineOps = { affine_enqueue_in_run_queue, affine_reschedule, affine_set_thread_priority, + affine_on_thread_create, + affine_on_thread_init, + affine_on_thread_destroy, affine_start }; diff --git a/src/system/kernel/scheduler/scheduler_simple.cpp b/src/system/kernel/scheduler/scheduler_simple.cpp index 8da6a8b084..2c38752e4c 100644 --- a/src/system/kernel/scheduler/scheduler_simple.cpp +++ b/src/system/kernel/scheduler/scheduler_simple.cpp @@ -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 the initial idle thread. */ @@ -400,6 +421,9 @@ static scheduler_ops kSimpleOps = { simple_enqueue_in_run_queue, simple_reschedule, simple_set_thread_priority, + simple_on_thread_create, + simple_on_thread_init, + simple_on_thread_destroy, simple_start }; diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 8f3450354b..8e5aebdbe6 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -195,6 +195,7 @@ create_thread_struct(struct thread *inthread, const char *name, struct thread *thread; cpu_status state; char temp[64]; + bool recycled = false; if (inthread == NULL) { // 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)); if (thread == NULL) return NULL; + } else { + recycled = true; } } else { thread = inthread; } + + if (!recycled) + scheduler_on_thread_create(thread); if (name != NULL) 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->post_interrupt_callback = NULL; thread->post_interrupt_data = NULL; - + sprintf(temp, "thread_%ld_retcode_sem", thread->id); thread->exit.sem = create_sem(0, temp); 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) goto err4; - + return thread; err4: @@ -282,8 +288,10 @@ err2: delete_sem(thread->exit.sem); err1: // ToDo: put them in the dead queue instead? - if (inthread == NULL) + if (inthread == NULL) { free(thread); + scheduler_on_thread_destroy(thread); + } return NULL; } @@ -295,6 +303,8 @@ delete_thread_struct(struct thread *thread) delete_sem(thread->msg.write_sem); delete_sem(thread->msg.read_sem); + scheduler_on_thread_destroy(thread); + // ToDo: put them in the dead queue instead? free(thread); } @@ -446,6 +456,7 @@ create_thread(thread_creation_attributes& attributes, bool kernel) // insert into global list hash_insert(sThreadHash, thread); sUsedThreads++; + scheduler_on_thread_init(thread); RELEASE_THREAD_LOCK(); GRAB_TEAM_LOCK();