PIT

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
JFF

PIT

Post by JFF »

Ok... now PIT is setup correctly....

In bochs my handler is called one time.... in vmware it never gets called. I call my handler from asm :

Code: Select all

void clock_handler()
{
   disable();
   kprintf("sched_ticks");
   enable();
}
I was wondering if there is another way to see if my handler gets called.

I heard that the handler must be reentrant... what does this means. How to make it reentrant.... can we make kprintf reentrant ?


Thx

--JFF
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:PIT

Post by Brendan »

Hi,
JFF wrote: In bochs my handler is called one time.... in vmware it never gets called. I call my handler from asm :

Code: Select all

void clock_handler()
{
   disable();
   kprintf("sched_ticks");
   enable();
}
I was wondering if there is another way to see if my handler gets called.
The easiest way to see if a handler gets called would be to add some code that changes the video directly in the assembly wrapper, e.g. (for text mode):

Code: Select all

IRQ1:
   inc dword [0x000B8000]
   inc dword [0x000B8004]
   pushad
   call _clock_handler
   mov al,0x20
   out 0x20,al
   popad
   iretd
JFF wrote: I heard that the handler must be reentrant... what does this means. How to make it reentrant.... can we make kprintf reentrant ?
If something is re-entrant it means that it can be run by multiple callers at the same time. For example, if another thread calls kprintf to display the string "012345678" and your timer IRQ interrupts it you may end up with "0123sched_ticks45678". Somewhere inside kprintf you probably put a character on the screen and then increment the cursor position, so you might even end up with "012sched_ticks 45678" if the IRQ interrupts between putting the character and incrementing the cursor.

There's a few different ways of dealing with re-entrancy. A pure OOP system (not fake OOP like C++) would have a seperate thread for the "video object". When kprintf is called it'd send a message containing the data to the video object thread. The video object thread would display the entire text string and then wait for the next message. Using this way you'd never need to worry about re-entrancy (except in your scheduler), but it does have a huge amount of overhead (thread/task switches, message queue, etc).

Another way would be to use re-entrancy locks. At the start of the kprintf function you'd check if the lock is set. If it is set you wait for it to be free, when it is free you lock it. At the end of kprintf you'd free the lock. This works for normal code and has less overhead than pure OOP, but it doesn't work when the function can be used by an IRQ handler. For e.g. if kprintf is being used when the IRQ handler wants it then the IRQ handler will wait until the IRQ handler has returned (which won't happen because it's waiting)..

The fastest way to make a function re-entrant is to disable interrupts (using "pushfd; cli; popfd"). This isn't recommended for slow functions as other more important IRQs could be waiting (it effects interrupt latency). It doesn't work if the code can directly cause a task/thread switch (which kprintf wouldn't), or if your OS supports multiple CPUs.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
JFF

Re:PIT

Post by JFF »

Ok.... I already planned to make a thread for my "video objects" as you were talking.

I'd like to call my scheduler from that handler... would that be better if I have something like....


void clock_handler()
{
if (c >1) return;
c++;
[...]
c--;
}

to limit the number of call to the handler... so the scheduler gets called only one time so if a second interrupt occurs it won't call the scheduler... should i put some kind of lock before "if (c >1)"... ???

Thx again

--JFF
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:PIT

Post by Brendan »

Hi,
JFF wrote: I'd like to call my scheduler from that handler... would that be better if I have something like....

void clock_handler()
{
if (c >1) return;
c++;
[...]
c--;
}
I'd have a system timer tick (a counter that's increased each IRQ):

Code: Select all

void clock_handler()
{
  systemTimerTick++;
  if (systemTimerTick < endOfTimeSlice) return;
  switchThreads();
}

switchThreads() {
  ...find thread to switch to here..
  gotoThread(thread);
}

gotoThread(threadID thread) {
  endOfTimeSlice = systemTimerTick + qTime;
  ..do thread switch here..
}

JFF wrote: should i put some kind of lock before "if (c >1)"... ???
I'd disable interrupts in the assembly wrapper using "pushfd; cli; popfd", and I'd do the same for switchThreads() and gotoThread(). If the scheduler code has to work with multiple CPUs you'd also need another form of locking in switchThreads() and gotoThread(). For e.g.:

Code: Select all


switchThreads:
  pushfd
  cli

  lock bts [schedulerLock],1
  jnc .l2
.l1:
  pause
  lock bts [schedulerLock],1
  jc .l1
.l2:

  ...find thread/task to switch to here...
  call gotoThread

  lock btc [schedulerLock],1
  popfd
  ret

Don't forget that the timer IRQ, switchThreads() and gotoThread() may be used for other things. A typical example would be the sleep() function which puts the thread to sleep and then calls switchThreads(). The timer IRQ could be used to determine if a thread needs to wake up, and if a higher priority thread is woken up gotoThread() would be used. It depends a lot on how your scheduler works though..


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:PIT

Post by Candy »

JFF wrote: void clock_handler()
{
if (c >1) return;
c++;
[...]
c--;
}
This holds a race condition with multiple CPU's or interrupts (which you both probably don't have, but might have in real life). Suggestion is to make a separate assembly function that does an atomic increase-and-return-value, or some define to the same extent.
JFF

Re:PIT

Post by JFF »

OK.... so I'll search on how to make such an atomic-increase-and return-value...
Suggestion is to make a separate assembly function that does an atomic increase-and-return-value, or some define to the same extent.
Do you mean to "#define" an asm routine that does "atomic-increase-and return-value" or you mean that if I use a define there is no need for atomic increase ?
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:PIT

Post by Candy »

JFF wrote:
Suggestion is to make a separate assembly function that does an atomic increase-and-return-value, or some define to the same extent.
Do you mean to "#define" an asm routine that does "atomic-increase-and return-value" or you mean that if I use a define there is no need for atomic increase ?
The first one. Note that if you're not cared about the actual content of the number you can also use a mutex. In this case, swapping the c++; and the if (c > 1) return; would also work. BTW, returning isn't the solution :)
Post Reply