This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Question about scheduler & sleep


>>>>> "Jim" == jyl087  <jyl087@netscape.net> writes:

    Jim> In my application, I have a section of code which is
    Jim> surrounded by cyg_scheduler_lock/unlock. Now, within that
    Jim> section, I call cyg_thread_delay(128). My intention is to
    Jim> have a 128 tick pause, without allowing context switching.

    Jim> When I step through the code with GDB, I find that the code
    Jim> does pause, however, when it returns from the
    Jim> cyg_thread_delay, the thread is still in the SLEEPING state.
    Jim> It actually continues to execute until the
    Jim> cyg_scheduler_unlock() is called, at which point it goes into
    Jim> a deep sleep...

    Jim> In summary:

    Jim>   cyg_scheduler_lock();      RUNNING
    Jim>     ...
    Jim>     cyg_thread_delay(128);   SLEEPING
    Jim>     ...                      SLEEPING, but executing code!
    Jim>   cyg_scheduler_unlock();    SLEEPING, and really dead

    Jim> Question... is this a bug in the thread mechanism, or is my
    Jim> use of the library wrong?

It is an interesting idea, but it is not going to work. The key point
is that cyg_scheduler_lock()/unlock() are also used throughout the
implementation of the kernel, so a function like cyg_thread_delay()
looks something like:

    cyg_scheduler_lock()
    mark current thread as asleep
    add thread to timer queue
    cyg_scheduler_unlock()
    cleanup

A context switch is possible when the scheduler lock drops to zero.
Since the current thread is no longer runnable, the scheduler will
pick another thread to run (possibly the idle thread). There is no
explicit context switch within cyg_thread_delay(), it happens as a
side effect of unlocking the scheduler.

Your code effectively changes this to:

    cyg_scheduler_lock()
    cyg_scheduler_lock()
    mark current thread as asleep
    add thread to timer queue
    cyg_scheduler_unlock()
    cleanup
    cyg_scheduler_unlock()

During the second unlock a context switch is allowed to occur, and
will occur because the current thread is not runnable. Control
transfers to some other runnable thread. After all, the cpu cannot
stop dead (barring power management support), it has to execute some
code.

Another approach that will not work is the following:

    start = cyg_current_time()
    cyg_scheduler_lock()
    while ((start + 128) > cyg_current_time())
        ;
    cyg_scheduler_unlock()

This will not work because the counter returned by cyg_current_time()
is updated by a DSR associated with the clock interrupt. DSRs will
only run when the scheduler is unlocked, thus ensuring that kernel
calls from a DSR only happen when the system data structures are
consistent. If you use lower-level functionality such as
HAL_CLOCK_READ() you may be able to get it working.

Instead I would suggest using thread priorities:

    cyg_thread_set_priority(0)
    start = cyg_current_time()
    while ((start + 128) > cyg_current_time())
        ;
    cyg_thread_set_priority(old_pri)

This will work as long as there are no other threads running at the
highest priority - you may need to reorganize some thread priorities
to ensure this. Also there could be problems with mutexes: switching
thread priorities while owning a mutex is a bad idea; with the
priority inheritance/ceiling code also manipulating thread priorities,
things can get confused.

A big advantage of this approach is that it allows for more selective
blocking of threads, rather than pausing the entire processor for 128
ticks. All you need to do is pick a slightly lower priority. Higher
priority threads can still run during the 128 ticks, servicing I/O or
whatever. Lower priority threads are blocked.

Bart

-- 
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]