Page 1 of 1

While loop never ends unless terminal is written to? [SLVED]

Posted: Sat Jun 11, 2016 7:07 pm
by aesculus
This issue is baffling me - my PIT is set up, oscillating at the default frequency, and 'calibrated' (~59 ms per interrupt). I have used a visual indicator to confirm this - I receive a debug message once per second once I begin receiving interrupts from IRQ0.

I am using the PIT as a timer with the following code (timer_ticks increments every time the PIT handler is called):

Code: Select all

void timer_wait(int ticks) { // Time offset in ticks as argument
	unsigned long w_ticks; // Ticks to wait for
	w_ticks = timer_ticks + ticks; // The current tick count plus the time offset
	while(timer_ticks < w_ticks) {
	} // Loop until timer_ticks > ticks count to wait for
}
Inexplicably, this while loop never exits (although interrupts on IRQ1 are still received; I have a keyboard handler set up which allows me to type) unless I write to the terminal in the while loop. This leads me to believe that I am dealing with a code optimization problem (or my IRQ handler is broken) - I am compiling with O2, but changing to O0 or O1 doesn't fix my problem.

However, nothing else fixes the issue - I have tried adding in an internal counter that ticks up and sending STI before the while loop to ensure interrupts are received and neither cause the loop to exit to allow the rest of the kernel to load.

To clarify, this code does work - the timer exits as expected:

Code: Select all

void timer_wait(int ticks) { // Time offset in ticks as argument
	unsigned long w_ticks; // Ticks to wait for
	w_ticks = timer_ticks + ticks; // The sum of the initial tick count and the time offset
	while(timer_ticks < w_ticks) {
             terminal_writestring(" \b"); // Write a space and delete it to produce no net output
	} // Loop until timer_ticks > ticks count to wait for
I have tested this in VMWare Player and Bochs. Any thoughts on why this is happening? I can provide additional code if necessary.

Edit: Global variable 'int timer_ticks' changed to 'volatile int timer_ticks' - fixed my problem with an explanation below

Re: While loop never ends unless terminal is written to?

Posted: Sat Jun 11, 2016 10:06 pm
by BrightLight
Does terminal_writestring() for any reason do something with interrupts?
BTW, what does "default frequency" mean? What is the divider value you use to initialize the PIT?

Re: While loop never ends unless terminal is written to?

Posted: Sat Jun 11, 2016 11:23 pm
by gerryg400
Hi. You need to make timer_ticks volatile.

Re: While loop never ends unless terminal is written to?

Posted: Sun Jun 12, 2016 2:04 am
by aesculus
gerryg400 wrote:Hi. You need to make timer_ticks volatile.
That solved it! Thanks!

C's volatile keyword is a qualifier that is applied to a variable when it is declared. It tells the compiler that the value of the variable may change at any time--without any action being taken by the code the compiler finds nearby. The implications of this are quite serious. However, before we examine them, let's take a look at the syntax.

Will remember this for the future.

Re: While loop never ends unless terminal is written to? [SL

Posted: Sun Jun 12, 2016 2:20 am
by iansjack
But why are you using a polling loop like this for a timer in the first place? Surely the processor should let another thread run whilst something is waiting for a timer to count down.

Re: While loop never ends unless terminal is written to? [SL

Posted: Sun Jun 12, 2016 2:33 am
by aesculus
iansjack wrote:But why are you using a polling loop like this for a timer in the first place? Surely the processor should let another thread run whilst something is waiting for a timer to count down.
timer_wait() is being used in this instance as the equivalent to POSIX's sleep/usleep(). I have not implemented a timer function for that purpose - right now I just need a function that will wait and allows me to service interrupts during the wait.

Re: While loop never ends unless terminal is written to? [SL

Posted: Sun Jun 12, 2016 3:29 am
by iansjack
aesculus wrote:timer_wait() is being used in this instance as the equivalent to POSIX's sleep/usleep().
Not "the equivalent". sleep/usleep suspend the calling thread rather than all threads.