How to write a wait function?

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
abhishekmaharana
Posts: 16
Joined: Sat Aug 23, 2008 4:13 am

How to write a wait function?

Post by abhishekmaharana »

Hello.
I have just been able to get my kernel up and working. I wanted to implement a "wait" function for my OS.
What I did is I created a global "wait_for" variable which has the amount of time(in seconds) for which nothing should happen.
In the timer driver,whenever a second passed,I check if the wait_for > 0. If yes,it is decremented. Else nothing.

I have written a wait() function which different programs can call.

Code: Select all

void wait(unsigned int secs)
{
    unsigned *temp=&wait_for;
    *temp=secs;
    while(*temp!=0)
    {
        ;
    }
}
This either results in an infinite loop or incorrect amount(very large) waiting time.
Can you suggest any corrections/alternatives please?
Thanks and regards.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: How to write a wait function?

Post by pcmattman »

Hi,

What happens if another thread calls wait() with a
  1. smaller
  2. larger
value than the one in wait_for at the moment?

Currently what will happen is *every* wait() will adjust to the new time.

Generally speaking you might want to keep a count of seconds since boot, and do something like this:

Code: Select all

extern unsigned int secsSinceBoot; // unsigned int may not be the best type ;)

void wait(unsigned int secs)
{
    unsigned int start = secsSinceBoot;
    unsigned int end = secsSinceBoot + secs;
    while(1)
    {
        unsigned int curr = secsSinceBoot;
        if(curr == end)
           break;
    }
}
Note though that using "==" like that will not always work - if your program misses a timeslice you'll be waiting another 4 billion seconds for the next loop :P

You can adjust the above to something like this:

Code: Select all

extern unsigned int secsSinceBoot; // unsigned int may not be the best type ;)

void wait(unsigned int secs)
{
    unsigned int start = secsSinceBoot;
    unsigned int end = secsSinceBoot + secs;
    int overflow = 0;
    if(end < start)
        overflow = 1;
    while(1)
    {
        unsigned int curr = secsSinceBoot;
        if(overflow && curr < start && end >= curr)
            break;
        else if(end >= curr)
            break;
    }
}
You could also store information about pending waits in your task structure, and as soon as one finishes (check in the timer), wake the task. Until it's woken, don't switch to that task.
User avatar
Troy Martin
Member
Member
Posts: 1686
Joined: Fri Apr 18, 2008 4:40 pm
Location: Langley, Vancouver, BC, Canada
Contact:

Re: How to write a wait function?

Post by Troy Martin »

If your timer frequency is a nice, say, 1 kHz, you can have milliseconds timed by the timer. It's quite easy, really:

Code: Select all

void wait(unsigned int msecs)
{
    while (msecs-- > 0)
    {
        asm_hlt();
    }
}
Assuming you have a small inline void called asm_hlt that just does a simple hlt instruction, your timer frequency is 1 kHz, and my C isn't that rusty.
Image
Image
Solar wrote:It keeps stunning me how friendly we - as a community - are towards people who start programming "their first OS" who don't even have a solid understanding of pointers, their compiler, or how a OS is structured.
I wish I could add more tex
giszo
Member
Member
Posts: 124
Joined: Tue Nov 06, 2007 2:37 pm
Location: Hungary

Re: How to write a wait function?

Post by giszo »

Troy Martin wrote:If your timer frequency is a nice, say, 1 kHz, you can have milliseconds timed by the timer. It's quite easy, really:

Code: Select all

void wait(unsigned int msecs)
{
    while (msecs-- > 0)
    {
        asm_hlt();
    }
}
Assuming you have a small inline void called asm_hlt that just does a simple hlt instruction, your timer frequency is 1 kHz, and my C isn't that rusty.
This works only if the timer interrupt is the only interrupt that fires in the OS.
abhishekmaharana
Posts: 16
Joined: Sat Aug 23, 2008 4:13 am

Re: How to write a wait function?

Post by abhishekmaharana »

pcmattman wrote:Hi,

What happens if another thread calls wait() with a
  1. smaller
  2. larger
value than the one in wait_for at the moment?
As of now,this is not possible in my OS,since there is only a single thread of control.
No one,other than interrupts can take over controls otherwise.
pcmattman wrote: Currently what will happen is *every* wait() will adjust to the new time.

Generally speaking you might want to keep a count of seconds since boot, and do something like this:

Code: Select all

extern unsigned int secsSinceBoot; // unsigned int may not be the best type ;)

void wait(unsigned int secs)
{
    unsigned int start = secsSinceBoot;
    unsigned int end = secsSinceBoot + secs;
    while(1)
    {
        unsigned int curr = secsSinceBoot;
        if(curr == end)
           break;
    }
}
Note though that using "==" like that will not always work - if your program misses a timeslice you'll be waiting another 4 billion seconds for the next loop :P
I had tried the above code too.But my OS still hangs but sometimes it does come out of the loop after an indefinite amount of time.
By the way,can you please tell me "why 4 billion secs"?
abhishekmaharana
Posts: 16
Joined: Sat Aug 23, 2008 4:13 am

Re: How to write a wait function?

Post by abhishekmaharana »

giszo wrote:
Troy Martin wrote:If your timer frequency is a nice, say, 1 kHz, you can have milliseconds timed by the timer. It's quite easy, really:

Code: Select all

