Rockbox.org home
release
dev builds
extras
themes manual
wiki
device status forums
mailing lists
IRC bugs
patches
dev guide



Rockbox mail archive

Subject: X11 simulator clock runs too fast
From: c s (rb_dev_at_yahoo.com)
Date: 2003-03-06


While developing a mod to the wps, I noticed that the
X11 simulator clock was running much faster than the
actual clock does on the Archos. As a result, when
running on the X11 simulator, current_tick runs at
more than 1000Hz and advances more than 200 ticks for
every cycle of wps_refresh as opposed to 20 ticks per
cycle of wps_refresh on the actual hardware. This
throws off current rockbox code that is checking if a
certain time period has passed using
"TIMEAFTER(current_tick, xxx)".

Part of the problem is how the clock is emulated in
the simulator. In the function x11_sleep() (in
uisimulator/x11/thread.c), current_tick is
incremented by 5 every time someone calls sleep(),
thus constant calls of sleep(1) (which rockbox
software does) will cause current_tick to advance at 5
times the desired rate.

Changing x11_sleep() to increment current_tick by the
number of ticks the caller passes to the sleep() call
makes current_tick run much closer to 100Hz, and is a
decent quick fix, however this does not completely
solve the fast clock problem.

Even with that quick fix, the clock will still run a
bit fast because more than one thread can call and be
waiting in sleep() at the same time. If thread #1
calls sleep(10) and control is passed to thread #2
which immediately calls sleep(10), current_tick will
be incremented by 20 (10 for each sleep call) when
only 10/100ths of a second will have actually elapsed
when the threads return from their sleep() calls.
Because of this phenomenon, this quick fix is not
perfect, but it makes it better the current situation.

I wrote a better fix that uses a separate thread that
does nothing but increment current_tick every 10ms,
however there is a problem with it because on many
(most?) Linux systems the shortest wait you can do
with a call to poll() (or usleep(), or nanosleep() )
is 20ms. This makes current_tick run at only 50Hz on
systems that can’t do a suspended wait of only 10ms.

There are a couple of ways around this. We can update
current_tick by 2 ticks every 20ms. Another is to
write a routine that can sleep for the required 10ms
period on most Linux systems. I wrote one such routine
that uses calls to clock_gettime() and goes into a
busy loop until 10ms has passed. Using this method, I
can get a good solid 100Hz clock, but since it uses a
busy loop to wait for the time to pass it's not doing
a true sleep but instead sucking up CPU, however
things still seem to run OK with the other threads
still getting CPU time when they need it and the
clock still remaining at 100Hz. The fix using
clock_gettime() also requires that the simulator be
linked with the –lrt library. Is this a standard
library that everyone has?

Does anybody have a better suggestion for a way to do
a 10ms wait that will work with more Linux systems and
doesn’t suck up CPU with a busy loop?

We should at least put the first quick fix in the
simulator code (correcting x11_sleep() to only
increment current_tick by the number of ticks passed
to it).

Also I believe that similar problems exist in the
win32 specific simulator code, but I didn't look into
details or fixes for the win32 code.

Is there any interest in using or improving the other
fixes that I have discussed? I have included some of
the code that I wrote below if anyonone is interested
in the details of what I discussed above.

-----------------------------------------

Here is the usleep that I wrote which uses a busy
loop, but can do a 10ms wait on systems that can’t do
a 10ms with the system usleep() call.

/* requires –lrt flag when linking */
#include <time.h>
void x11_usleep(int sleep_usec)
{
    struct timespec time;
    int curr_sec, curr_usec;
    int sleep_until_sec, sleep_until_usec;

    clock_gettime(CLOCK_REALTIME, &time);

    curr_sec = time.tv_sec;
    curr_usec = time.tv_nsec/1000000;

    sleep_until_sec =
       curr_sec + ((curr_usec + sleep_usec) / 1000);
    sleep_until_usec = (curr_usec + sleep_usec) %
1000;

    while (1)
    {
        clock_gettime(CLOCK_REALTIME, &time);
        curr_sec = time.tv_sec;
        curr_usec = time.tv_nsec/1000000;
        if ((curr_sec >= sleep_until_sec) &&
            (curr_usec >= sleep_until_usec))
            break;
    }
    return;
}

Using the x11_usleep function above and this function
to increment current_tick instead of incrementing it
in function x11_sleep gives a solid 100Hz clock, but
sucks up CPU.

void clock_emulator_thread()
{
    while (1)
    {
        x11_usleep(1000/HZ);
        current_tick++;
    }
}

-----------

This is our current x11_sleep from the CVS with my
comments added.

void x11_sleep(int ticks)
{
    current_tick+=5; /* QUICK FIX: change this line
to:
                        "current_tick+=ticks;" */
    pthread_mutex_unlock(&mp); /* return */
    /* portable subsecond "sleep" */
    poll((void *)0, 0, ticks * 1000/HZ); /* on many
                           systems, this sleeps for a
                           minumum of 20ms */

    pthread_mutex_lock(&mp); /* get it again */
}

---

Craig Sather

__________________________________________________ Do you Yahoo!? Yahoo! Tax Center - forms, calculators, tips, more http://taxes.yahoo.com/



Page was last modified "Jan 10 2012" The Rockbox Crew
aaa