How to make a 'sleep' timer

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
ManOfSteel

How to make a 'sleep' timer

Post by ManOfSteel »

Hello,

I recently saw posts about problems with the FDC and I know that most of them are caused by wrong delays between disk operations. I have exactly this problem and have been unable to fix it for a long time. The problem is that I use inaccurate "timers" -- simple loops that are just repeated many time. I saw that c programmers aften use a 'sleep' function. My question then is: what is behind this function, how does it work?
By the way, I am programming in assembler.

Thank you for any help.
Pyr0Mathic

Re:How to make a 'sleep' timer

Post by Pyr0Mathic »

Hi,

i dont know much about C, but u could solve your problem the following way.

RDTSC read Time-Stamp Counter, whit this asm command you get the ammount of cycles since boot-up, so if you know how fast the cpu is, (the MHz), you could easely calculate the time you have been waiting.

I know this is 100% accurate, atleast i believe it isnt for P3 or lower, the P4 should be accurate, but that's all explained in the Intel manuel 2 and there is also some additional info about the command in intel Manuel 3, system develepers guide.

I hope the above is usefull.

Regards
PyroMathic
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:How to make a 'sleep' timer

Post by Pype.Clicker »

typically, the "sleep" function depends on the operating system to do its job. The OS might for instance wait for N interrupts for the PIT (programmable timer) chip or simply run a RDTSC loop (provided that you have "calibrated" the loop -- that is, you know how much cpu cycles correspond to 1 sec.
guest

Re:How to make a 'sleep' timer

Post by guest »

The sleep function is provided by the operating system, it essentially puts the running thread/process into a 'sleep state' (ie. It won't be scheduled for CPU time) then queues it in a list to be unblocked after X clock (eg. IRQ0) [ticks/]interrupts. Everytime a clock interrupt occurs, the scheduler will decrement the 'ticks remaining' counters in the 'sleeping queue' then grab the processes/threads out of the list that have reached '0 ticks remaining' then add them back to the active scheduling queue.

If you understand that, the most efficient way to do this that I've come across is an offset linked list. You keep the list sorted from shortest to longest and just decrement the entry on the head. Each entry following that one will then be specified as a 'time offset'. ie.
[tt]List: Proc1 [5ticks]
Proc2 calls sleep for 10 ticks
List: Proc1 [5ticks], Proc2 [5ticks]
Proc3 calls sleep for 8 ticks
List: Proc1 [5ticks], Proc3 [3ticks], Proc2 [2ticks][/tt]
You can see that if we only decrement the head of the list then Proc3 will receive 3 ticks after Proc1 (5ticks+3ticks=8ticks) and Proc2 will receive 2 ticks after Proc3 (5ticks+3ticks+2ticks=10ticks)

Now I realise this has nothing to do with your problem (or so it may appear), to adapt this system to your problem you will need to support kernel threads in your scheduler [which is going to be pretty much a necessity if you are going to have kernel space drivers anyway] so that the FDC driver will receive CPU time just like any other thread (although you may want to give it a ready-to-run=will-run priority level). I would also like to note that I haven't bothered with the FDC yet, but have you checked to make sure it doesn't raise an interrupt signaling that the event in question has occurred?
Ryu

Re:How to make a 'sleep' timer

Post by Ryu »

Out of curiosity, how accurate is required inbetween disk operations?

I would discourage using RDTSC as a timer, there are some systems specially in laptops that can go into low power mode by slowing down the processor's frequency. There are ways around it but it just means more hacks in your code.
chasetec

Re:How to make a 'sleep' timer

Post by chasetec »

ManOfSteel wrote: Hello,

I recently saw posts about problems with the FDC and I know that most of them are caused by wrong delays between disk operations. I have exactly this problem and have been unable to fix it for a long time. The problem is that I use inaccurate "timers" -- simple loops that are just repeated many time. I saw that c programmers aften use a 'sleep' function. My question then is: what is behind this function, how does it work?
By the way, I am programming in assembler.
What makes your timer loops inaccurate? Are you not calibrating them? The typical approach is to use timer loops. You can either have a table that maps loop count to machine speed or you can calibrate the loop. To calibrate the loop you need to get the system time, run the loop for an insane number of times, get the system time again and figure out how many loops get done per time unit. Don't try to run your calibration routine for a set amount of time because repeated checking of the system time will throw off the execution speed of the loop. The only problem with using calibrated loops is systems that can change speed, the loops are never going to be perfect because of interrupts and caching but cpu mhz changes are a little more drasitc. Some people have just made sure to run the loop at the fastest cpu speed and made do with the overly long delays when the speed is slower, others run multiple calibration loops.

Timers and just keeping track of the system time is a fairly standard sources of headaches. Don't know if MS ever fixed Windows but I know in Windows 9x days the time displayed on the taskbar would sometimes become wrong. Windows would read the system clock only during boot and afterwards it increments the taskbar clock in a task that was scheduled to run every so often. The problem was that some software like virus scanners would keep the clock task from running as much as it wanted to. You'd have to reboot in order to get the correct time because the motherboard was still correct. You can imagine the problems this type of clock drift would cause with applications over time. I guess the fix for the system clock in Windows is NTP :)

There was also a problem very similar to what you have on Windows 95 and K6-2 350+ Mhz cpus. The timer loops were wrong for some of the storage drivers and the system would fatal exception during boot. The faster the cpu, the more likely to crash. You had to under clock the system and add a patch that would correct the timer routines.
ManOfSteel

Re:How to make a 'sleep' timer

Post by ManOfSteel »

Thank you all for your replies.

I am now using the PIT timer 2 running at 100hz (100ticks/sec). For the "millisecond-precision", it just takes a millisecond value as parameter from the user (eg: 2500ms = 2.5s), and divide it by 10 in the sleep routine (eg: 2500ms/10 = 250ticks/sec = 2.5s).
Slasher

Re:How to make a 'sleep' timer

Post by Slasher »

You can use the periodic timer on the realtime clock (RTC) for the sleeper function in place of the PIT. You can set the frequency of it as well.

RTC has 3 seperate timers - the clock/date, the Alarm and the periodic timer.

Am using the RTC periodic timer for my delay function and it works great. This frees the PIT for multitasking functions.

Also using the Alarm part for one off events that trigger at a user specified time/date i.e. shut pc off at 10am on friday.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:How to make a 'sleep' timer

Post by Pype.Clicker »

Code Slasher wrote: Am using the RTC periodic timer for my delay function and it works great. This frees the PIT for multitasking functions.
Well, all will depend on your actual needs of precision. Sure, the PIT can deliver you more accurate periodic interrupt (e.g. it is not bound to a multiple of 11xxxxx Hz, for instance), but it also run at lower priority than the PIT. Moreover, unless you invoke the multitasking code from your RTC timer, just flagging the thread as "ready" in the RTC interrupt and waiting for the PIT interrupt to schedule you seems a bit odd.
Also using the Alarm part for one off events that trigger at a user specified time/date i.e. shut pc off at 10am on friday.
Many TSRs on MS-DOS were using that service as well ... In a multitasking system, its advantage over a "cron" service is imho less obvious (but maybe i've been too much contaminated by flunix).
Post Reply