void wait(unsigned int msecs)
{
    while (msecs-- > 0)
    {
        asm_hlt();
    }
}
Assuming you have a small inline void called asm_hlt that just does a simple hlt instruction, your timer frequency is 1 kHz, and my C isn't that rusty.
This works only if the timer interrupt is the only interrupt that fires in the OS.
But generally this cannot be the case.There are generally other interrupts like keyboard etc.
Does that imply the above code will never work?
giszo
Member
Member
Posts: 124
Joined: Tue Nov 06, 2007 2:37 pm
Location: Hungary

Re: How to write a wait function?

Post by giszo »

abhishekmaharana wrote:
giszo wrote:
Troy Martin wrote:If your timer frequency is a nice, say, 1 kHz, you can have milliseconds timed by the timer. It's quite easy, really:

Code: Select all

void wait(unsigned int msecs)
{
    while (msecs-- > 0)
    {
        asm_hlt();
    }
}
Assuming you have a small inline void called asm_hlt that just does a simple hlt instruction, your timer frequency is 1 kHz, and my C isn't that rusty.
This works only if the timer interrupt is the only interrupt that fires in the OS.
But generally this cannot be the case.There are generally other interrupts like keyboard etc.
Does that imply the above code will never work?
The problem with that code is that the HLT instruction halts the CPU until the next interrupt. So if a keyboard IRQ fires before your timer IRQ, the amount of the time that the wait() function waits will be less than the time the caller requested.
User avatar
XanClic
Member
Member
Posts: 138
Joined: Wed Feb 13, 2008 9:38 am

Re: How to write a wait function?

Post by XanClic »

abhishekmaharana wrote:
pcmattman wrote: Currently what will happen is *every* wait() will adjust to the new time.

Generally speaking you might want to keep a count of seconds since boot, and do something like this:

Code: Select all

extern unsigned int secsSinceBoot; // unsigned int may not be the best type ;)

void wait(unsigned int secs)
{
    unsigned int start = secsSinceBoot;
    unsigned int end = secsSinceBoot + secs;
    while(1)
    {
        unsigned int curr = secsSinceBoot;
        if(curr == end)
           break;
    }
}
Note though that using "==" like that will not always work - if your program misses a timeslice you'll be waiting another 4 billion seconds for the next loop :P
I had tried the above code too.But my OS still hangs but sometimes it does come out of the loop after an indefinite amount of time.
By the way,can you please tell me "why 4 billion secs"?
Because then it increments "curr" forever until it wraps around (0xFFFFFFFF -> 0x00000000) and the loop starts again. Hence it has to wait 0xFFFFFFFF+1 seconds (4 294 967 296 seconds) until it passes "end" again, I think.
But you could replace the "==" sign with a ">=" sign, that would be better.
giszo wrote:The problem with that code is that the HLT instruction halts the CPU until the next interrupt. So if a keyboard IRQ fires before your timer IRQ, the amount of the time that the wait() function waits will be less than the time the caller requested.
That's true, but a keyboard IRQ doesn't happen more than 10 times per second... So the counter may leave the loop 1 % too early but I think that's OK.
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: How to write a wait function?

Post by Firestryke31 »

Here's how I would do it:

Code: Select all

// Global variable:
volatile unsigned int timerTicks;

// In initialization, before enabling the timer, set timerTicks to 0

// Timer ISR (fill out with your actual timer ISR):
timerISR()
{
  // do stuff
  timerTicks++;
}

// elsewhere:
inline unsigned int getTimerTicks();
{
  return timerTicks;
}

// The wait function
void wait(unsigned int ticksToWait)
{
  unsigned int start = getTimerTicks();
  while( getTimerTicks() < start + ticksToWait )
    asm_hlt();
}
This way you always wait at least ticksToWait, and can still service other interrupts, and can even find out system uptime if you care and never disable the timer. It could probably be made more efficient, though.
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
User avatar
ehenkes
Member
Member
Posts: 124
Joined: Mon Mar 23, 2009 3:15 am
Location: Germany
Contact:

Re: How to write a wait function?

Post by ehenkes »

Code: Select all

#include "os.h"

unsigned long timer_ticks = 0;
unsigned long eticks;

void timer_handler(struct regs* r)
{
    ++timer_ticks;
    if (eticks)
        --eticks;
}

void timer_wait (unsigned long ticks)
{
    timer_uninstall();
    eticks = ticks;
    timer_install();

    // busy wait...
    while (eticks)
    {
      asm_hlt();
    };
}

void sleepSeconds (unsigned long seconds)
{
    // based upon timer tick frequence of ~18 Hz
    timer_wait((unsigned long)18.2065*seconds);
}

void timer_install()
{
    /* Installs 'timer_handler' to IRQ0 */
    irq_install_handler(0, timer_handler);
}

void timer_uninstall()
{
    /* Uninstalls IRQ0 */
    irq_uninstall_handler(0);
}
User avatar
mystran
Member
Member
Posts: 670
Joined: Thu Mar 08, 2007 11:08 am

Re: How to write a wait function?

Post by mystran »

Assuming ISR works the problem is almost certainly not declaring the timer variables as "volatile" which would force the compiler to actually poll the in-memory variable (non-volatiles are free for the compiler to cache in a register).
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
abhishekmaharana
Posts: 16
Joined: Sat Aug 23, 2008 4:13 am

Re: How to write a wait function?

Post by abhishekmaharana »

Hi
Thanks alot for your posts
I apologize for delay and thank you for your posts.
So nice of all of you for taking time out and helping newbies like me.
Thanks a lot.
Post Reply