stippi + bonefish:

* Missing backslash in UPDATE_THREAD_KERNEL_TIME() macro. Caused the
  thread's kernel time never to be updated when the thread left the
  kernel. The time would be added to the user time instead.
* Changed semantics of thread_at_kernel_exit(). It leaves interrupts
  disabled when returning, now. All code using it would disable
  interrupts afterwards anyway, and inbetween the thread could be
  interrupted causing two more time updates (or actually not causing
  them erroneously).
* The code in x86's interrupt handler entry (int_bottom) also checks
  thread::in_kernel now, to determine whether the thread was already
  considered to be in userland. This is necessary since the sysexit
  instruction doesn't reenable interrupts, so that we have to do that
  with the preceeding instruction. Hence an interrupt can occur
  inbetween, which would incorrectly add the interrupt's kernel time
  to the thread's user time.
* For userland threads team_create_thread_start() didn't invoke
  thread_at_kernel_exit() or any equivalent. We do that in 
  arch_thread_enter_userspace() now.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26240 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2008-07-03 20:37:08 +00:00
parent 0875ae984f
commit dc27129332
3 changed files with 18 additions and 12 deletions

View File

@ -53,7 +53,7 @@
call system_time; \
\
movl %eax, %ebx; /* save for later */ \
movl %edx, %ecx;
movl %edx, %ecx; \
\
/* thread->kernel_time += now - thread->last_time; */ \
sub THREAD_last_time(%edi), %eax; \
@ -248,7 +248,16 @@ int_bottom:
testl $0x20000, IFRAME_flags(%ebp) // VM86 mode
jnz int_bottom_vm86
cmp $USER_CODE_SEG, IFRAME_cs(%ebp)
cmp $USER_CODE_SEG, IFRAME_cs(%ebp) // user mode
je int_bottom_user
// We need to recheck user mode using the thread's in_kernel flag, since
// sysexit introduces a raced condition: It doesn't reenable interrupts,
// so that we have to do it in the instruction before, thus opening a
// window for an interrupt while still being in the kernel, but having set
// up everything for userland already.
movl %dr3, %edi // thread pointer
cmpb $0, THREAD_in_kernel(%edi)
je int_bottom_user
// disable interrupts -- the handler will enable them, if necessary
@ -474,8 +483,7 @@ handle_syscall:
// make sure interrupts are enabled (they are, when coming from a syscall
// but otherwise they might be disabled)
sti
call thread_at_kernel_exit
cli // disable interrupts
call thread_at_kernel_exit // also disables interrupts
jmp kernel_exit_work_done
bad_syscall_params:

View File

@ -409,7 +409,8 @@ arch_thread_enter_userspace(struct thread *t, addr_t entry, void *args1,
if (user_memcpy((void *)stackTop, args, sizeof(args)) < B_OK)
return B_BAD_ADDRESS;
disable_interrupts();
thread_at_kernel_exit();
// also disables interrupts
i386_set_tss_and_kstack(t->kernel_stack_top);

View File

@ -331,9 +331,6 @@ _create_user_thread_kentry(void)
{
struct thread *thread = thread_get_current_thread();
// a signal may have been delivered here
thread_at_kernel_exit();
// jump to the entry point in user space
arch_thread_enter_userspace(thread, (addr_t)thread->entry,
thread->args1, thread->args2);
@ -1571,6 +1568,8 @@ thread_at_kernel_entry(bigtime_t now)
/*!
Called whenever a thread exits kernel space to user space.
Tracks time, handles signals, ...
Interrupts must be enabled. When the function returns, interrupts will be
disabled.
*/
void
thread_at_kernel_exit(void)
@ -1584,7 +1583,7 @@ thread_at_kernel_exit(void)
scheduler_reschedule();
}
cpu_status state = disable_interrupts();
disable_interrupts();
thread->in_kernel = false;
@ -1592,14 +1591,12 @@ thread_at_kernel_exit(void)
bigtime_t now = system_time();
thread->kernel_time += now - thread->last_time;
thread->last_time = now;
restore_interrupts(state);
}
/*! The quick version of thread_kernel_exit(), in case no signals are pending
and no debugging shall be done.
Interrupts are disabled in this case.
Interrupts must be disabled.
*/
void
thread_at_kernel_exit_no_signals(void)