Changed the way user/kernel time is tracked for threads. Now, thread_at_kernel_entry()
and thread_at_kernel_exit() are always called for userland threads at the appropriate situation (note, I've renamed those from *_atkernel_*). The timing should be more accurate this way, and the thread::last_time_type field is no longer needed: all interrupts are now added to the kernel time (where the time is actually spent). git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11331 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -31,9 +31,9 @@ struct thread *thread_dequeue_id(struct thread_queue *q, thread_id thr_id);
|
|||||||
void scheduler_enqueue_in_run_queue(struct thread *thread);
|
void scheduler_enqueue_in_run_queue(struct thread *thread);
|
||||||
void scheduler_remove_from_run_queue(struct thread *thread);
|
void scheduler_remove_from_run_queue(struct thread *thread);
|
||||||
|
|
||||||
void thread_atkernel_entry(void);
|
void thread_at_kernel_entry(void);
|
||||||
// called when the thread enters the kernel on behalf of the thread
|
// called when the thread enters the kernel on behalf of the thread
|
||||||
void thread_atkernel_exit(void);
|
void thread_at_kernel_exit(void);
|
||||||
|
|
||||||
status_t thread_init(struct kernel_args *args);
|
status_t thread_init(struct kernel_args *args);
|
||||||
status_t thread_per_cpu_init(int32 cpu_num);
|
status_t thread_per_cpu_init(int32 cpu_num);
|
||||||
@@ -80,11 +80,6 @@ struct rlimit;
|
|||||||
int _user_getrlimit(int resource, struct rlimit * rlp);
|
int _user_getrlimit(int resource, struct rlimit * rlp);
|
||||||
int _user_setrlimit(int resource, const struct rlimit * rlp);
|
int _user_setrlimit(int resource, const struct rlimit * rlp);
|
||||||
|
|
||||||
#if 1
|
|
||||||
// XXX remove later
|
|
||||||
int thread_test(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2004, Haiku Inc.
|
* Copyright 2004-2005, Haiku Inc.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Thread definition and structures
|
* Thread definition and structures
|
||||||
@@ -44,11 +44,6 @@ enum team_state {
|
|||||||
TEAM_STATE_DEATH // being killed
|
TEAM_STATE_DEATH // being killed
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
|
||||||
KERNEL_TIME,
|
|
||||||
USER_TIME
|
|
||||||
};
|
|
||||||
|
|
||||||
#define THREAD_RETURN_EXIT 0x1
|
#define THREAD_RETURN_EXIT 0x1
|
||||||
#define THREAD_RETURN_INTERRUPTED 0x2
|
#define THREAD_RETURN_INTERRUPTED 0x2
|
||||||
|
|
||||||
@@ -187,7 +182,6 @@ struct thread {
|
|||||||
bigtime_t user_time;
|
bigtime_t user_time;
|
||||||
bigtime_t kernel_time;
|
bigtime_t kernel_time;
|
||||||
bigtime_t last_time;
|
bigtime_t last_time;
|
||||||
int32 last_time_type; // KERNEL_TIME or USER_TIME
|
|
||||||
|
|
||||||
// architecture dependant section
|
// architecture dependant section
|
||||||
struct arch_thread arch_info;
|
struct arch_thread arch_info;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2002-2004, The Haiku Team. All rights reserved.
|
* Copyright 2002-2005, Axel Dörfler, [email protected].
|
||||||
** Distributed under the terms of the Haiku License.
|
* Distributed under the terms of the MIT License.
|
||||||
**
|
*
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||||
** Distributed under the terms of the NewOS License.
|
* Distributed under the terms of the NewOS License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <vm.h>
|
#include <vm.h>
|
||||||
#include <int.h>
|
#include <int.h>
|
||||||
@@ -201,6 +201,9 @@ i386_handle_trap(struct iframe frame)
|
|||||||
if (thread)
|
if (thread)
|
||||||
i386_push_iframe(thread, &frame);
|
i386_push_iframe(thread, &frame);
|
||||||
|
|
||||||
|
if (frame.cs == USER_CODE_SEG)
|
||||||
|
thread_at_kernel_entry();
|
||||||
|
|
||||||
// if(frame.vector != 0x20)
|
// if(frame.vector != 0x20)
|
||||||
// dprintf("i386_handle_trap: vector 0x%x, ip 0x%x, cpu %d\n", frame.vector, frame.eip, smp_get_current_cpu());
|
// dprintf("i386_handle_trap: vector 0x%x, ip 0x%x, cpu %d\n", frame.vector, frame.eip, smp_get_current_cpu());
|
||||||
|
|
||||||
@@ -228,8 +231,8 @@ i386_handle_trap(struct iframe frame)
|
|||||||
enable_interrupts();
|
enable_interrupts();
|
||||||
|
|
||||||
ret = vm_page_fault(cr2, frame.eip,
|
ret = vm_page_fault(cr2, frame.eip,
|
||||||
(frame.error_code & 0x2) != 0,
|
(frame.error_code & 0x2) != 0, // write access
|
||||||
(frame.error_code & 0x4) != 0,
|
(frame.error_code & 0x4) != 0, // userland
|
||||||
&newip);
|
&newip);
|
||||||
if (newip != 0) {
|
if (newip != 0) {
|
||||||
// the page fault handler wants us to modify the iframe to set the
|
// the page fault handler wants us to modify the iframe to set the
|
||||||
@@ -238,12 +241,12 @@ i386_handle_trap(struct iframe frame)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 99: // syscall
|
case 99: // syscall
|
||||||
{
|
{
|
||||||
uint64 retcode;
|
uint64 retcode;
|
||||||
unsigned int args[MAX_ARGS];
|
unsigned int args[MAX_ARGS];
|
||||||
|
|
||||||
thread_atkernel_entry();
|
|
||||||
#if 0
|
#if 0
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -253,13 +256,12 @@ i386_handle_trap(struct iframe frame)
|
|||||||
dprintf("\t0x%x\n", ((unsigned int *)frame.edx)[i]);
|
dprintf("\t0x%x\n", ((unsigned int *)frame.edx)[i]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/*
|
/* syscall interface works as such:
|
||||||
** syscall interface works as such:
|
* %eax has syscall #
|
||||||
** eax has syscall #
|
* %ecx has number of args (0-16)
|
||||||
** ecx has number of args (0-16)
|
* %edx has pointer to buffer containing args from first to last
|
||||||
** edx has pointer to buffer containing args from first to last
|
* each is verified to make sure someone doesn't try to clobber it
|
||||||
** each is verified to make sure someone doesn't try to clobber it
|
*/
|
||||||
*/
|
|
||||||
if (frame.ecx <= MAX_ARGS) {
|
if (frame.ecx <= MAX_ARGS) {
|
||||||
if (IS_KERNEL_ADDRESS(frame.edx)
|
if (IS_KERNEL_ADDRESS(frame.edx)
|
||||||
|| user_memcpy(args, (void *)frame.edx, frame.ecx * sizeof(unsigned int)) < B_OK) {
|
|| user_memcpy(args, (void *)frame.edx, frame.ecx * sizeof(unsigned int)) < B_OK) {
|
||||||
@@ -274,6 +276,7 @@ i386_handle_trap(struct iframe frame)
|
|||||||
frame.edx = retcode >> 32;
|
frame.edx = retcode >> 32;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (frame.vector >= 0x20) {
|
if (frame.vector >= 0x20) {
|
||||||
interrupt_ack(frame.vector); // ack the 8239 (if applicable)
|
interrupt_ack(frame.vector); // ack the 8239 (if applicable)
|
||||||
@@ -296,8 +299,8 @@ i386_handle_trap(struct iframe frame)
|
|||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame.cs == USER_CODE_SEG || frame.vector == 99)
|
if (frame.cs == USER_CODE_SEG)
|
||||||
thread_atkernel_exit();
|
thread_at_kernel_exit();
|
||||||
|
|
||||||
// dprintf("0x%x cpu %d!\n", thread_get_current_thread_id(), smp_get_current_cpu());
|
// dprintf("0x%x cpu %d!\n", thread_get_current_thread_id(), smp_get_current_cpu());
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2004, Axel Dörfler, [email protected].
|
* Copyright 2002-2005, Axel Dörfler, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||||
@@ -403,6 +403,9 @@ void
|
|||||||
arch_check_syscall_restart(struct thread *t)
|
arch_check_syscall_restart(struct thread *t)
|
||||||
{
|
{
|
||||||
struct iframe *frame = i386_get_current_iframe();
|
struct iframe *frame = i386_get_current_iframe();
|
||||||
|
if (frame == NULL)
|
||||||
|
// this thread is obviously new; we didn't come from an interrupt
|
||||||
|
return;
|
||||||
|
|
||||||
if ((status_t)frame->orig_eax >= 0 && (status_t)frame->eax == EINTR) {
|
if ((status_t)frame->orig_eax >= 0 && (status_t)frame->eax == EINTR) {
|
||||||
frame->eax = frame->orig_eax;
|
frame->eax = frame->orig_eax;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2004, Axel Dörfler, [email protected].
|
* Copyright 2002-2005, Axel Dörfler, [email protected].
|
||||||
* Copyright 2002, Angelo Mottola, [email protected].
|
* Copyright 2002, Angelo Mottola, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
@@ -70,7 +70,7 @@ dump_run_queue(int argc, char **argv)
|
|||||||
|
|
||||||
|
|
||||||
/** Enqueues the thread into the run queue.
|
/** Enqueues the thread into the run queue.
|
||||||
* Note: THREAD_LOCK must be held when entering this function
|
* Note: thread lock must be held when entering this function
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -90,6 +90,7 @@ scheduler_enqueue_in_run_queue(struct thread *thread)
|
|||||||
else
|
else
|
||||||
prev = sRunQueue.head;
|
prev = sRunQueue.head;
|
||||||
}
|
}
|
||||||
|
|
||||||
thread->queue_next = curr;
|
thread->queue_next = curr;
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->queue_next = thread;
|
prev->queue_next = thread;
|
||||||
@@ -99,7 +100,7 @@ scheduler_enqueue_in_run_queue(struct thread *thread)
|
|||||||
|
|
||||||
|
|
||||||
/** Removes a thread from the run queue.
|
/** Removes a thread from the run queue.
|
||||||
* Note: THREAD_LOCK must be held when entering this function
|
* Note: thread lock must be held when entering this function
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -127,14 +128,9 @@ scheduler_remove_from_run_queue(struct thread *thread)
|
|||||||
static void
|
static void
|
||||||
context_switch(struct thread *fromThread, struct thread *toThread)
|
context_switch(struct thread *fromThread, struct thread *toThread)
|
||||||
{
|
{
|
||||||
bigtime_t now;
|
|
||||||
|
|
||||||
// track kernel & user time
|
// track kernel & user time
|
||||||
now = system_time();
|
bigtime_t now = system_time();
|
||||||
if (fromThread->last_time_type == KERNEL_TIME)
|
fromThread->kernel_time += now - fromThread->last_time;
|
||||||
fromThread->kernel_time += now - fromThread->last_time;
|
|
||||||
else
|
|
||||||
fromThread->user_time += now - fromThread->last_time;
|
|
||||||
toThread->last_time = now;
|
toThread->last_time = now;
|
||||||
|
|
||||||
toThread->cpu = fromThread->cpu;
|
toThread->cpu = fromThread->cpu;
|
||||||
@@ -156,7 +152,7 @@ reschedule_event(timer *unused)
|
|||||||
|
|
||||||
|
|
||||||
/** Runs the scheduler.
|
/** Runs the scheduler.
|
||||||
* NOTE: expects thread_spinlock to be held
|
* Note: expects thread spinlock to be held
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -242,9 +238,9 @@ scheduler_reschedule(void)
|
|||||||
void
|
void
|
||||||
start_scheduler(void)
|
start_scheduler(void)
|
||||||
{
|
{
|
||||||
int state;
|
cpu_status state;
|
||||||
|
|
||||||
// XXX may not be the best place for this
|
// ToDo: may not be the best place for this
|
||||||
// invalidate all of the other processors' TLB caches
|
// invalidate all of the other processors' TLB caches
|
||||||
state = disable_interrupts();
|
state = disable_interrupts();
|
||||||
arch_cpu_global_TLB_invalidate();
|
arch_cpu_global_TLB_invalidate();
|
||||||
|
|||||||
+32
-40
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2004, Axel Dörfler, [email protected].
|
* Copyright 2002-2005, Axel Dörfler, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||||
@@ -193,7 +193,6 @@ create_thread_struct(const char *name)
|
|||||||
t->user_time = 0;
|
t->user_time = 0;
|
||||||
t->kernel_time = 0;
|
t->kernel_time = 0;
|
||||||
t->last_time = 0;
|
t->last_time = 0;
|
||||||
t->last_time_type = KERNEL_TIME;
|
|
||||||
t->exit.status = 0;
|
t->exit.status = 0;
|
||||||
t->exit.reason = 0;
|
t->exit.reason = 0;
|
||||||
list_init(&t->exit.waiters);
|
list_init(&t->exit.waiters);
|
||||||
@@ -248,9 +247,15 @@ delete_thread_struct(struct thread *thread)
|
|||||||
static void
|
static void
|
||||||
thread_kthread_entry(void)
|
thread_kthread_entry(void)
|
||||||
{
|
{
|
||||||
|
struct thread *thread = thread_get_current_thread();
|
||||||
|
|
||||||
// simulates the thread spinlock release that would occur if the thread had been
|
// simulates the thread spinlock release that would occur if the thread had been
|
||||||
// rescheded from. The resched didn't happen because the thread is new.
|
// rescheded from. The resched didn't happen because the thread is new.
|
||||||
RELEASE_THREAD_LOCK();
|
RELEASE_THREAD_LOCK();
|
||||||
|
|
||||||
|
// start tracking time
|
||||||
|
thread->last_time = system_time();
|
||||||
|
|
||||||
enable_interrupts(); // this essentially simulates a return-from-interrupt
|
enable_interrupts(); // this essentially simulates a return-from-interrupt
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,9 +263,9 @@ thread_kthread_entry(void)
|
|||||||
static void
|
static void
|
||||||
thread_kthread_exit(void)
|
thread_kthread_exit(void)
|
||||||
{
|
{
|
||||||
struct thread *t = thread_get_current_thread();
|
struct thread *thread = thread_get_current_thread();
|
||||||
|
|
||||||
t->exit.reason = THREAD_RETURN_EXIT;
|
thread->exit.reason = THREAD_RETURN_EXIT;
|
||||||
thread_exit();
|
thread_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,12 +281,8 @@ _create_user_thread_kentry(void)
|
|||||||
struct thread *thread = thread_get_current_thread();
|
struct thread *thread = thread_get_current_thread();
|
||||||
|
|
||||||
// a signal may have been delivered here
|
// a signal may have been delivered here
|
||||||
// ToDo: this looks broken
|
thread_at_kernel_exit();
|
||||||
// thread_atkernel_exit();
|
|
||||||
// start tracking kernel & user time
|
|
||||||
thread->last_time = system_time();
|
|
||||||
thread->last_time_type = KERNEL_TIME;
|
|
||||||
thread->in_kernel = false;
|
|
||||||
// jump to the entry point in user space
|
// jump to the entry point in user space
|
||||||
arch_thread_enter_uspace(thread, (addr_t)thread->entry, thread->args1, thread->args2);
|
arch_thread_enter_uspace(thread, (addr_t)thread->entry, thread->args1, thread->args2);
|
||||||
|
|
||||||
@@ -297,15 +298,9 @@ static int
|
|||||||
_create_kernel_thread_kentry(void)
|
_create_kernel_thread_kentry(void)
|
||||||
{
|
{
|
||||||
struct thread *thread = thread_get_current_thread();
|
struct thread *thread = thread_get_current_thread();
|
||||||
int (*func)(void *args);
|
int (*func)(void *args) = (void *)thread->entry;
|
||||||
|
|
||||||
// start tracking kernel & user time
|
|
||||||
thread->last_time = system_time();
|
|
||||||
thread->last_time_type = KERNEL_TIME;
|
|
||||||
|
|
||||||
// call the entry function with the appropriate args
|
// call the entry function with the appropriate args
|
||||||
func = (void *)thread->entry;
|
|
||||||
|
|
||||||
return func(thread->args1);
|
return func(thread->args1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -974,64 +969,61 @@ thread_get_thread_struct_locked(thread_id id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// called in the int handler code when a thread enters the kernel for any reason
|
/** Called in the interrupt handler code when a thread enters
|
||||||
|
* the kernel for any reason.
|
||||||
|
* Only tracks time for now.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
thread_atkernel_entry(void)
|
thread_at_kernel_entry(void)
|
||||||
{
|
{
|
||||||
|
struct thread *thread = thread_get_current_thread();
|
||||||
cpu_status state;
|
cpu_status state;
|
||||||
struct thread *t;
|
|
||||||
bigtime_t now;
|
bigtime_t now;
|
||||||
|
|
||||||
t = thread_get_current_thread();
|
TRACE(("thread_atkernel_entry: entry thread 0x%lx\n", thread->id));
|
||||||
|
|
||||||
TRACE(("thread_atkernel_entry: entry thread 0x%lx\n", t->id));
|
|
||||||
|
|
||||||
state = disable_interrupts();
|
state = disable_interrupts();
|
||||||
|
|
||||||
// track user time
|
// track user time
|
||||||
now = system_time();
|
now = system_time();
|
||||||
t->user_time += now - t->last_time;
|
thread->user_time += now - thread->last_time;
|
||||||
t->last_time = now;
|
thread->last_time = now;
|
||||||
t->last_time_type = KERNEL_TIME;
|
|
||||||
|
|
||||||
t->in_kernel = true;
|
thread->in_kernel = true;
|
||||||
|
|
||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// called when a thread exits kernel space to user space
|
/** Called whenever a thread exits kernel space to user space.
|
||||||
|
* Tracks time, handles signals, ...
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
thread_atkernel_exit(void)
|
thread_at_kernel_exit(void)
|
||||||
{
|
{
|
||||||
|
struct thread *thread = thread_get_current_thread();
|
||||||
cpu_status state;
|
cpu_status state;
|
||||||
struct thread *t;
|
|
||||||
bigtime_t now;
|
bigtime_t now;
|
||||||
|
|
||||||
TRACE(("thread_atkernel_exit: entry\n"));
|
TRACE(("thread_atkernel_exit: entry\n"));
|
||||||
|
|
||||||
// ToDo: this may be broken (when it is called, and what exactly should it do...)
|
|
||||||
|
|
||||||
t = thread_get_current_thread();
|
|
||||||
|
|
||||||
state = disable_interrupts();
|
state = disable_interrupts();
|
||||||
GRAB_THREAD_LOCK();
|
GRAB_THREAD_LOCK();
|
||||||
|
|
||||||
if (handle_signals(t, &state))
|
if (handle_signals(thread, &state))
|
||||||
scheduler_reschedule();
|
scheduler_reschedule();
|
||||||
// was: smp_send_broadcast_ici(SMP_MSG_RESCHEDULE, 0, 0, 0, NULL, SMP_MSG_FLAG_SYNC);
|
// was: smp_send_broadcast_ici(SMP_MSG_RESCHEDULE, 0, 0, 0, NULL, SMP_MSG_FLAG_SYNC);
|
||||||
|
|
||||||
t->in_kernel = false;
|
thread->in_kernel = false;
|
||||||
|
|
||||||
RELEASE_THREAD_LOCK();
|
RELEASE_THREAD_LOCK();
|
||||||
|
|
||||||
// track kernel time
|
// track kernel time
|
||||||
now = system_time();
|
now = system_time();
|
||||||
t->kernel_time += now - t->last_time;
|
thread->kernel_time += now - thread->last_time;
|
||||||
t->last_time = now;
|
thread->last_time = now;
|
||||||
t->last_time_type = USER_TIME;
|
|
||||||
|
|
||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
}
|
}
|
||||||
@@ -1041,7 +1033,7 @@ thread_atkernel_exit(void)
|
|||||||
// private kernel exported functions
|
// private kernel exported functions
|
||||||
|
|
||||||
|
|
||||||
/** insert a thread onto the tail of a queue
|
/** Insert a thread to the tail of a queue
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
Reference in New Issue
Block a user